network.c revision 62505210a7e6d1b2e35fac335a6c875a7c98ccfb
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/*
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen network.c : Network stuff with IPv6 support
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen Copyright (c) 1999-2002 Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen Permission is hereby granted, free of charge, to any person obtaining
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen a copy of this software and associated documentation files (the
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen "Software"), to deal in the Software without restriction, including
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen without limitation the rights to use, copy, modify, merge, publish,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen distribute, sublicense, and/or sell copies of the Software, and to
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen permit persons to whom the Software is furnished to do so, subject to
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen the following conditions:
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen The above copyright notice and this permission notice shall be
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen included in all copies or substantial portions of the Software.
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen*/
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include "lib.h"
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include "network.h"
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include <unistd.h>
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include <fcntl.h>
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include <ctype.h>
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include <sys/un.h>
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include <netinet/tcp.h>
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#define LISTEN_BACKLOG 8
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenunion sockaddr_union {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct sockaddr sa;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct sockaddr_in sin;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#ifdef HAVE_IPV6
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct sockaddr_in6 sin6;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#endif
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen};
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen#ifdef HAVE_IPV6
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen# define SIZEOF_SOCKADDR(so) ((so).sa.sa_family == AF_INET6 ? \
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen sizeof(so.sin6) : sizeof(so.sin))
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#else
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen# define SIZEOF_SOCKADDR(so) (sizeof(so.sin))
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen#endif
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenint net_ip_compare(IPADDR *ip1, IPADDR *ip2)
27a44fcfd8d19bffe0f267f20a2b5d3fe7600fddTimo Sirainen{
27a44fcfd8d19bffe0f267f20a2b5d3fe7600fddTimo Sirainen if (ip1->family != ip2->family)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#ifdef HAVE_IPV6
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (ip1->family == AF_INET6)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return memcmp(&ip1->ip, &ip2->ip, sizeof(ip1->ip)) == 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#endif
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return memcmp(&ip1->ip, &ip2->ip, 4) == 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen/* copy IP to sockaddr */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic inline void sin_set_ip(union sockaddr_union *so, const IPADDR *ip)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (ip == NULL) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#ifdef HAVE_IPV6
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen so->sin6.sin6_family = AF_INET6;
d868a04630bd7bfe9c1543a7c3f68703b3e276e4Timo Sirainen so->sin6.sin6_addr = in6addr_any;
d868a04630bd7bfe9c1543a7c3f68703b3e276e4Timo Sirainen#else
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen so->sin.sin_family = AF_INET;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen so->sin.sin_addr.s_addr = INADDR_ANY;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#endif
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen so->sin.sin_family = ip->family;
0f3d4fbcf88e2ffd674893aed8cc1288fe17d290Timo Sirainen#ifdef HAVE_IPV6
0f3d4fbcf88e2ffd674893aed8cc1288fe17d290Timo Sirainen if (ip->family == AF_INET6)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen memcpy(&so->sin6.sin6_addr, &ip->ip, sizeof(ip->ip));
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen else
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#endif
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen memcpy(&so->sin.sin_addr, &ip->ip, 4);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic inline void sin_get_ip(const union sockaddr_union *so, IPADDR *ip)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ip->family = so->sin.sin_family;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#ifdef HAVE_IPV6
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (ip->family == AF_INET6)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen memcpy(&ip->ip, &so->sin6.sin6_addr, sizeof(ip->ip));
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen else
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#endif
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen memcpy(&ip->ip, &so->sin.sin_addr, 4);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenstatic inline void sin_set_port(union sockaddr_union *so, unsigned int port)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#ifdef HAVE_IPV6
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (so->sin.sin_family == AF_INET6)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen so->sin6.sin6_port = htons((unsigned short) port);
27902ecd70d903ee3b426ac363443268f8934b9aTimo Sirainen else
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen#endif
27902ecd70d903ee3b426ac363443268f8934b9aTimo Sirainen so->sin.sin_port = htons((unsigned short) port);
1f85b15e9bfabc5ee390d2cddcfa347a33af8689Timo Sirainen}
1f85b15e9bfabc5ee390d2cddcfa347a33af8689Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic inline unsigned int sin_get_port(union sockaddr_union *so)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#ifdef HAVE_IPV6
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (so->sin.sin_family == AF_INET6)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return ntohs(so->sin6.sin6_port);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen#endif
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen return ntohs(so->sin.sin_port);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenstatic inline void close_save_errno(int fd)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen int old_errno = errno;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen close(fd);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen errno = old_errno;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen/* Connect to socket with ip address */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenint net_connect_ip(IPADDR *ip, unsigned int port, IPADDR *my_ip)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen union sockaddr_union so;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen int fd, ret, opt = 1;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (my_ip != NULL && ip->family != my_ip->family) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_warning("net_connect_ip(): ip->family != my_ip->family");
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen my_ip = NULL;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* create the socket */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen memset(&so, 0, sizeof(so));
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen so.sin.sin_family = ip->family;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen fd = socket(ip->family, SOCK_STREAM, 0);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
1f85b15e9bfabc5ee390d2cddcfa347a33af8689Timo Sirainen if (fd == -1)
1f85b15e9bfabc5ee390d2cddcfa347a33af8689Timo Sirainen return -1;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* set socket options */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen net_set_nonblock(fd, TRUE);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(opt));
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen /* set our own address */
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen if (my_ip != NULL) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen sin_set_ip(&so, my_ip);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (bind(fd, &so.sa, SIZEOF_SOCKADDR(so)) == -1) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* failed, set it back to INADDR_ANY */
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen sin_set_ip(&so, NULL);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen bind(fd, &so.sa, SIZEOF_SOCKADDR(so));
27902ecd70d903ee3b426ac363443268f8934b9aTimo Sirainen }
27902ecd70d903ee3b426ac363443268f8934b9aTimo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* connect */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen sin_set_ip(&so, ip);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen sin_set_port(&so, port);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ret = connect(fd, &so.sa, SIZEOF_SOCKADDR(so));
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#ifndef WIN32
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (ret < 0 && errno != EINPROGRESS)
8776322310b57a11c52cfb1822f35cf18b095525Timo Sirainen#else
8776322310b57a11c52cfb1822f35cf18b095525Timo Sirainen if (ret < 0 && WSAGetLastError() != WSAEWOULDBLOCK)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#endif
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen {
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen close_save_errno(fd);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return -1;
2795f6183049a8a4cc489869b3e866dc20a8a732Baofeng Wang }
8776322310b57a11c52cfb1822f35cf18b095525Timo Sirainen
8776322310b57a11c52cfb1822f35cf18b095525Timo Sirainen return fd;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenint net_connect_unix(const char *path)
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen{
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen struct sockaddr_un sa;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen int fd, ret;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (strlen(path) > sizeof(sa.sun_path)-1) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* too long path */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen errno = EINVAL;
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen return -1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* create the socket */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen fd = socket(PF_UNIX, SOCK_STREAM, 0);
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen if (fd == -1)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return -1;
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* set socket options */
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen net_set_nonblock(fd, TRUE);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* connect */
8776322310b57a11c52cfb1822f35cf18b095525Timo Sirainen memset(&sa, 0, sizeof(sa));
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen sa.sun_family = AF_UNIX;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen strcpy(sa.sun_path, path);
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen ret = connect(fd, (struct sockaddr *) &sa, sizeof(sa));
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (ret < 0 && errno != EINPROGRESS) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen close_save_errno(fd);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return -1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
6f187ae85911f63cb87271246c68f3c13a0adb7bTimo Sirainen return fd;
6f187ae85911f63cb87271246c68f3c13a0adb7bTimo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
0f3d4fbcf88e2ffd674893aed8cc1288fe17d290Timo Sirainen/* Disconnect socket */
0f3d4fbcf88e2ffd674893aed8cc1288fe17d290Timo Sirainenvoid net_disconnect(int fd)
0f3d4fbcf88e2ffd674893aed8cc1288fe17d290Timo Sirainen{
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen if (close(fd) < 0)
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen i_error("net_disconnect() failed: %m");
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen}
27caac427c21cc358ca969fa1ccebfa476874123Timo Sirainen
27caac427c21cc358ca969fa1ccebfa476874123Timo Sirainen/* Set socket blocking/nonblocking */
27caac427c21cc358ca969fa1ccebfa476874123Timo Sirainenvoid net_set_nonblock(int fd __attr_unused__, int nonblock __attr_unused__)
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen{
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen#ifdef HAVE_FCNTL
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen if (fcntl(fd, F_SETFL, nonblock ? O_NONBLOCK : 0) < 0)
27caac427c21cc358ca969fa1ccebfa476874123Timo Sirainen i_fatal("net_send_nonblock() failed: %m");
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen#endif
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainenvoid net_set_cork(int fd __attr_unused__, int cork __attr_unused__)
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen{
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen#ifdef TCP_CORK
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (setsockopt(fd, SOL_TCP, TCP_CORK, &cork, sizeof(cork)) < 0)
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen i_error("setsockopt(TCP_CORK) failed: %m");
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen#endif
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen/* Listen for connections on a socket. if `my_ip' is NULL, listen in any
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen address. */
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainenint net_listen(IPADDR *my_ip, unsigned int *port)
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen{
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen union sockaddr_union so;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen int ret, fd, opt = 1;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen socklen_t len;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen i_assert(port != NULL);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen memset(&so, 0, sizeof(so));
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen sin_set_port(&so, *port);
62958c5eefcd7dd84717b487ca36ec3a86949eb9Timo Sirainen sin_set_ip(&so, my_ip);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen /* create the socket */
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen fd = socket(so.sin.sin_family, SOCK_STREAM, 0);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen#ifdef HAVE_IPV6
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen if (fd == -1 && (errno == EINVAL || errno == EAFNOSUPPORT)) {
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen /* IPv6 is not supported by OS */
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen so.sin.sin_family = AF_INET;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen so.sin.sin_addr.s_addr = INADDR_ANY;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen fd = socket(AF_INET, SOCK_STREAM, 0);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen }
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen#endif
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen if (fd == -1)
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen return -1;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen /* set socket options */
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen net_set_nonblock(fd, TRUE);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(opt));
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen /* specify the address/port we want to listen in */
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen ret = bind(fd, &so.sa, SIZEOF_SOCKADDR(so));
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen if (ret >= 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* get the actual port we started listen */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen len = SIZEOF_SOCKADDR(so);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ret = getsockname(fd, &so.sa, &len);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (ret >= 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen *port = sin_get_port(&so);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* start listening */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (listen(fd, LISTEN_BACKLOG) >= 0)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return fd;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* error */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen close_save_errno(fd);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return -1;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
50854b51d6408653be4dd90bd0427978df25c2b7Timo Sirainenint net_listen_unix(const char *path)
50854b51d6408653be4dd90bd0427978df25c2b7Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct sockaddr_un sa;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen int fd;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen if (strlen(path) > sizeof(sa.sun_path)-1) {
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen /* too long path */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen errno = EINVAL;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return -1;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* create the socket */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen fd = socket(PF_UNIX, SOCK_STREAM, 0);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (fd == -1)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return -1;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen /* set socket options */
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen net_set_nonblock(fd, TRUE);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* bind */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen memset(&sa, 0, sizeof(sa));
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen sa.sun_family = AF_UNIX;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen strcpy(sa.sun_path, path);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) == 0) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* start listening */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (listen(fd, LISTEN_BACKLOG) == 0)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return fd;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen close_save_errno(fd);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return -1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen/* Accept a connection on a socket */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenint net_accept(int fd, IPADDR *addr, unsigned int *port)
50854b51d6408653be4dd90bd0427978df25c2b7Timo Sirainen{
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen union sockaddr_union so;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen int ret;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen socklen_t addrlen;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_assert(fd >= 0);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen addrlen = sizeof(so);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ret = accept(fd, &so.sa, &addrlen);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen if (ret < 0)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return -1;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (addr != NULL) sin_get_ip(&so, addr);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (port != NULL) *port = sin_get_port(&so);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen net_set_nonblock(ret, TRUE);
a81b240cfe84231eac64084efd5b0e1e91a9e817Timo Sirainen return ret;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen/* Read data from socket, return number of bytes read, -1 = error */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenssize_t net_receive(int fd, void *buf, size_t len)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ssize_t ret;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_assert(fd >= 0);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_assert(buf != NULL);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_assert(len <= SSIZE_T_MAX);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ret = recv(fd, buf, len, 0);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (ret == 0)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return -1; /* disconnected */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (ret < 0 && (errno == EINTR || errno == EAGAIN))
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return ret;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen/* Transmit data, return number of bytes sent, -1 = error */
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainenssize_t net_transmit(int fd, const void *data, size_t len)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ssize_t ret;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_assert(fd >= 0);
27caac427c21cc358ca969fa1ccebfa476874123Timo Sirainen i_assert(data != NULL);
27caac427c21cc358ca969fa1ccebfa476874123Timo Sirainen i_assert(len <= SSIZE_T_MAX);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ret = send(fd, data, len, 0);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (ret == -1 && (errno == EINTR || errno == EPIPE || errno == EAGAIN))
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return ret;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen/* Get IP addresses for host. ips contains ips_count of IPs, they don't need
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen to be free'd. Returns 0 = ok, others = error code for net_gethosterror() */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenint net_gethostbyname(const char *addr, IPADDR **ips, int *ips_count)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
cc4bac5d314d4801fa9759704a29393da8f29399Timo Sirainen#ifdef HAVE_IPV6
cc4bac5d314d4801fa9759704a29393da8f29399Timo Sirainen union sockaddr_union *so;
cc4bac5d314d4801fa9759704a29393da8f29399Timo Sirainen struct addrinfo hints, *ai, *origai;
cc4bac5d314d4801fa9759704a29393da8f29399Timo Sirainen char hbuf[NI_MAXHOST];
cc4bac5d314d4801fa9759704a29393da8f29399Timo Sirainen int host_error;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#else
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct hostent *hp;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#endif
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen int count;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen i_assert(addr != NULL);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen i_assert(ips != NULL);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen i_assert(ips_count != NULL);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen *ips = NULL;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen *ips_count = 0;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen#ifdef HAVE_IPV6
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen memset(&hints, 0, sizeof(struct addrinfo));
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen hints.ai_socktype = SOCK_STREAM;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen /* save error to host_error for later use */
d646a63462a696824b1facd73e00732d4ac0f3dcTimo Sirainen host_error = getaddrinfo(addr, NULL, &hints, &ai);
d646a63462a696824b1facd73e00732d4ac0f3dcTimo Sirainen if (host_error != 0)
d646a63462a696824b1facd73e00732d4ac0f3dcTimo Sirainen return host_error;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen if (getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf,
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen return 1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
d646a63462a696824b1facd73e00732d4ac0f3dcTimo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* get number of IPs */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen origai = ai;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen for (count = 0; ai != NULL; ai = ai->ai_next)
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen count++;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen *ips_count = count;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen *ips = t_malloc(sizeof(IPADDR) * count);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
50854b51d6408653be4dd90bd0427978df25c2b7Timo Sirainen count = 0;
d646a63462a696824b1facd73e00732d4ac0f3dcTimo Sirainen for (ai = origai; ai != NULL; ai = ai->ai_next, count++) {
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen so = (union sockaddr_union *) ai->ai_addr;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen
50854b51d6408653be4dd90bd0427978df25c2b7Timo Sirainen sin_get_ip(so, ips[count]);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
50854b51d6408653be4dd90bd0427978df25c2b7Timo Sirainen freeaddrinfo(origai);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#else
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen hp = gethostbyname(addr);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (hp == NULL)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return h_errno;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* get number of IPs */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen count = 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen while (hp->h_addr_list[count] != NULL)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen count++;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen *ips_count = count;
b67974c4b89ab6950c2694cce8dfb1b6561cc084Josef 'Jeff' Sipek *ips = t_malloc(sizeof(IPADDR) * count);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen while (count > 0) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen count--;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen (*ips)[count].family = AF_INET;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen memcpy(&(*ips)[count].ip, hp->h_addr_list[count], 4);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#endif
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen/* Get socket address/port */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenint net_getsockname(int fd, IPADDR *addr, unsigned int *port)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen union sockaddr_union so;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen socklen_t addrlen;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_assert(fd >= 0);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen addrlen = sizeof(so);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (getsockname(fd, (struct sockaddr *) &so, &addrlen) == -1)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return -1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (addr != NULL) sin_get_ip(&so, addr);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (port != NULL) *port = sin_get_port(&so);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenint net_ip2host(IPADDR *ip, char *host)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#ifdef HAVE_IPV6
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (!inet_ntop(ip->family, &ip->ip, host, MAX_IP_LEN))
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return -1;
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen#else
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen unsigned long ip4;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (ip->family != AF_INET) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen strcpy(host, "0.0.0.0");
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return -1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ip4 = ntohl(ip->ip.s_addr);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_snprintf(host, MAX_IP_LEN, "%lu.%lu.%lu.%lu",
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen (ip4 & 0xff000000UL) >> 24,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen (ip4 & 0x00ff0000) >> 16,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen (ip4 & 0x0000ff00) >> 8,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen (ip4 & 0x000000ff));
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#endif
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenint net_host2ip(const char *host, IPADDR *ip)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (strchr(host, ':') != NULL) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* IPv6 */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ip->family = AF_INET6;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen#ifdef HAVE_IPV6
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen if (inet_pton(AF_INET6, host, &ip->ip) == 0)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return -1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#else
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ip->ip.s_addr = 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#endif
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen } else {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* IPv4 */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ip->family = AF_INET;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (inet_aton(host, (struct in_addr *) &ip->ip) == 0)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return -1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen/* Get socket error */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenint net_geterror(int fd)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen int data;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen socklen_t len = sizeof(data);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &data, &len) == -1)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return -1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return data;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen/* get error of net_gethostname() */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenconst char *net_gethosterror(int error)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#ifdef HAVE_IPV6
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_assert(error != 0);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (error == 1) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* getnameinfo() failed */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return strerror(errno);
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return gai_strerror(error);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#else
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen switch (error) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen case HOST_NOT_FOUND:
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return "Host not found";
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen case NO_ADDRESS:
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return "No IP address found for name";
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen case NO_RECOVERY:
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return "A non-recovable name server error occurred";
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen case TRY_AGAIN:
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return "A temporary error on an authoritative name server";
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* unknown error */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return NULL;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#endif
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen/* return TRUE if host lookup failed because it didn't exist (ie. not
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen some error with name server) */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenint net_hosterror_notfound(int error)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#ifdef HAVE_IPV6
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return error != 1 && (error == EAI_NONAME || error == EAI_NODATA);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#else
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return error == HOST_NOT_FOUND || error == NO_ADDRESS;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#endif
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen/* Get name of TCP service */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenchar *net_getservbyport(unsigned short port)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen struct servent *entry;
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen entry = getservbyport(htons(port), "tcp");
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return entry == NULL ? NULL : entry->s_name;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenint is_ipv4_address(const char *host)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen while (*host != '\0') {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (*host != '.' && !i_isdigit(*host))
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen host++;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return 1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenint is_ipv6_address(const char *host)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen while (*host != '\0') {
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen if (*host != ':' && !i_isxdigit(*host))
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen host++;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return 1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen