From e092a4a0a4d04743001ded926804a1bd76dd98cf Mon Sep 17 00:00:00 2001 From: Michael Black W9MDB Date: Sun, 21 Jun 2020 17:47:04 -0500 Subject: [PATCH] rigctld -T ::1 now works with rigctl -r ::1 More IPV6 testing needed on Windows and MacOS Still not binding to link local addresses to be addressed next https://github.com/Hamlib/Hamlib/issues/29 --- src/misc.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++ src/misc.h | 2 ++ src/network.c | 71 ++++++++++++++++++++++---------------------- src/rig.c | 35 ++++++++++++++++------ tests/rigctld.c | 11 ++++++- 5 files changed, 153 insertions(+), 45 deletions(-) diff --git a/src/misc.c b/src/misc.c index c2db78040..f177f783a 100644 --- a/src/misc.c +++ b/src/misc.c @@ -1376,6 +1376,85 @@ vfo_t HAMLIB_API vfo_fixup(RIG *rig, vfo_t vfo) return vfo; } +int HAMLIB_API parse_hoststr(char *hoststr, char host[256], char port[6]) +{ + unsigned int net1, net2, net3, net4, net5; + char dummy[2], link[32], *p; + host[0] = 0; + port[0] = 0; + dummy[0] = 0; + + // bracketed IPV6 with optional port + int n = sscanf(hoststr, "[%255[^]]]:%s", host, port); + + if (n >= 1) + { + return RIG_OK; + } + + // non-bracketed IPV6 with optional link addr + n = sscanf(hoststr, "%x::%x:%x:%x:%x:%%%31[^:]:%s", &net1, &net2, &net3, + &net4, &net5, link, port); + + if (strchr(hoststr, '%') && (n == 5 || n == 6)) + { + strcpy(host, hoststr); + return RIG_OK; + } + else if (n == 7) + { + strcpy(host, hoststr); + p = strrchr(host, ':'); // remove port from host + *p = 0; + return RIG_OK; + } + + // non-bracketed IPV6 short form with optional port + n = sscanf(hoststr, "%x::%x:%x:%x:%x:%5[0-9]%1s", &net1, &net2, &net3, &net4, + &net5, port, dummy); + + if (n == 5) + { + strcpy(host, hoststr); + return RIG_OK; + } + else if (n == 6) + { + strcpy(host, hoststr); + p = strrchr(host, ':'); + *p = 0; + return RIG_OK; + } + else if (n == 7) + { + return -RIG_EINVAL; + } + + // bracketed localhost + if (strstr(hoststr, "::1")) + { + n = sscanf(hoststr, "::1%s", dummy); + strcpy(host, hoststr); + + if (n == 1) + { + p = strrchr(host, ':'); + *p = 0; + strcpy(port, p + 1); + } + + return RIG_OK; + } + + // if we're here then we must have a hostname + n = sscanf(hoststr, "%255[^:]:%5[0-9]%1s", host, port, dummy); + + if (n >= 1 && strlen(dummy) == 0) { return RIG_OK; } + + printf("Unhandled host=%s\n", hoststr); + + return -1; +} //! @endcond diff --git a/src/misc.h b/src/misc.h index 382b949d8..75b09fd06 100644 --- a/src/misc.h +++ b/src/misc.h @@ -106,6 +106,8 @@ extern HAMLIB_EXPORT(double) elapsed_ms(struct timespec *start, int start_flag); extern HAMLIB_EXPORT(vfo_t) vfo_fixup(RIG *rig, vfo_t vfo); +extern HAMLIB_EXPORT(int) parse_hoststr(char *host, char hoststr[256], char port[6]); + #ifdef PRId64 /** \brief printf(3) format to be used for long long (64bits) type */ # define PRIll PRId64 diff --git a/src/network.c b/src/network.c index 36c1739e6..b4ed224c3 100644 --- a/src/network.c +++ b/src/network.c @@ -114,7 +114,6 @@ static void handle_error(enum rig_debug_level_e lvl, const char *msg) #endif } - /** * \brief Open network port using rig.state data * @@ -130,9 +129,8 @@ int network_open(hamlib_port_t *rp, int default_port) 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]; + struct in6_addr serveraddr; + char hoststr[256], portstr[6]; rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); rig_debug(RIG_DEBUG_VERBOSE, "%s version 1.0\n", __func__); @@ -154,7 +152,8 @@ int network_open(hamlib_port_t *rp, int default_port) } memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; + hints.ai_flags = AI_NUMERICSERV; + hints.ai_family = AF_UNSPEC; if (rp->type.rig == RIG_PORT_UDP_NETWORK) { @@ -165,53 +164,55 @@ int network_open(hamlib_port_t *rp, int default_port) hints.ai_socktype = SOCK_STREAM; } - /* default of all local interfaces */ - hoststr = NULL; - - if (rp->pathname[0] == ':') + if (rp->pathname[0] == ':' && rp->pathname[1] != ':') { - portstr = rp->pathname + 1; + snprintf(portstr, sizeof(portstr) - 1, "%s", rp->pathname + 1); } else { if (strlen(rp->pathname)) { - snprintf(hostname, sizeof(hostname), "%s", rp->pathname); - hoststr = hostname; - /* look for IPv6 numeric form [] */ - bracketstr1 = strchr(hoststr, '['); - bracketstr2 = strrchr(hoststr, ']'); + status = parse_hoststr(rp->pathname, hoststr, portstr); - if (bracketstr1 && bracketstr2 && bracketstr2 > bracketstr1) - { - hoststr = bracketstr1 + 1; - *bracketstr2 = '\0'; - portstr = bracketstr2 + 1; /* possible port after ]: */ - } - else - { - bracketstr2 = NULL; - portstr = hoststr; /* possible port after : */ - } + if (status != RIG_OK) { return status; } - /* search last ':' */ - portstr = strrchr(portstr, ':'); + rig_debug(RIG_DEBUG_ERR, "%s: hoststr=%s, portstr=%s\n", __func__, hoststr, + portstr); - if (portstr) - { - *portstr++ = '\0'; - } } - if (!portstr) + if (strlen(portstr) == 0) { - sprintf(defaultportstr, "%d", default_port); - portstr = defaultportstr; + sprintf(portstr, "%d", default_port); + } + } + + status = inet_pton(AF_INET, hoststr, &serveraddr); + + if (status == 1) /* valid IPv4 address */ + { + hints.ai_family = AF_INET; + hints.ai_flags |= AI_NUMERICHOST; + } + else + { + status = inet_pton(AF_INET6, hoststr, &serveraddr); + + if (status == 1) /* valide IPv6 address */ + { + hints.ai_family = AF_INET6; + hints.ai_flags |= AI_NUMERICHOST; } } status = getaddrinfo(hoststr, portstr, &hints, &res); + if (status == 0 && res->ai_family == AF_INET6) + { + rig_debug(RIG_DEBUG_ERR, "%s: Using IPV6\n", __func__); + //inet_pton(AF_INET6, hoststr, &h_addr.sin6_addr); + } + if (status != 0) { rig_debug(RIG_DEBUG_ERR, diff --git a/src/rig.c b/src/rig.c index 67af05e67..e5ab5ee8b 100644 --- a/src/rig.c +++ b/src/rig.c @@ -556,9 +556,9 @@ int HAMLIB_API rig_open(RIG *rig) struct rig_state *rs; int status = RIG_OK; value_t parm_value; - unsigned int net1, net2, net3, net4, net5, net6, net7, net8, port; + //unsigned int net1, net2, net3, net4, net5, net6, net7, net8, port; int is_network = 0; - char *token, *strtokp; + char hoststr[256], portstr[6]; rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); @@ -570,6 +570,14 @@ int HAMLIB_API rig_open(RIG *rig) caps = rig->caps; rs = &rig->state; + if (strlen(rs->rigport.pathname) > 0) + { + status = parse_hoststr(rs->rigport.pathname, hoststr, portstr); + + if (status == RIG_OK) { is_network = 1; } + } + +#if 0 // determine if we have a network address // is_network |= sscanf(rs->rigport.pathname, "%u.%u.%u.%u:%u", &net1, &net2, @@ -594,6 +602,8 @@ int HAMLIB_API rig_open(RIG *rig) } } +#endif + if (is_network) { rig_debug(RIG_DEBUG_TRACE, "%s: using network address %s\n", __func__, @@ -3054,9 +3064,11 @@ int HAMLIB_API rig_get_split_freq(RIG *rig, vfo_t vfo, freq_t *tx_freq) if (!rig_has_vfo_op(rig, RIG_OP_XCHG)) { retcode = caps->set_vfo(rig, tx_vfo); - if (retcode != RIG_OK) return retcode; + + if (retcode != RIG_OK) { return retcode; } } - retcode = RIG_OK; + + retcode = RIG_OK; } else if (rig_has_vfo_op(rig, RIG_OP_TOGGLE) && caps->vfo_op) { @@ -3084,11 +3096,14 @@ int HAMLIB_API rig_get_split_freq(RIG *rig, vfo_t vfo, freq_t *tx_freq) /* try and revert even if we had an error above */ if (caps->set_vfo) { - // If we started with RIG_VFO_CURR we need to choose VFO_A/MAIN as appropriate to return to - if (save_vfo == RIG_VFO_CURR) { - save_vfo = VFO_HAS_A_B_ONLY?RIG_VFO_A:RIG_VFO_MAIN; - } - rig_debug(RIG_DEBUG_TRACE,"%s: retoring vfo=%s\n", __func__, rig_strvfo(save_vfo)); + // If we started with RIG_VFO_CURR we need to choose VFO_A/MAIN as appropriate to return to + if (save_vfo == RIG_VFO_CURR) + { + save_vfo = VFO_HAS_A_B_ONLY ? RIG_VFO_A : RIG_VFO_MAIN; + } + + rig_debug(RIG_DEBUG_TRACE, "%s: retoring vfo=%s\n", __func__, + rig_strvfo(save_vfo)); rc2 = caps->set_vfo(rig, save_vfo); } else @@ -3631,6 +3646,7 @@ int HAMLIB_API rig_get_split_vfo(RIG *rig, { return retcode; } + #endif retcode = caps->get_split_vfo(rig, vfo, split, tx_vfo); @@ -3643,6 +3659,7 @@ int HAMLIB_API rig_get_split_vfo(RIG *rig, /* return the first error code */ retcode = rc2; } + #endif if (retcode == RIG_OK) // only update cache on success diff --git a/tests/rigctld.c b/tests/rigctld.c index b5f09cbd6..144f6ad65 100644 --- a/tests/rigctld.c +++ b/tests/rigctld.c @@ -686,11 +686,20 @@ int main(int argc, char *argv[]) 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_flags = AI_CANONNAME; hints.ai_protocol = 0; /* Any protocol */ retcode = getaddrinfo(src_addr, portno, &hints, &result); - if (retcode != 0) + if (retcode == 0 && result->ai_family == AF_INET6) + { + rig_debug(RIG_DEBUG_TRACE, "%s: Using IPV6\n", __func__); + } + else if (retcode == 0) + { + rig_debug(RIG_DEBUG_TRACE, "%s: Using IPV4\n", __func__); + } + else { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(retcode)); exit(2);