it even compiles
[swift-upb.git] / datagram.cpp
1 /*
2  *  datagram.cpp
3  *  serp++
4  *
5  *  Created by Victor Grishchenko 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 #endif
17 #include "datagram.h"
18
19 namespace p2tp {
20
21 tint Datagram::now = Datagram::Time();
22 tint Datagram::epoch = now;
23 uint32_t Address::LOCALHOST = INADDR_LOOPBACK;
24 uint64_t Datagram::dgrams_up=0, Datagram::dgrams_down=0, 
25          Datagram::bytes_up=0, Datagram::bytes_down=0;
26
27 char* Datagram::TimeStr (tint time) {
28     assert(!time || time>=epoch);
29     static char ret_str[4][32]; // wow
30     static int i;
31     i = (i+1) & 3;
32     if (time==0)
33         time = now;
34     time -= epoch;
35     assert(time>=0);
36     int hours = time/TINT_HOUR;
37     time %= TINT_HOUR;
38     int mins = time/TINT_MIN;
39     time %= TINT_MIN;
40     int secs = time/TINT_SEC;
41     time %= TINT_SEC;
42     int msecs = time/TINT_MSEC;
43     time %= TINT_MSEC;
44     int usecs = time/TINT_uSEC;
45     sprintf(ret_str[i],"%i_%02i_%02i_%03i_%03i",hours,mins,secs,msecs,usecs);
46     return ret_str[i];
47 }
48     
49 int Datagram::Send () {
50         int r = sendto(sock,(const char *)buf+offset,length-offset,0,
51                                    (struct sockaddr*)&(addr.addr),sizeof(struct sockaddr_in));
52     if (r<0)
53         perror("can't send");
54         //offset=0;
55         //length=0;
56     dgrams_up++;
57     bytes_up+=size();
58         Time();
59         return r;
60 }
61
62 int Datagram::Recv () {
63         socklen_t addrlen = sizeof(struct sockaddr_in);
64         offset = 0;
65         length = recvfrom (sock, (char *)buf, MAXDGRAMSZ, 0,
66                                            (struct sockaddr*)&(addr), &addrlen);
67         if (length<0) {
68         length = 0;
69         print_error("error on recv");
70     }
71     dgrams_down++;
72     bytes_down+=length;
73         Time();
74         return length;
75 }
76
77
78 SOCKET Datagram::Wait (int sockcnt, SOCKET* sockets, tint usec) {
79         struct timeval timeout;
80         timeout.tv_sec = usec/TINT_SEC;
81         timeout.tv_usec = usec%TINT_SEC;
82         int max_sock_fd = 0;
83         fd_set bases, err;
84         FD_ZERO(&bases);
85         FD_ZERO(&err);
86         for(int i=0; i<sockcnt; i++) {
87                 FD_SET(sockets[i],&bases);
88                 FD_SET(sockets[i],&err);
89                 if (sockets[i]>max_sock_fd)
90                         max_sock_fd = sockets[i];
91         }
92         int sel = select(max_sock_fd+1, &bases, NULL, &err, &timeout);
93     Time();
94         if (sel>0) {
95                 for (int i=0; i<=sockcnt; i++)
96                         if (FD_ISSET(sockets[i],&bases))
97                                 return sockets[i];
98         } else if (sel<0) {
99                 print_error("select fails");
100     } 
101     return INVALID_SOCKET;
102 }
103
104 tint Datagram::Time () {
105         HiResTimeOfDay* tod = HiResTimeOfDay::Instance();
106         tint ret = tod->getTimeUSec();
107         //DLOG(INFO)<<"now is "<<ret;
108         return now=ret;
109 }
110
111 SOCKET Datagram::Bind (Address addr_) {
112     struct sockaddr_in addr = addr_;
113         SOCKET fd;
114         int len = sizeof(struct sockaddr_in), sndbuf=1<<20, rcvbuf=1<<20;
115         if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
116                 print_error("socket() fails");
117         return INVALID_SOCKET;
118     }
119 #ifdef _WIN32
120         u_long enable = 1;
121         ioctlsocket(fd, FIONBIO, &enable);
122         if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char *)&sndbuf, sizeof(int)) != 0 ) {
123         print_error("setsockopt fails");
124         return INVALID_SOCKET;
125     }
126         if ( setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char *)&rcvbuf, sizeof(int)) != 0 ) {
127         print_error("setsockopt2 fails");
128         return INVALID_SOCKET;
129     }
130 #else
131         if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
132                 return INVALID_SOCKET;
133         if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(int)) < 0 ) {
134         print_error("setsockopt fails");
135         return INVALID_SOCKET;
136     }
137         if ( setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(int)) < 0 ) {
138         print_error("setsockopt2 fails");
139         return INVALID_SOCKET;
140     }
141 #endif
142     dprintf("socket buffers: %i send %i recv\n",sndbuf,rcvbuf);
143         if (::bind(fd, (sockaddr*)&addr, len) != 0) {
144         print_error("bind fails");
145         return INVALID_SOCKET;
146     }
147         return fd;
148 }
149
150 void Datagram::Close (int sock) { // remove from fd_set
151 #ifdef _WIN32
152         if (closesocket(sock)!=0)
153 #else
154         if (::close(sock)!=0)
155 #endif
156                 print_error("on closing a socket");
157 }
158
159
160 std::string sock2str (struct sockaddr_in addr) {
161         char ipch[32];
162 #ifdef _WIN32
163         //Vista only: InetNtop(AF_INET,&(addr.sin_addr),ipch,32);
164         // IPv4 only:
165         struct in_addr inaddr;
166         memcpy(&inaddr, &(addr.sin_addr), sizeof(inaddr));
167         strncpy(ipch, inet_ntoa(inaddr),32);
168 #else
169         inet_ntop(AF_INET,&(addr.sin_addr),ipch,32);
170 #endif
171         sprintf(ipch+strlen(ipch),":%i",ntohs(addr.sin_port));
172         return std::string(ipch);
173 }
174
175 /*
176 std::string Datagram::to_string () const { // TODO: pretty-print P2TP
177         std::string addrs = sock2str(addr);
178         char hex[MAXDGRAMSZ*2];
179         for(int i=offset; i<length; i++)
180                 sprintf(hex+i*2,"%02x",buf[i]);
181         std::string hexs(hex+offset*2,(length-offset)*2);
182         return addrs + '\t' + hexs;
183 }*/
184
185 }