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