sockwrap.c 16.7 KB
Newer Older
1
2
3
4
5
6
/* Berkley/WinSock socket API wrappers */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
7
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
8
 *																			*
9
10
 * This program is free software; you can redistribute it and/or			*
 * modify it under the terms of the GNU General Public License				*
11
12
 * as published by the Free Software Foundation; either version 2			*
 * of the License, or (at your option) any later version.					*
13
14
 * See the GNU General Public License for more details: gpl.txt or			*
 * http://www.fsf.org/copyleft/gpl.html										*
15
16
17
18
19
20
21
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

22
#include <stdlib.h>		/* alloca/free on FreeBSD */
23
#include <string.h>		/* bzero (for FD_ZERO) on FreeBSD */
24
#include <errno.h>		/* ENOMEM */
25
#include <stdio.h>		/* SEEK_SET */
26
#include <string.h>
27
28
29
#if defined(_WIN32)
 #include <malloc.h>	/* alloca() on Win32 */
#endif
30

31
#include "genwrap.h"	/* SLEEP */
deuce's avatar
deuce committed
32
#include "gen_defs.h"	/* BOOL/LOG_WARNING */
33
34
35
#include "sockwrap.h"	/* sendsocket */
#include "filewrap.h"	/* filelength */

36
static socket_option_t socket_options[] = {
37
	{ "TYPE",				0,				SOL_SOCKET,		SO_TYPE				},
38
	{ "ERROR",				0,				SOL_SOCKET,		SO_ERROR			},
39
40
41
42
	{ "DEBUG",				0,				SOL_SOCKET,		SO_DEBUG			},
	{ "LINGER",				SOCK_STREAM,	SOL_SOCKET,		SO_LINGER			},
	{ "SNDBUF",				0,				SOL_SOCKET,		SO_SNDBUF			},
	{ "RCVBUF",				0,				SOL_SOCKET,		SO_RCVBUF			},
43
44

#ifndef _WINSOCKAPI_	/* Defined, but not supported, by WinSock */
45
46
47
48
	{ "SNDLOWAT",			0,				SOL_SOCKET,		SO_SNDLOWAT			},
	{ "RCVLOWAT",			0,				SOL_SOCKET,		SO_RCVLOWAT			},
	{ "SNDTIMEO",			0,				SOL_SOCKET,		SO_SNDTIMEO			},
	{ "RCVTIMEO",			0,				SOL_SOCKET,		SO_RCVTIMEO			},
49
50
51
#ifdef SO_USELOOPBACK	/* SunOS */
	{ "USELOOPBACK",		0,				SOL_SOCKET,		SO_USELOOPBACK		},
#endif
52
#endif
53

54
	{ "REUSEADDR",			0,				SOL_SOCKET,		SO_REUSEADDR		},	
deuce's avatar
deuce committed
55
56
#ifdef SO_REUSEPORT	/* BSD */
	{ "REUSEPORT",			0,				SOL_SOCKET,		SO_REUSEPORT		},	
57
58
59
#endif
#ifdef SO_EXCLUSIVEADDRUSE /* WinSock */
	{ "EXCLUSIVEADDRUSE",	0,				SOL_SOCKET,		SO_EXCLUSIVEADDRUSE },
deuce's avatar
deuce committed
60
#endif
61
62
63
64
	{ "KEEPALIVE",			SOCK_STREAM,	SOL_SOCKET,		SO_KEEPALIVE		},
	{ "DONTROUTE",			0,				SOL_SOCKET,		SO_DONTROUTE		},
	{ "BROADCAST",			SOCK_DGRAM,		SOL_SOCKET,		SO_BROADCAST		},
	{ "OOBINLINE",			SOCK_STREAM,	SOL_SOCKET,		SO_OOBINLINE		},
65

66
#ifdef SO_ACCEPTCONN											
67
	{ "ACCEPTCONN",			SOCK_STREAM,	SOL_SOCKET,		SO_ACCEPTCONN		},
68
#endif
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#ifdef SO_PRIORITY		/* Linux */
	{ "PRIORITY",			0,				SOL_SOCKET,		SO_PRIORITY			},
#endif
#ifdef SO_NO_CHECK		/* Linux */
	{ "NO_CHECK",			0,				SOL_SOCKET,		SO_NO_CHECK			},
#endif
#ifdef SO_PROTOTYPE		/* SunOS */
	{ "PROTOTYPE",			0,				SOL_SOCKET,		SO_PROTOTYPE		},
#endif
#ifdef SO_MAX_MSG_SIZE	/* WinSock2 */
	{ "MAX_MSG_SIZE",		SOCK_DGRAM,		SOL_SOCKET,		SO_MAX_MSG_SIZE		},
#endif
#ifdef SO_CONNECT_TIME	/* WinSock2 */
	{ "CONNECT_TIME",		SOCK_STREAM,	SOL_SOCKET,		SO_CONNECT_TIME		},
#endif
84
85

	/* IPPROTO-level socket options */
86
	{ "TCP_NODELAY",		SOCK_STREAM,	IPPROTO_TCP,	TCP_NODELAY			},
87
88
	/* The following are platform-specific */					
#ifdef TCP_MAXSEG											
89
	{ "TCP_MAXSEG",			SOCK_STREAM,	IPPROTO_TCP,	TCP_MAXSEG			},
90
91
#endif															
#ifdef TCP_CORK													
92
	{ "TCP_CORK",			SOCK_STREAM,	IPPROTO_TCP,	TCP_CORK			},
93
94
#endif															
#ifdef TCP_KEEPIDLE												
95
	{ "TCP_KEEPIDLE",		SOCK_STREAM,	IPPROTO_TCP,	TCP_KEEPIDLE		},
96
97
#endif															
#ifdef TCP_KEEPINTVL											
98
	{ "TCP_KEEPINTVL",		SOCK_STREAM,	IPPROTO_TCP,	TCP_KEEPINTVL		},
99
100
#endif															
#ifdef TCP_KEEPCNT												
101
	{ "TCP_KEEPCNT",		SOCK_STREAM,	IPPROTO_TCP,	TCP_KEEPCNT			},
102
#endif															
103
104
105
#ifdef TCP_KEEPALIVE	/* SunOS */
	{ "TCP_KEEPALIVE",		SOCK_STREAM,	IPPROTO_TCP,	TCP_KEEPALIVE		},
#endif															
106
#ifdef TCP_SYNCNT												
107
	{ "TCP_SYNCNT",			SOCK_STREAM,	IPPROTO_TCP,	TCP_SYNCNT			},
108
109
#endif															
#ifdef TCP_LINGER2												
110
	{ "TCP_LINGER2",		SOCK_STREAM,	IPPROTO_TCP,	TCP_LINGER2			},
111
112
#endif														
#ifdef TCP_DEFER_ACCEPT										
113
	{ "TCP_DEFER_ACCEPT",	SOCK_STREAM,	IPPROTO_TCP,	TCP_DEFER_ACCEPT	},
114
115
#endif															
#ifdef TCP_WINDOW_CLAMP											
116
	{ "TCP_WINDOW_CLAMP",	SOCK_STREAM,	IPPROTO_TCP,	TCP_WINDOW_CLAMP	},
117
118
#endif														
#ifdef TCP_QUICKACK											
119
	{ "TCP_QUICKACK",		SOCK_STREAM,	IPPROTO_TCP,	TCP_QUICKACK		},
120
121
#endif						
#ifdef TCP_NOPUSH			
122
	{ "TCP_NOPUSH",			SOCK_STREAM,	IPPROTO_TCP,	TCP_NOPUSH			},
123
124
#endif						
#ifdef TCP_NOOPT			
125
	{ "TCP_NOOPT",			SOCK_STREAM,	IPPROTO_TCP,	TCP_NOOPT			},
126
127
128
#endif
#if defined(IPV6_V6ONLY) && defined(IPPROTO_IPV6)
	{ "IPV6_V6ONLY",		0,				IPPROTO_IPV6,	IPV6_V6ONLY			},
129
130
131
132
#endif
	{ NULL }
};

