go home
[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 #define RND_DROP 10
18 #include <glog/logging.h>
19 #include "datagram.h"
20
21 namespace p2tp {
22
23 tint Datagram::now = Datagram::Time();
24 tint Datagram::epoch = now;
25 uint32_t Datagram::Address::LOCALHOST = INADDR_LOOPBACK;
26
27 char* Datagram::TimeStr (tint time) {
28     static char ret_str[128];
29     if (time==0)
30         time = now;
31     time -= epoch;
32     int hours = time/TINT_HOUR;
33     time %= TINT_HOUR;
34     int mins = time/TINT_MIN;
35     time %= TINT_MIN;
36     int secs = time/TINT_SEC;
37     time %= TINT_SEC;
38     int msecs = time/TINT_MSEC;
39     time %= TINT_MSEC;
40     int usecs = time/TINT_uSEC;
41     sprintf(ret_str,"%i_%02i_%02i_%03i_%03i",hours,mins,secs,msecs,usecs);
42     return ret_str;
43 }
44     
45 int Datagram::Send () {
46 #ifdef RND_DROP
47     if (rand()%RND_DROP==0) {
48         Time();
49         dprintf("%s datagram killed\n",TimeStr());
50         return size();
51     }
52 #endif
53         int r = sendto(sock,(const char *)buf+offset,length-offset,0,
54                                    (struct sockaddr*)&(addr.addr),sizeof(struct sockaddr_in));
55         //offset=0;
56         //length=0;
57         Time();
58         return r;
59 }
60
61 int Datagram::Recv () {
62         socklen_t addrlen = sizeof(struct sockaddr_in);
63         offset = 0;
64         length = recvfrom (sock, (char *)buf, MAXDGRAMSZ, 0,
65                                            (struct sockaddr*)&(addr), &addrlen);
66         if (length<0) // FIXME FIXME FIXME 
67 #ifdef _WIN32
68                 PLOG(ERROR)<<"on recv" << WSAGetLastError() << "\n";
69 #else
70                 PLOG(ERROR)<<"on recv";
71 #endif
72         Time();
73         return length;
74 }
75
76
77 SOCKET Datagram::Wait (int sockcnt, SOCKET* sockets, tint usec) {
78         dprintf("waiting (%i socks)\n",sockcnt);
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 #ifdef _WIN32
100                 PLOG(ERROR)<<"select fails" << WSAGetLastError() << "\n";
101 #else
102                 PLOG(ERROR)<<"select fails";
103 #endif
104     } 
105     return -1;
106 }
107
108 tint Datagram::Time () {
109         HiResTimeOfDay* tod = HiResTimeOfDay::Instance();
110         tint ret = tod->getTimeUSec();
111         //DLOG(INFO)<<"now is "<<ret;
112         return now=ret;
113 }
114
115 SOCKET Datagram::Bind (Address addr_) {
116     struct sockaddr_in addr = addr_;
117         SOCKET fd;
118         int len = sizeof(struct sockaddr_in), sndbuf=1<<20, rcvbuf=1<<20;
119         if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
120                 PLOG(ERROR)<<"socket fails";
121         return -1;
122     }
123 #ifdef _WIN32
124         u_long enable = 1;
125         ioctlsocket(fd, FIONBIO, &enable);
126         if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char *)&sndbuf, sizeof(int)) != 0 ) {
127         PLOG(ERROR)<<"setsockopt fails";
128         return -3;
129     }
130         if ( setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char *)&rcvbuf, sizeof(int)) != 0 ) {
131         PLOG(ERROR)<<"setsockopt2 fails";
132         return -3;
133     }
134 #else
135         if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
136                 return -2;
137         if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(int)) < 0 ) {
138         PLOG(ERROR)<<"setsockopt fails";
139         return -3;
140     }
141         if ( setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(int)) < 0 ) {
142         PLOG(ERROR)<<"setsockopt2 fails";
143         return -3;
144     }
145 #endif
146     printf("BUFS: %i %i\n",sndbuf,rcvbuf);
147     /*memset(&addr, 0, sizeof(struct sockaddr_in));
148         addr.sin_family = AF_INET;
149     addr.sin_port = htons(portno);
150     addr.sin_addr.s_addr = INADDR_ANY;*/
151         if (::bind(fd, (sockaddr*)&addr, len) != 0) {
152         PLOG(ERROR)<<"bind fails";
153         return -4;
154     }
155         return fd;
156 }
157
158 void Datagram::Close (int sock) { // remove from fd_set
159 #ifdef _WIN32
160         if (closesocket(sock)!=0)
161 #else
162         if (::close(sock)!=0)
163 #endif
164                 PLOG(ERROR)<<"on closing a socket";
165 }
166
167
168 std::string sock2str (struct sockaddr_in addr) {
169         char ipch[32];
170 #ifdef _WIN32
171         //Vista only: InetNtop(AF_INET,&(addr.sin_addr),ipch,32);
172         // IPv4 only:
173         struct in_addr inaddr;
174         memcpy(&inaddr, &(addr.sin_addr), sizeof(inaddr));
175         strncpy(ipch, inet_ntoa(inaddr),32);
176 #else
177         inet_ntop(AF_INET,&(addr.sin_addr),ipch,32);
178 #endif
179         sprintf(ipch+strlen(ipch),":%i",ntohs(addr.sin_port));
180         return std::string(ipch);
181 }
182
183 /*
184 std::string Datagram::to_string () const { // TODO: pretty-print P2TP
185         std::string addrs = sock2str(addr);
186         char hex[MAXDGRAMSZ*2];
187         for(int i=offset; i<length; i++)
188                 sprintf(hex+i*2,"%02x",buf[i]);
189         std::string hexs(hex+offset*2,(length-offset)*2);
190         return addrs + '\t' + hexs;
191 }*/
192
193 }