diff options
Diffstat (limited to 'lib/ftutil.c')
-rw-r--r-- | lib/ftutil.c | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/lib/ftutil.c b/lib/ftutil.c new file mode 100644 index 00000000..d59dd4e0 --- /dev/null +++ b/lib/ftutil.c @@ -0,0 +1,134 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Utility functions for file transfer * +* * +* Copyright 2008 Uli Meis <a.sporto+bee@gmail.com> * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License along * +* with this program; if not, write to the Free Software Foundation, Inc., * +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* * +\***************************************************************************/ + +#define BITLBEE_CORE +#include "bitlbee.h" +#include <poll.h> +#include <netinet/tcp.h> +#include "lib/ftutil.h" + +#define ASSERTSOCKOP(op, msg) \ + if( (op) == -1 ) {\ + g_snprintf( errmsg, sizeof( errmsg ), msg ": %s", strerror( errno ) ); \ + return -1; } + +/* + * Creates a listening socket and returns it in saddr_ptr. + */ +int ft_listen( struct sockaddr_storage *saddr_ptr, char *host, char *port, int for_bitlbee_client, char **errptr ) +{ + int fd, gret, saddrlen; + struct addrinfo hints, *rp; + socklen_t ssize = sizeof( struct sockaddr_storage ); + struct sockaddr_storage saddrs, *saddr = &saddrs; + static char errmsg[1024]; + char *ftlisten = global.conf->ft_listen; + + if( errptr ) + *errptr = errmsg; + + strcpy( port, "0" ); + + /* Format is <IP-A>[:<Port-A>];<IP-B>[:<Port-B>] where + * A is for connections with the bitlbee client (DCC) + * and B is for connections with IM peers. + */ + if( ftlisten ) + { + char *scolon = strchr( ftlisten, ';' ); + char *colon; + + if( scolon ) + { + if( for_bitlbee_client ) + { + *scolon = '\0'; + strncpy( host, ftlisten, HOST_NAME_MAX ); + *scolon = ';'; + } + else + { + strncpy( host, scolon + 1, HOST_NAME_MAX ); + } + } + else + { + strncpy( host, ftlisten, HOST_NAME_MAX ); + } + + if( ( colon = strchr( host, ':' ) ) ) + { + *colon = '\0'; + strncpy( port, colon + 1, 5 ); + } + } + else + { + ASSERTSOCKOP( gethostname( host, HOST_NAME_MAX + 1 ), "gethostname()" ); + } + + memset( &hints, 0, sizeof( struct addrinfo ) ); + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICSERV; + + if ( ( gret = getaddrinfo( host, port, &hints, &rp ) ) != 0 ) + { + sprintf( errmsg, "getaddrinfo() failed: %s", gai_strerror( gret ) ); + return -1; + } + + saddrlen = rp->ai_addrlen; + + memcpy( saddr, rp->ai_addr, saddrlen ); + + freeaddrinfo( rp ); + + ASSERTSOCKOP( fd = socket( saddr->ss_family, SOCK_STREAM, 0 ), "Opening socket" ); + ASSERTSOCKOP( bind( fd, ( struct sockaddr *)saddr, saddrlen ), "Binding socket" ); + ASSERTSOCKOP( listen( fd, 1 ), "Making socket listen" ); + + if ( !inet_ntop( saddr->ss_family, saddr->ss_family == AF_INET ? + ( void * )&( ( struct sockaddr_in * ) saddr )->sin_addr.s_addr : + ( void * )&( ( struct sockaddr_in6 * ) saddr )->sin6_addr.s6_addr, + host, HOST_NAME_MAX ) ) + { + strcpy( errmsg, "inet_ntop failed on listening socket" ); + return -1; + } + + ASSERTSOCKOP( getsockname( fd, ( struct sockaddr *)saddr, &ssize ), "Getting socket name" ); + + if( saddr->ss_family == AF_INET ) + g_snprintf( port, 6, "%d", ntohs( ( (struct sockaddr_in *) saddr )->sin_port ) ); + else + g_snprintf( port, 6, "%d", ntohs( ( (struct sockaddr_in6 *) saddr )->sin6_port ) ); + + if( saddr_ptr ) + memcpy( saddr_ptr, saddr, saddrlen ); + + /* I hate static-length strings.. */ + host[HOST_NAME_MAX] = '\0'; + port[5] = '\0'; + + return fd; +} |