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