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