add .gitignore
[swift-upb.git] / datagram.cpp
1 /*
2  *  datagram.cpp
3  *  serp++
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 #include <iostream>
10
11 #ifdef _WIN32
12     #include <winsock2.h>
13     typedef int socklen_t;
14 #else
15     #include <arpa/inet.h>
16     #include <netdb.h>
17 #endif
18
19 #include "datagram.h"
20 #include "compat.h"
21
22 namespace swift {
23
24 tint Datagram::now = Datagram::Time();
25 tint Datagram::start = now;
26 tint Datagram::epoch = now/360000000LL*360000000LL; // make logs mergeable
27 uint32_t Address::LOCALHOST = INADDR_LOOPBACK;
28 uint64_t Datagram::dgrams_up=0, Datagram::dgrams_down=0,
29          Datagram::bytes_up=0, Datagram::bytes_down=0;
30 sckrwecb_t Datagram::sock_open[] = {};
31 int Datagram::sock_count = 0;
32
33 const char* tintstr (tint time) {
34     if (time==0)
35         time = Datagram::now;
36     static char ret_str[4][32]; // wow
37     static int i;
38     i = (i+1) & 3;
39     if (time==TINT_NEVER)
40         return "NEVER";
41     time -= Datagram::epoch;
42     assert(time>=0);
43     int hours = time/TINT_HOUR;
44     time %= TINT_HOUR;
45     int mins = time/TINT_MIN;
46     time %= TINT_MIN;
47     int secs = time/TINT_SEC;
48     time %= TINT_SEC;
49     int msecs = time/TINT_MSEC;
50     time %= TINT_MSEC;
51     int usecs = time/TINT_uSEC;
52     sprintf(ret_str[i],"%i_%02i_%02i_%03i_%03i",hours,mins,secs,msecs,usecs);
53     return ret_str[i];
54 }
55
56 void Address::set_ipv4 (const char* ip_str) {
57     struct hostent *h = gethostbyname(ip_str);
58     if (h == NULL) {
59         print_error("cannot lookup address");
60         return;
61     } else {
62         addr.sin_addr.s_addr = *(u_long *) h->h_addr_list[0];
63     }
64 }
65
66
67 Address::Address(const char* ip_port) {
68     clear();
69     if (strlen(ip_port)>=1024)
70         return;
71     char ipp[1024];
72     strncpy(ipp,ip_port,1024);
73     char* semi = strchr(ipp,':');
74     if (semi) {
75         *semi = 0;
76         set_ipv4(ipp);
77         set_port(semi+1);
78     } else {
79         if (strchr(ipp, '.')) {
80             set_ipv4(ipp);
81             set_port((uint16_t)0);
82         } else {
83             set_ipv4(INADDR_LOOPBACK);
84             set_port(ipp);
85         }
86     }
87 }
88
89     
90 bool    Datagram::Listen3rdPartySocket (sckrwecb_t cb) {
91     int i=0;
92     while (i<sock_count && sock_open[i].sock!=cb.sock) i++;
93     if (i==sock_count)
94         if (i==DGRAM_MAX_SOCK_OPEN)
95             return false;
96         else
97             sock_count++;
98     sock_open[i]=cb;
99     //if (!cb.may_read && !cb.may_write && !cb.on_error)
100     //    sock_open[i] = sock_open[--sock_count];
101     return true;
102 }
103
104     
105 void Datagram::Shutdown () {
106     while (sock_count--)
107         Close(sock_open[sock_count].sock);
108 }
109     
110
111 int Datagram::Send () {
112     int r = sendto(sock,(const char *)buf+offset,length-offset,0,
113                    (struct sockaddr*)&(addr.addr),sizeof(struct sockaddr_in));
114     if (r<0)
115         perror("can't send");
116     dgrams_up++;
117     bytes_up+=size();
118     offset=0;
119     length=0;
120     Time();
121     return r;
122 }
123
124 int Datagram::Recv () {
125     socklen_t addrlen = sizeof(struct sockaddr_in);
126     offset = 0;
127     length = recvfrom (sock, (char *)buf, MAXDGRAMSZ*2, 0,
128                        (struct sockaddr*)&(addr.addr), &addrlen);
129     if (length<0) {
130         length = 0;
131         print_error("error on recv");
132     }
133     dgrams_down++;
134     bytes_down+=length;
135     Time();
136     return length;
137 }
138
139
140 SOCKET Datagram::Wait (tint usec) {
141     struct timeval timeout;
142     timeout.tv_sec = usec/TINT_SEC;
143     timeout.tv_usec = usec%TINT_SEC;
144     int max_sock_fd = 0;
145     fd_set rdfd, wrfd, errfd;
146     FD_ZERO(&rdfd);
147     FD_ZERO(&wrfd);
148     FD_ZERO(&errfd);
149     for(int i=0; i<sock_count; i++) {
150         if (sock_open[i].may_read!=0)
151             FD_SET(sock_open[i].sock,&rdfd);
152         if (sock_open[i].may_write!=0)
153             FD_SET(sock_open[i].sock,&wrfd);
154         if (sock_open[i].on_error!=0)
155             FD_SET(sock_open[i].sock,&errfd);
156         if (sock_open[i].sock>max_sock_fd)
157             max_sock_fd = sock_open[i].sock;
158     }
159     SOCKET sel = select(max_sock_fd+1, &rdfd, &wrfd, &errfd, &timeout);
160     Time();
161     if (sel>0) {
162         for (int i=0; i<=sock_count; i++) {
163             sckrwecb_t& sct = sock_open[i];
164             if (sct.may_read && FD_ISSET(sct.sock,&rdfd))
165                 (*(sct.may_read))(sct.sock);
166             if (sct.may_write && FD_ISSET(sct.sock,&wrfd))
167                 (*(sct.may_write))(sct.sock);
168             if (sct.on_error && FD_ISSET(sct.sock,&errfd))
169                 (*(sct.on_error))(sct.sock);
170         }
171     } else if (sel<0) {
172         print_error("select fails");
173     }
174     return sel;
175 }
176
177 tint Datagram::Time () {
178     //HiResTimeOfDay* tod = HiResTimeOfDay::Instance();
179     //tint ret = tod->getTimeUSec();
180     //DLOG(INFO)<<"now is "<<ret;
181     return now = usec_time();
182 }
183
184 SOCKET Datagram::Bind (Address address, sckrwecb_t callbacks) {
185     struct sockaddr_in addr = address;
186     SOCKET fd;
187     int len = sizeof(struct sockaddr_in), sndbuf=1<<20, rcvbuf=1<<20;
188     #define dbnd_ensure(x) { if (!(x)) { \
189         print_error("binding fails"); close_socket(fd); return INVALID_SOCKET; } }
190     dbnd_ensure ( (fd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0 );
191     dbnd_ensure( make_socket_nonblocking(fd) );  // FIXME may remove this
192     int enable = true;
193     dbnd_ensure ( setsockopt(fd, SOL_SOCKET, SO_SNDBUF, 
194                              (setsockoptptr_t)&sndbuf, sizeof(int)) == 0 );
195     dbnd_ensure ( setsockopt(fd, SOL_SOCKET, SO_RCVBUF, 
196                              (setsockoptptr_t)&rcvbuf, sizeof(int)) == 0 );
197     //setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (setsockoptptr_t)&enable, sizeof(int));
198     dbnd_ensure ( ::bind(fd, (sockaddr*)&addr, len) == 0 );
199     callbacks.sock = fd;
200     Datagram::sock_open[Datagram::sock_count++] = callbacks;
201     return fd;
202 }
203
204 void Datagram::Close (SOCKET sock) {
205     for(int i=0; i<Datagram::sock_count; i++)
206         if (Datagram::sock_open[i].sock==sock)
207             Datagram::sock_open[i] = Datagram::sock_open[--Datagram::sock_count];
208     if (!close_socket(sock))
209         print_error("on closing a socket");
210 }
211
212
213 std::string sock2str (struct sockaddr_in addr) {
214     char ipch[32];
215 #ifdef _WIN32
216     //Vista only: InetNtop(AF_INET,&(addr.sin_addr),ipch,32);
217     // IPv4 only:
218     struct in_addr inaddr;
219     memcpy(&inaddr, &(addr.sin_addr), sizeof(inaddr));
220     strncpy(ipch, inet_ntoa(inaddr),32);
221 #else
222     inet_ntop(AF_INET,&(addr.sin_addr),ipch,32);
223 #endif
224     sprintf(ipch+strlen(ipch),":%i",ntohs(addr.sin_port));
225     return std::string(ipch);
226 }
227
228 /*
229 std::string Datagram::to_string () const { // TODO: pretty-print swift
230     std::string addrs = sock2str(addr);
231     char hex[MAXDGRAMSZ*2];
232     for(int i=offset; i<length; i++)
233         sprintf(hex+i*2,"%02x",buf[i]);
234     std::string hexs(hex+offset*2,(length-offset)*2);
235     return addrs + '\t' + hexs;
236 }*/
237
238 }