133
int getSocketOptionByName(const char* name, int* level)
134
135
136
137
138
139
140
141
142
143
144
145
{
	int i;

	if(level!=NULL)
		*level=SOL_SOCKET;	/* default option level */
	for(i=0;socket_options[i].name;i++) {
		if(stricmp(name,socket_options[i].name)==0) {
			if(level!=NULL)
				*level = socket_options[i].level;
			return(socket_options[i].value);
		}
	}
146
	if(!IS_DIGIT(*name))	/* unknown option name */
147
148
149
150
		return(-1);
	return(strtol(name,NULL,0));
}

151
socket_option_t* getSocketOptionList(void)
152
153
154
155
{
	return(socket_options);
}

156
off_t sendfilesocket(int sock, int file, off_t *offset, off_t count)
157
{
158
	char		buf[1024*16];
159
	off_t		len;
160
161
162
163
	ssize_t		rd;
	ssize_t		wr=0;
	off_t		total=0;
	ssize_t		i;
164

165
166
167
/* sendfile() on Linux may or may not work with non-blocking sockets ToDo */
	len=filelength(file);

168
169
170
171
	if(offset!=NULL)
		if(lseek(file,*offset,SEEK_SET)<0)
			return(-1);

172
	if(count<1 || count>len) {
173
		count=len;
174
175
		count-=tell(file);		/* don't try to read beyond EOF */
	}
176
177
178
179
180
181
#if USE_SENDFILE
	while((i=sendfile(file,sock,(offset==NULL?0:*offset)+total,count-total,NULL,&wr,0))==-1 && errno==EAGAIN)  {
		total+=wr;
		SLEEP(1);
	}
	if(i==0)
182
		return(count);
183
#endif
184

185
186
187
188
189
190
	if(count<0) {
		errno=EINVAL;
		return(-1);
	}

	while(total<count) {
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
		rd=read(file,buf,sizeof(buf));
		if(rd==-1)
			return(-1);
		if(rd==0)
			break;
		for(i=wr=0;i<rd;i+=wr) {
			wr=sendsocket(sock,buf+i,rd-i);
			if(wr>0)
				continue;
			if(wr==SOCKET_ERROR && ERROR_VALUE==EWOULDBLOCK) {
				wr=0;
				SLEEP(1);
				continue;
			}
			return(wr);
206
		}
207
208
209
		if(i!=rd)
			return(-1);
		total+=rd;
210
211
	}

212
	if(offset!=NULL)
213
214
215
		(*offset)+=total;

	return(total);
216
217
}

