sockwrap.c 20.6 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 274 275 276 277
/*
 * The exact conditions where rd_p is set to TRUE and the return value
 * is true or false are complex, but the intent appears to be as follows:
 *
 * If the remote has half-closed the socket, rd_p should be FALSE and
278 279 280
 * the function should return FALSE, unless rd_p is NULL in which case
 * the function should return TRUE.  wr_p will indicate that transmit
 * buffers are available.
281
 *
282 283 284
 * If we have half-closed the socket, wr_p should be TRUE, the function
 * should return TRUE, and rd_p will indicate if there is data available
 * to be received.
285 286 287 288 289
 *
 * If the socket is completely closed, wr_p should be TRUE, rd_p should be
 * FALSE, and the function should return FALSE, unless rd_p is NULL in which
 * case, the function should return TRUE.
 *
290
 * When the function is open in both directions, wr_p will indicate transmit
291 292 293 294 295 296 297 298 299 300 301
 * buffers are available, rd_p will indicate data is available to be recv()ed
 * and the return value should be TRUE.
 *
 * If the socket is invalid, rd_p should be FALSE, wr_p should be FALSE, and
 * the function should return FALSE.
 *
 * These rules have various exceptions when errors are returned by select(),
 * poll(), or recv(), which will generally cause a FALSE return with rd_p
 * being FALSE and wr_p being FALSE if select/poll failed, or indicating
 * available write buffers otherwise.
 */
302
BOOL socket_check(SOCKET sock, BOOL* rd_p, BOOL* wr_p, DWORD timeout)
303
{
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
#ifdef PREFER_POLL
	struct pollfd pfd = {0};
	int j, rd;
	char ch;

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

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

	if(sock==INVALID_SOCKET)
		return(FALSE);

	pfd.fd = sock;
	pfd.events = POLLIN | POLLHUP;
	if (wr_p != NULL)
		pfd.events |= POLLOUT;

	j = poll(&pfd, 1, timeout);

	if (j == 0)
		return TRUE;

	if (j == 1) {
329
		if (wr_p != NULL && (pfd.revents & POLLOUT)) {
330
			*wr_p = TRUE;
331 332 333
			if (rd_p == NULL)
				return TRUE;
		}
334

335
		if (pfd.revents & (POLLERR | POLLNVAL | POLLHUP))
336 337
			return FALSE;

338
		if(pfd.revents & ~(POLLOUT) && (rd_p !=NULL || wr_p==NULL))  {
339 340 341 342
			rd=recv(sock,&ch,1,MSG_PEEK);
			if(rd==1 || (rd==SOCKET_ERROR && ERROR_VALUE==EMSGSIZE)) {
				if(rd_p!=NULL)
					*rd_p=TRUE;
343
				return TRUE;
344 345
			}
		}
346
		return FALSE;
347 348 349 350 351 352 353
	}

	if (j == -1) {
		if (errno == EINTR || errno == ENOMEM)
			return TRUE;
	}

354
	return FALSE;
355
#else
356 357
	char	ch;
	int		i,rd;
358
	fd_set	rd_set;
359
	fd_set*	rd_set_p=&rd_set;
360 361
	fd_set	wr_set;
	fd_set*	wr_set_p=NULL;
362 363 364 365 366
	struct	timeval tv;

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

367 368 369
	if(wr_p!=NULL)
		*wr_p=FALSE;

370 371 372
	if(sock==INVALID_SOCKET)
		return(FALSE);

373 374 375 376 377 378
	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);
379
		if(rd_p==NULL)
380
			rd_set_p=NULL;
381
	}
382

383 384 385
	/* Convert timeout from ms to sec/usec */
	tv.tv_sec=timeout/1000;
	tv.tv_usec=(timeout%1000)*1000;
386

387
	i=select(sock+1,rd_set_p,wr_set_p,NULL,&tv);
388 389 390 391 392 393
	if(i==SOCKET_ERROR)
		return(FALSE);

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

394 395 396 397 398 399
	if(wr_p!=NULL && FD_ISSET(sock,wr_set_p)) {
		*wr_p=TRUE;
		if(i==1)
			return(TRUE);
	}

