Added a parameter to semaphore constructor to avoid ambiguity
[pwlib.git] / src / ptclib / udp.cxx
blobdf8521a5689f12c53ef95ad733bb2c94f7903f5b
1 //
2 // stund/udp.cxx
3 //
4 // Copyright (c) 2002 Alan Hawrylyshen, Jason Fischl
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining
7 // a copy of this software and associated documentation files (the
8 // "Software"), to deal in the Software without restriction, including
9 // without limitation the rights to use, copy, modify, merge, publish,
10 // distribute, sublicense, and/or sell copies of the Software, and to
11 // permit persons to whom the Software is furnished to do so, subject to
12 // the following conditions:
13 //
14 // The above copyright notice and this permission notice shall be
15 // included in all copies or substantial portions of the Software.
16 //
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 // A portion of this code is taken from lbproxy, a part of VOCAL.
28 // http://www.vovida.org/vocal/
30 //
32 #ifndef _WIN32_WCE
33 #include <cassert>
34 #include <cstdio>
35 #include <cstring>
36 #include <errno.h>
37 #include <stdlib.h>
38 #else
39 #include <stdlibx.h>
40 #endif // !_WIN32_WCE
41 #include <time.h>
43 #if defined(__GNUC__) && __GNUC__ > 2
44 #include <iostream>
45 #else
46 #include <iostream.h>
47 #endif
49 #ifdef WIN32
51 #ifndef _WIN32_WCE
52 #include <winsock2.h>
53 #endif // !_WIN32_WCE
55 #include <stdlib.h>
56 #include <io.h>
58 #else
60 #include <arpa/inet.h>
61 #include <stdlib.h>
62 #include <unistd.h>
63 #include <fcntl.h>
64 #include <netinet/in.h>
65 #include <sys/socket.h>
66 #include <sys/types.h>
67 #include <netdb.h>
68 #include <string.h>
69 #include <unistd.h>
71 #endif
74 #include "string.h"
75 #include "udp.h"
78 void
79 parseHostName( char* peerName,
80 unsigned int* ip,
81 unsigned short* portVal,
82 unsigned int defaultPort )
84 in_addr sin_addr;
86 char host[512];
87 strncpy(host,peerName,512);
88 host[512-1]='\0';
89 char* port = NULL;
91 int portNum = defaultPort;
93 // pull out the port part if present.
94 char* sep = strchr(host,':');
96 if ( sep == NULL )
98 portNum = defaultPort;
100 else
102 *sep = '\0';
103 port = sep + 1;
104 // set port part
106 char* endPtr=NULL;
108 portNum = strtol(port,&endPtr,0);
110 if ( endPtr != NULL )
112 if ( *endPtr != '\0' )
114 portNum = defaultPort;
119 assert( portNum >= 1024 );
120 assert( portNum <= 65000 );
124 // figure out the host part
125 struct hostent* h;
127 h = gethostbyname( host );
128 if ( h == NULL )
130 *ip = ntohl( 0x7F000001L );
132 else
134 sin_addr = *(struct in_addr*)h->h_addr;
135 *ip = ntohl( sin_addr.s_addr );
138 *portVal = portNum;
142 Socket
143 openPort( unsigned short port, unsigned int interfaceIp )
145 Socket fd;
147 fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
148 if ( fd == INVALID_SOCKET )
150 //int err = errno;
151 //cerr << "Could not create a UDP socket:" << err << endl;
152 return INVALID_SOCKET;
155 #if 0
156 if ( port == 0 )
158 // just use an ephermieal port - no bind
159 return fd;
161 #endif
163 struct sockaddr_in addr;
164 memset((char*) &(addr),0, sizeof((addr)));
165 addr.sin_family = AF_INET;
166 addr.sin_addr.s_addr = htonl(INADDR_ANY);
167 addr.sin_port = htons(port);
169 if ( (interfaceIp != 0) &&
170 ( interfaceIp != 0x100007f ) )
172 addr.sin_addr.s_addr = htonl(interfaceIp);
175 if ( bind( fd,(struct sockaddr*)&addr, sizeof(addr)) != 0 )
177 int e = errno;
179 switch (e)
181 case EADDRINUSE:
183 //cerr << "Port " << port << " for receiving UDP is in use" << endl;
184 return INVALID_SOCKET;
186 break;
187 case EADDRNOTAVAIL:
189 //cerr << "Cannot assign requested address" << endl;
190 return INVALID_SOCKET;
192 break;
193 default:
195 //cerr << "Could not bind UDP receive port. Error=" << e << endl;
196 return INVALID_SOCKET;
198 break;
201 //clog << "Opened port " << port << " on fd " << fd << endl;
203 assert( fd != INVALID_SOCKET );
205 return fd;
209 bool
210 getMessage( Socket fd, char* buf, int* len,
211 unsigned int* srcIp, unsigned short* srcPort )
213 assert( fd != INVALID_SOCKET );
215 int originalSize = *len;
217 struct sockaddr_in from;
218 #if defined(P_MACOSX) || defined (__BEOS__)
219 int fromLen = sizeof(from);
220 #else
221 socklen_t fromLen = sizeof(from);
222 #endif
224 *len = recvfrom(fd,
225 buf,
226 *len,
228 (struct sockaddr *)&from,
229 &fromLen);
231 if ( *len == SOCKET_ERROR )
233 int err = errno;
235 switch (err)
237 case ENOTSOCK:
238 //cerr << "Error fd not a socket" << endl;
239 break;
240 default:
241 ;//cerr << "Error=" << err << endl;
244 return false;
247 if ( *len < 0 )
249 //clog << "socket closed?" << endl;
250 return false;
253 if ( *len == 0 )
255 //clog << "socket closed?" << endl;
256 return false;
259 *srcPort = ntohs(from.sin_port);
260 *srcIp = ntohl(from.sin_addr.s_addr);
262 if ( (*len)+1 >= originalSize )
264 //cerr << "Received a message that was too large" << endl;
265 return false;
267 buf[*len]=0;
269 return true;
273 bool
274 sendMessage( Socket fd, char* buf, int l,
275 unsigned int dstIp, unsigned short dstPort )
277 assert( fd != INVALID_SOCKET );
279 int s;
280 if ( dstPort == 0 )
282 // sending on a connected port
283 assert( dstIp == 0 );
285 s = send(fd,buf,l,0);
287 else
289 assert( dstIp != 0 );
290 assert( dstPort != 0 );
292 struct sockaddr_in to;
293 int toLen = sizeof(to);
294 memset(&to,0,toLen);
296 to.sin_family = AF_INET;
297 to.sin_port = htons(dstPort);
298 to.sin_addr.s_addr = htonl(dstIp);
300 s = sendto(fd, buf, l, 0,(sockaddr*)&to, toLen);
303 if ( s == SOCKET_ERROR )
305 int e = errno;
306 switch (e)
308 case ECONNREFUSED:
310 #ifndef __BEOS__
311 case EHOSTDOWN:
312 #endif
314 case EHOSTUNREACH:
316 // quietly ignore this
318 break;
319 case EAFNOSUPPORT:
321 //cerr << "err EAFNOSUPPORT in send" << endl;
323 break;
324 default:
326 //cerr << "err " << e << " " << strerror(e) << " in send" << endl;
329 return false;
332 if ( s == 0 )
334 //cerr << "no data sent in send" << endl;
335 return false;
338 if ( s != l )
340 //cerr << "only " << s << " out of " << l << " bytes sent" << endl;
341 return false;
344 return true;
348 void
349 initNetwork()
351 #ifdef WIN32
352 WORD wVersionRequested = MAKEWORD( 2, 2 );
353 WSADATA wsaData;
354 int err;
356 err = WSAStartup( wVersionRequested, &wsaData );
357 if ( err != 0 )
359 // could not find a usable WinSock DLL
360 //cerr << "Could not load winsock" << endl;
361 assert(0); // is this is failing, try a different version that 2.2, 1.0 or later will likely work
362 exit(1);
365 /* Confirm that the WinSock DLL supports 2.2.*/
366 /* Note that if the DLL supports versions greater */
367 /* than 2.2 in addition to 2.2, it will still return */
368 /* 2.2 in wVersion since that is the version we */
369 /* requested. */
371 if ( LOBYTE( wsaData.wVersion ) != 2 ||
372 HIBYTE( wsaData.wVersion ) != 2 )
374 /* Tell the user that we could not find a usable */
375 /* WinSock DLL. */
376 WSACleanup( );
377 //cerr << "Bad winsock verion" << endl;
378 assert(0); // is this is failing, try a different version that 2.2, 1.0 or later will likely work
379 exit(1);
381 #endif
385 // Local Variables:
386 // mode:c++
387 // c-file-style:"ellemtel"
388 // c-file-offsets:((case-label . +))
389 // indent-tabs-mode:nil
390 // End: