compat fixes
[swift-upb.git] / datagram.h
1 /*
2  *  datagram.h
3  *  nice IPv4 UDP wrappers
4  *
5  *  Created by Victor Grishchenko, Arno Bakker on 3/9/09.
6  *  Copyright 2009 Delft University of Technology. All rights reserved.
7  *
8  */
9 #ifndef DATAGRAM_H
10 #define DATAGRAM_H
11
12 #include <sys/stat.h>
13 #include <string.h>
14 #include "hashtree.h"
15 #include "compat.h"
16
17
18 namespace swift {
19
20 #define MAXDGRAMSZ 2800
21 #ifndef _WIN32
22 #define INVALID_SOCKET -1
23 #endif
24
25
26 /** IPv4 address, just a nice wrapping around struct sockaddr_in. */
27 struct Address {
28     struct sockaddr_in  addr;
29     static uint32_t LOCALHOST;
30     void set_port (uint16_t port) {
31         addr.sin_port = htons(port);
32     }
33     void set_port (const char* port_str) {
34         int p;
35         if (sscanf(port_str,"%i",&p))
36             set_port(p);
37     }
38     void set_ipv4 (uint32_t ipv4) {
39         addr.sin_addr.s_addr = htonl(ipv4);
40     }
41     void set_ipv4 (const char* ipv4_str) ;
42     //{    inet_aton(ipv4_str,&(addr.sin_addr));    }
43     void clear () {
44         memset(&addr,0,sizeof(struct sockaddr_in));
45         addr.sin_family = AF_INET;
46     }
47     Address() {
48         clear();
49     }
50     Address(const char* ip, uint16_t port)  {
51         clear();
52         set_ipv4(ip);
53         set_port(port);
54     }
55     Address(const char* ip_port);
56     Address(uint16_t port) {
57         clear();
58         set_ipv4((uint32_t)INADDR_ANY);
59         set_port(port);
60     }
61     Address(uint32_t ipv4addr, uint16_t port) {
62         clear();
63         set_ipv4(ipv4addr);
64         set_port(port);
65     }
66     Address(const struct sockaddr_in& address) : addr(address) {}
67     uint32_t ipv4 () const { return ntohl(addr.sin_addr.s_addr); }
68     uint16_t port () const { return ntohs(addr.sin_port); }
69     operator sockaddr_in () const {return addr;}
70     bool operator == (const Address& b) const {
71         return addr.sin_family==b.addr.sin_family &&
72         addr.sin_port==b.addr.sin_port &&
73         addr.sin_addr.s_addr==b.addr.sin_addr.s_addr;
74     }
75     const char* str () const {
76         static char rs[4][32];
77         static int i;
78         i = (i+1) & 3;
79         sprintf(rs[i],"%i.%i.%i.%i:%i",ipv4()>>24,(ipv4()>>16)&0xff,
80                 (ipv4()>>8)&0xff,ipv4()&0xff,port());
81         return rs[i];
82     }
83     bool operator != (const Address& b) const { return !(*this==b); }
84 };
85
86
87 typedef void (*sock_cb_t) (SOCKET);
88 struct socket_callbacks_t {
89     socket_callbacks_t (SOCKET s=0, sock_cb_t mr=NULL, sock_cb_t mw=NULL, sock_cb_t oe=NULL) :
90         sock(s), may_read(mr), may_write(mw), on_error(oe) {}
91     SOCKET sock;
92     sock_cb_t   may_read;
93     sock_cb_t   may_write;
94     sock_cb_t   on_error;
95 };
96
97
98 /** UDP datagram class, a nice wrapping around sendto/recvfrom/select. 
99     Reading/writing from/to a datagram is done in a FIFO (deque) fashion:
100     written data is appended to the tail (push) while read data is
101     taken from the "head" of the buffer. */
102 class Datagram {
103
104     Address addr;
105     SOCKET sock;
106     int offset, length;
107     uint8_t    buf[MAXDGRAMSZ*2];
108
109 public:
110
111     /** bind to the address */
112     static SOCKET Bind(Address address);
113
114     /** close the port */
115     static void Close(int port);
116
117     /** the current time */
118     static tint Time();
119
120     /** wait till one of the sockets has some io to do; usec is the timeout */
121     static void Wait (int sockcnt, socket_callbacks_t* sockets, tint usec=0);
122
123     static tint now, epoch, start;
124     static uint64_t dgrams_up, dgrams_down, bytes_up, bytes_down;
125
126     /** This constructor is normally used to SEND something to the address. */
127     Datagram (SOCKET socket, const Address addr_) : addr(addr_), offset(0),
128         length(0), sock(socket) {}
129     /** This constructor is normally used to RECEIVE something at the socket. */
130     Datagram (SOCKET socket) : offset(0), length(0), sock(socket) {
131     }
132
133     /** space remaining */
134     int space () const { return MAXDGRAMSZ-length; }
135     /** size of the data (not counting UDP etc headers) */
136     int size() const { return length-offset; }
137     std::string str() const { return std::string((char*)buf+offset,size()); }
138     const uint8_t* operator * () const { return buf+offset; }
139     const Address& address () const { return addr; }
140     /** Append some data at the back */
141     int Push (const uint8_t* data, int l) { // scatter-gather one day
142         int toc = l<space() ? l : space();
143         memcpy(buf+length,data,toc);
144         length += toc;
145         return toc;
146     }
147     /** Read something from the front of the datagram */
148     int Pull (uint8_t** data, int l) {
149         int toc = l<size() ? l : size();
150         //memcpy(data,buf+offset,toc);
151         *data = buf+offset;
152         offset += toc;
153         return toc;
154     }
155
156     int Send ();
157     int Recv ();
158
159     void Clear() { offset=length=0; }
160
161     void    PushString (std::string str) {
162         Push((uint8_t*)str.c_str(),str.size());
163     }
164     void    Push8 (uint8_t b) {
165         buf[length++] = b;
166     }
167     void    Push16 (uint16_t w) {
168         *(uint16_t*)(buf+length) = htons(w);
169         length+=2;
170     }
171     void    Push32 (uint32_t i) {
172         *(uint32_t*)(buf+length) = htonl(i);
173         length+=4;
174     }
175     void    Push64 (uint64_t l) {
176         *(uint32_t*)(buf+length) = htonl((uint32_t)(l>>32));
177         *(uint32_t*)(buf+length+4) = htonl((uint32_t)(l&0xffffffff));
178         length+=8;
179     }
180     void    PushHash (const Sha1Hash& hash) {
181         Push((uint8_t*)hash.bits, Sha1Hash::SIZE);
182     }
183
184     uint8_t    Pull8() {
185         if (size()<1) return 0;
186         return buf[offset++];
187     }
188     uint16_t Pull16() {
189         if (size()<2) return 0;
190         offset+=2;
191         return ntohs(*(uint16_t*)(buf+offset-2));
192     }
193     uint32_t Pull32() {
194         if (size()<4) return 0;
195         uint32_t i = ntohl(*(uint32_t*)(buf+offset));
196         offset+=4;
197         return i;
198     }
199     uint64_t Pull64() {
200         if (size()<8) return 0;
201         uint64_t l = ntohl(*(uint32_t*)(buf+offset));
202         l<<=32;
203         l |= ntohl(*(uint32_t*)(buf+offset+4));
204         offset+=8;
205         return l;
206     }
207     Sha1Hash PullHash() {
208         if (size()<Sha1Hash::SIZE) return Sha1Hash::ZERO;
209         offset += Sha1Hash::SIZE;
210         return Sha1Hash(false,(char*)buf+offset-Sha1Hash::SIZE);
211     }
212     //std::string    to_string () const ;
213
214 };
215
216 const char* tintstr(tint t=0);
217 std::string sock2str (struct sockaddr_in addr);
218
219 }
220
221 #endif