218
off_t recvfilesocket(int sock, int file, off_t *offset, off_t count)
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
{
	/* Writes a file from a socket -
	 *
	 * sock		- Socket to read from
	 * file		- File descriptior to write to
	 *				MUST be open and writeable
	 * offset	- pointer to file offset to start writing at
	 *				is set to offset writing STOPPED
	 *				on return
	 * count	- number of bytes to read/write
	 *
	 * returns -1 if an error occurse, otherwise
	 * returns number ob bytes written and sets offset
	 * to the new offset
	 */
	 
	char*	buf;
236
237
	ssize_t	rd;
	ssize_t	wr;
238
239
240
241
242
243

	if(count<1) {
		errno=ERANGE;
		return(-1);
	}
		
244
	if((buf=(char*)malloc((size_t)count))==NULL) {
245
246
247
248
		errno=ENOMEM;
		return(-1);
	}

249
250
251
	if(offset!=NULL) {
		if(lseek(file,*offset,SEEK_SET)<0) {
			free(buf);
252
			return(-1);
253
254
		}
	}
255

256
	rd=read(sock,buf,(size_t)count);
257
258
	if(rd!=count) {
		free(buf);
259
		return(-1);
260
	}
261
262
263
264
265
266

	wr=write(file,buf,rd);

	if(offset!=NULL)
		(*offset)+=wr;

267
	free(buf);
268
269
270
271
	return(wr);
}