400
	if(rd_p !=NULL || wr_p==NULL)  {
401 402 403 404 405 406 407
		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);
		}
408 409 410
	}

	return(FALSE);
411
#endif
412
}
deuce's avatar
deuce committed
413

414 415 416 417 418 419 420 421 422
/*
 * 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)
{
423 424 425 426 427 428 429 430 431
#ifdef PREFER_POLL
	struct pollfd pfd = {0};
	pfd.fd = sock;
	pfd.events = POLLIN;

	if (poll(&pfd, 1, timeout) == 1)
		return TRUE;
	return FALSE;
#else
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 464
	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;
#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)
{
465 466 467 468 469 470 471 472 473
#ifdef PREFER_POLL
	struct pollfd pfd = {0};
	pfd.fd = sock;
	pfd.events = POLLOUT;

	if (poll(&pfd, 1, timeout) == 1)
		return TRUE;
	return FALSE;
#else
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505
	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;
#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)
{
506 507 508 509 510 511 512 513 514
#ifdef PREFER_POLL
	struct pollfd pfd = {0};
	pfd.fd = sock;
	pfd.events = POLLIN;
	char ch;
	int rd;

	switch (poll(&pfd, 1, timeout)) {
		case 1:
515
			if (pfd.revents) {
516 517 518 519 520 521 522 523 524 525 526 527 528
				rd = recv(sock,&ch,1,MSG_PEEK);
				if (rd == 1 || (rd==SOCKET_ERROR && ERROR_VALUE==EMSGSIZE))
					return FALSE;
				return TRUE;
			}
			return FALSE;
		case -1:
			if (errno == EINTR || errno == ENOMEM)
				return FALSE;
			return TRUE;
	}
	return FALSE;
#else
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556
	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;
#endif
}

557
int retry_bind(SOCKET s, const struct sockaddr *addr, socklen_t addrlen
558 559
			   ,uint retries, uint wait_secs
			   ,const char* prot
560
			   ,int (*lprintf)(int level, const char *fmt, ...))
deuce's avatar
deuce committed
561
{
562
	char	port_str[128];
563
	char	err[256];
deuce's avatar
deuce committed
564
	int		result=-1;
565
	uint	i;
deuce's avatar
deuce committed
566

567
	if(addr->sa_family==AF_INET)
deuce's avatar
deuce committed
568
		SAFEPRINTF(port_str," to port %u",ntohs(((SOCKADDR_IN *)(addr))->sin_port));
569 570
	else
		port_str[0]=0;
deuce's avatar
deuce committed
571
	for(i=0;i<=retries;i++) {
572
		if((result=bind(s,addr,addrlen))==0)
deuce's avatar
deuce committed
573
			break;
574
		if(lprintf!=NULL)
575
			lprintf(i<retries ? LOG_WARNING:LOG_CRIT
576
				,"%04d !ERROR %d binding %s socket%s: %s", s, ERROR_VALUE, prot, port_str, socket_strerror(socket_errno, err, sizeof(err)));
577 578
		if(i<retries) {
			if(lprintf!=NULL)
579 580
				lprintf(LOG_WARNING,"%04d Will retry in %u seconds (%u of %u)"
					,s, wait_secs, i+1, retries);
581 582
			SLEEP(wait_secs*1000);
		}
deuce's avatar
deuce committed
583 584 585
	}
	return(result);
}
586

587
int nonblocking_connect(SOCKET sock, struct sockaddr* addr, size_t size, unsigned timeout)
588 589
{
	int result;
590
	socklen_t optlen;
591 592 593

	result=connect(sock, addr, size);

594 595 596
	if(result==SOCKET_ERROR) {
		result=ERROR_VALUE;
		if(result==EWOULDBLOCK || result==EINPROGRESS) {
597 598 599 600
			if (socket_writable(sock, timeout * 1000)) {
				result = 0;
			}
			else {
601
				optlen = sizeof(result);
602
				if(getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)&result, &optlen)==SOCKET_ERROR)
603 604 605
					result=ERROR_VALUE;
			}
		}
606 607 608
	}
	return result;
}
609

deuce's avatar
deuce committed
610

611
union xp_sockaddr* inet_ptoaddr(const char *addr_str, union xp_sockaddr *addr, size_t size)
deuce's avatar
deuce committed
612 613 614 615 616 617 618 619
{
    struct addrinfo hints = {0};
    struct addrinfo *res, *cur;

    hints.ai_flags = AI_NUMERICHOST|AI_PASSIVE;
    if(getaddrinfo(addr_str, NULL, &hints, &res))
        return NULL;
    
620
    for(cur = res; cur; cur = cur->ai_next) {
deuce's avatar
deuce committed
621 622
        if(cur->ai_addr->sa_family == AF_INET6)
            break;
623 624
        if(cur->ai_addr->sa_family == AF_INET)
            break;
deuce's avatar
deuce committed
625 626 627 628 629
    }
    if(!cur) {
        freeaddrinfo(res);
        return NULL;
    }
630 631 632 633 634 635
    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
636 637 638 639
    freeaddrinfo(res);
    return addr;
}

640
const char* inet_addrtop(union xp_sockaddr *addr, char *dest, size_t size)
641
{
642
#ifdef _WIN32
deuce's avatar
deuce committed
643
	if(getnameinfo(&addr->addr, xp_sockaddr_len(addr), dest, size, NULL, 0, NI_NUMERICHOST))
644
		safe_snprintf(dest, size, "<Error %u converting address, family=%u>", WSAGetLastError(), addr->addr.sa_family);
645 646
	return dest;
#else
647
	switch(addr->addr.sa_family) {
648
		case AF_INET:
649
			return inet_ntop(addr->in.sin_family, &addr->in.sin_addr, dest, size);
650
		case AF_INET6:
651
			return inet_ntop(addr->in6.sin6_family, &addr->in6.sin6_addr, dest, size);
652 653 654 655
		case AF_UNIX:
			strncpy(dest, addr->un.sun_path, size);
			dest[size-1]=0;
			return dest;
656
		default:
657
			safe_snprintf(dest, size, "<unknown address family: %u>", addr->addr.sa_family);
658 659
			return NULL;
	}
660
#endif
661 662
}

663
uint16_t inet_addrport(union xp_sockaddr *addr)
664
{
665
	switch(addr->addr.sa_family) {
666
		case AF_INET:
667
			return ntohs(addr->in.sin_port);
668
		case AF_INET6:
669
			return ntohs(addr->in6.sin6_port);
670 671 672 673
		default:
			return 0;
	}
}
deuce's avatar
deuce committed
674

675
void inet_setaddrport(union xp_sockaddr *addr, uint16_t port)
deuce's avatar
deuce committed
676 677 678 679 680 681 682 683 684 685
{
	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;
	}
}
686 687

/* Return TRUE if the 2 addresses are the same host (type and address) */
688
BOOL inet_addrmatch(union xp_sockaddr* addr1, union xp_sockaddr* addr2)
689 690 691 692 693 694 695 696 697 698 699 700
{
	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;
}
701 702

