Replaced _MSC_VER with _WIN32 which will work on all windows compilers, not just...
[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 <glog/logging.h>
18 #include "datagram.h"
19
20 namespace p2tp {
21
22 tint Datagram::now = Datagram::Time();
23 uint32_t Datagram::Address::LOCALHOST = INADDR_LOOPBACK;
24
25 int Datagram::Send () {
26         int r = sendto(sock,(const char *)buf+offset,length-offset,0,
27                                    (struct sockaddr*)&(addr.addr),sizeof(struct sockaddr_in));
28         offset=0;
29         length=0;
30         now = Time();
31         return r;
32 }
33
34 int Datagram::Recv () {
35         socklen_t addrlen = sizeof(struct sockaddr_in);
36         offset = 0;
37         length = recvfrom (sock, (char *)buf, MAXDGRAMSZ, 0,
38                                            (struct sockaddr*)&(addr), &addrlen);
39         if (length<0)
40 #ifdef _WIN32
41                 PLOG(ERROR)<<"on recv" << WSAGetLastError() << "\n";
42 #else
43                 PLOG(ERROR)<<"on recv";
44 #endif
45         now = Time();
46         return length;
47 }
48
49
50 SOCKET Datagram::Wait (int sockcnt, SOCKET* sockets, tint usec) {
51         // ARNOTODO: LOG commented out, it causes a crash on win32 (in a strlen()
52         // done as part of a std::local::name() ??
53         //
54         //LOG(INFO)<<"waiting for "<<sockcnt;
55         struct timeval timeout;
56         timeout.tv_sec = usec/TINT_SEC;
57         timeout.tv_usec = usec%TINT_SEC;
58         int max_sock_fd = 0;
59         fd_set bases, err;
60         FD_ZERO(&bases);
61         FD_ZERO(&err);
62         for(int i=0; i<sockcnt; i++) {
63                 FD_SET(sockets[i],&bases);
64                 FD_SET(sockets[i],&err);
65                 if (sockets[i]>max_sock_fd)
66                         max_sock_fd = sockets[i];
67         }
68         int sel = select(max_sock_fd+1, &bases, NULL, &err, &timeout);
69         if (sel>0) {
70                 for (int i=0; i<=sockcnt; i++)
71                         if (FD_ISSET(sockets[i],&bases))
72                                 return sockets[i];
73         } else if (sel<0)
74 #ifdef _WIN32
75                 PLOG(ERROR)<<"select fails" << WSAGetLastError() << "\n";
76 #else
77                 PLOG(ERROR)<<"select fails";
78 #endif
79
80         // Arno: may return 0 when timeout expired
81         return sel;
82 }
83
84 tint Datagram::Time () {
85         HiResTimeOfDay* tod = HiResTimeOfDay::Instance();
86         tint ret = tod->getTimeUSec();
87         //DLOG(INFO)<<"now is "<<ret;
88         return now=ret;
89 }
90
91 SOCKET Datagram::Bind (Address addr_) {
92     struct sockaddr_in addr = addr_;
93         SOCKET fd;
94         int len = sizeof(struct sockaddr_in), sndbuf=1<<20, rcvbuf=1<<20;
95         if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
96                 PLOG(ERROR)<<"socket fails";
97         return -1;
98     }
99 #ifdef _WIN32
100         u_long enable = 1;
101         ioctlsocket(fd, FIONBIO, &enable);
102         if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char *)&sndbuf, sizeof(int)) != 0 ) {
103         PLOG(ERROR)<<"setsockopt fails";
104         return -3;
105     }
106         if ( setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char *)&rcvbuf, sizeof(int)) != 0 ) {
107         PLOG(ERROR)<<"setsockopt2 fails";
108         return -3;
109     }
110 #else
111         if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
112                 return -2;
113         if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(int)) < 0 ) {
114         PLOG(ERROR)<<"setsockopt fails";
115         return -3;
116     }
117         if ( setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(int)) < 0 ) {
118         PLOG(ERROR)<<"setsockopt2 fails";
119         return -3;
120     }
121 #endif
122     printf("BUFS: %i %i\n",sndbuf,rcvbuf);
123     /*memset(&addr, 0, sizeof(struct sockaddr_in));
124         addr.sin_family = AF_INET;
125     addr.sin_port = htons(portno);
126     addr.sin_addr.s_addr = INADDR_ANY;*/
127         if (::bind(fd, (sockaddr*)&addr, len) != 0) {
128         PLOG(ERROR)<<"bind fails";
129         return -4;
130     }
131         return fd;
132 }
133
134 void Datagram::Close (int sock) { // remove from fd_set
135 #ifdef _WIN32
136         if (closesocket(sock)!=0)
137 #else
138         if (::close(sock)!=0)
139 #endif
140                 PLOG(ERROR)<<"on closing a socket";
141 }
142
143
144 std::string sock2str (struct sockaddr_in addr) {
145         char ipch[32];
146 #ifdef _WIN32
147         //Vista only: InetNtop(AF_INET,&(addr.sin_addr),ipch,32);
148         // IPv4 only:
149         struct in_addr inaddr;
150         memcpy(&inaddr, &(addr.sin_addr), sizeof(inaddr));
151         strncpy(ipch, inet_ntoa(inaddr),32);
152 #else
153         inet_ntop(AF_INET,&(addr.sin_addr),ipch,32);
154 #endif
155         sprintf(ipch+strlen(ipch),":%i",ntohs(addr.sin_port));
156         return std::string(ipch);
157 }
158
159 /*
160 std::string Datagram::to_string () const { // TODO: pretty-print P2TP
161         std::string addrs = sock2str(addr);
162         char hex[MAXDGRAMSZ*2];
163         for(int i=offset; i<length; i++)
164                 sprintf(hex+i*2,"%02x",buf[i]);
165         std::string hexs(hex+offset*2,(length-offset)*2);
166         return addrs + '\t' + hexs;
167 }*/
168
169 }