Proper IPv6 and dual stack networking for rotator net daemon

This means that rigctl & rigctld  now work with default arguments on a
modern Windows  machine with dual  stack and localhost being  [::1] as
the first interface returned by getaddrinfo().

Try all the interfaces return by DNS lookups to establish a connection
or listening  port. Handle  Windows network  errors correctly  so that
meaningful messages are printed.

The rigctl program now accepts  IPv6 numeric addresses in the portname
field like [<addr>}:<port> for example  the IPv6 loopback on port 4531
would be [::1]:4531.
libusb-1-0
Bill Somerville 2015-11-27 19:41:04 +00:00
rodzic ca7cbd89f4
commit 6061cae8df
1 zmienionych plików z 100 dodań i 28 usunięć

Wyświetl plik

@ -68,7 +68,7 @@
struct handle_data { struct handle_data {
ROT *rot; ROT *rot;
int sock; int sock;
struct sockaddr_in cli_addr; struct sockaddr_storage cli_addr;
socklen_t clilen; socklen_t clilen;
}; };
@ -111,6 +111,36 @@ char send_cmd_term = '\r'; /* send_cmd termination char */
#define MAXCONFLEN 128 #define MAXCONFLEN 128
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
}
int main (int argc, char *argv[]) int main (int argc, char *argv[])
{ {
ROT *my_rot; /* handle to rot (instance) */ ROT *my_rot; /* handle to rot (instance) */
@ -125,9 +155,11 @@ int main (int argc, char *argv[])
int serial_rate = 0; int serial_rate = 0;
char conf_parms[MAXCONFLEN] = ""; char conf_parms[MAXCONFLEN] = "";
struct addrinfo hints, *result; struct addrinfo hints, *result, *saved_result;
int sock_listen; int sock_listen;
int reuseaddr = 1; int reuseaddr = 1;
char host[NI_MAXHOST];
char serv[NI_MAXSERV];
while(1) { while(1) {
int c; int c;
@ -301,27 +333,56 @@ int main (int argc, char *argv[])
exit(2); exit(2);
} }
saved_result = result;
do
{
sock_listen = socket(result->ai_family, result->ai_socktype, sock_listen = socket(result->ai_family, result->ai_socktype,
result->ai_protocol); result->ai_protocol);
if (sock_listen < 0) { if (sock_listen < 0) {
perror("ERROR opening socket"); handle_error (RIG_DEBUG_ERR, "socket");
freeaddrinfo(result); /* No longer needed */
exit(1); exit(1);
} }
if (setsockopt(sock_listen, SOL_SOCKET, SO_REUSEADDR, if (setsockopt(sock_listen, SOL_SOCKET, SO_REUSEADDR,
(char *)&reuseaddr,sizeof(reuseaddr)) < 0) { (char *)&reuseaddr,sizeof(reuseaddr)) < 0) {
rig_debug(RIG_DEBUG_ERR, "setsockopt: %s\n", strerror(errno)); handle_error (RIG_DEBUG_ERR, "setsockopt");
exit (1);
}
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 */ freeaddrinfo(result); /* No longer needed */
exit (1);
}
if (listen(sock_listen,4) < 0) { #ifdef __MINGW32__
rig_debug(RIG_DEBUG_ERR, "listening: %s\n", strerror(errno)); /* allow IPv4 mapped to IPv6 clients, MS default this to 1! */
sockopt = 0;
if (setsockopt(sock_listen, IPPROTO_IPV6, IPV6_V6ONLY,
(char *)&sockopt, sizeof(sockopt)) < 0) {
handle_error (RIG_DEBUG_ERR, "setsockopt");
freeaddrinfo(saved_result); /* No longer needed */
exit (1);
}
#endif
if (0 == bind(sock_listen, result->ai_addr, result->ai_addrlen)) {
break;
}
handle_error (RIG_DEBUG_WARN, "binding failed (trying next interface)");
#ifdef __MINGW32__
closesocket (sock_listen);
#else
close (sock_listen);
#endif
} while ((result = result->ai_next) != NULL);
freeaddrinfo(saved_result); /* No longer needed */
if (NULL == result)
{
rig_debug(RIG_DEBUG_ERR, "bind error - no available interface\n");
exit (1);
}
if (listen(sock_listen, 4) < 0) {
handle_error (RIG_DEBUG_ERR, "listening");
exit (1); exit (1);
} }
@ -346,13 +407,17 @@ int main (int argc, char *argv[])
arg->sock = accept(sock_listen, (struct sockaddr *) &arg->cli_addr, arg->sock = accept(sock_listen, (struct sockaddr *) &arg->cli_addr,
&arg->clilen); &arg->clilen);
if (arg->sock < 0) { if (arg->sock < 0) {
rig_debug(RIG_DEBUG_ERR, "accept: %s\n", strerror(errno)); handle_error (RIG_DEBUG_ERR, "accept");
break; break;
} }
rig_debug(RIG_DEBUG_VERBOSE, "Connection opened from %s:%d\n", if ((retcode = getnameinfo ((struct sockaddr const *)&arg->cli_addr, arg->clilen, host, sizeof (host)
inet_ntoa(arg->cli_addr.sin_addr), , serv, sizeof (serv), NI_NOFQDN)) < 0)
ntohs(arg->cli_addr.sin_port)); {
rig_debug (RIG_DEBUG_WARN, "Peer lookup error: %s", gai_strerror (retcode));
}
rig_debug(RIG_DEBUG_VERBOSE, "Connection opened from %s:%s\n",
host, serv);
#ifdef HAVE_PTHREAD #ifdef HAVE_PTHREAD
pthread_attr_init(&attr); pthread_attr_init(&attr);
@ -389,6 +454,8 @@ void * handle_socket(void *arg)
FILE *fsockin; FILE *fsockin;
FILE *fsockout; FILE *fsockout;
int retcode; int retcode;
char host[NI_MAXHOST];
char serv[NI_MAXSERV];
#ifdef __MINGW32__ #ifdef __MINGW32__
int sock_osfhandle = _open_osfhandle(handle_data_arg->sock, _O_RDONLY); int sock_osfhandle = _open_osfhandle(handle_data_arg->sock, _O_RDONLY);
@ -424,9 +491,14 @@ void * handle_socket(void *arg)
} }
while (retcode == 0 || retcode == 2); while (retcode == 0 || retcode == 2);
rig_debug(RIG_DEBUG_VERBOSE, "Connection closed from %s:%d\n", if ((retcode = getnameinfo ((struct sockaddr const *)&handle_data_arg->cli_addr
inet_ntoa(handle_data_arg->cli_addr.sin_addr), , handle_data_arg->clilen, host, sizeof (host)
ntohs(handle_data_arg->cli_addr.sin_port)); , serv, sizeof (serv), NI_NOFQDN)) < 0)
{
rig_debug (RIG_DEBUG_WARN, "Peer lookup error: %s", gai_strerror (retcode));
}
rig_debug(RIG_DEBUG_VERBOSE, "Connection closed from %s:%s\n",
host, serv);
fclose(fsockin); fclose(fsockin);
fclose(fsockout); fclose(fsockout);