1 /*
2  * file w32_socket.c - true bsd sockets for xblast
3  *
4  * $Id: w32_socket.c,v 1.13 2006/02/19 13:33:01 lodott Exp $
5  *
6  * Program XBLAST
7  * (C) by Oliver Vogel (e-mail: m.vogel@ndh.net)
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published
11  * by the Free Software Foundation; either version 2; or (at your option)
12  * any later version
13  *
14  * This program is distributed in the hope that it will be entertaining,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILTY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
17  * Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write to the Free Software Foundation, Inc.
21  * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23 #include "xblast.h"
24 #define __USE_W32_SOCKETS
25 #include <winsock2.h>
26 #include <ws2tcpip.h>
27 #include "socket.h"
28 #include "w32_socket.h"
29 #include "w32_event.h"
30 #include "str_util.h"
31 #include "com.h"
32 #include "gui.h"
33 
34 /*
35  * local constants
36  */
37 #define LISTENQ 5
38 /* needed winsock version */
39 #define WINSOCK_VERSION (MAKEWORD (2, 0))
40 /* maximum number of sockets in map */
41 #define MAX_SOCKET 64
42 /* interface detection modes */
43 #define XBIF_MS 0x01
44 #define XBIF_MOD 0x02
45 
46 /*
47  * type definitions
48  */
49 
50 /* socket address */
51 typedef struct _xb_socket_address
52 {
53 	int len;					/* allocated length */
54 	struct sockaddr *addr;		/* protocol dependent data */
55 } XBSocketAddress;
56 
57 /* socket data */
58 struct _xb_socket
59 {
60 	SOCKET fd;					/* file descriptor */
61 	XBSocketAddress sock;		/* local address */
62 	XBSocketAddress peer;		/* remote address */
63 	XBBool read;				/* read flag */
64 	XBBool write;				/* write flag */
65 	XBBool shutdown;			/* shutdown flag */
66 };
67 
68 /* list of all sockets */
69 typedef struct
70 {
71 	size_t num;
72 	SOCKET fd[MAX_SOCKET];
73 	const XBSocket *socket[MAX_SOCKET];
74 } XBSocketMap;
75 
76 /* modified sockaddr_gen, to deal with winsock bug */
77 typedef union sockaddr_genk
78 {
79 	struct sockaddr address;
80 	struct sockaddr_in addressIn;
81 	struct sockaddr_in6 addressIn6;
82 } sockaddr_genk;
83 
84 /* modified INTERFACE_INFO using the modified sockaddr_gen */
85 typedef struct _interface_info_mod
86 {
87 	u_long iiFlags;				/* Interface flags */
88 	sockaddr_genk iiAddress;	/* Interface address */
89 	sockaddr_genk iiBroadcastAddress;	/* Broadcast address */
90 	sockaddr_genk iiNetmask;	/* Network mask */
91 } INTERFACE_INFO_MOD;
92 
93 /* both INTERFACE_INFO versions */
94 typedef union
95 {
96 	INTERFACE_INFO ms;
97 	INTERFACE_INFO_MOD mod;
98 } XB_INTERFACE_INFO;
99 
100 /*
101  * local variables
102  */
103 static XBSocketMap socketMap;	/* socket list */
104 static XBSocketInterface *inter = NULL;	/* interface list */
105 static size_t numInter = 0;		/* number of interfaces */
106 static short modeflags = 0;		/* interface detection mode */
107 
108 /***************
109  * local stuff *
110  ***************/
111 
112  /**/ static void AsyncSelect (const XBSocket * pSocket);
113 
114 /*
115  * delete list with all interfaces
116  */
117 static void
DeleteInterfaces(void)118 DeleteInterfaces (void)
119 {
120 	if (NULL != inter) {
121 		size_t i;
122 		for (i = 0; i < numInter; i++) {
123 			if (NULL != inter[i].name) {
124 				free (inter[i].name);
125 			}
126 			if (NULL != inter[i].addrDevice) {
127 				free (inter[i].addrDevice);
128 			}
129 			if (NULL != inter[i].addrBroadcast) {
130 				free (inter[i].addrBroadcast);
131 			}
132 		}
133 		free (inter);
134 	}
135 	inter = NULL;
136 	numInter = 0;
137 }								/* DeleteInterfaces */
138 
139 /*
140  * get inet address from string, host byte order
141  */
142 static unsigned long
GetAddressInet(const char * hostName)143 GetAddressInet (const char *hostName)
144 {
145 	long addr;
146 	struct hostent *serverEnt;
147 	assert (hostName != NULL);
148 	/* check if ip string */
149 	if (-1L != (addr = inet_addr (hostName))) {
150 		return ntohl (addr);
151 	}
152 	/* lookup hostname if not an ip string */
153 	if (NULL != (serverEnt = gethostbyname (hostName))) {
154 		return ntohl (*(long *)serverEnt->h_addr_list[0]);
155 	}
156 	/* lookup failed */
157 	return 0L;
158 }								/* GetAddressInet */
159 
160 /***************************
161  * general socket managing *
162  ***************************/
163 
164 /*
165  * initialize winsock
166  */
167 XBBool
Socket_Init(void)168 Socket_Init (void)
169 {
170 	WSADATA wsaData;
171 	memset (&socketMap, 0, sizeof (XBSocketMap));
172 	if (0 != WSAStartup (WINSOCK_VERSION, &wsaData)) {
173 		GUI_ErrorMessage ("winsock startup failed - unknown version\n");
174 		return XBFalse;
175 	}
176 	if (wsaData.wVersion != WINSOCK_VERSION) {
177 		GUI_ErrorMessage ("winsock startup failed - wrong version (2.0 required)\n");
178 		WSACleanup ();
179 		return XBFalse;
180 	}
181 	return XBTrue;
182 }								/* Socket_Init */
183 
184 /*
185  * add socket to list
186  */
187 static void
SocketMapAdd(XBSocketMap * map,const XBSocket * pSocket)188 SocketMapAdd (XBSocketMap * map, const XBSocket * pSocket)
189 {
190 	assert (NULL != socket);
191 	assert (NULL != map);
192 	assert (map->num < MAX_SOCKET);
193 	Dbg_Socket ("add fd=%u at map position #%u\n", pSocket->fd, map->num);
194 	map->fd[map->num] = pSocket->fd;
195 	map->socket[map->num] = pSocket;
196 	map->num++;
197 }								/* SocketMapAdd */
198 
199 /*
200  * subtract socket from set
201  */
202 static void
SocketMapSubtract(XBSocketMap * map,const XBSocket * pSocket)203 SocketMapSubtract (XBSocketMap * map, const XBSocket * pSocket)
204 {
205 	size_t i;
206 
207 	assert (NULL != socket);
208 	assert (NULL != map);
209 	assert (map->num > 0);
210 	for (i = 0; i < map->num; i++) {
211 		if (map->socket[i] == pSocket) {
212 			Dbg_Socket ("sub fd=%u from map pos #%u (total %u)\n", pSocket->fd, i, map->num);
213 			map->num--;
214 			if (i < map->num) {
215 				map->fd[i] = map->fd[map->num];
216 				map->socket[i] = map->socket[map->num];
217 			}
218 		}
219 	}
220 }								/* SocketMapSubtract */
221 
222 /*
223  * find socket to fd
224  */
225 static const XBSocket *
SocketMapFind(XBSocketMap * map,SOCKET fd)226 SocketMapFind (XBSocketMap * map, SOCKET fd)
227 {
228 	size_t i;
229 
230 	assert (NULL != socket);
231 	assert (NULL != map);
232 	for (i = 0; i < map->num; i++) {
233 		if (map->fd[i] == fd) {
234 			return map->socket[i];
235 		}
236 	}
237 	return NULL;
238 }								/* SocketMapFind */
239 
240 /*
241  * shutdown winsock
242  */
243 void
Socket_Finish(void)244 Socket_Finish (void)
245 {
246 	Dbg_Socket ("shutting down winsock\n");
247 	DeleteInterfaces ();
248 	WSACleanup ();
249 }								/* Socket_Finish */
250 
251 /***************
252  * socket data *
253  ***************/
254 
255 /*
256  * return file descriptor for socket
257  */
258 int
Socket_Fd(const XBSocket * pSocket)259 Socket_Fd (const XBSocket * pSocket)
260 {
261 	assert (NULL != pSocket);
262 	return pSocket->fd;
263 }								/* Socket_Fd */
264 
265 /*
266  * return adress family for socket
267  */
268 int
Socket_Family(const XBSocket * pSocket)269 Socket_Family (const XBSocket * pSocket)
270 {
271 	assert (NULL != pSocket);
272 
273 	return pSocket->sock.addr->sa_family;
274 }								/* Socket_Family */
275 
276 /*
277  * get host name of client
278  */
279 const char *
Socket_HostName(const XBSocket * pSocket,XBBool peer)280 Socket_HostName (const XBSocket * pSocket, XBBool peer)
281 {
282 	const XBSocketAddress *sa;
283 	struct sockaddr_in *inetAddr;
284 	assert (NULL != pSocket);
285 	/* determine address struct */
286 	sa = peer ? &pSocket->peer : &pSocket->sock;
287 	assert (NULL != sa);
288 	assert (NULL != sa->addr);
289 	/* reconstruct address */
290 	inetAddr = (struct sockaddr_in *)sa->addr;
291 	return inet_ntoa (inetAddr->sin_addr);
292 }								/* Socket_HostName */
293 
294 /*
295  * get port of host
296  */
297 unsigned
Socket_HostPort(const XBSocket * pSocket,XBBool peer)298 Socket_HostPort (const XBSocket * pSocket, XBBool peer)
299 {
300 	const XBSocketAddress *sa;
301 	struct sockaddr_in *inetAddr;
302 	assert (NULL != pSocket);
303 	/* determine address struct */
304 	sa = peer ? &pSocket->peer : &pSocket->sock;
305 	assert (NULL != sa);
306 	assert (NULL != sa->addr);
307 	/* reconstruct port */
308 	inetAddr = (struct sockaddr_in *)sa->addr;
309 	return ntohs (inetAddr->sin_port);
310 }								/* Socket_HostPort */
311 
312 /*******************
313  * socket creation *
314  *******************
315 
316 /*
317  * create socket structure
318  */
319 XBSocket *
Socket_Alloc(int family)320 Socket_Alloc (int family)
321 {
322 	int len;
323 	XBSocket *pSocket;
324 	/* require AF_INET family */
325 	switch (family) {
326 	case AF_INET:
327 		len = sizeof (struct sockaddr_in);
328 		break;
329 	default:
330 		Dbg_Socket ("AF_INET family required, socket not created\n");
331 		return NULL;
332 	}
333 	/* alloc socket data structure */
334 	pSocket = calloc (1, sizeof (XBSocket));
335 	assert (NULL != pSocket);
336 	pSocket->fd = -1;
337 	pSocket->read = XBFalse;
338 	pSocket->write = XBFalse;
339 	pSocket->shutdown = XBFalse;
340 	/* out address */
341 	pSocket->sock.len = len;
342 	pSocket->sock.addr = calloc (1, len);
343 	assert (NULL != pSocket->sock.addr);
344 	pSocket->sock.addr->sa_family = family;
345 	/* other addresse */
346 	pSocket->peer.len = len;
347 	pSocket->peer.addr = calloc (1, len);
348 	assert (NULL != pSocket->peer.addr);
349 	pSocket->peer.addr->sa_family = family;
350 	/* that's all */
351 	return pSocket;
352 }								/* Socket_Alloc */
353 
354 /*
355  * free socket structure memory
356  */
357 void
Socket_Free(XBSocket * pSocket)358 Socket_Free (XBSocket * pSocket)
359 {
360 	assert (NULL != pSocket);
361 	if (NULL != pSocket->sock.addr) {
362 		free (pSocket->sock.addr);
363 	}
364 	if (NULL != pSocket->peer.addr) {
365 		free (pSocket->peer.addr);
366 	}
367 	free (pSocket);
368 }								/* Socket_Free */
369 
370 /*
371  * set socket adress
372  */
373 XBBool
Socket_SetAddressInet(XBSocket * pSocket,XBBool peer,const char * hostName,unsigned short port)374 Socket_SetAddressInet (XBSocket * pSocket, XBBool peer, const char *hostName, unsigned short port)
375 {
376 	XBSocketAddress *sa;
377 	unsigned long addr;
378 	struct sockaddr_in *serverAddr;
379 	assert (NULL != pSocket);
380 	/* determine address structure to set */
381 	sa = peer ? &pSocket->peer : &pSocket->sock;
382 	/* get address in host byte order */
383 	if (NULL != hostName) {
384 		if (0 == (addr = GetAddressInet (hostName))) {
385 			Dbg_Socket ("failed to set address %s:%u for fd=%u\n", hostName, port, pSocket->fd);
386 			return XBFalse;
387 		}
388 	}
389 	else {
390 		addr = INADDR_ANY;
391 	}
392 	/* now set the address */
393 	assert (NULL != sa);
394 	memset (sa->addr, 0, sa->len);
395 	serverAddr = (struct sockaddr_in *)sa->addr;
396 	serverAddr->sin_family = AF_INET;
397 	serverAddr->sin_addr.s_addr = htonl (addr);
398 	serverAddr->sin_port = htons (port);
399 	Dbg_Socket ("set %s address %s:%u for fd=%u\n", peer ? "remote" : "local", hostName, port,
400 				pSocket->fd);
401 	return XBTrue;
402 }								/* Socket_SetAddressInet */
403 
404 /*
405  * set broadcast option for socket
406  */
407 XBBool
Socket_SetBroadcast(XBSocket * pSocket,XBBool enable)408 Socket_SetBroadcast (XBSocket * pSocket, XBBool enable)
409 {
410 	BOOL flag = enable ? TRUE : FALSE;
411 	assert (NULL != pSocket);
412 	return (0 == setsockopt (pSocket->fd, SOL_SOCKET, SO_BROADCAST, (void *)&flag, sizeof (flag)));
413 }								/* Socket_SetBroadcast */
414 
415 /*
416  * set socket option reuse
417  */
418 XBBool
Socket_SetReuse(XBSocket * pSocket)419 Socket_SetReuse (XBSocket * pSocket)
420 {
421 #if 0
422 	/* TODO: implement for windows */
423 	int so_reuseaddr = 1;
424 	if (-1 ==
425 		setsockopt (pSocket->fd, SOL_SOCKET, SO_REUSEADDR, &so_reuseaddr, sizeof (so_reuseaddr))) {
426 		return XBFalse;
427 	}
428 	/* that's all */
429 #endif
430 	return XBTrue;
431 }								/* Socket_SetReuse */
432 
433 /*
434  * register read socket for event handling
435  */
436 void
Socket_RegisterRead(XBSocket * pSocket)437 Socket_RegisterRead (XBSocket * pSocket)
438 {
439 	assert (NULL != pSocket);
440 	if (!pSocket->read) {
441 		pSocket->read = XBTrue;
442 		AsyncSelect (pSocket);
443 	}
444 }								/* Socket_RegisterRead */
445 
446 /*
447  * register read socket for event handling
448  */
449 void
Socket_RegisterWrite(XBSocket * pSocket)450 Socket_RegisterWrite (XBSocket * pSocket)
451 {
452 	assert (NULL != pSocket);
453 	if (!pSocket->write) {
454 		pSocket->write = XBTrue;
455 		AsyncSelect (pSocket);
456 	}
457 }								/* Socket_RegisterWrite */
458 
459 /*
460  * register read socket for event handling
461  */
462 void
Socket_UnregisterRead(XBSocket * pSocket)463 Socket_UnregisterRead (XBSocket * pSocket)
464 {
465 	assert (NULL != pSocket);
466 	if (pSocket->read) {
467 		pSocket->read = XBFalse;
468 		AsyncSelect (pSocket);
469 	}
470 }								/* Socket_UnregisterRead */
471 
472 /*
473  * register read socket for event handling
474  */
475 void
Socket_UnregisterWrite(XBSocket * pSocket)476 Socket_UnregisterWrite (XBSocket * pSocket)
477 {
478 	assert (NULL != pSocket);
479 	if (pSocket->write) {
480 		pSocket->write = XBFalse;
481 		AsyncSelect (pSocket);
482 	}
483 }								/* Socket_UnregisterWrite */
484 
485 /*************
486  * BSD calls *
487  *************
488 
489 /*
490  * open socket
491  */
492 XBBool
Socket_Open(XBSocket * pSocket,int type)493 Socket_Open (XBSocket * pSocket, int type)
494 {
495 	assert (pSocket != NULL);
496 	/* request a socket from system */
497 	if (-1 == (pSocket->fd = socket (pSocket->sock.addr->sa_family, type, 0))) {
498 #ifndef WMS
499 		Dbg_Socket ("failed to open socket of type=%i, err=%u\n", type, WSAGetLastError ());
500 #endif
501 		pSocket->shutdown = XBTrue;
502 		return XBFalse;
503 	}
504 	SocketMapAdd (&socketMap, pSocket);
505 	Dbg_Socket ("open socket fd=%u (type=%i)\n", pSocket->fd, type);
506 	return XBTrue;
507 }								/* Socket_Open */
508 
509 /*
510  * close socket
511  */
512 void
Socket_Close(XBSocket * pSocket)513 Socket_Close (XBSocket * pSocket)
514 {
515 	assert (NULL != pSocket);
516 	if (pSocket->fd >= 0) {
517 		if (!pSocket->shutdown) {
518 			SocketMapSubtract (&socketMap, pSocket);
519 			pSocket->shutdown = XBTrue;
520 		}
521 		closesocket (pSocket->fd);
522 		Dbg_Socket ("socket fd=%u closed\n", pSocket->fd);
523 	}
524 }								/* Socket_Close */
525 
526 /*
527  * close write access
528  */
529 void
Socket_ShutdownWrite(XBSocket * pSocket)530 Socket_ShutdownWrite (XBSocket * pSocket)
531 {
532 	assert (NULL != pSocket);
533 
534 	if (pSocket->fd >= 0) {
535 		if (!pSocket->shutdown) {
536 			SocketMapSubtract (&socketMap, pSocket);
537 			pSocket->shutdown = XBTrue;
538 		}
539 		shutdown (pSocket->fd, SD_SEND);
540 		Dbg_Socket ("socket fd=%u shutdown write\n", pSocket->fd);
541 	}
542 }								/* Socket_ShutdownWrite */
543 
544 /*
545  * connect a socket
546  */
547 XBBool
Socket_Connect(XBSocket * pSocket)548 Socket_Connect (XBSocket * pSocket)
549 {
550 	assert (pSocket != NULL);
551 	/* connect */
552 	if (-1 == connect (pSocket->fd, pSocket->peer.addr, pSocket->peer.len)) {
553 #ifndef WMS
554 		Dbg_Socket ("failed to connect socket fd=%u to %s:%u, err=%u\n", pSocket->fd,
555 					Socket_HostName (pSocket, XBTrue), Socket_HostPort (pSocket, XBTrue),
556 					WSAGetLastError ());
557 #endif
558 		return XBFalse;
559 	}
560 	/* now get adress assigned by kernel. the cast to void* is needed since not all systems know socklen_t */
561 	if (-1 == getsockname (pSocket->fd, pSocket->sock.addr, (void *)&pSocket->sock.len)) {
562 #ifndef WMS
563 		Dbg_Socket ("failed to get local address of socket fd=%u after connecting, err=%u\n",
564 					pSocket->fd, WSAGetLastError ());
565 #endif
566 		return XBFalse;
567 	}
568 	Dbg_Socket ("socket fd=%u connected to %s:%u\n", pSocket->fd, Socket_HostName (pSocket, XBTrue),
569 				Socket_HostPort (pSocket, XBTrue));
570 	return XBTrue;
571 }								/* Socket_Connect */
572 
573 /*
574  * bind a socket
575  */
576 XBBool
Socket_Bind(XBSocket * pSocket)577 Socket_Bind (XBSocket * pSocket)
578 {
579 	/* bind to port */
580 	if (-1 == bind (pSocket->fd, pSocket->sock.addr, pSocket->sock.len)) {
581 #ifndef WMS
582 		Dbg_Socket ("failed to bind socket fd=%u, err=%u\n", pSocket->fd, WSAGetLastError ());
583 #endif
584 		return XBFalse;
585 	}
586 	/* now get adress assigned by kernel. the cast to void* is needed since not all systems know socklen_t */
587 	if (-1 == getsockname (pSocket->fd, pSocket->sock.addr, (void *)&pSocket->sock.len)) {
588 #ifndef WMS
589 		Dbg_Socket ("failed to get local address of socket fd=%u after binding, err=%u\n",
590 					pSocket->fd, WSAGetLastError ());
591 #endif
592 		return XBFalse;
593 	}
594 	Dbg_Socket ("socket fd=%u bound to %s:%u\n", pSocket->fd, Socket_HostName (pSocket, XBFalse),
595 				Socket_HostPort (pSocket, XBFalse));
596 	/* that's all */
597 	return XBTrue;
598 }								/* Socket_Bind */
599 
600 /*
601  * accept a socket
602  */
603 XBBool
Socket_Accept(XBSocket * pSocket,const XBSocket * pListen)604 Socket_Accept (XBSocket * pSocket, const XBSocket * pListen)
605 {
606 	assert (pSocket != NULL);
607 	assert (pListen != NULL);
608 	/* try to accept */
609 	if (-1 == (pSocket->fd = accept (pListen->fd, pSocket->peer.addr, (void *)&pSocket->peer.len))) {
610 #ifndef WMS
611 		Dbg_Socket ("failed to accept from socket fd=%u, err=%u\n", pListen->fd,
612 					WSAGetLastError ());
613 #endif
614 		return XBFalse;
615 	}
616 	/* now retrieve local adress */
617 	if (-1 == getsockname (pSocket->fd, pSocket->sock.addr, (void *)&pSocket->sock.len)) {
618 #ifndef WMS
619 		Dbg_Socket ("failed to get local address from accepted socket fd=%u, err=%u\n", pListen->fd,
620 					WSAGetLastError ());
621 #endif
622 		return XBFalse;
623 	}
624 	/* add the new socket */
625 	SocketMapAdd (&socketMap, pSocket);
626 	Dbg_Out ("accepted socket %d from socket fd=%u\n", pSocket->fd, pListen->fd);
627 	/* that's all */
628 	return XBTrue;
629 }								/* Socket_Accept */
630 
631 /*
632  * create listen socket
633  */
634 XBBool
Socket_Listen(XBSocket * pSocket)635 Socket_Listen (XBSocket * pSocket)
636 {
637 	assert (pSocket != NULL);
638 	/* now listen for client to connect */
639 	if (0 != listen (pSocket->fd, LISTENQ)) {
640 #ifndef WMS
641 		Dbg_Socket ("failed to listen on socket fd=%u (%s:%u), err=%u\n", pSocket->fd,
642 					Socket_HostName (pSocket, XBFalse), Socket_HostPort (pSocket, XBFalse),
643 					WSAGetLastError ());
644 #endif
645 		return XBFalse;
646 	}
647 	Dbg_Socket ("listening on socket fd=%u (%s:%u)\n", pSocket->fd,
648 				Socket_HostName (pSocket, XBFalse), Socket_HostPort (pSocket, XBFalse));
649 	return XBTrue;
650 }								/* Socket_Listen */
651 
652 /*
653  * write to socket, non blocking i/o assumed
654  */
655 int
Socket_Send(const XBSocket * pSocket,const void * buf,size_t len)656 Socket_Send (const XBSocket * pSocket, const void *buf, size_t len)
657 {
658 	int result;
659 	assert (NULL != pSocket);
660 	assert (NULL != buf);
661 	/* try to write */
662 	result = send (pSocket->fd, buf, len, 0);
663 	if (result < 0) {
664 		int err = WSAGetLastError ();
665 		if (err == WSAEWOULDBLOCK) {
666 			Dbg_Socket ("send on fd=%d would block\n", pSocket->fd);
667 			return XB_SOCKET_WOULD_BLOCK;
668 		}
669 		else {
670 			Dbg_Out ("send error %d on fd=%u\n", err, pSocket->fd);
671 			return XB_SOCKET_ERROR;
672 		}
673 	}
674 	Dbg_Socket ("sent %u bytes on fd=%u\n", result, pSocket->fd);
675 	return result;
676 }								/* Socket_Send */
677 
678 /*
679  * write to socket, given target, non blocking i/o assumed
680  */
681 int
Socket_SendTo(XBSocket * pSocket,const void * buf,size_t len,const char * host,unsigned short port)682 Socket_SendTo (XBSocket * pSocket, const void *buf, size_t len, const char *host,
683 			   unsigned short port)
684 {
685 	int result;
686 	assert (NULL != pSocket);
687 	assert (NULL != buf);
688 	assert (NULL != host);
689 	/* convert destination adress */
690 	if (!Socket_SetAddressInet (pSocket, XBTrue, host, port)) {
691 		Dbg_Socket ("failed to send on fd=%u - failed to resolve %s:%u", pSocket->fd, host, port);
692 		return -1;
693 	}
694 	/* now try to write data */
695 	result = sendto (pSocket->fd, buf, len, 0, pSocket->peer.addr, pSocket->peer.len);
696 	if (result < 0) {
697 		int err = WSAGetLastError ();
698 		if (err == WSAEWOULDBLOCK) {
699 			Dbg_Socket ("sendto on fd=%u would block\n", pSocket->fd);
700 			return XB_SOCKET_WOULD_BLOCK;
701 		}
702 		else {
703 			Dbg_Out ("sendto error on fd=%u\n", err);
704 			return XB_SOCKET_ERROR;
705 		}
706 	}
707 	Dbg_Socket ("sent %u bytes on fd=%u to %s:%u\n", result, pSocket->fd, host, port);
708 	return result;
709 }								/* Socket_SendTo */
710 
711 /*
712  * read from socket
713  */
714 int
Socket_Receive(const XBSocket * pSocket,void * buf,size_t len)715 Socket_Receive (const XBSocket * pSocket, void *buf, size_t len)
716 {
717 	int result;
718 	assert (NULL != pSocket);
719 	assert (NULL != buf);
720 	/* try to read */
721 	result = recv (pSocket->fd, buf, len, 0);
722 	if (result < 0) {
723 		int err = WSAGetLastError ();
724 		if (err == WSAEWOULDBLOCK) {
725 			Dbg_Out ("receive on fd=%u would block\n", pSocket->fd);
726 			if (pSocket->read) {
727 				AsyncSelect (pSocket);
728 			}
729 			return XB_SOCKET_WOULD_BLOCK;
730 		}
731 		else {
732 			Dbg_Socket ("receive error %u on fd=%u\n", err, pSocket->fd);
733 			return XB_SOCKET_ERROR;
734 		}
735 	}
736 	Dbg_Socket ("received %u bytes on fd=%u\n", result, pSocket->fd);
737 	return result;
738 }								/* Socket_Receive */
739 
740 /*
741  * read from socket, get sender
742  */
743 int
Socket_ReceiveFrom(XBSocket * pSocket,void * buf,size_t len,const char ** host,unsigned short * port)744 Socket_ReceiveFrom (XBSocket * pSocket, void *buf, size_t len, const char **host,
745 					unsigned short *port)
746 {
747 	long numRead;
748 	assert (NULL != pSocket);
749 	assert (NULL != buf);
750 	assert (NULL != host);
751 	/* try to read */
752 	numRead = recvfrom (pSocket->fd, buf, len, 0, pSocket->peer.addr, &pSocket->peer.len);
753 	if (numRead >= 0) {
754 		*host = Socket_HostName (pSocket, XBTrue);
755 		*port = Socket_HostPort (pSocket, XBTrue);
756 	}
757 	else {
758 		int err = WSAGetLastError ();
759 		*host = NULL;
760 		*port = 0;
761 		if (err == WSAEWOULDBLOCK) {
762 			Dbg_Socket ("socket receivefrom on fd=%u would block\n", pSocket->fd);
763 			return XB_SOCKET_WOULD_BLOCK;
764 		}
765 		else {
766 			Dbg_Socket ("receivefrom error %u on fd=%u\n", err, pSocket->fd);
767 			return XB_SOCKET_ERROR;
768 		}
769 	}
770 	Dbg_Socket ("received %u bytes on fd=%u from %s:%u\n", numRead, pSocket->fd, *host, *port);
771 	return numRead;
772 }								/* Net_ReceiveFrom */
773 
774 /*****************
775  * socket events *
776  *****************/
777 
778 /*
779  * handle selection events, needed in w32_event.c
780  */
781 void
HandleSelect(UINT wParam,LONG lParam)782 HandleSelect (UINT wParam, LONG lParam)
783 {
784 	SOCKET fd = wParam;
785 	UINT event = WSAGETSELECTEVENT (lParam);
786 	const XBSocket *pSocket;
787 
788 	switch (event) {
789 	case FD_READ:
790 	case FD_ACCEPT:
791 	case FD_CLOSE:
792 		Dbg_Socket ("socket fd=%u readable\n", fd);
793 		CommReadable (fd);
794 		break;
795 	case FD_WRITE:
796 		Dbg_Socket ("socket fd=%u writeable\n", fd);
797 		CommWriteable (fd);
798 		if (NULL != (pSocket = SocketMapFind (&socketMap, fd)) && pSocket->write) {
799 			AsyncSelect (pSocket);
800 		}
801 		break;
802 	default:
803 		Dbg_Socket ("unknown select event %04x\n", event);
804 		break;
805 	}
806 }								/* HandleSelect */
807 
808 /*
809  * trigger async select
810  */
811 static void
AsyncSelect(const XBSocket * pSocket)812 AsyncSelect (const XBSocket * pSocket)
813 {
814 	long event = 0;
815 	assert (NULL != pSocket);
816 	Dbg_Socket ("async select on fd=%u, flags=%c%c\n", pSocket->fd, pSocket->read ? 'R' : '-',
817 				pSocket->write ? 'W' : '-');
818 	if (pSocket->read) {
819 		event |= (FD_READ | FD_ACCEPT | FD_CLOSE);
820 	}
821 	if (pSocket->write) {
822 		event |= FD_WRITE;
823 	}
824 	WSAAsyncSelect (pSocket->fd, window, MSG_XBLAST_SELECT, event);
825 }								/* AsyncSelect */
826 
827 /**************
828  * interfaces *
829  **************/
830 
831 /*
832  * get all available interfaces
833  */
834 const XBSocketInterface *
Socket_GetInterfaces(size_t * num)835 Socket_GetInterfaces (size_t * num)
836 {
837 	SOCKET fd = SOCKET_ERROR;
838 	DWORD nr, len;
839 	SOCKADDR_IN *pAddrInet = NULL;
840 	SOCKADDR_IN *pAddrNetmask = NULL;
841 	SOCKADDR_IN *pAddrBroadcast = NULL;
842 	u_long iFlags = 0;
843 	void *info = NULL;
844 	INTERFACE_INFO *ii = NULL;
845 	INTERFACE_INFO_MOD *iimod = NULL;
846 	DWORD iLen = 10;
847 
848 	/* clean up */
849 	DeleteInterfaces ();
850 	/* get test udp socket for interface detection */
851 	if (SOCKET_ERROR == (fd = socket (AF_INET, SOCK_DGRAM, 0))) {
852 		Dbg_Socket ("failed to open udp socket for interface detection\n");
853 		goto Error;
854 	}
855 	/* allocate space for iLen interfaces */
856 	info = calloc (iLen, sizeof (XB_INTERFACE_INFO));
857 	assert (NULL != info);
858 	/* start scanning */
859 	Dbg_Socket ("guessing %u interfaces\n", iLen);
860 	while (SOCKET_ERROR ==
861 		   WSAIoctl (fd, SIO_GET_INTERFACE_LIST, NULL, 0, info, iLen * sizeof (XB_INTERFACE_INFO),
862 					 &len, NULL, NULL)) {
863 		if (WSAEFAULT != WSAGetLastError ()) {
864 			Dbg_Socket ("ioctl failed, err=%u\n", WSAGetLastError ());
865 			goto Error;
866 		}
867 		/* more space needed */
868 		free (info);
869 		iLen += 10;
870 		info = calloc (iLen, sizeof (XB_INTERFACE_INFO));
871 		assert (NULL != info);
872 		Dbg_Socket ("increasing guess to %u\n", iLen);
873 	}
874 	/* determine interface count */
875 	modeflags |= XBIF_MS & (len % sizeof (INTERFACE_INFO) == 0);
876 	modeflags |= XBIF_MOD & (len % sizeof (INTERFACE_INFO_MOD) == 0);
877 	switch (modeflags) {
878 	case XBIF_MS:
879 		len /= sizeof (INTERFACE_INFO);
880 		Dbg_Socket ("using MS mode!\n");
881 		break;
882 	case XBIF_MOD:
883 		len /= sizeof (INTERFACE_INFO_MOD);
884 		Dbg_Socket ("using modified MS mode!\n");
885 		break;
886 	default:
887 		*num = 0;
888 		Dbg_Socket ("no matching mode, interface detection unreliable!\n");
889 		goto Error;
890 	}
891 	Dbg_Socket ("interfaces detected = %u\n", len);
892 	/* allocate output buffer */
893 	inter = calloc (len, sizeof (XBSocketInterface));
894 	assert (NULL != inter);
895 	Dbg_Socket ("allocated %u interface descriptions\n", len);
896 	/* create interface list */
897 	numInter = 0;
898 	for (nr = 0; nr < len; nr++) {
899 		Dbg_Out ("### interface %u ###\n", nr);
900 		/* get flags and addresses */
901 		switch (modeflags) {
902 		case XBIF_MS:
903 			ii = (INTERFACE_INFO *) info;
904 			pAddrInet = (SOCKADDR_IN *) & ii[nr].iiAddress;
905 			pAddrNetmask = (SOCKADDR_IN *) & ii[nr].iiNetmask;
906 			pAddrBroadcast = (SOCKADDR_IN *) & ii[nr].iiBroadcastAddress;
907 			iFlags = ii[nr].iiFlags;
908 			break;
909 		case XBIF_MOD:
910 			iimod = (INTERFACE_INFO_MOD *) info;
911 			pAddrInet = (SOCKADDR_IN *) & iimod[nr].iiAddress;
912 			pAddrNetmask = (SOCKADDR_IN *) & iimod[nr].iiNetmask;
913 			pAddrBroadcast = (SOCKADDR_IN *) & iimod[nr].iiBroadcastAddress;
914 			iFlags = iimod[nr].iiFlags;
915 			break;
916 		default:
917 			break;
918 		}
919 		/* require INET family, up and broadcast */
920 		if (pAddrInet->sin_family == AF_INET &&
921 			pAddrInet->sin_addr.s_addr != INADDR_ANY && (iFlags & (IFF_UP | IFF_BROADCAST))) {
922 			struct in_addr bcAddr = pAddrInet->sin_addr;
923 			bcAddr.s_addr |= ~pAddrNetmask->sin_addr.s_addr;
924 			/* set interface data */
925 			inter[numInter].name = DupString ("net");
926 			inter[numInter].addrDevice = DupString (inet_ntoa (pAddrInet->sin_addr));
927 			inter[numInter].addrBroadcast = DupString (inet_ntoa (bcAddr));
928 			/* output data */
929 			Dbg_Out ("IP = %s\n", inter[numInter].addrDevice);
930 			Dbg_Out ("NET= %s\n", inet_ntoa (pAddrNetmask->sin_addr));
931 			Dbg_Out ("GBC= %s\n", inet_ntoa (pAddrBroadcast->sin_addr));
932 			Dbg_Out ("BC = %s\n", inter[numInter].addrBroadcast);
933 			numInter++;
934 		}
935 		else {
936 			/* output interface data */
937 			Dbg_Out ("IP = %s\n", inet_ntoa (pAddrInet->sin_addr));
938 			Dbg_Out ("NET= %s\n", inet_ntoa (pAddrNetmask->sin_addr));
939 			Dbg_Out ("GBC= %s\n", inet_ntoa (pAddrBroadcast->sin_addr));
940 			Dbg_Out ("skipping interface\n");
941 		}
942 	}
943 	/* clean up */
944 	free (info);
945 	closesocket (fd);
946 	/* that's all */
947 	*num = numInter;
948 	return inter;
949 
950   Error:
951 	if (NULL != info) {
952 		free (info);
953 	}
954 	if (SOCKET_ERROR != fd) {
955 		closesocket (fd);
956 	}
957 	return NULL;
958 }								/* Socket_GetInterfaces */
959 
960 /*
961  * return auto interface for given target and socket
962  */
963 const char *
Socket_GetAutoInterface(XBSocket * pSocket,const char * trg)964 Socket_GetAutoInterface (XBSocket * pSocket, const char *trg)
965 {
966 	SOCKADDR_IN inaddr_trg;
967 	SOCKADDR_IN inaddr_if;
968 	DWORD ret = 0;
969 	const char *ifname;
970 	/* construct target address */
971 	inaddr_trg.sin_family = AF_INET;
972 	inaddr_trg.sin_addr.s_addr = inet_addr (trg);
973 	/* ioctl to get interface address */
974 	if (SOCKET_ERROR == WSAIoctl (pSocket->fd, SIO_ROUTING_INTERFACE_QUERY,
975 								  &inaddr_trg, sizeof (SOCKADDR_IN),
976 								  &inaddr_if, sizeof (SOCKADDR_IN), &ret, NULL, NULL)) {
977 		Dbg_Socket ("failed to find auto-interface, ioctl error %u\n", WSAGetLastError ());
978 		ifname = NULL;
979 	}
980 	else {
981 		ifname = inet_ntoa (inaddr_if.sin_addr);
982 	}
983 	return ifname;
984 }								/* Socket_GetAutoInterface */
985 
986 /*
987  * end of file w32_socket.c
988  */
989