116b495af418462f2fc4ed74178e200f9903e5cc
[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
31 const char* tintstr (tint time) {
32     if (time==0)
33         time = Datagram::now;
34     static char ret_str[4][32]; // wow
35     static int i;
36     i = (i+1) & 3;
37     if (time==TINT_NEVER)
38         return "NEVER";
39     time -= Datagram::epoch;
40     assert(time>=0);
41     int hours = time/TINT_HOUR;
42     time %= TINT_HOUR;
43     int mins = time/TINT_MIN;
44     time %= TINT_MIN;
45     int secs = time/TINT_SEC;
46     time %= TINT_SEC;
47     int msecs = time/TINT_MSEC;
48     time %= TINT_MSEC;
49     int usecs = time/TINT_uSEC;
50     sprintf(ret_str[i],"%i_%02i_%02i_%03i_%03i",hours,mins,secs,msecs,usecs);
51     return ret_str[i];
52 }
53
54 void Address::set_ipv4 (const char* ip_str) {
55     struct hostent *h = gethostbyname(ip_str);
56     if (h == NULL) {
57         print_error("cannot lookup address");
58         return;
59     } else {
60         addr.sin_addr.s_addr = *(u_long *) h->h_addr_list[0];
61     }
62 }
63
64
65 Address::Address(const char* ip_port) {
66     clear();
67     if (strlen(ip_port)>=1024)
68         return;
69     char ipp[1024];
70     strncpy(ipp,ip_port,1024);
71     char* semi = strchr(ipp,':');
72     if (semi) {
73         *semi = 0;
74         set_ipv4(ipp);
75         set_port(semi+1);
76     } else {
77         if (strchr(ipp, '.')) {
78             set_ipv4(ipp);
79             set_port((uint16_t)0);
80         } else {
81             set_ipv4(INADDR_LOOPBACK);
82             set_port(ipp);
83         }
84     }
85 }
86
87
88 int Datagram::Send () {
89     int r = sendto(sock,(const char *)buf+offset,length-offset,0,
90                    (struct sockaddr*)&(addr.addr),sizeof(struct sockaddr_in));
91     if (r<0)
92         perror("can't send");
93     dgrams_up++;
94     bytes_up+=size();
95         offset=0;
96         length=0;
97         Time();
98         return r;
99 }
100
101 int Datagram::Recv () {
102     socklen_t addrlen = sizeof(struct sockaddr_in);
103     offset = 0;
104     length = recvfrom (sock, (char *)buf, MAXDGRAMSZ, 0,
105                        (struct sockaddr*)&(addr.addr), &addrlen);
106     if (length<0) {
107         length = 0;
108         print_error("error on recv");
109     }
110     dgrams_down++;
111     bytes_down+=length;
112     Time();
113     return length;
114 }
115
116
117 SOCKET Datagram::Wait (int sockcnt, SOCKET* sockets, tint usec) {
118     struct timeval timeout;
119     timeout.tv_sec = usec/TINT_SEC;
120     timeout.tv_usec = usec%TINT_SEC;
121     int max_sock_fd = 0;
122     fd_set bases, err;
123     FD_ZERO(&bases);
124     FD_ZERO(&err);
125     for(int i=0; i<sockcnt; i++) {
126         FD_SET(sockets[i],&bases);
127         FD_SET(sockets[i],&err);
128         if (sockets[i]>max_sock_fd)
129             max_sock_fd = sockets[i];
130     }
131     int sel = select(max_sock_fd+1, &bases, NULL, &err, &timeout);
132     Time();
133     if (sel>0) {
134         for (int i=0; i<=sockcnt; i++)
135             if (FD_ISSET(sockets[i],&bases))
136                 return sockets[i];
137     } else if (sel<0) {
138         print_error("select fails");
139     }
140     return INVALID_SOCKET;
141 }
142
143 tint Datagram::Time () {
144     //HiResTimeOfDay* tod = HiResTimeOfDay::Instance();
145     //tint ret = tod->getTimeUSec();
146     //DLOG(INFO)<<"now is "<<ret;
147     return now = usec_time();
148 }
149
150 SOCKET Datagram::Bind (Address addr_) {
151     struct sockaddr_in addr = addr_;
152     SOCKET fd;
153     int len = sizeof(struct sockaddr_in), sndbuf=1<<20, rcvbuf=1<<20;
154     if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
155         print_error("socket() fails");
156         return INVALID_SOCKET;
157     }
158 #ifdef _WIN32
159     u_long enable = 1;
160     ioctlsocket(fd, FIONBIO, &enable);
161     if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char *)&sndbuf, sizeof(int)) != 0 ) {
162         print_error("setsockopt fails");
163         return INVALID_SOCKET;
164     }
165        if ( setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char *)&rcvbuf, sizeof(int)) != 0 ) {
166         print_error("setsockopt2 fails");
167         return INVALID_SOCKET;
168     }
169     setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&enable, sizeof(int));
170 #else
171     int enable=1;
172     if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
173         return INVALID_SOCKET;
174     if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(int)) < 0 ) {
175         print_error("setsockopt fails");
176         return INVALID_SOCKET;
177     }
178        if ( setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(int)) < 0 ) {
179         print_error("setsockopt2 fails");
180         return INVALID_SOCKET;
181     }
182     setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
183 #endif
184     dprintf("socket buffers: %i send %i recv\n",sndbuf,rcvbuf);
185     if (::bind(fd, (sockaddr*)&addr, len) != 0) {
186         print_error("bind fails");
187         return INVALID_SOCKET;
188     }
189     return fd;
190 }
191
192 void Datagram::Close (int sock) { // remove from fd_set
193 #ifdef _WIN32
194     if (closesocket(sock)!=0)
195 #else
196     if (::close(sock)!=0)
197 #endif
198         print_error("on closing a socket");
199 }
200
201
202 std::string sock2str (struct sockaddr_in addr) {
203     char ipch[32];
204 #ifdef _WIN32
205     //Vista only: InetNtop(AF_INET,&(addr.sin_addr),ipch,32);
206     // IPv4 only:
207     struct in_addr inaddr;
208     memcpy(&inaddr, &(addr.sin_addr), sizeof(inaddr));
209     strncpy(ipch, inet_ntoa(inaddr),32);
210 #else
211     inet_ntop(AF_INET,&(addr.sin_addr),ipch,32);
212 #endif
213     sprintf(ipch+strlen(ipch),":%i",ntohs(addr.sin_port));
214     return std::string(ipch);
215 }
216
217 /*
218 std::string Datagram::to_string () const { // TODO: pretty-print swift
219     std::string addrs = sock2str(addr);
220     char hex[MAXDGRAMSZ*2];
221     for(int i=offset; i<length; i++)
222         sprintf(hex+i*2,"%02x",buf[i]);
223     std::string hexs(hex+offset*2,(length-offset)*2);
224     return addrs + '\t' + hexs;
225 }*/
226
227 }