diff --git a/configure.ac b/configure.ac index ac1e2d7ac..f8fe898c0 100644 --- a/configure.ac +++ b/configure.ac @@ -146,15 +146,7 @@ AC_CHECK_FUNC(gethostbyname, , AC_CHECK_LIB(nsl, main, AC_CHECK_FUNC(gethostbyname, , AC_CHECK_LIB(ws2_32, main, [NET_LIBS="$NET_LIBS -lws2_32"], [], [])) LIBS="$LIBS $NET_LIBS" -AC_CHECK_FUNCS(getaddrinfo gai_strerror) -AC_CHECK_TYPES([struct addrinfo],[],[],[ - #ifdef HAVE_NETDB_H - #include - #endif - #ifdef HAVE_WS2TCPIP_H - #include - #endif - ]) +HL_GETADDRINFO LIBS=$hl_oldLibs AC_SUBST(NET_LIBS) diff --git a/lib/Makefile.am b/lib/Makefile.am index 7df9e3b14..45d978614 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,7 +1,7 @@ EXTRA_DIST = getopt.c getopt.h getopt_long.c usleep.c \ - termios.c win32termios.h gettimeofday.c + termios.c win32termios.h gettimeofday.c getaddrinfo.c noinst_LTLIBRARIES = libmisc.la libmisc_la_SOURCES = -libmisc_la_LIBADD = @LTLIBOBJS@ +libmisc_la_LIBADD = @LTLIBOBJS@ @NET_LIBS@ diff --git a/lib/getaddrinfo.c b/lib/getaddrinfo.c new file mode 100644 index 000000000..d99e0aac7 --- /dev/null +++ b/lib/getaddrinfo.c @@ -0,0 +1,130 @@ +/* + * Hamlib Interface - getaddrinfo replacement + * Copyright (c) 2000-2010 by Stephane Fillod + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library 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 Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* Forcing WINVER in MinGW yanks in getaddrinfo(), but locks out Win95/Win98 */ +/* #define WINVER 0x0501 */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include /* Standard input/output definitions */ +#include /* UNIX standard function definitions */ +#include /* File control definitions */ +#include /* Error number definitions */ +#include +#include + + +#ifdef HAVE_NETINET_IN_H +#include +#endif +#if HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#elif HAVE_WS2TCPIP_H +#include +#endif + +/* + * Replacement for getaddrinfo. Only one addrinfo is returned. + * Weak checking. + * Return 0 when success, otherwise -1. + */ +#ifndef HAVE_GETADDRINFO +int getaddrinfo(const char *node, const char *service, + const struct addrinfo *hints, struct addrinfo **res) +{ + struct addrinfo *p; + int ai_family, ai_socktype, ai_protocol, ai_flags; + + /* limitation: service must be non null */ + if (!service) + return -1; + + if (hints == NULL) { + ai_family = AF_UNSPEC; + ai_socktype = 0; + ai_protocol = 0; + ai_flags = 0; + } else { + ai_family = hints->ai_family; + ai_socktype = hints->ai_socktype; + ai_protocol = hints->ai_protocol; + ai_flags = hints->ai_flags; + } + + /* limitation: this replacement function only for IPv4 */ + if (ai_family == AF_UNSPEC) + ai_family = AF_INET; + + if (ai_family != AF_INET) + return -1; + + p = malloc(sizeof(struct addrinfo)); + if (!p) + return -1; + + memset(p, 0, sizeof(struct addrinfo)); + p->ai_family = ai_family; + p->ai_socktype = ai_socktype; + p->ai_protocol = ai_protocol; + p->ai_addrlen = sizeof(struct sockaddr_in); + p->ai_addr = malloc(p->ai_addrlen); + if (!p->ai_addr) { + free(p); + return -1; + } + memset((char *) p->ai_addr, 0, p->ai_addrlen); + + ((struct sockaddr_in*)p->ai_addr)->sin_family = p->ai_family; + /* limitation: the service must be a port _number_ */ + ((struct sockaddr_in*)p->ai_addr)->sin_port = htons(atoi(service)); + /* limitation: the node must be in numbers-and-dots notation */ + if (!node && (ai_flags & AI_PASSIVE)) + ((struct sockaddr_in*)p->ai_addr)->sin_addr.s_addr = INADDR_ANY; + else + ((struct sockaddr_in*)p->ai_addr)->sin_addr.s_addr = inet_addr(node); + + *res = p; + + return 0; +} + +void freeaddrinfo(struct addrinfo *res) +{ + free(res->ai_addr); + free(res); +} +#endif /* !HAVE_GETADDRINFO */ + +#if !defined(HAVE_GAI_STRERROR) && !defined(gai_strerror) +const char *gai_strerror(int errcode) +{ + return strerror(errcode); +} +#endif /* !HAVE_GAI_STRERROR */ + diff --git a/macros/Makefile.am b/macros/Makefile.am index cc7658718..dd96b861e 100644 --- a/macros/Makefile.am +++ b/macros/Makefile.am @@ -7,6 +7,7 @@ MACROS = \ gr_doxygen.m4 \ gr_pwin32.m4 \ gr_swig.m4 \ + hl_getaddrinfo.m4 \ libtool.m4 \ ltdl.m4 \ perl.m4 \ diff --git a/macros/hl_getaddrinfo.m4 b/macros/hl_getaddrinfo.m4 new file mode 100644 index 000000000..42894c8e5 --- /dev/null +++ b/macros/hl_getaddrinfo.m4 @@ -0,0 +1,107 @@ +# Check for getaddrinfo replacement. -*- Autoconf -*- + +# Copyright (c) 2010 by Stephane Fillod +# +# This file is part of Hamlib +# +# This library is free software; you can redistribute it and/or modify +# it under the terms of the GNU Library 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 Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + +AC_DEFUN([HL_GETADDRINFO], +[ + +AC_CHECK_TYPES([struct addrinfo],[],[],[ + #if HAVE_NETDB_H + # include + #endif + #ifdef HAVE_WS2TCPIP_H + # include + #endif + ]) + +AC_CHECK_FUNCS([getaddrinfo gai_strerror]) + +dnl Checks for replacements +AC_REPLACE_FUNCS([getaddrinfo]) + +AH_BOTTOM( +[ +/* Define missing prototypes, implemented in replacement lib */ +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef HAVE_STRUCT_ADDRINFO +#ifdef HAVE_NETINET_IN_H +#include +#endif +#if HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#elif HAVE_WS2TCPIP_H +#include +#endif +struct addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + socklen_t ai_addrlen; + struct sockaddr *ai_addr; +}; +#endif + +#ifndef HAVE_GETADDRINFO + +#ifdef HAVE_NETINET_IN_H +#include +#endif +#if HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#elif HAVE_WS2TCPIP_H +#include +#endif + +#ifndef AI_PASSIVE +#define AI_PASSIVE 0x0001 +#endif + +int getaddrinfo(const char *node, const char *service, + const struct addrinfo *hints, struct addrinfo **res); +void freeaddrinfo(struct addrinfo *res); +#endif + +#if !defined(HAVE_GAI_STRERROR) && !defined(gai_strerror) +const char *gai_strerror(int errcode); +#endif /* !HAVE_GAI_STRERROR */ + +#ifdef __cplusplus +} +#endif +]) + + +]) diff --git a/src/network.c b/src/network.c index 10af2a0e0..ba4071235 100644 --- a/src/network.c +++ b/src/network.c @@ -1,6 +1,6 @@ /* * Hamlib Interface - network communication low-level support - * Copyright (c) 2000-2008 by Stephane Fillod + * Copyright (c) 2000-2010 by Stephane Fillod * * $Id: network.c,v 1.6 2008-11-05 23:02:00 fillods Exp $ * @@ -45,8 +45,6 @@ #include /* Error number definitions */ #include #include -#include -#include #include @@ -70,72 +68,6 @@ #include "misc.h" -#ifndef HAVE_STRUCT_ADDRINFO -struct addrinfo { - int ai_family; - int ai_socktype; - int ai_protocol; - struct sockaddr *ai_addr; - socklen_t ai_addrlen; -}; -#endif - -/* - * Replacement for getaddrinfo. Only one addrinfo is returned. - * Weak checking. - */ -#ifndef HAVE_GETADDRINFO -static int getaddrinfo(const char *node, const char *service, - const struct addrinfo *hints, struct addrinfo **res) -{ - struct addrinfo *p; - - /* limitation: this replacement function only for IPv4 */ - if (hints && hints->ai_family != AF_INET) - return EINVAL; - - p = malloc(sizeof(struct addrinfo)); - if (!p) - return ENOMEM; - - memset(p, 0, sizeof(struct addrinfo)); - p->ai_family = hints->ai_family; - p->ai_socktype = hints->ai_socktype; - p->ai_protocol = hints->ai_protocol; - p->ai_addrlen = sizeof(struct sockaddr_in); - p->ai_addr = malloc(p->ai_addrlen); - if (!p->ai_addr) { - free(p); - return ENOMEM; - } - memset((char *) p->ai_addr, 0, p->ai_addrlen); - - ((struct sockaddr_in*)p->ai_addr)->sin_family = p->ai_family; - /* limitation: the service must be a port _number_ */ - ((struct sockaddr_in*)p->ai_addr)->sin_port = htons(atoi(service)); - /* limitation: the node must be in numbers-and-dots notation */ - ((struct sockaddr_in*)p->ai_addr)->sin_addr.s_addr = inet_addr(node); - - *res = p; - - return 0; -} - -static void freeaddrinfo(struct addrinfo *res) -{ - free(res->ai_addr); - free(res); -} -#endif /* !HAVE_GETADDRINFO */ - -#if !defined(HAVE_GAI_STRERROR) && !defined(gai_strerror) -static const char *gai_strerror(int errcode) -{ - return strerror(errcode); -} -#endif /* !HAVE_GAI_STRERROR */ - - #ifdef __MINGW32__ static int wsstarted; #endif @@ -170,7 +102,7 @@ int network_open(hamlib_port_t *rp, int default_port) return -RIG_EINVAL; memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET /* PF_UNSPEC */; + hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if (rp->pathname[0] == ':') { diff --git a/tests/rigctld.c b/tests/rigctld.c index 4b7e6d335..019a3e153 100644 --- a/tests/rigctld.c +++ b/tests/rigctld.c @@ -1,11 +1,9 @@ /* - * rigctld.c - (C) Stephane Fillod 2000-2009 + * rigctld.c - (C) Stephane Fillod 2000-2010 * * This program test/control a radio using Hamlib. * It takes commands from network connection. * - * $Id: rigctld.c,v 1.11 2009-01-04 14:49:17 fillods Exp $ - * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -49,6 +47,9 @@ #elif HAVE_WS2TCPIP_H #include #endif +#ifdef HAVE_NETDB_H +#include +#endif #ifdef HAVE_PTHREAD #include @@ -110,8 +111,8 @@ int vfo_mode = 0; /* vfo_mode=0 means target VFO is current VFO */ char send_cmd_term = '\r'; /* send_cmd termination char */ -int portno = 4532; -uint32_t src_addr = INADDR_ANY; +const char *portno = "4532"; +const char *src_addr = NULL; /* INADDR_ANY */ #define MAXCONFLEN 128 @@ -132,10 +133,9 @@ int main (int argc, char *argv[]) char *civaddr = NULL; /* NULL means no need to set conf */ char conf_parms[MAXCONFLEN] = ""; + struct addrinfo hints, *result; int sock_listen; - struct sockaddr_in serv_addr; int reuseaddr = 1; - int a0,a1,a2,a3; while(1) { int c; @@ -247,18 +247,14 @@ int main (int argc, char *argv[]) usage(); /* wrong arg count */ exit(1); } - portno = atoi(optarg); + portno = optarg; break; case 'T': if (!optarg) { usage(); /* wrong arg count */ exit(1); } - if (4 != sscanf(optarg, "%d.%d.%d.%d", &a0,&a1,&a2,&a3)) { - usage(); /* wrong arg count */ - exit(1); - } - src_addr = (a0<<24)|(a1<<16)|(a2<<8)|a3; + src_addr = optarg; break; case 'o': vfo_mode++; @@ -358,27 +354,37 @@ int main (int argc, char *argv[]) /* * Prepare listening socket */ - sock_listen = socket(AF_INET, SOCK_STREAM, 0); + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_socktype = SOCK_STREAM;/* TCP socket */ + hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ + hints.ai_protocol = 0; /* Any protocol */ + + retcode = getaddrinfo(src_addr, portno, &hints, &result); + if (retcode != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(retcode)); + exit(2); + } + + sock_listen = socket(result->ai_family, result->ai_socktype, + result->ai_protocol); if (sock_listen < 0) { perror("ERROR opening socket"); exit(2); } - memset((char *)&serv_addr, 0, sizeof(serv_addr)); - - serv_addr.sin_family = AF_INET; - serv_addr.sin_port = htons(portno); - serv_addr.sin_addr.s_addr = htonl(src_addr); - if (setsockopt(sock_listen, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseaddr, sizeof(reuseaddr)) < 0) { rig_debug(RIG_DEBUG_ERR, "setsockopt: %s\n", strerror(errno)); exit (1); } - if (bind(sock_listen, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { + if (bind(sock_listen, result->ai_addr, result->ai_addrlen) < 0) { rig_debug(RIG_DEBUG_ERR, "binding: %s\n", strerror(errno)); exit (1); } + + freeaddrinfo(result); /* No longer needed */ + if (listen(sock_listen, 4) < 0) { rig_debug(RIG_DEBUG_ERR, "listening: %s\n", strerror(errno)); exit (1); @@ -505,7 +511,7 @@ void usage(void) " -D, --dcd-type=TYPE set type of the DCD device to operate on\n" " -s, --serial-speed=BAUD set serial speed of the serial port\n" " -c, --civaddr=ID set CI-V address, decimal (for Icom rigs only)\n" - " -t, --port=NUM set TCP listening port, default %d\n" + " -t, --port=NUM set TCP listening port, default %s\n" " -T, --listen-addr=IPADDR set listening IP address, default ANY\n" " -C, --set-conf=PARM=VAL set config parameters\n" " -L, --show-conf list all config parameters\n" diff --git a/tests/rotctld.c b/tests/rotctld.c index 50a3c1190..e5d7b95af 100644 --- a/tests/rotctld.c +++ b/tests/rotctld.c @@ -4,8 +4,6 @@ * This program test/control a rotator using Hamlib. * It takes commands from network connection. * - * $Id: rotctld.c,v 1.7 2009-01-04 14:49:17 fillods Exp $ - * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -49,6 +47,9 @@ #elif HAVE_WS2TCPIP_H #include #endif +#ifdef HAVE_NETDB_H +#include +#endif #ifdef HAVE_PTHREAD #include @@ -99,8 +100,8 @@ int interactive = 1; /* no cmd because of daemon */ int prompt= 0 ; /* Daemon mode for rigparse return string */ int opt_end= 0 ; /* END marker for rotctld */ -int portno = 4533; -uint32_t src_addr = INADDR_ANY; +const char *portno = "4533"; +const char *src_addr = NULL; /* INADDR_ANY */ char send_cmd_term = '\r'; /* send_cmd termination char */ @@ -121,10 +122,9 @@ int main (int argc, char *argv[]) int serial_rate = 0; char conf_parms[MAXCONFLEN] = ""; + struct addrinfo hints, *result; int sock_listen; - struct sockaddr_in serv_addr; int reuseaddr = 1; - int a0,a1,a2,a3; while(1) { int c; @@ -177,18 +177,14 @@ int main (int argc, char *argv[]) usage(); /* wrong arg count */ exit(1); } - portno = atoi(optarg); + portno = optarg; break; case 'T': if (!optarg) { usage(); /* wrong arg count */ exit(1); } - if (4 != sscanf(optarg, "%d.%d.%d.%d", &a0,&a1,&a2,&a3)) { - usage(); /* wrong arg count */ - exit(1); - } - src_addr = (a0<<24)|(a1<<16)|(a2<<8)|a3; + src_addr = optarg; break; case 'v': verbose++; @@ -273,27 +269,37 @@ int main (int argc, char *argv[]) /* * Prepare listening socket */ - sock_listen = socket(AF_INET, SOCK_STREAM, 0); + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_socktype = SOCK_STREAM;/* TCP socket */ + hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ + hints.ai_protocol = 0; /* Any protocol */ + + retcode = getaddrinfo(src_addr, portno, &hints, &result); + if (retcode != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(retcode)); + exit(2); + } + + sock_listen = socket(result->ai_family, result->ai_socktype, + result->ai_protocol); if (sock_listen < 0) { perror("ERROR opening socket"); exit(1); } - memset((char *) &serv_addr, 0, sizeof(serv_addr)); - - serv_addr.sin_family = AF_INET; - serv_addr.sin_port = htons(portno); - serv_addr.sin_addr.s_addr = htonl(src_addr); - if (setsockopt(sock_listen, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseaddr,sizeof(reuseaddr)) < 0) { rig_debug(RIG_DEBUG_ERR, "setsockopt: %s\n", strerror(errno)); exit (1); } - if (bind(sock_listen, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { + if (bind(sock_listen, result->ai_addr, result->ai_addrlen) < 0) { rig_debug(RIG_DEBUG_ERR, "binding: %s\n", strerror(errno)); exit (1); } + + freeaddrinfo(result); /* No longer needed */ + if (listen(sock_listen,4) < 0) { rig_debug(RIG_DEBUG_ERR, "listening: %s\n", strerror(errno)); exit (1); @@ -414,7 +420,7 @@ void usage() " -m, --model=ID select rotator model number. See model list\n" " -r, --rot-file=DEVICE set device of the rotator to operate on\n" " -s, --serial-speed=BAUD set serial speed of the serial port\n" - " -t, --port=NUM set TCP listening port, default %d\n" + " -t, --port=NUM set TCP listening port, default %s\n" " -T, --listen-addr=IPADDR set listening IP address, default ANY\n" " -C, --set-conf=PARM=VAL set config parameters\n" " -L, --show-conf list all config parameters\n"