272
/* Return true if connected, optionally sets *rd_p to true if read data available */
273
BOOL socket_check(SOCKET sock, BOOL* rd_p, BOOL* wr_p, DWORD timeout)
274
275
276
{
	char	ch;
	int		i,rd;
277
	fd_set	rd_set;
278
	fd_set*	rd_set_p=&rd_set;
279
280
	fd_set	wr_set;
	fd_set*	wr_set_p=NULL;
281
282
283
284
285
	struct	timeval tv;

	if(rd_p!=NULL)
		*rd_p=FALSE;

286
287
288
	if(wr_p!=NULL)
		*wr_p=FALSE;

289
290
291
	if(sock==INVALID_SOCKET)
		return(FALSE);

292
293
294
295
296
297
	FD_ZERO(&rd_set);
	FD_SET(sock,&rd_set);
	if(wr_p!=NULL) {
		wr_set_p=&wr_set;
		FD_ZERO(wr_set_p);
		FD_SET(sock,wr_set_p);
298
		if(rd_p==NULL)
299
			rd_set_p=NULL;
300
	}
301

302
303
304
	/* Convert timeout from ms to sec/usec */
	tv.tv_sec=timeout/1000;
	tv.tv_usec=(timeout%1000)*1000;
305

306
	i=select(sock+1,rd_set_p,wr_set_p,NULL,&tv);
307
308
309
310
311
312
	if(i==SOCKET_ERROR)
		return(FALSE);

	if(i==0) 
		return(TRUE);

313
314
315
316
317
318
	if(wr_p!=NULL && FD_ISSET(sock,wr_set_p)) {
		*wr_p=TRUE;
		if(i==1)
			return(TRUE);
	}

319
	if(rd_p !=NULL || wr_p==NULL)  {
320
321
322
323
324
325
326
		rd=recv(sock,&ch,1,MSG_PEEK);
		if(rd==1 
			|| (rd==SOCKET_ERROR && ERROR_VALUE==EMSGSIZE)) {
			if(rd_p!=NULL)
				*rd_p=TRUE;
			return(TRUE);
		}
327
328
329
330
	}

	return(FALSE);
}
deuce's avatar
deuce committed
331

332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
/*
 * Return TRUE if recv() will not block on socket
 * Will block for timeout ms or forever if timeout is negative
 *
 * This means it will return true if recv() will return an error
 * as well as if the socket is closed (and recv() will return 0)
 */
BOOL socket_readable(SOCKET sock, int timeout)
{
#ifdef _WIN32
	fd_set rd_set;
	struct timeval tv = {0};
	struct timeval *tvp = &tv;

	FD_ZERO(&rd_set);
	FD_SET(sock, &rd_set);
	if (timeout < 0)
		tvp = NULL;
	else {
		tv.tv_sec = timeout / 1000;
		tv.tv_usec = (timeout % 1000) * 1000;
	}

	switch (select(sock+1, &rd_set, NULL, NULL, tvp)) {
		case 0:		// Nothing to read
			return FALSE;
		case 1:
			return TRUE;
	}
	// Errors and unexpected cases
	return TRUE;
#else
	struct pollfd pfd = {0};
	pfd.fd = sock;
	pfd.events = POLLIN;

	if (poll(&pfd, 1, timeout) == 1)
		return TRUE;
	return FALSE;
#endif
}

