/*- * Copyright (c) 2004 Free (Olivier Beyssac) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "net.h" #include "utils.h" #include "options.h" #define LISTENQ 5 struct options opt; /* Set a socket non-blocking. Return 1 if successful, 0 if not */ extern int net_socket_set_nb(const int sd) { int flags; if ((flags = fcntl(sd, F_GETFL, 0)) == -1) { syslog(LOG_ERR, "fcntl: %s", strerror(errno)); return 0; } if ((fcntl(sd, F_SETFL, flags | O_NONBLOCK)) == -1) { syslog(LOG_ERR, "fcntl: %s", strerror(errno)); return 0; } return 1; } /* Return a TCP socket listening on ip:port Return -1 on error */ extern int net_server_sock_create(const char *ip, const char *port) { struct sockaddr_in servaddr; struct servent *sv; struct hostent *h; int listen_port; int optval = 1; int sd; if ((listen_port = atoi(port)) == 0) { if ((sv = getservbyname(port, "tcp")) == NULL) { syslog(LOG_ERR, "getservbyname() error on %s", port); return -1; } else { listen_port = ntohs(sv->s_port); } } if ((h = gethostbyname(ip)) == NULL) { syslog(LOG_ERR, "gethostbyname() error on %s\n", ip); return -1; } memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = h->h_addrtype; memcpy((char *)&servaddr.sin_addr.s_addr, h->h_addr_list[0], h->h_length); servaddr.sin_port = htons(listen_port); if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { syslog(LOG_ERR, "socket(): %s", strerror(errno)); return -1; } setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); if (bind(sd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) { syslog(LOG_ERR, "bind() to port %s: %s", port, strerror(errno)); return -1; } if (listen(sd, LISTENQ) == -1) { syslog(LOG_ERR, "listen() on port %s: %s", port, strerror(errno)); return -1; } return sd; } static void alrm_signal_handler(const int signum) { if (opt.log_level >= 3) syslog(LOG_INFO, "caught signal %d", signum); } /* Return a TCP socket connected to server:port Return -1 on error NOTE: SIGALRM used to handle connect(2) timeout */ extern int net_client_sock_create(const char *server, const char *server_port) { int sd, port; struct sockaddr_in local_addr, serv_addr; struct hostent *h; struct servent *sv; struct sigaction sa; if ((h = gethostbyname(server)) == NULL) return -1; if ((port = atoi(server_port)) == 0) { if ((sv = getservbyname(server_port, "tcp")) == NULL) return -1; else port = sv->s_port; } serv_addr.sin_family = h->h_addrtype; memcpy((char *)&serv_addr.sin_addr.s_addr, h->h_addr_list[0], h->h_length); serv_addr.sin_port = htons(port); if ((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0) return -1; local_addr.sin_family = AF_INET; local_addr.sin_addr.s_addr = htonl(INADDR_ANY); local_addr.sin_port = htons(0); if (bind(sd, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) return -1; xsigaction(sa, SIGALRM, alrm_signal_handler); alarm(opt.connect_timeout); if (connect(sd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) return -1; alarm(0); xsigaction(sa, SIGALRM, SIG_IGN); return sd; }