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
|
2017-10-05 02:32:08 +00:00
|
|
|
# include "config.h"
|
2008-09-21 19:30:35 +00:00
|
|
|
#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
|
2017-10-05 02:32:08 +00:00
|
|
|
# include <netinet/in.h>
|
2008-11-02 12:42:45 +00:00
|
|
|
#endif
|
2017-10-05 02:32:08 +00:00
|
|
|
|
2008-11-02 12:42:45 +00:00
|
|
|
#if HAVE_NETDB_H
|
2017-10-05 02:32:08 +00:00
|
|
|
# include <netdb.h>
|
2008-09-21 19:30:35 +00:00
|
|
|
#endif
|
2017-10-05 02:32:08 +00:00
|
|
|
|
2008-09-21 19:30:35 +00:00
|
|
|
#ifdef HAVE_ARPA_INET_H
|
2017-10-05 02:32:08 +00:00
|
|
|
# include <arpa/inet.h>
|
2008-09-21 19:30:35 +00:00
|
|
|
#endif
|
2017-10-05 02:32:08 +00:00
|
|
|
|
2017-01-26 14:28:14 +00:00
|
|
|
#if defined (HAVE_SYS_SOCKET_H) && defined (HAVE_SYS_IOCTL_H)
|
2017-10-05 02:32:08 +00:00
|
|
|
# include <sys/socket.h>
|
|
|
|
# include <sys/ioctl.h>
|
2008-09-21 19:30:35 +00:00
|
|
|
#elif HAVE_WS2TCPIP_H
|
2017-10-05 02:32:08 +00:00
|
|
|
# include <ws2tcpip.h>
|
|
|
|
# if defined(HAVE_WSPIAPI_H)
|
|
|
|
# include <wspiapi.h>
|
|
|
|
# endif
|
2008-09-21 19:30:35 +00:00
|
|
|
#endif
|
|
|
|
|
2017-08-05 14:09:12 +00:00
|
|
|
#include <hamlib/rig.h>
|
2008-09-21 19:30:35 +00:00
|
|
|
#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
|
|
|
|
|
2020-04-09 22:56:19 +00:00
|
|
|
//! @cond Doxygen_Suppress
|
2020-04-22 17:26:08 +00:00
|
|
|
#define NET_BUFFER_SIZE 8192
|
2020-04-09 22:56:19 +00:00
|
|
|
//! @endcond
|
2017-01-24 04:21:49 +00:00
|
|
|
|
2017-08-05 14:09:12 +00:00
|
|
|
static void handle_error(enum rig_debug_level_e lvl, const char *msg)
|
2015-11-27 12:59:21 +00:00
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
int e;
|
2015-11-27 12:59:21 +00:00
|
|
|
#ifdef __MINGW32__
|
2017-08-05 14:09:12 +00:00
|
|
|
LPVOID lpMsgBuf;
|
|
|
|
|
|
|
|
lpMsgBuf = (LPVOID)"Unknown error";
|
|
|
|
e = WSAGetLastError();
|
|
|
|
|
|
|
|
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
|
|
|
|
| FORMAT_MESSAGE_FROM_SYSTEM
|
|
|
|
| FORMAT_MESSAGE_IGNORE_INSERTS,
|
2017-10-05 02:32:08 +00:00
|
|
|
NULL,
|
|
|
|
e,
|
2017-08-05 14:09:12 +00:00
|
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
|
|
// Default language
|
|
|
|
(LPTSTR)&lpMsgBuf,
|
|
|
|
0,
|
2017-10-05 02:32:08 +00:00
|
|
|
NULL))
|
|
|
|
{
|
2020-02-23 17:26:09 +00:00
|
|
|
rig_debug(lvl, "%s: Network error %d: %s\n", msg, e, (char *)lpMsgBuf);
|
2017-08-05 14:09:12 +00:00
|
|
|
LocalFree(lpMsgBuf);
|
2017-10-05 02:32:08 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
rig_debug(lvl, "%s: Network error %d\n", msg, e);
|
|
|
|
}
|
|
|
|
|
2015-11-27 12:59:21 +00:00
|
|
|
#else
|
2017-08-05 14:09:12 +00:00
|
|
|
e = errno;
|
|
|
|
rig_debug(lvl, "%s: Network error %d: %s\n", msg, e, strerror(e));
|
2015-11-27 12:59:21 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-08-05 14:09:12 +00:00
|
|
|
|
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)
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
int fd; /* File descriptor for the port */
|
|
|
|
int status;
|
|
|
|
struct addrinfo hints, *res, *saved_res;
|
|
|
|
char *hoststr = NULL, *portstr = NULL, *bracketstr1, *bracketstr2;
|
|
|
|
char hostname[FILPATHLEN];
|
|
|
|
char defaultportstr[8];
|
|
|
|
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
2019-02-07 17:44:33 +00:00
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s version 1.0\n", __func__);
|
2008-09-21 19:30:35 +00:00
|
|
|
|
2008-11-05 23:02:00 +00:00
|
|
|
#ifdef __MINGW32__
|
2017-08-05 14:09:12 +00:00
|
|
|
WSADATA wsadata;
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (!(wsstarted++) && WSAStartup(MAKEWORD(1, 1), &wsadata) == SOCKET_ERROR)
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: error creating socket\n", __func__);
|
|
|
|
return -RIG_EIO;
|
|
|
|
}
|
|
|
|
|
2008-11-05 23:02:00 +00:00
|
|
|
#endif
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (!rp)
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
return -RIG_EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&hints, 0, sizeof(hints));
|
|
|
|
hints.ai_family = PF_UNSPEC;
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (rp->type.rig == RIG_PORT_UDP_NETWORK)
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
hints.ai_socktype = SOCK_DGRAM;
|
2017-10-05 02:32:08 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* default of all local interfaces */
|
|
|
|
hoststr = NULL;
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (rp->pathname[0] == ':')
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
portstr = rp->pathname + 1;
|
2017-10-05 02:32:08 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (strlen(rp->pathname))
|
|
|
|
{
|
2018-04-16 15:38:47 +00:00
|
|
|
snprintf(hostname, sizeof(hostname), "%s", rp->pathname);
|
2017-08-05 14:09:12 +00:00
|
|
|
hoststr = hostname;
|
|
|
|
/* look for IPv6 numeric form [<addr>] */
|
|
|
|
bracketstr1 = strchr(hoststr, '[');
|
|
|
|
bracketstr2 = strrchr(hoststr, ']');
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (bracketstr1 && bracketstr2 && bracketstr2 > bracketstr1)
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
hoststr = bracketstr1 + 1;
|
|
|
|
*bracketstr2 = '\0';
|
|
|
|
portstr = bracketstr2 + 1; /* possible port after ]: */
|
2017-10-05 02:32:08 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
bracketstr2 = NULL;
|
|
|
|
portstr = hoststr; /* possible port after : */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* search last ':' */
|
|
|
|
portstr = strrchr(portstr, ':');
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (portstr)
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
*portstr++ = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (!portstr)
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
sprintf(defaultportstr, "%d", default_port);
|
|
|
|
portstr = defaultportstr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
status = getaddrinfo(hoststr, portstr, &hints, &res);
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (status != 0)
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR,
|
|
|
|
"%s: cannot get host \"%s\": %s\n",
|
|
|
|
__func__,
|
|
|
|
rp->pathname,
|
|
|
|
gai_strerror(errno));
|
|
|
|
return -RIG_ECONF;
|
|
|
|
}
|
|
|
|
|
|
|
|
saved_res = res;
|
|
|
|
|
|
|
|
/* we don't want a signal when connection get broken */
|
2008-10-27 22:18:39 +00:00
|
|
|
#ifdef SIGPIPE
|
2017-08-05 14:09:12 +00:00
|
|
|
signal(SIGPIPE, SIG_IGN);
|
2008-10-27 22:18:39 +00:00
|
|
|
#endif
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
do
|
|
|
|
{
|
2019-12-09 23:12:13 +00:00
|
|
|
char msg[1024];
|
2017-08-05 14:09:12 +00:00
|
|
|
fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (fd < 0)
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
handle_error(RIG_DEBUG_ERR, "socket");
|
|
|
|
freeaddrinfo(saved_res);
|
|
|
|
return -RIG_EIO;
|
|
|
|
}
|
|
|
|
|
2020-01-15 05:36:01 +00:00
|
|
|
if (connect(fd, res->ai_addr, res->ai_addrlen) == 0)
|
2017-10-05 02:32:08 +00:00
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
break;
|
|
|
|
}
|
2019-02-07 17:46:52 +00:00
|
|
|
|
|
|
|
snprintf(msg, sizeof(msg), "connect to %s failed, (trying next interface)",
|
|
|
|
rp->pathname);
|
2018-04-14 15:46:13 +00:00
|
|
|
handle_error(RIG_DEBUG_WARN, msg);
|
2008-09-21 19:30:35 +00:00
|
|
|
|
2015-11-27 12:59:21 +00:00
|
|
|
#ifdef __MINGW32__
|
2017-08-05 14:09:12 +00:00
|
|
|
closesocket(fd);
|
2015-11-27 12:59:21 +00:00
|
|
|
#else
|
2017-08-05 14:09:12 +00:00
|
|
|
close(fd);
|
2015-11-27 12:59:21 +00:00
|
|
|
#endif
|
2017-10-05 02:32:08 +00:00
|
|
|
}
|
|
|
|
while ((res = res->ai_next) != NULL);
|
2015-11-27 12:59:21 +00:00
|
|
|
|
2017-08-05 14:09:12 +00:00
|
|
|
freeaddrinfo(saved_res);
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (NULL == res)
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR,
|
|
|
|
"%s: failed to connect to %s\n",
|
|
|
|
__func__,
|
|
|
|
rp->pathname);
|
|
|
|
return -RIG_EIO;
|
|
|
|
}
|
2015-11-27 12:59:21 +00:00
|
|
|
|
2017-08-05 14:09:12 +00:00
|
|
|
rp->fd = fd;
|
2008-09-21 19:30:35 +00:00
|
|
|
|
2017-08-05 14:09:12 +00:00
|
|
|
return RIG_OK;
|
2008-09-21 19:30:35 +00:00
|
|
|
}
|
|
|
|
|
2017-08-05 14:09:12 +00:00
|
|
|
|
2017-01-26 14:28:14 +00:00
|
|
|
/**
|
|
|
|
* \brief Clears any data in the read buffer of the socket
|
|
|
|
*
|
|
|
|
* \param rp Port data structure
|
|
|
|
*/
|
2017-08-05 14:09:12 +00:00
|
|
|
void network_flush(hamlib_port_t *rp)
|
2017-01-26 14:28:14 +00:00
|
|
|
{
|
|
|
|
#ifdef __MINGW32__
|
2020-01-15 05:36:01 +00:00
|
|
|
ULONG len;
|
2017-01-26 14:28:14 +00:00
|
|
|
#else
|
2020-01-15 05:36:01 +00:00
|
|
|
uint len;
|
2017-01-26 14:28:14 +00:00
|
|
|
#endif
|
|
|
|
|
2017-08-05 14:09:12 +00:00
|
|
|
char buffer[NET_BUFFER_SIZE] = { 0 };
|
|
|
|
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
for (;;)
|
|
|
|
{
|
2019-12-08 23:09:08 +00:00
|
|
|
int ret;
|
2019-02-05 15:40:46 +00:00
|
|
|
len = 0;
|
2017-01-26 14:28:14 +00:00
|
|
|
#ifdef __MINGW32__
|
2019-02-05 15:40:46 +00:00
|
|
|
ret = ioctlsocket(rp->fd, FIONREAD, &len);
|
2017-01-26 14:28:14 +00:00
|
|
|
#else
|
2019-02-05 15:40:46 +00:00
|
|
|
ret = ioctl(rp->fd, FIONREAD, &len);
|
2017-01-26 14:28:14 +00:00
|
|
|
#endif
|
2019-02-07 17:46:52 +00:00
|
|
|
|
|
|
|
if (ret != 0)
|
|
|
|
{
|
2019-11-30 16:16:28 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: ioctl err '%s'\n", __func__, strerror(errno));
|
2019-02-07 17:46:52 +00:00
|
|
|
break;
|
2019-02-05 15:40:46 +00:00
|
|
|
}
|
2019-02-07 17:46:52 +00:00
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (len > 0)
|
|
|
|
{
|
2019-02-07 17:44:33 +00:00
|
|
|
int len_read = 0;
|
2017-08-05 14:09:12 +00:00
|
|
|
rig_debug(RIG_DEBUG_WARN,
|
2019-11-30 16:04:31 +00:00
|
|
|
"%s: network data clear d: ret=%d, len=%d, '%s'\n",
|
2017-08-05 14:09:12 +00:00
|
|
|
__func__,
|
2019-11-30 19:05:21 +00:00
|
|
|
ret, (int)len, buffer);
|
2019-02-07 17:46:52 +00:00
|
|
|
len_read = recv(rp->fd, buffer, len < NET_BUFFER_SIZE ? len : NET_BUFFER_SIZE,
|
|
|
|
0);
|
|
|
|
|
|
|
|
if (len_read < 0) // -1 indicates error occurred
|
|
|
|
{
|
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: read error '%s'\n", __func__, strerror(errno));
|
2019-02-07 17:44:33 +00:00
|
|
|
break;
|
|
|
|
}
|
2019-02-07 17:46:52 +00:00
|
|
|
|
2019-02-07 17:44:33 +00:00
|
|
|
rig_debug(RIG_DEBUG_WARN,
|
|
|
|
"%s: network data cleared: ret=%d, len_read=%d/0x%x, '%s'\n",
|
|
|
|
__func__,
|
|
|
|
ret, len_read, len_read, buffer);
|
2017-10-05 02:32:08 +00:00
|
|
|
}
|
2019-11-30 16:19:08 +00:00
|
|
|
else
|
|
|
|
{
|
2019-08-01 04:13:35 +00:00
|
|
|
break;
|
|
|
|
}
|
2017-01-26 14:28:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-05 14:09:12 +00:00
|
|
|
|
2020-04-09 22:56:19 +00:00
|
|
|
//! @cond Doxygen_Suppress
|
2008-11-05 23:02:00 +00:00
|
|
|
int network_close(hamlib_port_t *rp)
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
|
|
|
|
2008-11-05 23:02:00 +00:00
|
|
|
#ifdef __MINGW32__
|
2017-08-05 14:09:12 +00:00
|
|
|
ret = closesocket(rp->fd);
|
|
|
|
|
2017-10-05 02:32:08 +00:00
|
|
|
if (--wsstarted)
|
|
|
|
{
|
2017-08-05 14:09:12 +00:00
|
|
|
WSACleanup();
|
|
|
|
}
|
|
|
|
|
2008-11-05 23:02:00 +00:00
|
|
|
#else
|
2017-08-05 14:09:12 +00:00
|
|
|
ret = close(rp->fd);
|
2008-11-05 23:02:00 +00:00
|
|
|
#endif
|
2017-08-05 14:09:12 +00:00
|
|
|
return ret;
|
2008-11-05 23:02:00 +00:00
|
|
|
}
|
2020-04-09 22:56:19 +00:00
|
|
|
//! @endcond
|
2008-11-05 23:02:00 +00:00
|
|
|
|
2008-09-21 19:30:35 +00:00
|
|
|
/** @} */
|