/* Return the current socket error description (for Windows), like strerror() does for errno */
703
DLLEXPORT char* socket_strerror(int error_number, char* buf, size_t buflen)
704
{
705
#if defined(_WINSOCKAPI_)
706 707
	strncpy(buf, "Unknown error", buflen);
	buf[buflen - 1] = 0;
708 709
	if(error_number > 0 && error_number < WSABASEERR)
		error_number += WSABASEERR;
710
	if(!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK,	// dwFlags
711 712 713
		NULL,			// lpSource
		error_number,	// dwMessageId
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),    // dwLanguageId
714 715
		buf,
		buflen,
716 717
		NULL))
		safe_snprintf(buf, buflen, "Error %d getting error description", GetLastError());
718 719 720 721
	truncsp(buf);
	return buf;
#else
	return safe_strerror(error_number, buf, buflen);
722
#endif
723
}
Deucе's avatar
Deucе committed
724

725 726 727 728 729 730 731 732 733
DLLEXPORT void set_socket_errno(int err)
{
#if defined(_WINSOCKAPI_)
	WSASetLastError(err);
#else
	errno = err;
#endif
}

734
DLLEXPORT int xp_inet_pton(int af, const char *src, void *dst)
Deucе's avatar
Deucе committed
735 736 737 738 739
{
	struct addrinfo hints = {0};
	struct addrinfo *res, *cur;

	if (af != AF_INET && af != AF_INET6) {
740
		set_socket_errno(EAFNOSUPPORT);
Deucе's avatar
Deucе committed
741 742 743 744
		return -1;
	}

	hints.ai_flags = AI_NUMERICHOST|AI_PASSIVE;
745
	if(getaddrinfo(src, NULL, &hints, &res))
Deucе's avatar
Deucе committed
746 747 748 749 750 751 752 753 754 755 756 757
		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:
758
			memcpy(dst, &(((struct sockaddr_in *)cur->ai_addr)->sin_addr), sizeof(((struct sockaddr_in *)cur->ai_addr)->sin_addr));
Deucе's avatar
Deucе committed
759 760
			break;
		case AF_INET6:
761
			memcpy(dst, &(((struct sockaddr_in6 *)cur->ai_addr)->sin6_addr), sizeof(((struct sockaddr_in6 *)cur->ai_addr)->sin6_addr));
Deucе's avatar
Deucе committed
762 763 764
			break;
	}
	freeaddrinfo(res);
