2008-09-21 19:30:35 +00:00
|
|
|
/*
|
|
|
|
* Hamlib Interface - network communication low-level support
|
2012-01-06 08:28:24 +00:00
|
|
|
* Copyright (c) 2000-2012 by Stephane Fillod
|
2008-09-21 19:30:35 +00:00
|
|
|
*
|
2011-08-22 01:07:57 +00:00
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
2008-09-21 19:30:35 +00:00
|
|
|
*
|
2011-08-22 01:07:57 +00:00
|
|
|
* This library is distributed in the hope that it will be useful,
|
2008-09-21 19:30:35 +00:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2011-08-22 01:07:57 +00:00
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
2008-09-21 19:30:35 +00:00
|
|
|
*
|
2011-08-22 01:07:57 +00:00
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2008-09-21 19:30:35 +00:00
|
|
|
* License along with this library; if not, write to the Free Software
|
2011-08-22 01:07:57 +00:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
2008-09-21 19:30:35 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \addtogroup rig_internal
|
|
|
|
* @{
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Network port IO
|
|
|
|
* \file network.c
|
|
|
|
*/
|
|
|
|
|
2008-11-02 12:42:45 +00:00
|
|
|
/* Forcing WINVER in MinGW yanks in getaddrinfo(), but locks out Win95/Win98 */
|
|
|
|
/* #define WINVER 0x0501 */
|
2008-09-21 19:30:35 +00:00
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h> /* Standard input/output definitions */
|
|
|
|
#include <string.h> /* String function definitions */
|
|
|
|
#include <unistd.h> /* UNIX standard function definitions */
|
|
|
|
#include <fcntl.h> /* File control definitions */
|
|
|
|
#include <errno.h> /* Error number definitions */
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/types.h>
|
2008-10-27 22:18:39 +00:00
|
|
|
#include <signal.h>
|
2008-09-21 19:30:35 +00:00
|
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_NETINET_IN_H
|
|
|
|
#include <netinet/in.h>
|
2008-11-02 12:42:45 +00:00
|
|
|
#endif
|
|
|
|
#if HAVE_NETDB_H
|
|
|
|
#include <netdb.h>
|
2008-09-21 19:30:35 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_ARPA_INET_H
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_SOCKET_H
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#elif HAVE_WS2TCPIP_H
|
|
|
|
#include <ws2tcpip.h>
|
2013-05-18 12:31:40 +00:00
|
|
|
# if defined(HAVE_WSPIAPI_H)
|
|
|
|
# include <wspiapi.h>
|
|
|
|
# endif
|
2008-09-21 19:30:35 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "hamlib/rig.h"
|
|
|
|
#include "network.h"
|
|
|
|
#include "misc.h"
|
|
|
|
|
2008-11-02 12:42:45 +00:00
|
|
|
|
2008-11-05 23:02:00 +00:00
|
|
|
#ifdef __MINGW32__
|
|
|
|
static int wsstarted;
|
|
|
|
#endif
|
|
|
|
|
2015-11-27 12:59:21 +00:00
|
|
|
static void handle_error (enum rig_debug_level_e lvl, const char *msg)
|
|
|
|
{
|
|
|
|
int e;
|
|
|
|
#ifdef __MINGW32__
|
|
|
|
LPVOID lpMsgBuf;
|
|
|
|
|
|
|
|
lpMsgBuf = (LPVOID)"Unknown error";
|
|
|
|
e = WSAGetLastError();
|
|
|
|
if (FormatMessage(
|
|
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
|
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
|
|
NULL, e,
|
|
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
|
|
// Default language
|
|
|
|
(LPTSTR)&lpMsgBuf, 0, NULL))
|
|
|
|
{
|
|
|
|
rig_debug (lvl, "%s: Network error %d: %s\n", msg, e, lpMsgBuf);
|
|
|
|
LocalFree(lpMsgBuf);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
rig_debug (lvl, "%s: Network error %d\n", msg, e);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
e = errno;
|
|
|
|
rig_debug (lvl, "%s: Network error %d: %s\n", msg, e, strerror (e));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2008-09-21 19:30:35 +00:00
|
|
|
/**
|
|
|
|
* \brief Open network port using rig.state data
|
2008-10-27 22:18:39 +00:00
|
|
|
*
|
|
|
|
* Open Open network port using rig.state data.
|
2011-02-03 02:52:17 +00:00
|
|
|
* NB: The signal PIPE will be ignored for the whole application.
|
2008-10-27 22:18:39 +00:00
|
|
|
*
|
2011-02-03 02:52:17 +00:00
|
|
|
* \param rp Port data structure (must spec port id eg hostname:port)
|
|
|
|
* \param default_port Default network socket port
|
2008-09-21 19:30:35 +00:00
|
|
|
* \return RIG_OK or < 0 if error
|
|
|
|
*/
|
2008-10-31 07:51:46 +00:00
|
|
|
int network_open(hamlib_port_t *rp, int default_port)
|
|
|
|
{
|
2008-09-21 19:30:35 +00:00
|
|
|
int fd; /* File descriptor for the port */
|
|
|
|
int status;
|
2015-11-27 12:59:21 +00:00
|
|
|
struct addrinfo hints, *res, *saved_res;
|
2015-11-27 19:17:47 +00:00
|
|
|
char *hoststr = NULL, *portstr = NULL, *bracketstr1, *bracketstr2;
|
2015-11-27 12:59:21 +00:00
|
|
|
char hostname[FILPATHLEN];
|
2008-09-23 22:02:40 +00:00
|
|
|
char defaultportstr[8];
|
2008-09-21 19:30:35 +00:00
|
|
|
|
2008-11-05 23:02:00 +00:00
|
|
|
#ifdef __MINGW32__
|
|
|
|
WSADATA wsadata;
|
|
|
|
if (!(wsstarted++) && WSAStartup(MAKEWORD(1,1), &wsadata) == SOCKET_ERROR) {
|
|
|
|
rig_debug(RIG_DEBUG_ERR, "Error creating socket\n");
|
|
|
|
return -RIG_EIO;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-09-21 19:30:35 +00:00
|
|
|
if (!rp)
|
|
|
|
return -RIG_EINVAL;
|
|
|
|
|
|
|
|
memset(&hints, 0, sizeof(hints));
|
2010-04-16 20:50:14 +00:00
|
|
|
hints.ai_family = PF_UNSPEC;
|
2012-01-06 08:28:24 +00:00
|
|
|
if (rp->type.rig == RIG_PORT_UDP_NETWORK)
|
|
|
|
hints.ai_socktype = SOCK_DGRAM;
|
|
|
|
else
|
|
|
|
hints.ai_socktype = SOCK_STREAM;
|
2008-09-21 19:30:35 +00:00
|
|
|
|
2015-11-27 12:59:21 +00:00
|
|
|
hoststr = NULL; /* default of all local interfaces */
|
2016-02-06 06:59:15 +00:00
|
|
|
if (rp->pathname[0] == ':')
|
2015-11-27 12:59:21 +00:00
|
|
|
{
|
|
|
|
portstr = rp->pathname + 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (strlen (rp->pathname))
|
|
|
|
{
|
|
|
|
strncpy(hostname, rp->pathname, FILPATHLEN-1);
|
|
|
|
hoststr = hostname;
|
|
|
|
/* look for IPv6 numeric form [<addr>] */
|
|
|
|
bracketstr1 = strchr(hoststr, '[');
|
|
|
|
bracketstr2 = strrchr(hoststr, ']');
|
|
|
|
if (bracketstr1 && bracketstr2 && bracketstr2 > bracketstr1)
|
|
|
|
{
|
|
|
|
hoststr = bracketstr1 + 1;
|
|
|
|
*bracketstr2 = '\0';
|
|
|
|
portstr = bracketstr2 + 1; /* possible port after ]: */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
bracketstr2 = NULL;
|
|
|
|
portstr = hoststr; /* possible port after : */
|
|
|
|
}
|
|
|
|
/* search last ':' */
|
|
|
|
portstr = strrchr(portstr, ':');
|
|
|
|
if (portstr)
|
|
|
|
{
|
|
|
|
*portstr++ = '\0';
|
|
|
|
}
|
2015-11-27 19:17:47 +00:00
|
|
|
}
|
|
|
|
if (!portstr)
|
|
|
|
{
|
|
|
|
sprintf(defaultportstr, "%d", default_port);
|
|
|
|
portstr = defaultportstr;
|
2015-11-27 12:59:21 +00:00
|
|
|
}
|
2008-09-23 22:02:40 +00:00
|
|
|
}
|
2011-08-22 01:07:57 +00:00
|
|
|
|
2015-11-27 12:59:21 +00:00
|
|
|
status=getaddrinfo(hoststr, portstr, &hints, &res);
|
2008-09-21 19:30:35 +00:00
|
|
|
if (status != 0) {
|
|
|
|
rig_debug(RIG_DEBUG_ERR, "Cannot get host \"%s\": %s\n",
|
|
|
|
rp->pathname, gai_strerror(errno));
|
|
|
|
return -RIG_ECONF;
|
|
|
|
}
|
2015-11-27 12:59:21 +00:00
|
|
|
saved_res = res;
|
2008-09-21 19:30:35 +00:00
|
|
|
|
2008-10-27 22:18:39 +00:00
|
|
|
/* we don't want a signal when connection get broken */
|
|
|
|
#ifdef SIGPIPE
|
|
|
|
signal(SIGPIPE, SIG_IGN);
|
|
|
|
#endif
|
|
|
|
|
2015-11-27 12:59:21 +00:00
|
|
|
do
|
|
|
|
{
|
|
|
|
fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
|
|
|
if (fd < 0)
|
|
|
|
{
|
|
|
|
handle_error (RIG_DEBUG_ERR, "socket");
|
|
|
|
freeaddrinfo (saved_res);
|
|
|
|
return -RIG_EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((status = connect(fd, res->ai_addr, res->ai_addrlen)) == 0)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
handle_error (RIG_DEBUG_WARN, "connect (trying next interface)");
|
2008-09-21 19:30:35 +00:00
|
|
|
|
2015-11-27 12:59:21 +00:00
|
|
|
#ifdef __MINGW32__
|
|
|
|
closesocket (fd);
|
|
|
|
#else
|
|
|
|
close (fd);
|
|
|
|
#endif
|
|
|
|
} while ((res = res->ai_next) != NULL);
|
|
|
|
|
|
|
|
freeaddrinfo (saved_res);
|
|
|
|
|
|
|
|
if (NULL == res) {
|
2016-12-18 04:17:54 +00:00
|
|
|
rig_debug (RIG_DEBUG_ERR, "Failed to connect to %s\n" , rp->pathname);
|
2008-09-21 19:30:35 +00:00
|
|
|
return -RIG_EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
rp->fd = fd;
|
|
|
|
return RIG_OK;
|
|
|
|
}
|
|
|
|
|
2008-11-05 23:02:00 +00:00
|
|
|
int network_close(hamlib_port_t *rp)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
#ifdef __MINGW32__
|
|
|
|
ret = closesocket(rp->fd);
|
|
|
|
if (--wsstarted)
|
|
|
|
WSACleanup();
|
|
|
|
#else
|
|
|
|
ret = close(rp->fd);
|
|
|
|
#endif
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2008-09-21 19:30:35 +00:00
|
|
|
/** @} */
|