/*
 * Return TRUE if send() will not block on socket
 * Will block for timeout ms or forever if timeout is negative
 *
 * This means it will return true if send() will return an error
 * as well as if the socket is closed (and send() will return 0)
 */
BOOL socket_writable(SOCKET sock, int timeout)
{
#ifdef _WIN32
	fd_set wr_set;
	struct timeval tv = {0};
	struct timeval *tvp = &tv;

	FD_ZERO(&wr_set);
	FD_SET(sock, &wr_set);
	if (timeout < 0)
		tvp = NULL;
	else {
		tv.tv_sec = timeout / 1000;
		tv.tv_usec = (timeout % 1000) * 1000;
	}

	switch (select(sock+1, NULL, &wr_set, NULL, tvp)) {
		case 0:		// Nothing to read
			return FALSE;
		case 1:
			return TRUE;
	}
	// Errors and unexpected cases
	return TRUE;
#else
	struct pollfd pfd = {0};
	pfd.fd = sock;
	pfd.events = POLLOUT;

	if (poll(&pfd, 1, timeout) == 1)
		return TRUE;
	return FALSE;
#endif
}

/*
 * Return TRUE if recv() will not block and will return zero
 * or an error. This is *not* a test if a socket is
 * disconnected, but rather that it is disconnected *AND* all
 * data has been recv()ed.
 */
BOOL socket_recvdone(SOCKET sock, int timeout)
{
#ifdef _WIN32
	fd_set rd_set;
	struct timeval tv = {0};
	struct timeval *tvp = &tv;
	char ch;
	int rd;

	FD_ZERO(&rd_set);
	FD_SET(sock, &rd_set);
	if (timeout < 0)
		tvp = NULL;
	else {
		tv.tv_sec = timeout / 1000;
		tv.tv_usec = (timeout % 1000) * 1000;
	}

	switch (select(sock+1, &rd_set, NULL, NULL, tvp)) {
		case -1:	// Error, call this disconnected
			return TRUE;
		case 0:		// Nothing to read
			return FALSE;
	}
	rd = recv(sock,&ch,1,MSG_PEEK);
	if (rd == 1 || (rd==SOCKET_ERROR && ERROR_VALUE==EMSGSIZE))
		return FALSE;
	return TRUE;
#else
	struct pollfd pfd = {0};
	pfd.fd = sock;
	pfd.events = POLLIN;

	if (poll(&pfd, 1, timeout) == 1) {
		if (pfd.revents & POLLIN)
			return FALSE;
		return TRUE;
	}
	return FALSE;
#endif
}

464
int retry_bind(SOCKET s, const struct sockaddr *addr, socklen_t addrlen
465
466
			   ,uint retries, uint wait_secs
			   ,const char* prot
467
			   ,int (*lprintf)(int level, const char *fmt, ...))
deuce's avatar
deuce committed
468
{
469
	char	port_str[128];
470
	char	err[256];
deuce's avatar
deuce committed
471
	int		result=-1;
472
	uint	i;
deuce's avatar
deuce committed
473

474
	if(addr->sa_family==AF_INET)
deuce's avatar
deuce committed
475
		SAFEPRINTF(port_str," to port %u",ntohs(((SOCKADDR_IN *)(addr))->sin_port));
476
477
	else
		port_str[0]=0;
deuce's avatar
deuce committed
478
	for(i=0;i<=retries;i++) {
479
		if((result=bind(s,addr,addrlen))==0)
deuce's avatar
deuce committed
480
			break;
481
		if(lprintf!=NULL)
482
			lprintf(i<retries ? LOG_WARNING:LOG_CRIT
483
				,"%04d !ERROR %d binding %s socket%s: %s", s, ERROR_VALUE, prot, port_str, socket_strerror(socket_errno, err, sizeof(err)));
484
485
		if(i<retries) {
			if(lprintf!=NULL)
486
487
				lprintf(LOG_WARNING,"%04d Will retry in %u seconds (%u of %u)"
					,s, wait_secs, i+1, retries);
488
489
			SLEEP(wait_secs*1000);
		}
deuce's avatar
deuce committed
490
491
492
	}
	return(result);
}
493

