add .gitignore
[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 (*sockcb_t) (SOCKET);
88 struct sckrwecb_t {
89     sckrwecb_t (SOCKET s=0, sockcb_t mr=NULL, sockcb_t mw=NULL, sockcb_t oe=NULL) :
90         sock(s), may_read(mr), may_write(mw), on_error(oe) {}
91     SOCKET sock;
92     sockcb_t   may_read;
93     sockcb_t   may_write;
94     sockcb_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 #define DGRAM_MAX_SOCK_OPEN 128
110     static int sock_count;
111     static sckrwecb_t sock_open[DGRAM_MAX_SOCK_OPEN];
112     
113 public:
114
115     /** bind to the address */
116     static SOCKET Bind(Address address, sckrwecb_t callbacks=sckrwecb_t());
117
118     /** close the port */
119     static void Close(SOCKET sock);
120
121     /** the current time */
122     static tint Time();
123
124     /** wait till one of the sockets has some io to do; usec is the timeout */
125     static SOCKET Wait (tint usec);
126     
127     static bool Listen3rdPartySocket (sckrwecb_t cb) ;
128     
129     static void Shutdown ();
130     
131     static SOCKET default_socket() 
132         { return sock_count ? sock_open[0].sock : INVALID_SOCKET; }
133
134     static tint now, epoch, start;
135     static uint64_t dgrams_up, dgrams_down, bytes_up, bytes_down;
136
137     /** This constructor is normally used to SEND something to the address. */
138     Datagram (SOCKET socket, const Address addr_) : addr(addr_), offset(0),
139         length(0), sock(socket) {}
140     /** This constructor is normally used to RECEIVE something at the socket. */
141     Datagram (SOCKET socket) : offset(0), length(0), sock(socket) {
142     }
143
144     /** space remaining */
145     int space () const { return MAXDGRAMSZ-length; }
146     /** size of the data (not counting UDP etc headers) */
147     int size() const { return length-offset; }
148     std::string str() const { return std::string((char*)buf+offset,size()); }
149     const uint8_t* operator * () const { return buf+offset; }
150     const Address& address () const { return addr; }
151     /** Append some data at the back */
152     int Push (const uint8_t* data, int l) { // scatter-gather one day
153         int toc = l<space() ? l : space();
154         memcpy(buf+length,data,toc);
155         length += toc;
156         return toc;
157     }
158     /** Read something from the front of the datagram */
159     int Pull (uint8_t** data, int l) {
160         int toc = l<size() ? l : size();
161         //memcpy(data,buf+offset,toc);
162         *data = buf+offset;
163         offset += toc;
164         return toc;
165     }
166
167     int Send ();
168     int Recv ();
169
170     void Clear() { offset=length=0; }
171
172     void    PushString (std::string str) {
173         Push((uint8_t*)str.c_str(),str.size());
174     }
175     void    Push8 (uint8_t b) {
176         buf[length++] = b;
177     }
178     void    Push16 (uint16_t w) {
179         *(uint16_t*)(buf+length) = htons(w);
180         length+=2;
181     }
182     void    Push32 (uint32_t i) {
183         *(uint32_t*)(buf+length) = htonl(i);
184         length+=4;
185     }
186     void    Push64 (uint64_t l) {
187         *(uint32_t*)(buf+length) = htonl((uint32_t)(l>>32));
188         *(uint32_t*)(buf+length+4) = htonl((uint32_t)(l&0xffffffff));
189         length+=8;
190     }
191     void    PushHash (const Sha1Hash& hash) {
192         Push((uint8_t*)hash.bits, Sha1Hash::SIZE);
193     }
194
195     uint8_t    Pull8() {
196         if (size()<1) return 0;
197         return buf[offset++];
198     }
199     uint16_t Pull16() {
200         if (size()<2) return 0;
201         offset+=2;
202         return ntohs(*(uint16_t*)(buf+offset-2));
203     }
204     uint32_t Pull32() {
205         if (size()<4) return 0;
206         uint32_t i = ntohl(*(uint32_t*)(buf+offset));
207         offset+=4;
208         return i;
209     }
210     uint64_t Pull64() {
211         if (size()<8) return 0;
212         uint64_t l = ntohl(*(uint32_t*)(buf+offset));
213         l<<=32;
214         l |= ntohl(*(uint32_t*)(buf+offset+4));
215         offset+=8;
216         return l;
217     }
218     Sha1Hash PullHash() {
219         if (size()<Sha1Hash::SIZE) return Sha1Hash::ZERO;
220         offset += Sha1Hash::SIZE;
221         return Sha1Hash(false,(char*)buf+offset-Sha1Hash::SIZE);
222     }
223     //std::string    to_string () const ;
224
225 };
226
227 const char* tintstr(tint t=0);
228 std::string sock2str (struct sockaddr_in addr);
229
230 }
231
232 #endif