network.c revision 0b56ba659328b7186b74c764702ecbe403c98839
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen network.c : Network stuff with IPv6 support
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen Copyright (c) 1999-2002 Timo Sirainen
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen Permission is hereby granted, free of charge, to any person obtaining
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen a copy of this software and associated documentation files (the
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen "Software"), to deal in the Software without restriction, including
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen without limitation the rights to use, copy, modify, merge, publish,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen distribute, sublicense, and/or sell copies of the Software, and to
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen permit persons to whom the Software is furnished to do so, subject to
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen the following conditions:
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen The above copyright notice and this permission notice shall be
300e4e43ed1ca46d0614459161ca2fb460ef661aTimo Sirainen included in all copies or substantial portions of the Software.
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
ae46f6ba5bb9eee8900254d3042e89d490023be0Timo Sirainen SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi# define SIZEOF_SOCKADDR(so) ((so).sa.sa_family == AF_INET6 ? \
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomiint net_ip_compare(const struct ip_addr *ip1, const struct ip_addr *ip2)
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi return memcmp(&ip1->ip, &ip2->ip, sizeof(ip1->ip)) == 0;
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi/* copy IP to sockaddr */
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvistatic inline void
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvisin_set_ip(union sockaddr_union *so, const struct ip_addr *ip)
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen memcpy(&so->sin6.sin6_addr, &ip->ip, sizeof(ip->ip));
6468191d64827a2d1481c091ec499874583c834eTimo Sirainenstatic inline void
6468191d64827a2d1481c091ec499874583c834eTimo Sirainensin_get_ip(const union sockaddr_union *so, struct ip_addr *ip)
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen memcpy(&ip->ip, &so->sin6.sin6_addr, sizeof(ip->ip));
6468191d64827a2d1481c091ec499874583c834eTimo Sirainenstatic inline void sin_set_port(union sockaddr_union *so, unsigned int port)
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen so->sin6.sin6_port = htons((unsigned short) port);
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen so->sin.sin_port = htons((unsigned short) port);
5545acdd3aa90a6e0cca2b665f909ec4c2fb2513Baofengstatic inline unsigned int sin_get_port(union sockaddr_union *so)
009217abb57a24a4076092e8e4e165545747839eStephan Bosch/* Connect to socket with ip address */
6468191d64827a2d1481c091ec499874583c834eTimo Sirainenint net_connect_ip(const struct ip_addr *ip, unsigned int port,
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen if (my_ip != NULL && ip->family != my_ip->family) {
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen i_warning("net_connect_ip(): ip->family != my_ip->family");
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen /* create the socket */
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen /* set socket options */
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(opt));
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen /* set our own address */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (bind(fd, &so.sa, SIZEOF_SOCKADDR(so)) == -1) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* failed, set it back to INADDR_ANY */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* connect */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ret = connect(fd, &so.sa, SIZEOF_SOCKADDR(so));
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen if (ret < 0 && WSAGetLastError() != WSAEWOULDBLOCK)
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen if (strocpy(sa.sun_path, path, sizeof(sa.sun_path)) < 0) {
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen /* too long path */
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen /* create the socket */
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen /* connect */
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen ret = connect(fd, (struct sockaddr *) &sa, sizeof(sa));
db3b95d5a33ddce552d41136ae68d7331f8bf5feTimo Sirainen/* Disconnect socket */
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen/* Set socket blocking/nonblocking */
6468191d64827a2d1481c091ec499874583c834eTimo Sirainenvoid net_set_nonblock(int fd __attr_unused__, int nonblock __attr_unused__)
6468191d64827a2d1481c091ec499874583c834eTimo Sirainen if (fcntl(fd, F_SETFL, nonblock ? O_NONBLOCK : 0) < 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenint net_set_cork(int fd __attr_unused__, int cork __attr_unused__)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return setsockopt(fd, SOL_TCP, TCP_CORK, &cork, sizeof(cork));
2efe19d9045768d985a3bd549cff12f65ba40cc8Timo Sirainen struct in_addr *in_ip = (struct in_addr *) &ip->ip;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen/* Listen for connections on a socket. if `my_ip' is NULL, listen in any
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenint net_listen(const struct ip_addr *my_ip, unsigned int *port)
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen /* create the socket */
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen fd = socket(so.sin.sin_family, SOCK_STREAM, 0);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (fd == -1 && (errno == EINVAL || errno == EAFNOSUPPORT)) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* IPv6 is not supported by OS */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* set socket options */
c4900d31385344bfadaee53a897daeafdb3063d8Timo Sirainen setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(opt));
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen /* specify the address/port we want to listen in */
69b22a0c0c84087e5bdeec71faae7ea77295240fTimo Sirainen /* get the actual port we started listen */
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek /* start listening */
412b772c337428b72149605c1410524c2353e5d4Timo Sirainen if (strocpy(sa.sun_path, path, sizeof(sa.sun_path)) < 0) {
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen /* too long path */
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen /* create the socket */
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) == 0) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen /* start listening */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen/* Accept a connection on a socket */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenint net_accept(int fd, struct ip_addr *addr, unsigned int *port)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen errno == EOPNOTSUPP || errno == EFAULT || errno == EINVAL)
if (ret == 0) {
errno = 0;
if (ret < 0) {
return ret;
return ret;
#ifdef HAVE_IPV6
int host_error;
int count;
*ips_count = 0;
#ifdef HAVE_IPV6
if (host_error != 0)
return host_error;
count++;
count = 0;
return h_errno;
count = 0;
count++;
while (count > 0) {
count--;
#ifdef HAVE_IPV6
return NULL;
unsigned long ip4;
return NULL;
#ifdef HAVE_IPV6
int data;
return data;
#ifdef HAVE_IPV6
switch (error) {
case HOST_NOT_FOUND:
case NO_ADDRESS:
case NO_RECOVERY:
case TRY_AGAIN:
return NULL;
#ifdef HAVE_IPV6
host++;
host++;