source: trunk/synergy/lib/arch/CArchNetworkWinsock.cpp

Last change on this file was 2749, checked in by bird, 19 years ago

synergy v1.3.1 sources (zip).

File size: 24.4 KB
Line 
1/*
2 * synergy -- mouse and keyboard sharing utility
3 * Copyright (C) 2002 Chris Schoeneman
4 *
5 * This package is free software you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * found in the file COPYING that should have accompanied this file.
8 *
9 * This package is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15
16#include "CArchNetworkWinsock.h"
17#include "CArch.h"
18#include "CArchMultithreadWindows.h"
19#include "IArchMultithread.h"
20#include "XArchWindows.h"
21#include <malloc.h>
22
23static const int s_family[] = {
24 PF_UNSPEC,
25 PF_INET
26};
27static const int s_type[] = {
28 SOCK_DGRAM,
29 SOCK_STREAM
30};
31
32static SOCKET (PASCAL FAR *accept_winsock)(SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen);
33static int (PASCAL FAR *bind_winsock)(SOCKET s, const struct sockaddr FAR *addr, int namelen);
34static int (PASCAL FAR *close_winsock)(SOCKET s);
35static int (PASCAL FAR *connect_winsock)(SOCKET s, const struct sockaddr FAR *name, int namelen);
36static int (PASCAL FAR *gethostname_winsock)(char FAR * name, int namelen);
37static int (PASCAL FAR *getsockerror_winsock)(void);
38static int (PASCAL FAR *getsockopt_winsock)(SOCKET s, int level, int optname, void FAR * optval, int FAR *optlen);
39static u_short (PASCAL FAR *htons_winsock)(u_short v);
40static char FAR * (PASCAL FAR *inet_ntoa_winsock)(struct in_addr in);
41static unsigned long (PASCAL FAR *inet_addr_winsock)(const char FAR * cp);
42static int (PASCAL FAR *ioctl_winsock)(SOCKET s, int cmd, void FAR * data);
43static int (PASCAL FAR *listen_winsock)(SOCKET s, int backlog);
44static u_short (PASCAL FAR *ntohs_winsock)(u_short v);
45static int (PASCAL FAR *recv_winsock)(SOCKET s, void FAR * buf, int len, int flags);
46static int (PASCAL FAR *select_winsock)(int nfds, fd_set FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout);
47static int (PASCAL FAR *send_winsock)(SOCKET s, const void FAR * buf, int len, int flags);
48static int (PASCAL FAR *setsockopt_winsock)(SOCKET s, int level, int optname, const void FAR * optval, int optlen);
49static int (PASCAL FAR *shutdown_winsock)(SOCKET s, int how);
50static SOCKET (PASCAL FAR *socket_winsock)(int af, int type, int protocol);
51static struct hostent FAR * (PASCAL FAR *gethostbyaddr_winsock)(const char FAR * addr, int len, int type);
52static struct hostent FAR * (PASCAL FAR *gethostbyname_winsock)(const char FAR * name);
53static int (PASCAL FAR *WSACleanup_winsock)(void);
54static int (PASCAL FAR *WSAFDIsSet_winsock)(SOCKET, fd_set FAR * fdset);
55static WSAEVENT (PASCAL FAR *WSACreateEvent_winsock)(void);
56static BOOL (PASCAL FAR *WSACloseEvent_winsock)(WSAEVENT);
57static BOOL (PASCAL FAR *WSASetEvent_winsock)(WSAEVENT);
58static BOOL (PASCAL FAR *WSAResetEvent_winsock)(WSAEVENT);
59static int (PASCAL FAR *WSAEventSelect_winsock)(SOCKET, WSAEVENT, long);
60static DWORD (PASCAL FAR *WSAWaitForMultipleEvents_winsock)(DWORD, const WSAEVENT FAR*, BOOL, DWORD, BOOL);
61static int (PASCAL FAR *WSAEnumNetworkEvents_winsock)(SOCKET, WSAEVENT, LPWSANETWORKEVENTS);
62
63#undef FD_ISSET
64#define FD_ISSET(fd, set) WSAFDIsSet_winsock((SOCKET)(fd), (fd_set FAR *)(set))
65
66#define setfunc(var, name, type) var = (type)netGetProcAddress(module, #name)
67
68static HMODULE s_networkModule = NULL;
69
70static
71FARPROC
72netGetProcAddress(HMODULE module, LPCSTR name)
73{
74 FARPROC func = ::GetProcAddress(module, name);
75 if (!func) {
76 throw XArchNetworkSupport("");
77 }
78 return func;
79}
80
81CArchNetAddressImpl*
82CArchNetAddressImpl::alloc(size_t size)
83{
84 size_t totalSize = size + ADDR_HDR_SIZE;
85 CArchNetAddressImpl* addr = (CArchNetAddressImpl*)malloc(totalSize);
86 addr->m_len = size;
87 return addr;
88}
89
90
91//
92// CArchNetworkWinsock
93//
94
95CArchNetworkWinsock::CArchNetworkWinsock()
96{
97 static const char* s_library[] = { "ws2_32.dll" };
98
99 assert(WSACleanup_winsock == NULL);
100 assert(s_networkModule == NULL);
101
102 // try each winsock library
103 for (size_t i = 0; i < sizeof(s_library) / sizeof(s_library[0]); ++i) {
104 try {
105 init((HMODULE)::LoadLibrary(s_library[i]));
106 m_mutex = ARCH->newMutex();
107 return;
108 }
109 catch (XArchNetwork&) {
110 // ignore
111 }
112 }
113
114 // can't initialize any library
115 throw XArchNetworkSupport("Cannot load winsock library");
116}
117
118CArchNetworkWinsock::~CArchNetworkWinsock()
119{
120 if (s_networkModule != NULL) {
121 WSACleanup_winsock();
122 ::FreeLibrary(s_networkModule);
123
124 WSACleanup_winsock = NULL;
125 s_networkModule = NULL;
126 }
127 ARCH->closeMutex(m_mutex);
128}
129
130void
131CArchNetworkWinsock::init(HMODULE module)
132{
133 if (module == NULL) {
134 throw XArchNetworkSupport("");
135 }
136
137 // get startup function address
138 int (PASCAL FAR *startup)(WORD, LPWSADATA);
139 setfunc(startup, WSAStartup, int(PASCAL FAR*)(WORD, LPWSADATA));
140
141 // startup network library
142 WORD version = MAKEWORD(2 /*major*/, 0 /*minor*/);
143 WSADATA data;
144 int err = startup(version, &data);
145 if (data.wVersion != version) {
146 throw XArchNetworkSupport(new XArchEvalWinsock(err));
147 }
148 if (err != 0) {
149 // some other initialization error
150 throwError(err);
151 }
152
153 // get function addresses
154 setfunc(accept_winsock, accept, SOCKET (PASCAL FAR *)(SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen));
155 setfunc(bind_winsock, bind, int (PASCAL FAR *)(SOCKET s, const struct sockaddr FAR *addr, int namelen));
156 setfunc(close_winsock, closesocket, int (PASCAL FAR *)(SOCKET s));
157 setfunc(connect_winsock, connect, int (PASCAL FAR *)(SOCKET s, const struct sockaddr FAR *name, int namelen));
158 setfunc(gethostname_winsock, gethostname, int (PASCAL FAR *)(char FAR * name, int namelen));
159 setfunc(getsockerror_winsock, WSAGetLastError, int (PASCAL FAR *)(void));
160 setfunc(getsockopt_winsock, getsockopt, int (PASCAL FAR *)(SOCKET s, int level, int optname, void FAR * optval, int FAR *optlen));
161 setfunc(htons_winsock, htons, u_short (PASCAL FAR *)(u_short v));
162 setfunc(inet_ntoa_winsock, inet_ntoa, char FAR * (PASCAL FAR *)(struct in_addr in));
163 setfunc(inet_addr_winsock, inet_addr, unsigned long (PASCAL FAR *)(const char FAR * cp));
164 setfunc(ioctl_winsock, ioctlsocket, int (PASCAL FAR *)(SOCKET s, int cmd, void FAR *));
165 setfunc(listen_winsock, listen, int (PASCAL FAR *)(SOCKET s, int backlog));
166 setfunc(ntohs_winsock, ntohs, u_short (PASCAL FAR *)(u_short v));
167 setfunc(recv_winsock, recv, int (PASCAL FAR *)(SOCKET s, void FAR * buf, int len, int flags));
168 setfunc(select_winsock, select, int (PASCAL FAR *)(int nfds, fd_set FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout));
169 setfunc(send_winsock, send, int (PASCAL FAR *)(SOCKET s, const void FAR * buf, int len, int flags));
170 setfunc(setsockopt_winsock, setsockopt, int (PASCAL FAR *)(SOCKET s, int level, int optname, const void FAR * optval, int optlen));
171 setfunc(shutdown_winsock, shutdown, int (PASCAL FAR *)(SOCKET s, int how));
172 setfunc(socket_winsock, socket, SOCKET (PASCAL FAR *)(int af, int type, int protocol));
173 setfunc(gethostbyaddr_winsock, gethostbyaddr, struct hostent FAR * (PASCAL FAR *)(const char FAR * addr, int len, int type));
174 setfunc(gethostbyname_winsock, gethostbyname, struct hostent FAR * (PASCAL FAR *)(const char FAR * name));
175 setfunc(WSACleanup_winsock, WSACleanup, int (PASCAL FAR *)(void));
176 setfunc(WSAFDIsSet_winsock, __WSAFDIsSet, int (PASCAL FAR *)(SOCKET, fd_set FAR *));
177 setfunc(WSACreateEvent_winsock, WSACreateEvent, WSAEVENT (PASCAL FAR *)(void));
178 setfunc(WSACloseEvent_winsock, WSACloseEvent, BOOL (PASCAL FAR *)(WSAEVENT));
179 setfunc(WSASetEvent_winsock, WSASetEvent, BOOL (PASCAL FAR *)(WSAEVENT));
180 setfunc(WSAResetEvent_winsock, WSAResetEvent, BOOL (PASCAL FAR *)(WSAEVENT));
181 setfunc(WSAEventSelect_winsock, WSAEventSelect, int (PASCAL FAR *)(SOCKET, WSAEVENT, long));
182 setfunc(WSAWaitForMultipleEvents_winsock, WSAWaitForMultipleEvents, DWORD (PASCAL FAR *)(DWORD, const WSAEVENT FAR*, BOOL, DWORD, BOOL));
183 setfunc(WSAEnumNetworkEvents_winsock, WSAEnumNetworkEvents, int (PASCAL FAR *)(SOCKET, WSAEVENT, LPWSANETWORKEVENTS));
184
185 s_networkModule = module;
186}
187
188CArchSocket
189CArchNetworkWinsock::newSocket(EAddressFamily family, ESocketType type)
190{
191 // create socket
192 SOCKET fd = socket_winsock(s_family[family], s_type[type], 0);
193 if (fd == INVALID_SOCKET) {
194 throwError(getsockerror_winsock());
195 }
196 try {
197 setBlockingOnSocket(fd, false);
198 }
199 catch (...) {
200 close_winsock(fd);
201 throw;
202 }
203
204 // allocate socket object
205 CArchSocketImpl* socket = new CArchSocketImpl;
206 socket->m_socket = fd;
207 socket->m_refCount = 1;
208 socket->m_event = WSACreateEvent_winsock();
209 socket->m_pollWrite = true;
210 return socket;
211}
212
213CArchSocket
214CArchNetworkWinsock::copySocket(CArchSocket s)
215{
216 assert(s != NULL);
217
218 // ref the socket and return it
219 ARCH->lockMutex(m_mutex);
220 ++s->m_refCount;
221 ARCH->unlockMutex(m_mutex);
222 return s;
223}
224
225void
226CArchNetworkWinsock::closeSocket(CArchSocket s)
227{
228 assert(s != NULL);
229
230 // unref the socket and note if it should be released
231 ARCH->lockMutex(m_mutex);
232 const bool doClose = (--s->m_refCount == 0);
233 ARCH->unlockMutex(m_mutex);
234
235 // close the socket if necessary
236 if (doClose) {
237 if (close_winsock(s->m_socket) == SOCKET_ERROR) {
238 // close failed. restore the last ref and throw.
239 int err = getsockerror_winsock();
240 ARCH->lockMutex(m_mutex);
241 ++s->m_refCount;
242 ARCH->unlockMutex(m_mutex);
243 throwError(err);
244 }
245 WSACloseEvent_winsock(s->m_event);
246 delete s;
247 }
248}
249
250void
251CArchNetworkWinsock::closeSocketForRead(CArchSocket s)
252{
253 assert(s != NULL);
254
255 if (shutdown_winsock(s->m_socket, SD_RECEIVE) == SOCKET_ERROR) {
256 if (getsockerror_winsock() != WSAENOTCONN) {
257 throwError(getsockerror_winsock());
258 }
259 }
260}
261
262void
263CArchNetworkWinsock::closeSocketForWrite(CArchSocket s)
264{
265 assert(s != NULL);
266
267 if (shutdown_winsock(s->m_socket, SD_SEND) == SOCKET_ERROR) {
268 if (getsockerror_winsock() != WSAENOTCONN) {
269 throwError(getsockerror_winsock());
270 }
271 }
272}
273
274void
275CArchNetworkWinsock::bindSocket(CArchSocket s, CArchNetAddress addr)
276{
277 assert(s != NULL);
278 assert(addr != NULL);
279
280 if (bind_winsock(s->m_socket, &addr->m_addr, addr->m_len) == SOCKET_ERROR) {
281 throwError(getsockerror_winsock());
282 }
283}
284
285void
286CArchNetworkWinsock::listenOnSocket(CArchSocket s)
287{
288 assert(s != NULL);
289
290 // hardcoding backlog
291 if (listen_winsock(s->m_socket, 3) == SOCKET_ERROR) {
292 throwError(getsockerror_winsock());
293 }
294}
295
296CArchSocket
297CArchNetworkWinsock::acceptSocket(CArchSocket s, CArchNetAddress* addr)
298{
299 assert(s != NULL);
300
301 // create new socket and temporary address
302 CArchSocketImpl* socket = new CArchSocketImpl;
303 CArchNetAddress tmp = CArchNetAddressImpl::alloc(sizeof(struct sockaddr));
304
305 // accept on socket
306 SOCKET fd = accept_winsock(s->m_socket, &tmp->m_addr, &tmp->m_len);
307 if (fd == INVALID_SOCKET) {
308 int err = getsockerror_winsock();
309 delete socket;
310 free(tmp);
311 *addr = NULL;
312 if (err == WSAEWOULDBLOCK) {
313 return NULL;
314 }
315 throwError(err);
316 }
317
318 try {
319 setBlockingOnSocket(fd, false);
320 }
321 catch (...) {
322 close_winsock(fd);
323 delete socket;
324 free(tmp);
325 *addr = NULL;
326 throw;
327 }
328
329 // initialize socket
330 socket->m_socket = fd;
331 socket->m_refCount = 1;
332 socket->m_event = WSACreateEvent_winsock();
333 socket->m_pollWrite = true;
334
335 // copy address if requested
336 if (addr != NULL) {
337 *addr = ARCH->copyAddr(tmp);
338 }
339
340 free(tmp);
341 return socket;
342}
343
344bool
345CArchNetworkWinsock::connectSocket(CArchSocket s, CArchNetAddress addr)
346{
347 assert(s != NULL);
348 assert(addr != NULL);
349
350 if (connect_winsock(s->m_socket, &addr->m_addr,
351 addr->m_len) == SOCKET_ERROR) {
352 if (getsockerror_winsock() == WSAEISCONN) {
353 return true;
354 }
355 if (getsockerror_winsock() == WSAEWOULDBLOCK) {
356 return false;
357 }
358 throwError(getsockerror_winsock());
359 }
360 return true;
361}
362
363int
364CArchNetworkWinsock::pollSocket(CPollEntry pe[], int num, double timeout)
365{
366 int i;
367 DWORD n;
368
369 // prepare sockets and wait list
370 bool canWrite = false;
371 WSAEVENT* events = (WSAEVENT*)alloca((num + 1) * sizeof(WSAEVENT));
372 for (i = 0, n = 0; i < num; ++i) {
373 // reset return flags
374 pe[i].m_revents = 0;
375
376 // set invalid flag if socket is bogus then go to next socket
377 if (pe[i].m_socket == NULL) {
378 pe[i].m_revents |= kPOLLNVAL;
379 continue;
380 }
381
382 // select desired events
383 long socketEvents = 0;
384 if ((pe[i].m_events & kPOLLIN) != 0) {
385 socketEvents |= FD_READ | FD_ACCEPT | FD_CLOSE;
386 }
387 if ((pe[i].m_events & kPOLLOUT) != 0) {
388 socketEvents |= FD_WRITE | FD_CONNECT | FD_CLOSE;
389
390 // if m_pollWrite is false then we assume the socket is
391 // writable. winsock doesn't signal writability except
392 // when the state changes from unwritable.
393 if (!pe[i].m_socket->m_pollWrite) {
394 canWrite = true;
395 pe[i].m_revents |= kPOLLOUT;
396 }
397 }
398
399 // if no events then ignore socket
400 if (socketEvents == 0) {
401 continue;
402 }
403
404 // select socket for desired events
405 WSAEventSelect_winsock(pe[i].m_socket->m_socket,
406 pe[i].m_socket->m_event, socketEvents);
407
408 // add socket event to wait list
409 events[n++] = pe[i].m_socket->m_event;
410 }
411
412 // if no sockets then return immediately
413 if (n == 0) {
414 return 0;
415 }
416
417 // add the unblock event
418 CArchMultithreadWindows* mt = CArchMultithreadWindows::getInstance();
419 CArchThread thread = mt->newCurrentThread();
420 WSAEVENT* unblockEvent = (WSAEVENT*)mt->getNetworkDataForThread(thread);
421 ARCH->closeThread(thread);
422 if (unblockEvent == NULL) {
423 unblockEvent = new WSAEVENT;
424 *unblockEvent = WSACreateEvent_winsock();
425 mt->setNetworkDataForCurrentThread(unblockEvent);
426 }
427 events[n++] = *unblockEvent;
428
429 // prepare timeout
430 DWORD t = (timeout < 0.0) ? INFINITE : (DWORD)(1000.0 * timeout);
431 if (canWrite) {
432 // if we know we can write then don't block
433 t = 0;
434 }
435
436 // wait
437 DWORD result = WSAWaitForMultipleEvents_winsock(n, events, FALSE, t, FALSE);
438
439 // reset the unblock event
440 WSAResetEvent_winsock(*unblockEvent);
441
442 // handle results
443 if (result == WSA_WAIT_FAILED) {
444 if (getsockerror_winsock() == WSAEINTR) {
445 // interrupted system call
446 ARCH->testCancelThread();
447 return 0;
448 }
449 throwError(getsockerror_winsock());
450 }
451 if (result == WSA_WAIT_TIMEOUT && !canWrite) {
452 return 0;
453 }
454 if (result == WSA_WAIT_EVENT_0 + n - 1) {
455 // the unblock event was signalled
456 return 0;
457 }
458 for (i = 0, n = 0; i < num; ++i) {
459 // skip events we didn't check
460 if (pe[i].m_socket == NULL ||
461 (pe[i].m_events & (kPOLLIN | kPOLLOUT)) == 0) {
462 continue;
463 }
464
465 // get events
466 WSANETWORKEVENTS info;
467 if (WSAEnumNetworkEvents_winsock(pe[i].m_socket->m_socket,
468 pe[i].m_socket->m_event, &info) == SOCKET_ERROR) {
469 continue;
470 }
471 if ((info.lNetworkEvents & FD_READ) != 0) {
472 pe[i].m_revents |= kPOLLIN;
473 }
474 if ((info.lNetworkEvents & FD_ACCEPT) != 0) {
475 pe[i].m_revents |= kPOLLIN;
476 }
477 if ((info.lNetworkEvents & FD_WRITE) != 0) {
478 pe[i].m_revents |= kPOLLOUT;
479
480 // socket is now writable so don't bothing polling for
481 // writable until it becomes unwritable.
482 pe[i].m_socket->m_pollWrite = false;
483 }
484 if ((info.lNetworkEvents & FD_CONNECT) != 0) {
485 if (info.iErrorCode[FD_CONNECT_BIT] != 0) {
486 pe[i].m_revents |= kPOLLERR;
487 }
488 else {
489 pe[i].m_revents |= kPOLLOUT;
490 pe[i].m_socket->m_pollWrite = false;
491 }
492 }
493 if ((info.lNetworkEvents & FD_CLOSE) != 0) {
494 if (info.iErrorCode[FD_CLOSE_BIT] != 0) {
495 pe[i].m_revents |= kPOLLERR;
496 }
497 else {
498 if ((pe[i].m_events & kPOLLIN) != 0) {
499 pe[i].m_revents |= kPOLLIN;
500 }
501 if ((pe[i].m_events & kPOLLOUT) != 0) {
502 pe[i].m_revents |= kPOLLOUT;
503 }
504 }
505 }
506 if (pe[i].m_revents != 0) {
507 ++n;
508 }
509 }
510
511 return (int)n;
512}
513
514void
515CArchNetworkWinsock::unblockPollSocket(CArchThread thread)
516{
517 // set the unblock event
518 CArchMultithreadWindows* mt = CArchMultithreadWindows::getInstance();
519 WSAEVENT* unblockEvent = (WSAEVENT*)mt->getNetworkDataForThread(thread);
520 if (unblockEvent != NULL) {
521 WSASetEvent_winsock(*unblockEvent);
522 }
523}
524
525size_t
526CArchNetworkWinsock::readSocket(CArchSocket s, void* buf, size_t len)
527{
528 assert(s != NULL);
529
530 int n = recv_winsock(s->m_socket, buf, len, 0);
531 if (n == SOCKET_ERROR) {
532 int err = getsockerror_winsock();
533 if (err == WSAEINTR || err == WSAEWOULDBLOCK) {
534 return 0;
535 }
536 throwError(err);
537 }
538 return static_cast<size_t>(n);
539}
540
541size_t
542CArchNetworkWinsock::writeSocket(CArchSocket s, const void* buf, size_t len)
543{
544 assert(s != NULL);
545
546 int n = send_winsock(s->m_socket, buf, len, 0);
547 if (n == SOCKET_ERROR) {
548 int err = getsockerror_winsock();
549 if (err == WSAEINTR) {
550 return 0;
551 }
552 if (err == WSAEWOULDBLOCK) {
553 s->m_pollWrite = true;
554 return 0;
555 }
556 throwError(err);
557 }
558 return static_cast<size_t>(n);
559}
560
561void
562CArchNetworkWinsock::throwErrorOnSocket(CArchSocket s)
563{
564 assert(s != NULL);
565
566 // get the error from the socket layer
567 int err = 0;
568 int size = sizeof(err);
569 if (getsockopt_winsock(s->m_socket, SOL_SOCKET,
570 SO_ERROR, &err, &size) == SOCKET_ERROR) {
571 err = getsockerror_winsock();
572 }
573
574 // throw if there's an error
575 if (err != 0) {
576 throwError(err);
577 }
578}
579
580void
581CArchNetworkWinsock::setBlockingOnSocket(SOCKET s, bool blocking)
582{
583 assert(s != 0);
584
585 int flag = blocking ? 0 : 1;
586 if (ioctl_winsock(s, FIONBIO, &flag) == SOCKET_ERROR) {
587 throwError(getsockerror_winsock());
588 }
589}
590
591bool
592CArchNetworkWinsock::setNoDelayOnSocket(CArchSocket s, bool noDelay)
593{
594 assert(s != NULL);
595
596 // get old state
597 BOOL oflag;
598 int size = sizeof(oflag);
599 if (getsockopt_winsock(s->m_socket, IPPROTO_TCP,
600 TCP_NODELAY, &oflag, &size) == SOCKET_ERROR) {
601 throwError(getsockerror_winsock());
602 }
603
604 // set new state
605 BOOL flag = noDelay ? 1 : 0;
606 size = sizeof(flag);
607 if (setsockopt_winsock(s->m_socket, IPPROTO_TCP,
608 TCP_NODELAY, &flag, size) == SOCKET_ERROR) {
609 throwError(getsockerror_winsock());
610 }
611
612 return (oflag != 0);
613}
614
615bool
616CArchNetworkWinsock::setReuseAddrOnSocket(CArchSocket s, bool reuse)
617{
618 assert(s != NULL);
619
620 // get old state
621 BOOL oflag;
622 int size = sizeof(oflag);
623 if (getsockopt_winsock(s->m_socket, SOL_SOCKET,
624 SO_REUSEADDR, &oflag, &size) == SOCKET_ERROR) {
625 throwError(getsockerror_winsock());
626 }
627
628 // set new state
629 BOOL flag = reuse ? 1 : 0;
630 size = sizeof(flag);
631 if (setsockopt_winsock(s->m_socket, SOL_SOCKET,
632 SO_REUSEADDR, &flag, size) == SOCKET_ERROR) {
633 throwError(getsockerror_winsock());
634 }
635
636 return (oflag != 0);
637}
638
639std::string
640CArchNetworkWinsock::getHostName()
641{
642 char name[256];
643 if (gethostname_winsock(name, sizeof(name)) == -1) {
644 name[0] = '\0';
645 }
646 else {
647 name[sizeof(name) - 1] = '\0';
648 }
649 return name;
650}
651
652CArchNetAddress
653CArchNetworkWinsock::newAnyAddr(EAddressFamily family)
654{
655 CArchNetAddressImpl* addr = NULL;
656 switch (family) {
657 case kINET: {
658 addr = CArchNetAddressImpl::alloc(sizeof(struct sockaddr_in));
659 struct sockaddr_in* ipAddr = TYPED_ADDR(struct sockaddr_in, addr);
660 ipAddr->sin_family = AF_INET;
661 ipAddr->sin_port = 0;
662 ipAddr->sin_addr.s_addr = INADDR_ANY;
663 break;
664 }
665
666 default:
667 assert(0 && "invalid family");
668 }
669 return addr;
670}
671
672CArchNetAddress
673CArchNetworkWinsock::copyAddr(CArchNetAddress addr)
674{
675 assert(addr != NULL);
676
677 CArchNetAddressImpl* copy = CArchNetAddressImpl::alloc(addr->m_len);
678 memcpy(TYPED_ADDR(void, copy), TYPED_ADDR(void, addr), addr->m_len);
679 return copy;
680}
681
682CArchNetAddress
683CArchNetworkWinsock::nameToAddr(const std::string& name)
684{
685 // allocate address
686 CArchNetAddressImpl* addr = NULL;
687
688 // try to convert assuming an IPv4 dot notation address
689 struct sockaddr_in inaddr;
690 memset(&inaddr, 0, sizeof(inaddr));
691 inaddr.sin_family = AF_INET;
692 inaddr.sin_port = 0;
693 inaddr.sin_addr.s_addr = inet_addr_winsock(name.c_str());
694 if (inaddr.sin_addr.s_addr != INADDR_NONE) {
695 // it's a dot notation address
696 addr = CArchNetAddressImpl::alloc(sizeof(struct sockaddr_in));
697 memcpy(TYPED_ADDR(void, addr), &inaddr, addr->m_len);
698 }
699
700 else {
701 // address lookup
702 struct hostent* info = gethostbyname_winsock(name.c_str());
703 if (info == NULL) {
704 throwNameError(getsockerror_winsock());
705 }
706
707 // copy over address (only IPv4 currently supported)
708 if (info->h_addrtype == AF_INET) {
709 addr = CArchNetAddressImpl::alloc(sizeof(struct sockaddr_in));
710 memcpy(&inaddr.sin_addr, info->h_addr_list[0],
711 sizeof(inaddr.sin_addr));
712 memcpy(TYPED_ADDR(void, addr), &inaddr, addr->m_len);
713 }
714 else {
715 throw XArchNetworkNameUnsupported(
716 "The requested name is valid but "
717 "does not have a supported address family");
718 }
719 }
720
721 return addr;
722}
723
724void
725CArchNetworkWinsock::closeAddr(CArchNetAddress addr)
726{
727 assert(addr != NULL);
728
729 free(addr);
730}
731
732std::string
733CArchNetworkWinsock::addrToName(CArchNetAddress addr)
734{
735 assert(addr != NULL);
736
737 // name lookup
738 struct hostent* info = gethostbyaddr_winsock(
739 reinterpret_cast<const char FAR*>(&addr->m_addr),
740 addr->m_len, addr->m_addr.sa_family);
741 if (info == NULL) {
742 throwNameError(getsockerror_winsock());
743 }
744
745 // return (primary) name
746 return info->h_name;
747}
748
749std::string
750CArchNetworkWinsock::addrToString(CArchNetAddress addr)
751{
752 assert(addr != NULL);
753
754 switch (getAddrFamily(addr)) {
755 case kINET: {
756 struct sockaddr_in* ipAddr =
757 reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
758 return inet_ntoa_winsock(ipAddr->sin_addr);
759 }
760
761 default:
762 assert(0 && "unknown address family");
763 return "";
764 }
765}
766
767IArchNetwork::EAddressFamily
768CArchNetworkWinsock::getAddrFamily(CArchNetAddress addr)
769{
770 assert(addr != NULL);
771
772 switch (addr->m_addr.sa_family) {
773 case AF_INET:
774 return kINET;
775
776 default:
777 return kUNKNOWN;
778 }
779}
780
781void
782CArchNetworkWinsock::setAddrPort(CArchNetAddress addr, int port)
783{
784 assert(addr != NULL);
785
786 switch (getAddrFamily(addr)) {
787 case kINET: {
788 struct sockaddr_in* ipAddr =
789 reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
790 ipAddr->sin_port = htons_winsock(static_cast<u_short>(port));
791 break;
792 }
793
794 default:
795 assert(0 && "unknown address family");
796 break;
797 }
798}
799
800int
801CArchNetworkWinsock::getAddrPort(CArchNetAddress addr)
802{
803 assert(addr != NULL);
804
805 switch (getAddrFamily(addr)) {
806 case kINET: {
807 struct sockaddr_in* ipAddr =
808 reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
809 return ntohs_winsock(ipAddr->sin_port);
810 }
811
812 default:
813 assert(0 && "unknown address family");
814 return 0;
815 }
816}
817
818bool
819CArchNetworkWinsock::isAnyAddr(CArchNetAddress addr)
820{
821 assert(addr != NULL);
822
823 switch (getAddrFamily(addr)) {
824 case kINET: {
825 struct sockaddr_in* ipAddr =
826 reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
827 return (addr->m_len == sizeof(struct sockaddr_in) &&
828 ipAddr->sin_addr.s_addr == INADDR_ANY);
829 }
830
831 default:
832 assert(0 && "unknown address family");
833 return true;
834 }
835}
836
837bool
838CArchNetworkWinsock::isEqualAddr(CArchNetAddress a, CArchNetAddress b)
839{
840 return (a == b || (a->m_len == b->m_len &&
841 memcmp(&a->m_addr, &b->m_addr, a->m_len) == 0));
842}
843
844void
845CArchNetworkWinsock::throwError(int err)
846{
847 switch (err) {
848 case WSAEACCES:
849 throw XArchNetworkAccess(new XArchEvalWinsock(err));
850
851 case WSAEMFILE:
852 case WSAENOBUFS:
853 case WSAENETDOWN:
854 throw XArchNetworkResource(new XArchEvalWinsock(err));
855
856 case WSAEPROTOTYPE:
857 case WSAEPROTONOSUPPORT:
858 case WSAEAFNOSUPPORT:
859 case WSAEPFNOSUPPORT:
860 case WSAESOCKTNOSUPPORT:
861 case WSAEINVAL:
862 case WSAENOPROTOOPT:
863 case WSAEOPNOTSUPP:
864 case WSAESHUTDOWN:
865 case WSANOTINITIALISED:
866 case WSAVERNOTSUPPORTED:
867 case WSASYSNOTREADY:
868 throw XArchNetworkSupport(new XArchEvalWinsock(err));
869
870 case WSAEADDRNOTAVAIL:
871 throw XArchNetworkNoAddress(new XArchEvalWinsock(err));
872
873 case WSAEADDRINUSE:
874 throw XArchNetworkAddressInUse(new XArchEvalWinsock(err));
875
876 case WSAEHOSTUNREACH:
877 case WSAENETUNREACH:
878 throw XArchNetworkNoRoute(new XArchEvalWinsock(err));
879
880 case WSAENOTCONN:
881 throw XArchNetworkNotConnected(new XArchEvalWinsock(err));
882
883 case WSAEDISCON:
884 throw XArchNetworkShutdown(new XArchEvalWinsock(err));
885
886 case WSAENETRESET:
887 case WSAECONNABORTED:
888 case WSAECONNRESET:
889 throw XArchNetworkDisconnected(new XArchEvalWinsock(err));
890
891 case WSAECONNREFUSED:
892 throw XArchNetworkConnectionRefused(new XArchEvalWinsock(err));
893
894 case WSAEHOSTDOWN:
895 case WSAETIMEDOUT:
896 throw XArchNetworkTimedOut(new XArchEvalWinsock(err));
897
898 case WSAHOST_NOT_FOUND:
899 throw XArchNetworkNameUnknown(new XArchEvalWinsock(err));
900
901 case WSANO_DATA:
902 throw XArchNetworkNameNoAddress(new XArchEvalWinsock(err));
903
904 case WSANO_RECOVERY:
905 throw XArchNetworkNameFailure(new XArchEvalWinsock(err));
906
907 case WSATRY_AGAIN:
908 throw XArchNetworkNameUnavailable(new XArchEvalWinsock(err));
909
910 default:
911 throw XArchNetwork(new XArchEvalWinsock(err));
912 }
913}
914
915void
916CArchNetworkWinsock::throwNameError(int err)
917{
918 switch (err) {
919 case WSAHOST_NOT_FOUND:
920 throw XArchNetworkNameUnknown(new XArchEvalWinsock(err));
921
922 case WSANO_DATA:
923 throw XArchNetworkNameNoAddress(new XArchEvalWinsock(err));
924
925 case WSANO_RECOVERY:
926 throw XArchNetworkNameFailure(new XArchEvalWinsock(err));
927
928 case WSATRY_AGAIN:
929 throw XArchNetworkNameUnavailable(new XArchEvalWinsock(err));
930
931 default:
932 throw XArchNetworkName(new XArchEvalWinsock(err));
933 }
934}
Note: See TracBrowser for help on using the repository browser.