serve: Refactor some socket utility code into its own module.
We'll be using this in proxy mode later
This commit is contained in:
104
src/sockutil.c
Normal file
104
src/sockutil.c
Normal file
@@ -0,0 +1,104 @@
|
||||
#include "sockutil.h"
|
||||
#include "util.h"
|
||||
|
||||
size_t sockaddr_size(const struct sockaddr* sa)
|
||||
{
|
||||
size_t ret = 0;
|
||||
|
||||
switch( sa->sa_family ) {
|
||||
case AF_INET:
|
||||
ret = sizeof( struct sockaddr_in );
|
||||
break;
|
||||
case AF_INET6:
|
||||
ret = sizeof( struct sockaddr_in6 );
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char* sockaddr_address_string(const struct sockaddr* sa, char* dest, size_t len)
|
||||
{
|
||||
NULLCHECK( sa );
|
||||
NULLCHECK( dest );
|
||||
|
||||
struct sockaddr_in* in = ( struct sockaddr_in* ) sa;
|
||||
struct sockaddr_in6* in6 = ( struct sockaddr_in6* ) sa;
|
||||
|
||||
unsigned short real_port = ntohs( in->sin_port ); // common to in and in6
|
||||
size_t size;
|
||||
const char* ret = NULL;
|
||||
|
||||
memset( dest, 0, len );
|
||||
|
||||
if ( sa->sa_family == AF_INET ) {
|
||||
ret = inet_ntop( AF_INET, &in->sin_addr, dest, len );
|
||||
} else if ( sa->sa_family == AF_INET6 ) {
|
||||
ret = inet_ntop( AF_INET6, &in6->sin6_addr, dest, len );
|
||||
} else {
|
||||
strncpy( dest, "???", len );
|
||||
}
|
||||
|
||||
if ( NULL != ret && real_port > 0 ) {
|
||||
size = strlen( dest );
|
||||
snprintf( dest + size, len - size, " port %d", real_port );
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sock_set_reuseaddr(int fd, int optval)
|
||||
{
|
||||
return setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval) );
|
||||
}
|
||||
|
||||
/* Set the tcp_nodelay option */
|
||||
int sock_set_tcp_nodelay(int fd, int optval)
|
||||
{
|
||||
return setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval) );
|
||||
}
|
||||
|
||||
int sock_try_bind(int fd, const struct sockaddr* sa)
|
||||
{
|
||||
int bind_result;
|
||||
char s_address[256];
|
||||
|
||||
sockaddr_address_string( sa, &s_address[0], 256 );
|
||||
|
||||
do {
|
||||
bind_result = bind( fd, sa, sockaddr_size( sa ) );
|
||||
if ( 0 == bind_result ) {
|
||||
info( "Bound to %s", s_address );
|
||||
break;
|
||||
}
|
||||
else {
|
||||
warn( SHOW_ERRNO( "Couldn't bind to %s", s_address ) );
|
||||
|
||||
switch ( errno ) {
|
||||
/* bind() can give us EACCES, EADDRINUSE, EADDRNOTAVAIL, EBADF,
|
||||
* EINVAL, ENOTSOCK, EFAULT, ELOOP, ENAMETOOLONG, ENOENT,
|
||||
* ENOMEM, ENOTDIR, EROFS
|
||||
*
|
||||
* Any of these other than EADDRINUSE & EADDRNOTAVAIL signify
|
||||
* that there's a logic error somewhere.
|
||||
*
|
||||
* EADDRINUSE is fatal: if there's something already where we
|
||||
* want to be listening, we have no guarantees that any clients
|
||||
* will cope with it.
|
||||
*/
|
||||
case EADDRNOTAVAIL:
|
||||
debug( "retrying" );
|
||||
sleep( 1 );
|
||||
continue;
|
||||
case EADDRINUSE:
|
||||
warn( "%s in use, giving up.", s_address );
|
||||
break;
|
||||
default:
|
||||
warn( "giving up" );
|
||||
}
|
||||
}
|
||||
} while ( 1 );
|
||||
|
||||
return bind_result;
|
||||
}
|
||||
|
Reference in New Issue
Block a user