1 // _________ __ __
2 // / _____// |_____________ _/ |______ ____ __ __ ______
3 // \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
4 // / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
5 // /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
6 // \/ \/ \//_____/ \/
7 // ______________________ ______________________
8 // T H E W A R B E G I N S
9 // Stratagus - A free fantasy real time strategy game engine
10 //
11 /**@name lowlevel.cpp - The network lowlevel. */
12 //
13 // (c) Copyright 2000-2007 by Lutz Sammer and Jimmy Salmon
14 //
15 // This program is free software; you can redistribute it and/or modify
16 // it under the terms of the GNU General Public License as published by
17 // the Free Software Foundation; only version 2 of the License.
18 //
19 // This program is distributed in the hope that it will be useful,
20 // but WITHOUT ANY WARRANTY; without even the implied warranty of
21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 // GNU General Public License for more details.
23 //
24 // You should have received a copy of the GNU General Public License
25 // along with this program; if not, write to the Free Software
26 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 // 02111-1307, USA.
28 //
29
30 //@{
31
32 //----------------------------------------------------------------------------
33 // Includes
34 //----------------------------------------------------------------------------
35
36 #include "stratagus.h"
37
38 #include "net_lowlevel.h"
39
40 #include <stdio.h>
41 #include <fcntl.h>
42 #include <errno.h>
43
44 //----------------------------------------------------------------------------
45 // Declarations
46 //----------------------------------------------------------------------------
47
48 #ifdef USE_WIN32
49
50 #include <windows.h>
51 #include <winsock.h>
52 //#include <ws2tcpip.h>
53
54 // MS Knowledge base fix for SIO_GET_INTERFACE_LIST with NT4.0 ++
55 #define SIO_GET_INTERFACE_LIST 0x4004747F
56 #define IFF_UP 1
57 #define IFF_LOOPBACK 4
58 struct OLD_INTERFACE_INFO {
59 unsigned long iiFlags; /* Interface flags */
60 SOCKADDR iiAddress; /* Interface address */
61 SOCKADDR iiBroadcastAddress; /* Broadcast address */
62 SOCKADDR iiNetmask; /* Network mask */
63 };
64 #define INTERFACE_INFO OLD_INTERFACE_INFO
65
66 typedef const char *setsockopttype;
67 typedef char *recvfrombuftype;
68 typedef char *recvbuftype;
69 typedef const char *sendtobuftype;
70 typedef const char *sendbuftype;
71 typedef int socklen_t;
72 #else
73 typedef const void *setsockopttype;
74 typedef void *recvfrombuftype;
75 typedef void *recvbuftype;
76 typedef const void *sendtobuftype;
77 typedef const void *sendbuftype;
78 #endif
79 #if defined(__MORPHOS__)
80 typedef int socklen_t;
81 #undef closesocket
82 #define closesocket CloseSocket
83 #define ioctl(x,y,z) IoctlSocket(x,y,(char *)z)
84 #endif
85 //----------------------------------------------------------------------------
86 // Low level functions
87 //----------------------------------------------------------------------------
88
89 #ifdef USE_WINSOCK // {
90
91 /**
92 ** Hardware dependend network init.
93 */
NetInit()94 int NetInit()
95 {
96 WSADATA wsaData;
97
98 // Start up the windows networking
99 if (WSAStartup(MAKEWORD(2, 2), &wsaData)) {
100 fprintf(stderr, "Couldn't initialize Winsock 2\n");
101 return -1;
102 }
103 return 0;
104 }
105
106 /**
107 ** Hardware dependend network exit.
108 */
NetExit()109 void NetExit()
110 {
111 // Clean up windows networking
112 if (WSACleanup() == SOCKET_ERROR) {
113 if (WSAGetLastError() == WSAEINPROGRESS) {
114 WSACancelBlockingCall();
115 WSACleanup();
116 }
117 }
118 }
119
120 /**
121 ** Close an UDP socket port.
122 **
123 ** @param sockfd Socket fildes
124 */
NetCloseUDP(Socket sockfd)125 void NetCloseUDP(Socket sockfd)
126 {
127 closesocket(sockfd);
128 }
129
130 /**
131 ** Close a TCP socket port.
132 **
133 ** @param sockfd Socket fildes
134 */
NetCloseTCP(Socket sockfd)135 void NetCloseTCP(Socket sockfd)
136 {
137 closesocket(sockfd);
138 }
139
140 #endif // } !USE_WINSOCK
141
142 #if !defined(USE_WINSOCK) // {
143
144 /**
145 ** Hardware dependend network init.
146 */
NetInit()147 int NetInit()
148 {
149 return 0;
150 }
151
152 /**
153 ** Hardware dependend network exit.
154 */
NetExit()155 void NetExit()
156 {
157 }
158
159 /**
160 ** Close an UDP socket port.
161 **
162 ** @param sockfd Socket fildes
163 */
NetCloseUDP(Socket sockfd)164 void NetCloseUDP(Socket sockfd)
165 {
166 close(sockfd);
167 }
168
169 /**
170 ** Close a TCP socket port.
171 **
172 ** @param sockfd Socket fildes
173 */
NetCloseTCP(Socket sockfd)174 void NetCloseTCP(Socket sockfd)
175 {
176 close(sockfd);
177 }
178
179 #endif // } !USE_WINSOCK
180
181 /**
182 ** Set socket to non-blocking.
183 **
184 ** @param sockfd Socket
185 **
186 ** @return 0 for success, -1 for error
187 */
188 #ifdef USE_WINSOCK
NetSetNonBlocking(Socket sockfd)189 int NetSetNonBlocking(Socket sockfd)
190 {
191 unsigned long opt = 1;
192 return ioctlsocket(sockfd, FIONBIO, &opt);
193 }
194 #else
NetSetNonBlocking(Socket sockfd)195 int NetSetNonBlocking(Socket sockfd)
196 {
197 int flags = fcntl(sockfd, F_GETFL, 0);
198 return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
199 }
200 #endif
201
202 /**
203 ** Resolve host in name or dotted quad notation.
204 **
205 ** @param host Host name (f.e. 192.168.0.0 or stratagus.net)
206 */
NetResolveHost(const std::string & host)207 unsigned long NetResolveHost(const std::string &host)
208 {
209 if (!host.empty()) {
210 #ifdef __MORPHOS__
211 unsigned long addr = inet_addr((UBYTE *)host.c_str()); // try dot notation
212 #else
213 unsigned long addr = inet_addr(host.c_str()); // try dot notation
214 #endif
215 if (addr == INADDR_NONE) {
216 #ifdef __MORPHOS__
217 struct hostent *he = gethostbyname((UBYTE *)host.c_str());
218 #else
219 struct hostent *he = gethostbyname(host.c_str());
220 #endif
221 if (he) {
222 addr = 0;
223 Assert(he->h_length == 4);
224 memcpy(&addr, he->h_addr, he->h_length);
225 }
226 }
227 return addr;
228 }
229 return INADDR_NONE;
230 }
231
232 /**
233 ** Get IP-addrs of local interfaces from Network file descriptor
234 **
235 ** @param sock local socket.
236 ** @param ips where to stock ip addrs.
237 ** @param maxAddr size of ips.
238 **
239 ** @return number of IP-addrs found.
240 */
241 #ifdef USE_WINSOCK // {
242 // ARI: MS documented this for winsock2, so I finally found it..
243 // I also found a way for winsock1.1 (= win95), but
244 // that one was too complex to start with.. -> trouble
245 // Lookout for INTRFC.EXE on the MS web site...
NetSocketAddr(const Socket sock,unsigned long * ips,int maxAddr)246 int NetSocketAddr(const Socket sock, unsigned long *ips, int maxAddr)
247 {
248 INTERFACE_INFO *localAddr = new INTERFACE_INFO[maxAddr]; // Assume there will be no more than maxAddr interfaces
249 int nif = 0;
250
251 if (sock != static_cast<Socket>(-1)) {
252 DWORD bytesReturned;
253 int wsError = WSAIoctl(sock, SIO_GET_INTERFACE_LIST, nullptr, 0, &localAddr,
254 sizeof(INTERFACE_INFO) * maxAddr, &bytesReturned, nullptr, nullptr);
255 if (wsError == SOCKET_ERROR) {
256 DebugPrint("SIOCGIFCONF:WSAIoctl(SIO_GET_INTERFACE_LIST) - errno %d\n" _C_ WSAGetLastError());
257 }
258
259 // parse interface information
260 const int numLocalAddr = (bytesReturned / sizeof(INTERFACE_INFO));
261 for (int i = 0; i < numLocalAddr; ++i) {
262 u_long SetFlags = localAddr[i].iiFlags;
263 if ((SetFlags & IFF_UP) == 0) {
264 continue;
265 }
266 if ((SetFlags & IFF_LOOPBACK)) {
267 continue;
268 }
269 SOCKADDR_IN *pAddrInet = (SOCKADDR_IN *)&localAddr[i].iiAddress;
270 ips[nif] = pAddrInet->sin_addr.s_addr;
271 ++nif;
272 if (nif == maxAddr) {
273 break;
274 }
275 }
276 }
277 delete [] localAddr;
278 return nif;
279 }
280 #elif USE_LINUX // } {
281 // ARI: I knew how to write this for a unix environment,
282 // but am quite certain that porting this can cause you
283 // trouble..
NetSocketAddr(const Socket sock,unsigned long * ips,int maxAddr)284 int NetSocketAddr(const Socket sock, unsigned long *ips, int maxAddr)
285 {
286 if (sock == static_cast<Socket>(-1)) {
287 return 0;
288 }
289 char buf[4096];
290 struct ifconf ifc;
291 ifc.ifc_len = sizeof(buf);
292 ifc.ifc_buf = buf;
293 if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
294 DebugPrint("SIOCGIFCONF - errno %d\n" _C_ errno);
295 return 0;
296 }
297 // with some inspiration from routed..
298 int nif = 0;
299 struct ifreq *ifr = ifc.ifc_req;
300 char *cplim = buf + ifc.ifc_len; // skip over if's with big ifr_addr's
301
302 for (char *cp = buf; cp < cplim;
303 cp += sizeof(ifr->ifr_name) + sizeof(ifr->ifr_ifru)) {
304 ifr = (struct ifreq *)cp;
305 struct ifreq ifreq = *ifr;
306 if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
307 DebugPrint("%s: SIOCGIFFLAGS - errno %d\n" _C_
308 ifr->ifr_name _C_ errno);
309 continue;
310 }
311 if ((ifreq.ifr_flags & IFF_UP) == 0 || ifr->ifr_addr.sa_family == AF_UNSPEC) {
312 continue;
313 }
314 // argh, this'll have to change sometime
315 if (ifr->ifr_addr.sa_family != AF_INET) {
316 continue;
317 }
318 if (ifreq.ifr_flags & IFF_LOOPBACK) {
319 continue;
320 }
321 struct sockaddr_in *sap = (struct sockaddr_in *)&ifr->ifr_addr;
322 struct sockaddr_in sa = *sap;
323 ips[nif] = sap->sin_addr.s_addr;
324 if (ifreq.ifr_flags & IFF_POINTOPOINT) {
325 if (ioctl(sock, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
326 DebugPrint("%s: SIOCGIFDSTADDR - errno %d\n" _C_
327 ifr->ifr_name _C_ errno);
328 // failed to obtain dst addr - ignore
329 continue;
330 }
331 if (ifr->ifr_addr.sa_family == AF_UNSPEC) {
332 continue;
333 }
334 }
335 // avoid p-t-p links with common src
336 if (nif) {
337 int i;
338 for (i = 0; i < nif; ++i) {
339 if (sa.sin_addr.s_addr == ips[i]) {
340 i = -1;
341 break;
342 }
343 }
344 if (i == -1) {
345 continue;
346 }
347 }
348 ++nif;
349 if (nif == maxAddr) {
350 break;
351 }
352 }
353 return nif;
354 }
355 #else // } {
356 // Beos?? Mac??
NetSocketAddr(const Socket sock,unsigned long * ips,int maxAddr)357 int NetSocketAddr(const Socket sock, unsigned long *ips, int maxAddr)
358 {
359 ips[0] = htonl(0x7f000001);
360 return 1;
361 }
362 #endif // }
363
364 /**
365 ** Open an UDP Socket port.
366 **
367 ** @param ip !=0 Ip to bind in host notation.
368 ** @param port !=0 Port to bind in host notation.
369 **
370 ** @return If success the socket fildes, -1 otherwise.
371 */
NetOpenUDP(unsigned long ip,int port)372 Socket NetOpenUDP(unsigned long ip, int port)
373 {
374 // open the socket
375 Socket sockfd = socket(AF_INET, SOCK_DGRAM, 0);
376
377 if (sockfd == INVALID_SOCKET) {
378 return static_cast<Socket>(-1);
379 }
380 // bind local port
381 if (port) {
382 struct sockaddr_in sock_addr;
383
384 memset(&sock_addr, 0, sizeof(sock_addr));
385 sock_addr.sin_family = AF_INET;
386 sock_addr.sin_addr.s_addr = ip;
387 sock_addr.sin_port = port;
388 // Bind the socket for listening
389 if (bind(sockfd, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) < 0) {
390 fprintf(stderr, "Couldn't bind to local port\n");
391 NetCloseUDP(sockfd);
392 return static_cast<Socket>(-1);
393 }
394 }
395 return sockfd;
396 }
397
398 /**
399 ** Open a TCP socket
400 **
401 ** @param port Bind socket to a specific port number
402 **
403 ** @return If success the socket fildes, -1 otherwise
404 */
NetOpenTCP(const char * addr,int port)405 Socket NetOpenTCP(const char *addr, int port)
406 {
407 Socket sockfd = socket(AF_INET, SOCK_STREAM, 0);
408
409 if (sockfd == INVALID_SOCKET) {
410 return static_cast<Socket>(-1);
411 }
412 // bind local port
413 if (port) {
414 struct sockaddr_in sock_addr;
415
416 memset(&sock_addr, 0, sizeof(sock_addr));
417 sock_addr.sin_family = AF_INET;
418 if (addr) {
419 #ifdef __MORPHOS__
420 sock_addr.sin_addr.s_addr = inet_addr((UBYTE *)addr);
421 #else
422 sock_addr.sin_addr.s_addr = inet_addr(addr);
423 #endif
424 } else {
425 sock_addr.sin_addr.s_addr = INADDR_ANY;
426 }
427 sock_addr.sin_port = port;
428
429 int opt = 1;
430 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (setsockopttype)&opt, sizeof(opt));
431
432 if (bind(sockfd, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) < 0) {
433 fprintf(stderr, "Couldn't bind to local port\n");
434 NetCloseTCP(sockfd);
435 return static_cast<Socket>(-1);
436 }
437 }
438 return sockfd;
439 }
440
441 /**
442 ** Open a TCP connection
443 **
444 ** @param sockfd An open socket to use
445 ** @param addr Address returned from NetResolveHost
446 ** @param port Port on remote host to connect to
447 **
448 ** @return 0 if success, -1 if failure
449 */
NetConnectTCP(Socket sockfd,unsigned long addr,int port)450 int NetConnectTCP(Socket sockfd, unsigned long addr, int port)
451 {
452 struct sockaddr_in sa;
453 #ifndef __BEOS__
454 int opt = 1;
455 setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (setsockopttype)&opt, sizeof(opt));
456 opt = 0;
457 setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (setsockopttype)&opt, sizeof(opt));
458 #endif
459
460 if (addr == INADDR_NONE) {
461 return -1;
462 }
463
464 memset(&sa, 0, sizeof(sa));
465 memcpy(&sa.sin_addr, &addr, sizeof(addr));
466 sa.sin_family = AF_INET;
467 sa.sin_port = htons(port);
468
469 if (connect(sockfd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
470 fprintf(stderr, "connect to %d.%d.%d.%d:%d failed\n",
471 NIPQUAD(ntohl(addr)), port);
472 return -1;
473 }
474 return sockfd;
475 }
476
477 /**
478 ** Wait for socket ready.
479 **
480 ** @param sockfd Socket fildes to probe.
481 ** @param timeout Timeout in 1/1000 seconds.
482 **
483 ** @return 1 if data is available, 0 if not, -1 if failure.
484 */
NetSocketReady(Socket sockfd,int timeout)485 int NetSocketReady(Socket sockfd, int timeout)
486 {
487 int retval;
488 struct timeval tv;
489 fd_set mask;
490
491 // Check the file descriptors for available data
492 do {
493 // Set up the mask of file descriptors
494 FD_ZERO(&mask);
495 FD_SET(sockfd, &mask);
496
497 // Set up the timeout
498 tv.tv_sec = timeout / 1000;
499 tv.tv_usec = (timeout % 1000) * 1000;
500
501 // Data available?
502 retval = select(sockfd + 1, &mask, nullptr, nullptr, &tv);
503 #ifdef USE_WINSOCK
504 } while (retval == SOCKET_ERROR && WSAGetLastError() == WSAEINTR);
505 #else
506 } while (retval == -1 && errno == EINTR);
507 #endif
508
509 return retval;
510 }
511
512 /**
513 ** Wait for socket set ready.
514 **
515 ** @param timeout Timeout in 1/1000 seconds.
516 **
517 ** @return 1 if data is available, 0 if not, -1 if failure.
518 */
Select(int timeout)519 int SocketSet::Select(int timeout)
520 {
521 int retval;
522 fd_set mask;
523
524 // Check the file descriptors for available data
525 do {
526 // Set up the mask of file descriptors
527 FD_ZERO(&mask);
528 for (size_t i = 0; i < this->Sockets.size(); ++i) {
529 FD_SET(this->Sockets[i], &mask);
530 }
531
532 // Set up the timeout
533 struct timeval tv;
534 tv.tv_sec = timeout / 1000;
535 tv.tv_usec = (timeout % 1000) * 1000;
536
537 // Data available?
538 retval = select(this->MaxSockFD + 1, &mask, nullptr, nullptr, &tv);
539 #ifdef USE_WINSOCK
540 } while (retval == SOCKET_ERROR && WSAGetLastError() == WSAEINTR);
541 #else
542 } while (retval == -1 && errno == EINTR);
543 #endif
544
545 for (size_t i = 0; i != this->Sockets.size(); ++i)
546 {
547 this->SocketReady[i] = FD_ISSET(this->Sockets[i], &mask);
548 }
549 return retval;
550 }
551
552 /**
553 ** Check if a socket in a socket set is ready.
554 **
555 ** @param socket Socket to check
556 **
557 ** @return Non-zero if socket is ready
558 */
HasDataToRead(Socket socket) const559 int SocketSet::HasDataToRead(Socket socket) const
560 {
561 for (size_t i = 0; i < this->Sockets.size(); ++i) {
562 if (this->Sockets[i] == socket) {
563 return this->SocketReady[i];
564 }
565 }
566 DebugPrint("Socket not found in socket set\n");
567 return 0;
568 }
569
570 /**
571 ** Receive from a UDP socket.
572 **
573 ** @param sockfd Socket
574 ** @param buf Receive message buffer.
575 ** @param len Receive message buffer length.
576 ** @param hostFrom host of the sender.
577 ** @param portFrom port of the sender.
578 **
579 ** @return Number of bytes placed in buffer, or -1 if failure.
580 */
NetRecvUDP(Socket sockfd,void * buf,int len,unsigned long * hostFrom,int * portFrom)581 int NetRecvUDP(Socket sockfd, void *buf, int len, unsigned long *hostFrom, int *portFrom)
582 {
583 struct sockaddr_in sock_addr;
584 socklen_t n = sizeof(struct sockaddr_in);
585 #ifdef __MORPHOS__
586 const int l = recvfrom(sockfd, (UBYTE*)buf, len, 0, (struct sockaddr *)&sock_addr, (LONG*)&n);
587 #else
588 const int l = recvfrom(sockfd, (recvfrombuftype)buf, len, 0, (struct sockaddr *)&sock_addr, &n);
589 #endif
590
591 if (l < 0) {
592 PrintFunction();
593 fprintf(stdout, "Could not read from UDP socket\n");
594 return -1;
595 }
596
597 // Packet check for validness is done higher up, we don't know who should be
598 // sending us packets at this level
599
600 *hostFrom = sock_addr.sin_addr.s_addr;
601 *portFrom = sock_addr.sin_port;
602
603 return l;
604 }
605
606 /**
607 ** Receive from a TCP socket.
608 **
609 ** @param sockfd Socket
610 ** @param buf Receive message buffer.
611 ** @param len Receive message buffer length.
612 **
613 ** @return Number of bytes placed in buffer or -1 if failure.
614 */
NetRecvTCP(Socket sockfd,void * buf,int len)615 int NetRecvTCP(Socket sockfd, void *buf, int len)
616 {
617 #ifdef __MORPHOS__
618 int ret = recv(sockfd, (UBYTE*)buf, len, 0);
619 #else
620 int ret = recv(sockfd, (recvbuftype)buf, len, 0);
621 #endif
622 if (ret > 0) {
623 return ret;
624 }
625 if (ret == 0) {
626 return -1;
627 }
628 #ifdef USE_WINSOCK
629 if (WSAGetLastError() == WSAEWOULDBLOCK) {
630 #else
631 if (errno == EWOULDBLOCK || errno == EAGAIN) {
632 #endif
633 return 0;
634 }
635 return ret;
636 }
637
638 /**
639 ** Send through a UPD socket to a host:port.
640 **
641 ** @param sockfd Socket
642 ** @param host Host to send to (network byte order).
643 ** @param port Port of host to send to (network byte order).
644 ** @param buf Send message buffer.
645 ** @param len Send message buffer length.
646 **
647 ** @return Number of bytes sent.
648 */
649 int NetSendUDP(Socket sockfd, unsigned long host, int port,
650 const void *buf, int len)
651 {
652 struct sockaddr_in sock_addr;
653
654 const int n = sizeof(struct sockaddr_in);
655 sock_addr.sin_addr.s_addr = host;
656 sock_addr.sin_port = port;
657 sock_addr.sin_family = AF_INET;
658 #ifdef __MORPHOS__
659 return sendto(sockfd, (const UBYTE*)(sendtobuftype)buf, len, 0, (struct sockaddr *)&sock_addr, n);
660 #else
661 return sendto(sockfd, (sendtobuftype)buf, len, 0, (struct sockaddr *)&sock_addr, n);
662 #endif
663 }
664
665 /**
666 ** Send through a TCP socket.
667 **
668 ** @param sockfd Socket
669 ** @param buf Send message buffer.
670 ** @param len Send message buffer length.
671 **
672 ** @return Number of bytes sent.
673 */
674 int NetSendTCP(Socket sockfd, const void *buf, int len)
675 {
676 #ifdef __MORPHOS__
677 return send(sockfd, (const UBYTE*)buf, len, 0);
678 #else
679 return send(sockfd, (sendbuftype)buf, len, 0);
680 #endif
681 }
682
683 /**
684 ** Listen for connections on a TCP socket.
685 **
686 ** @param sockfd Socket
687 **
688 ** @return 0 for success, -1 for error
689 */
690 int NetListenTCP(Socket sockfd)
691 {
692 return listen(sockfd, PlayerMax);
693 }
694
695 /**
696 ** Accept a connection on a TCP socket.
697 **
698 ** @param sockfd Socket
699 ** @param clientHost host of the client connected.
700 ** @param clientPort port of the client connected.
701 **
702 ** @return If success the new socket fildes, -1 otherwise.
703 */
704 Socket NetAcceptTCP(Socket sockfd, unsigned long *clientHost, int *clientPort)
705 {
706 struct sockaddr_in sa;
707 socklen_t len = sizeof(struct sockaddr_in);
708 #ifdef __MORPHOS__
709 Socket socket = accept(sockfd, (struct sockaddr *)&sa, (LONG*)&len);
710 #else
711 Socket socket = accept(sockfd, (struct sockaddr *)&sa, &len);
712 #endif
713 *clientHost = sa.sin_addr.s_addr;
714 *clientPort = sa.sin_port;
715 return socket;
716 }
717
718 /**
719 ** Add a socket to a socket set
720 **
721 ** @param socket Socket to add to the socket set
722 */
723 void SocketSet::AddSocket(Socket socket)
724 {
725 Sockets.push_back(socket);
726 SocketReady.push_back(0);
727 MaxSockFD = std::max(MaxSockFD, socket);
728 }
729
730 /**
731 ** Delete a socket from a socket set
732 **
733 ** @param socket Socket to delete from the socket set
734 */
735 void SocketSet::DelSocket(Socket socket)
736 {
737 std::vector<Socket>::iterator i;
738 std::vector<int>::iterator j;
739
740 for (i = Sockets.begin(), j = SocketReady.begin(); i != Sockets.end(); ++i, ++j) {
741 if (*i == socket) {
742 Sockets.erase(i);
743 SocketReady.erase(j);
744 break;
745 }
746 }
747 if (socket == MaxSockFD) {
748 MaxSockFD = 0;
749 for (i = Sockets.begin(); i != Sockets.end(); ++i) {
750 MaxSockFD = std::max(this->MaxSockFD, *i);
751 }
752 }
753 }
754
755 //@}
756