494
int nonblocking_connect(SOCKET sock, struct sockaddr* addr, size_t size, unsigned timeout)
495
496
497
498
499
{
	int result;

	result=connect(sock, addr, size);

500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
	if(result==SOCKET_ERROR) {
		result=ERROR_VALUE;
		if(result==EWOULDBLOCK || result==EINPROGRESS) {
			fd_set		wsocket_set;
			fd_set		esocket_set;
			struct		timeval tv;
			socklen_t	optlen=sizeof(result);
			tv.tv_sec = timeout;
			tv.tv_usec = 0;
			FD_ZERO(&wsocket_set);
			FD_SET(sock,&wsocket_set);
			FD_ZERO(&esocket_set);
			FD_SET(sock,&esocket_set);
			switch(select(sock+1,NULL,&wsocket_set,&esocket_set,&tv)) {
				case 1:
					if(getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)&result, &optlen)==SOCKET_ERROR)
						result=ERROR_VALUE;
					break;
				case 0:
					break;
				case SOCKET_ERROR:
					result=ERROR_VALUE;
					break;
			}
		}
525
526
527
	}
	return result;
}
528

deuce's avatar
deuce committed
529

530
union xp_sockaddr* inet_ptoaddr(char *addr_str, union xp_sockaddr *addr, size_t size)
deuce's avatar
deuce committed
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
{
    struct addrinfo hints = {0};
    struct addrinfo *res, *cur;

    hints.ai_flags = AI_NUMERICHOST|AI_PASSIVE;
    if(getaddrinfo(addr_str, NULL, &hints, &res))
        return NULL;
    
    for(cur = res; cur; cur++) {
        if(cur->ai_addr->sa_family == AF_INET6)
            break;
    }
    if(!cur) {
        freeaddrinfo(res);
        return NULL;
    }
547
548
549
550
551
552
    if (size < sizeof(struct sockaddr_in6)) {
        freeaddrinfo(res);
        return NULL;
	}
	size = sizeof(struct sockaddr_in6);
    memcpy(addr, ((struct sockaddr_in6 *)(cur->ai_addr)), size);
deuce's avatar
deuce committed
553
554
555
556
    freeaddrinfo(res);
    return addr;
}

557
const char* inet_addrtop(union xp_sockaddr *addr, char *dest, size_t size)
558
{
559
#ifdef _WIN32
deuce's avatar
deuce committed
560
	if(getnameinfo(&addr->addr, xp_sockaddr_len(addr), dest, size, NULL, 0, NI_NUMERICHOST))
561
		safe_snprintf(dest, size, "<Error %u converting address, family=%u>", WSAGetLastError(), addr->addr.sa_family);
562
563
	return dest;
#else
564
	switch(addr->addr.sa_family) {
565
		case AF_INET:
566
			return inet_ntop(addr->in.sin_family, &addr->in.sin_addr, dest, size);
567
		case AF_INET6:
568
			return inet_ntop(addr->in6.sin6_family, &addr->in6.sin6_addr, dest, size);
569
570
571
572
		case AF_UNIX:
			strncpy(dest, addr->un.sun_path, size);
			dest[size-1]=0;
			return dest;
573
		default:
574
			safe_snprintf(dest, size, "<unknown address family: %u>", addr->addr.sa_family);
575
576
			return NULL;
	}
577
#endif
578
579
}

580
uint16_t inet_addrport(union xp_sockaddr *addr)
581
{
582
	switch(addr->addr.sa_family) {
583
		case AF_INET:
584
			return ntohs(addr->in.sin_port);
585
		case AF_INET6:
586
			return ntohs(addr->in6.sin6_port);
587
588
589
590
		default:
			return 0;
	}
}
deuce's avatar
deuce committed
591

