1 /***************************************************************************\
3 * BitlBee - An IRC to IM gateway *
4 * Utility functions for file transfer *
6 * Copyright 2008 Uli Meis <a.sporto+bee@gmail.com> *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
18 * You should have received a copy of the GNU General Public License along *
19 * with this program; if not, write to the Free Software Foundation, Inc., *
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
22 \***************************************************************************/
27 #include <netinet/tcp.h>
28 #include "lib/ftutil.h"
30 #define ASSERTSOCKOP(op, msg) \
32 g_snprintf( errmsg, sizeof( errmsg ), msg ": %s", strerror( errno ) ); \
36 * Creates a listening socket and returns it in saddr_ptr.
38 int ft_listen( struct sockaddr_storage
*saddr_ptr
, char *host
, char *port
, int copy_fd
, int for_bitlbee_client
, char **errptr
)
40 int fd
, gret
, saddrlen
;
41 struct addrinfo hints
, *rp
;
42 socklen_t ssize
= sizeof( struct sockaddr_storage
);
43 struct sockaddr_storage saddrs
, *saddr
= &saddrs
;
44 static char errmsg
[1024];
45 char *ftlisten
= global
.conf
->ft_listen
;
52 /* Format is <IP-A>[:<Port-A>];<IP-B>[:<Port-B>] where
53 * A is for connections with the bitlbee client (DCC)
54 * and B is for connections with IM peers.
58 char *scolon
= strchr( ftlisten
, ';' );
63 if( for_bitlbee_client
)
66 strncpy( host
, ftlisten
, HOST_NAME_MAX
);
71 strncpy( host
, scolon
+ 1, HOST_NAME_MAX
);
76 strncpy( host
, ftlisten
, HOST_NAME_MAX
);
79 if( ( colon
= strchr( host
, ':' ) ) )
82 strncpy( port
, colon
+ 1, 5 );
85 else if( copy_fd
>= 0 && getsockname( copy_fd
, (struct sockaddr
*) &saddrs
, &ssize
) == 0 &&
86 ( saddrs
.ss_family
== AF_INET
|| saddrs
.ss_family
== AF_INET6
) &&
87 getnameinfo( (struct sockaddr
*) &saddrs
, ssize
, host
, HOST_NAME_MAX
,
88 NULL
, 0, NI_NUMERICHOST
) == 0 )
90 /* We just took our local address on copy_fd, which is likely to be a
91 sensible address from which we can do a file transfer now - the
92 most sensible we can get easily. */
96 ASSERTSOCKOP( gethostname( host
, HOST_NAME_MAX
+ 1 ), "gethostname()" );
99 memset( &hints
, 0, sizeof( struct addrinfo
) );
100 hints
.ai_socktype
= SOCK_STREAM
;
101 hints
.ai_flags
= AI_NUMERICSERV
;
103 if ( ( gret
= getaddrinfo( host
, port
, &hints
, &rp
) ) != 0 )
105 sprintf( errmsg
, "getaddrinfo() failed: %s", gai_strerror( gret
) );
109 saddrlen
= rp
->ai_addrlen
;
111 memcpy( saddr
, rp
->ai_addr
, saddrlen
);
115 ASSERTSOCKOP( fd
= socket( saddr
->ss_family
, SOCK_STREAM
, 0 ), "Opening socket" );
116 ASSERTSOCKOP( bind( fd
, ( struct sockaddr
*)saddr
, saddrlen
), "Binding socket" );
117 ASSERTSOCKOP( listen( fd
, 1 ), "Making socket listen" );
119 if ( !inet_ntop( saddr
->ss_family
, saddr
->ss_family
== AF_INET
?
120 ( void * )&( ( struct sockaddr_in
* ) saddr
)->sin_addr
.s_addr
:
121 ( void * )&( ( struct sockaddr_in6
* ) saddr
)->sin6_addr
.s6_addr
,
122 host
, HOST_NAME_MAX
) )
124 strcpy( errmsg
, "inet_ntop failed on listening socket" );
128 ssize
= sizeof( struct sockaddr_storage
);
129 ASSERTSOCKOP( getsockname( fd
, ( struct sockaddr
*)saddr
, &ssize
), "Getting socket name" );
131 if( saddr
->ss_family
== AF_INET
)
132 g_snprintf( port
, 6, "%d", ntohs( ( (struct sockaddr_in
*) saddr
)->sin_port
) );
134 g_snprintf( port
, 6, "%d", ntohs( ( (struct sockaddr_in6
*) saddr
)->sin6_port
) );
137 memcpy( saddr_ptr
, saddr
, saddrlen
);
139 /* I hate static-length strings.. */
140 host
[HOST_NAME_MAX
] = '\0';