765
	return 1;
Deucе's avatar
Deucе committed
766
}
Deucе's avatar
Deucе committed
767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844

#ifdef _WIN32
DLLEXPORT int
socketpair(int domain, int type, int protocol, SOCKET *sv)
{
	union xp_sockaddr la = {0};
	const int ra = 1;
	SOCKET ls;
	SOCKET *check;
	fd_set rfd;
	struct timeval tv;
	size_t sa_len;

	sv[0] = sv[1] = INVALID_SOCKET;
	ls = socket(domain, type, protocol);
	if (ls == INVALID_SOCKET)
		goto fail;
	switch (domain) {
		case PF_INET:
			if (inet_ptoaddr("127.0.0.1", &la, sizeof(la)) == NULL)
				goto fail;
			sa_len = sizeof(la.in);
			break;
		case PF_INET6:
			if (inet_ptoaddr("::1", &la, sizeof(la)) == NULL)
				goto fail;
			sa_len = sizeof(la.in6);
			break;
		default:
			goto fail;
	}
	inet_setaddrport(&la, 0);
	if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, (const char *)&ra, sizeof(ra)) == -1)
		goto fail;
	if (bind(ls, &la.addr, sa_len) == -1)
		goto fail;
	if (getsockname(ls, &la.addr, &sa_len) == -1)
		goto fail;
	if (listen(ls, 1) == -1)
		goto fail;
	sv[0] = socket(la.addr.sa_family, type, protocol);
	if (sv[0] == INVALID_SOCKET)
		goto fail;
	if (connect(sv[0], &la.addr, sa_len) == -1)
		goto fail;
	sv[1] = accept(ls, NULL, NULL);
	if (sv[1] == INVALID_SOCKET)
		goto fail;
	closesocket(ls);
	ls = INVALID_SOCKET;

	if (send(sv[1], (const char *)&sv, sizeof(sv), 0) != sizeof(sv))
		goto fail;
	tv.tv_sec = 0;
	tv.tv_usec = 50000;
	FD_ZERO(&rfd);
	FD_SET(sv[0], &rfd);
	if (select(sv[0] + 1, &rfd, NULL, NULL, &tv) != 1)
		goto fail;
	if (recv(sv[0], (char *)&check, sizeof(check), 0) != sizeof(check))
		goto fail;
	if (check != sv)
		goto fail;
	return 0;

fail:
	if (ls != INVALID_SOCKET)
		closesocket(ls);
	if (sv[0] != INVALID_SOCKET)
		closesocket(sv[0]);
	sv[0] = INVALID_SOCKET;
	if (sv[1] != INVALID_SOCKET)
		closesocket(sv[1]);
	sv[1] = INVALID_SOCKET;
	return -1;
}
#endif