592
void inet_setaddrport(union xp_sockaddr *addr, uint16_t port)
deuce's avatar
deuce committed
593
594
595
596
597
598
599
600
601
602
{
	switch(addr->addr.sa_family) {
		case AF_INET:
			addr->in.sin_port = htons(port);
			break;
		case AF_INET6:
			addr->in6.sin6_port = htons(port);
			break;
	}
}
603
604

/* Return TRUE if the 2 addresses are the same host (type and address) */
605
BOOL inet_addrmatch(union xp_sockaddr* addr1, union xp_sockaddr* addr2)
606
607
608
609
610
611
612
613
614
615
616
617
{
	if(addr1->addr.sa_family != addr2->addr.sa_family)
		return FALSE;

	switch(addr1->addr.sa_family) {
		case AF_INET:
			return memcmp(&addr1->in.sin_addr, &addr2->in.sin_addr, sizeof(addr1->in.sin_addr)) == 0;
		case AF_INET6:
			return memcmp(&addr1->in6.sin6_addr, &addr2->in6.sin6_addr, sizeof(addr1->in6.sin6_addr)) == 0;
	}
	return FALSE;
}
618
619

/* Return the current socket error description (for Windows), like strerror() does for errno */
620
DLLEXPORT char* socket_strerror(int error_number, char* buf, size_t buflen)
621
{
622
#if defined(_WINSOCKAPI_)
623
624
	strncpy(buf, "Unknown error", buflen);
	buf[buflen - 1] = 0;
625
626
	if(error_number > 0 && error_number < WSABASEERR)
		error_number += WSABASEERR;
627
	if(!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK,	// dwFlags
628
629
630
		NULL,			// lpSource
		error_number,	// dwMessageId
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),    // dwLanguageId
631
632
		buf,
		buflen,
633
634
		NULL))
		safe_snprintf(buf, buflen, "Error %d getting error description", GetLastError());
635
636
637
638
	truncsp(buf);
	return buf;
#else
	return safe_strerror(error_number, buf, buflen);
639
#endif
640
}
Deucе's avatar
Deucе committed
641

642
643
644
645
646
647
648
649
650
DLLEXPORT void set_socket_errno(int err)
{
#if defined(_WINSOCKAPI_)
	WSASetLastError(err);
#else
	errno = err;
#endif
}

651
DLLEXPORT int xp_inet_pton(int af, const char *src, void *dst)
Deucе's avatar
Deucе committed
652
653
654
655
656
{
	struct addrinfo hints = {0};
	struct addrinfo *res, *cur;

	if (af != AF_INET && af != AF_INET6) {
657
		set_socket_errno(EAFNOSUPPORT);
Deucе's avatar
Deucе committed
658
659
660
661
		return -1;
	}

	hints.ai_flags = AI_NUMERICHOST|AI_PASSIVE;
662
	if(getaddrinfo(src, NULL, &hints, &res))
Deucе's avatar
Deucе committed
663
664
665
666
667
668
669
670
671
672
673
674
		return -1;

	for(cur = res; cur; cur++) {
		if(cur->ai_addr->sa_family == af)
			break;
	}
	if(!cur) {
		freeaddrinfo(res);
		return 0;
	}
	switch(af) {
		case AF_INET:
675
			memcpy(dst, &(((struct sockaddr_in *)cur)->sin_addr), sizeof(((struct sockaddr_in *)cur)->sin_addr));
Deucе's avatar
Deucе committed
676
677
			break;
		case AF_INET6:
678
			memcpy(dst, &(((struct sockaddr_in6 *)cur)->sin6_addr), sizeof(((struct sockaddr_in6 *)cur)->sin6_addr));
Deucе's avatar
Deucе committed
679
680
681
			break;
	}
	freeaddrinfo(res);
682
	return 1;
Deucе's avatar
Deucе committed
683
}