kopia lustrzana https://github.com/Hamlib/Hamlib
Make rig_open() call in rigctld lazy and add graceful termination
Because some rigs lock their front panel when opened for CAT it is helpful to call rig_close() in rigctld when no clients are connected. This change does that. A CTRL+C handler is also added to allow rig_close() to be called during exit.pull/6/head
rodzic
09e6ab6ef1
commit
489564a1af
|
@ -153,6 +153,7 @@ dnl Checks for typedefs, structures, and compiler characteristics.
|
||||||
AC_TYPE_SIZE_T
|
AC_TYPE_SIZE_T
|
||||||
AC_HEADER_TIME
|
AC_HEADER_TIME
|
||||||
AC_CHECK_TYPES([siginfo_t],[],[],[[#include <signal.h>]])
|
AC_CHECK_TYPES([siginfo_t],[],[],[[#include <signal.h>]])
|
||||||
|
AC_CHECK_TYPES([sig_atomic_t],[],[],[[#include <signal.h>]])
|
||||||
|
|
||||||
|
|
||||||
dnl Checks for libraries.
|
dnl Checks for libraries.
|
||||||
|
|
|
@ -567,7 +567,7 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
retcode = rigctl_parse(my_rig, stdin, stdout, argv, argc);
|
retcode = rigctl_parse(my_rig, stdin, stdout, argv, argc, NULL);
|
||||||
|
|
||||||
if (retcode == 2)
|
if (retcode == 2)
|
||||||
{
|
{
|
||||||
|
|
|
@ -90,12 +90,6 @@ extern int read_history();
|
||||||
/* Hash table implementation See: http://uthash.sourceforge.net/ */
|
/* Hash table implementation See: http://uthash.sourceforge.net/ */
|
||||||
#include "uthash.h"
|
#include "uthash.h"
|
||||||
|
|
||||||
#ifdef HAVE_PTHREAD
|
|
||||||
# include <pthread.h>
|
|
||||||
|
|
||||||
static pthread_mutex_t rig_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define STR1(S) #S
|
#define STR1(S) #S
|
||||||
#define STR(S) STR1(S)
|
#define STR(S) STR1(S)
|
||||||
|
|
||||||
|
@ -601,7 +595,7 @@ int ext_resp = 0;
|
||||||
unsigned char resp_sep = '\n'; /* Default response separator */
|
unsigned char resp_sep = '\n'; /* Default response separator */
|
||||||
|
|
||||||
|
|
||||||
int rigctl_parse(RIG *my_rig, FILE *fin, FILE *fout, char *argv[], int argc)
|
int rigctl_parse(RIG *my_rig, FILE *fin, FILE *fout, char *argv[], int argc, sync_cb_t sync_cb)
|
||||||
{
|
{
|
||||||
int retcode; /* generic return code from functions */
|
int retcode; /* generic return code from functions */
|
||||||
unsigned char cmd;
|
unsigned char cmd;
|
||||||
|
@ -1512,14 +1506,7 @@ int rigctl_parse(RIG *my_rig, FILE *fin, FILE *fout, char *argv[], int argc)
|
||||||
|
|
||||||
#endif /* HAVE_LIBREADLINE */
|
#endif /* HAVE_LIBREADLINE */
|
||||||
|
|
||||||
|
if (sync_cb) sync_cb (1); /* lock if necessary */
|
||||||
/*
|
|
||||||
* mutex locking needed because rigctld is multithreaded
|
|
||||||
* and hamlib is not MT-safe
|
|
||||||
*/
|
|
||||||
#ifdef HAVE_PTHREAD
|
|
||||||
pthread_mutex_lock(&rig_mutex);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!prompt)
|
if (!prompt)
|
||||||
{
|
{
|
||||||
|
@ -1572,10 +1559,7 @@ int rigctl_parse(RIG *my_rig, FILE *fin, FILE *fout, char *argv[], int argc)
|
||||||
p2 ? p2 : "",
|
p2 ? p2 : "",
|
||||||
p3 ? p3 : "");
|
p3 ? p3 : "");
|
||||||
|
|
||||||
#ifdef HAVE_PTHREAD
|
if (sync_cb) sync_cb (0); /* unlock if necessary */
|
||||||
pthread_mutex_unlock(&rig_mutex);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
if (retcode != RIG_OK)
|
if (retcode != RIG_OK)
|
||||||
{
|
{
|
||||||
|
|
|
@ -45,6 +45,7 @@ int dump_chan(FILE *, RIG *, channel_t *);
|
||||||
int print_conf_list(const struct confparams *cfp, rig_ptr_t data);
|
int print_conf_list(const struct confparams *cfp, rig_ptr_t data);
|
||||||
int set_conf(RIG *my_rig, char *conf_parms);
|
int set_conf(RIG *my_rig, char *conf_parms);
|
||||||
|
|
||||||
int rigctl_parse(RIG *my_rig, FILE *fin, FILE *fout, char *argv[], int argc);
|
typedef void (*sync_cb_t)(int);
|
||||||
|
int rigctl_parse(RIG *my_rig, FILE *fin, FILE *fout, char *argv[], int argc, sync_cb_t sync_cb);
|
||||||
|
|
||||||
#endif /* RIGCTL_PARSE_H */
|
#endif /* RIGCTL_PARSE_H */
|
||||||
|
|
264
tests/rigctld.c
264
tests/rigctld.c
|
@ -27,6 +27,11 @@
|
||||||
# include "config.h"
|
# include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -118,6 +123,19 @@ void *handle_socket(void *arg);
|
||||||
void usage(void);
|
void usage(void);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_PTHREAD
|
||||||
|
static unsigned client_count;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static RIG * my_rig; /* handle to rig (instance) */
|
||||||
|
static int verbose;
|
||||||
|
|
||||||
|
#ifdef HAVE_SIG_ATOMIC_T
|
||||||
|
static sig_atomic_t volatile ctrl_c;
|
||||||
|
#else
|
||||||
|
static int volatile ctrl_c;
|
||||||
|
#endif
|
||||||
|
|
||||||
int interactive = 1; /* no cmd because of daemon */
|
int interactive = 1; /* no cmd because of daemon */
|
||||||
int prompt = 0; /* Daemon mode for rigparse return string */
|
int prompt = 0; /* Daemon mode for rigparse return string */
|
||||||
int vfo_mode = 0; /* vfo_mode=0 means target VFO is current VFO */
|
int vfo_mode = 0; /* vfo_mode=0 means target VFO is current VFO */
|
||||||
|
@ -129,6 +147,51 @@ const char *src_addr = NULL; /* INADDR_ANY */
|
||||||
|
|
||||||
#define MAXCONFLEN 128
|
#define MAXCONFLEN 128
|
||||||
|
|
||||||
|
static void sync_callback (int lock)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_PTHREAD
|
||||||
|
static pthread_mutex_t client_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
if (lock) {
|
||||||
|
pthread_mutex_lock (&client_lock);
|
||||||
|
rig_debug (RIG_DEBUG_VERBOSE, "client lock engaged\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rig_debug (RIG_DEBUG_VERBOSE, "client lock disengaged\n");
|
||||||
|
pthread_mutex_unlock (&client_lock);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
static BOOL WINAPI CtrlHandler (DWORD fdwCtrlType)
|
||||||
|
{
|
||||||
|
rig_debug (RIG_DEBUG_VERBOSE, "CtrlHandler called\n");
|
||||||
|
switch (fdwCtrlType)
|
||||||
|
{
|
||||||
|
case CTRL_C_EVENT:
|
||||||
|
case CTRL_CLOSE_EVENT:
|
||||||
|
ctrl_c = 1;
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static void signal_handler (int sig)
|
||||||
|
{
|
||||||
|
switch (sig)
|
||||||
|
{
|
||||||
|
case SIGINT:
|
||||||
|
ctrl_c = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* do nothing */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void handle_error(enum rig_debug_level_e lvl, const char *msg)
|
static void handle_error(enum rig_debug_level_e lvl, const char *msg)
|
||||||
{
|
{
|
||||||
|
@ -165,12 +228,10 @@ static void handle_error(enum rig_debug_level_e lvl, const char *msg)
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
RIG *my_rig; /* handle to rig (instance) */
|
|
||||||
rig_model_t my_model = RIG_MODEL_DUMMY;
|
rig_model_t my_model = RIG_MODEL_DUMMY;
|
||||||
|
|
||||||
int retcode; /* generic return code from functions */
|
int retcode; /* generic return code from functions */
|
||||||
|
|
||||||
int verbose = 0;
|
|
||||||
int show_conf = 0;
|
int show_conf = 0;
|
||||||
int dump_caps_opt = 0;
|
int dump_caps_opt = 0;
|
||||||
const char *rig_file = NULL, *ptt_file = NULL, *dcd_file = NULL;
|
const char *rig_file = NULL, *ptt_file = NULL, *dcd_file = NULL;
|
||||||
|
@ -500,6 +561,7 @@ int main(int argc, char *argv[])
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* open and close rig connection to check early for issues */
|
||||||
retcode = rig_open(my_rig);
|
retcode = rig_open(my_rig);
|
||||||
|
|
||||||
if (retcode != RIG_OK)
|
if (retcode != RIG_OK)
|
||||||
|
@ -518,6 +580,14 @@ int main(int argc, char *argv[])
|
||||||
rig_debug(RIG_DEBUG_VERBOSE, "Backend version: %s, Status: %s\n",
|
rig_debug(RIG_DEBUG_VERBOSE, "Backend version: %s, Status: %s\n",
|
||||||
my_rig->caps->version, rig_strstatus(my_rig->caps->status));
|
my_rig->caps->version, rig_strstatus(my_rig->caps->status));
|
||||||
|
|
||||||
|
rig_close(my_rig); /* we will reopen for clients */
|
||||||
|
if (verbose > 0)
|
||||||
|
{
|
||||||
|
printf("Closed rig model %d, '%s - will reopen for clients'\n",
|
||||||
|
my_rig->caps->rig_model,
|
||||||
|
my_rig->caps->model_name);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __MINGW32__
|
#ifdef __MINGW32__
|
||||||
# ifndef SO_OPENTYPE
|
# ifndef SO_OPENTYPE
|
||||||
# define SO_OPENTYPE 0x7008
|
# define SO_OPENTYPE 0x7008
|
||||||
|
@ -639,28 +709,47 @@ int main(int argc, char *argv[])
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if HAVE_SIGACTION
|
||||||
|
struct sigaction act;
|
||||||
|
|
||||||
#ifdef SIGPIPE
|
#ifdef SIGPIPE
|
||||||
/* Ignore SIGPIPE as we will handle it at the write()/send() calls
|
/* Ignore SIGPIPE as we will handle it at the write()/send() calls
|
||||||
that will consequently fail with EPIPE. All child threads will
|
that will consequently fail with EPIPE. All child threads will
|
||||||
inherit this disposition which is what we want. */
|
inherit this disposition which is what we want. */
|
||||||
#if HAVE_SIGACTION
|
|
||||||
struct sigaction act;
|
|
||||||
memset(&act, 0, sizeof act);
|
memset(&act, 0, sizeof act);
|
||||||
act.sa_handler = SIG_IGN;
|
act.sa_handler = SIG_IGN;
|
||||||
act.sa_flags = SA_RESTART;
|
act.sa_flags = SA_RESTART;
|
||||||
|
|
||||||
if (sigaction(SIGPIPE, &act, NULL))
|
if (sigaction(SIGPIPE, &act, NULL))
|
||||||
{
|
{
|
||||||
handle_error(RIG_DEBUG_ERR, "sigaction");
|
handle_error(RIG_DEBUG_ERR, "sigaction SIGPIPE");
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#elif HAVE_SIGNAL
|
#ifdef SIGINT
|
||||||
|
memset(&act, 0, sizeof act);
|
||||||
if (SIG_ERR == signal(SIGPIPE, SIG_IGN))
|
act.sa_handler = signal_handler;
|
||||||
|
if (sigaction(SIGINT, &act, NULL))
|
||||||
{
|
{
|
||||||
handle_error(RIG_DEBUG_ERR, "signal");
|
handle_error(RIG_DEBUG_ERR, "sigaction SIGINT");
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#elif defined (WIN32)
|
||||||
|
if (!SetConsoleCtrlHandler (CtrlHandler, TRUE))
|
||||||
|
{
|
||||||
|
handle_error(RIG_DEBUG_ERR, "SetConsoleCtrlHandler");
|
||||||
|
}
|
||||||
|
#elif HAVE_SIGNAL
|
||||||
|
#ifdef SIGPIPE
|
||||||
|
if (SIG_ERR == signal(SIGPIPE, SIG_IGN))
|
||||||
|
{
|
||||||
|
handle_error(RIG_DEBUG_ERR, "signal SIGPIPE");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef SIGINT
|
||||||
|
if (SIG_ERR == signal(SIGINT, signal_handler))
|
||||||
|
{
|
||||||
|
handle_error(RIG_DEBUG_ERR, "signal SIGINT");
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -677,57 +766,84 @@ int main(int argc, char *argv[])
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
arg->rig = my_rig;
|
/* use select to allow for periodic checks for CTRL+C */
|
||||||
arg->clilen = sizeof(arg->cli_addr);
|
fd_set set;
|
||||||
arg->sock = accept(sock_listen,
|
struct timeval timeout;
|
||||||
(struct sockaddr *)&arg->cli_addr,
|
FD_ZERO (&set);
|
||||||
&arg->clilen);
|
FD_SET (sock_listen, &set);
|
||||||
|
timeout.tv_sec = 5;
|
||||||
if (arg->sock < 0)
|
timeout.tv_usec = 0;
|
||||||
{
|
retcode = select (sock_listen + 1, &set, NULL, NULL, &timeout);
|
||||||
handle_error(RIG_DEBUG_ERR, "accept");
|
if (-1 == retcode) {
|
||||||
|
rig_debug (RIG_DEBUG_ERR, "select\n");
|
||||||
|
}
|
||||||
|
else if (!retcode) {
|
||||||
|
if (ctrl_c) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
arg->rig = my_rig;
|
||||||
|
arg->clilen = sizeof(arg->cli_addr);
|
||||||
|
arg->sock = accept(sock_listen,
|
||||||
|
(struct sockaddr *)&arg->cli_addr,
|
||||||
|
&arg->clilen);
|
||||||
|
|
||||||
if ((retcode = getnameinfo((struct sockaddr const *)&arg->cli_addr,
|
if (arg->sock < 0)
|
||||||
arg->clilen,
|
{
|
||||||
host,
|
handle_error(RIG_DEBUG_ERR, "accept");
|
||||||
sizeof(host),
|
break;
|
||||||
serv,
|
}
|
||||||
sizeof(serv),
|
|
||||||
NI_NOFQDN))
|
|
||||||
< 0)
|
|
||||||
{
|
|
||||||
|
|
||||||
rig_debug(RIG_DEBUG_WARN,
|
if ((retcode = getnameinfo((struct sockaddr const *)&arg->cli_addr,
|
||||||
"Peer lookup error: %s",
|
arg->clilen,
|
||||||
gai_strerror(retcode));
|
host,
|
||||||
}
|
sizeof(host),
|
||||||
|
serv,
|
||||||
|
sizeof(serv),
|
||||||
|
NI_NOFQDN))
|
||||||
|
< 0)
|
||||||
|
{
|
||||||
|
rig_debug(RIG_DEBUG_WARN,
|
||||||
|
"Peer lookup error: %s",
|
||||||
|
gai_strerror(retcode));
|
||||||
|
}
|
||||||
|
|
||||||
rig_debug(RIG_DEBUG_VERBOSE,
|
rig_debug(RIG_DEBUG_VERBOSE,
|
||||||
"Connection opened from %s:%s\n",
|
"Connection opened from %s:%s\n",
|
||||||
host,
|
host,
|
||||||
serv);
|
serv);
|
||||||
|
|
||||||
#ifdef HAVE_PTHREAD
|
#ifdef HAVE_PTHREAD
|
||||||
pthread_attr_init(&attr);
|
pthread_attr_init(&attr);
|
||||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||||
|
|
||||||
retcode = pthread_create(&thread, &attr, handle_socket, arg);
|
retcode = pthread_create(&thread, &attr, handle_socket, arg);
|
||||||
|
|
||||||
if (retcode != 0)
|
if (retcode != 0)
|
||||||
{
|
{
|
||||||
rig_debug(RIG_DEBUG_ERR, "pthread_create: %s\n", strerror(retcode));
|
rig_debug(RIG_DEBUG_ERR, "pthread_create: %s\n", strerror(retcode));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
handle_socket(arg);
|
handle_socket(arg);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
while (retcode == 0);
|
while (retcode == 0 && !ctrl_c);
|
||||||
|
|
||||||
|
#ifdef HAVE_PTHREAD
|
||||||
|
/* allow threads to finish current action */
|
||||||
|
sync_callback (1);
|
||||||
|
if (client_count) {
|
||||||
|
rig_debug (RIG_DEBUG_WARN, "%d outstanding client(s)\n", client_count);
|
||||||
|
}
|
||||||
|
rig_close (my_rig);
|
||||||
|
sync_callback (0);
|
||||||
|
#else
|
||||||
rig_close(my_rig); /* close port */
|
rig_close(my_rig); /* close port */
|
||||||
|
#endif
|
||||||
rig_cleanup(my_rig); /* if you care about memory */
|
rig_cleanup(my_rig); /* if you care about memory */
|
||||||
|
|
||||||
#ifdef __MINGW32__
|
#ifdef __MINGW32__
|
||||||
|
@ -746,7 +862,7 @@ void * handle_socket(void *arg)
|
||||||
struct handle_data *handle_data_arg = (struct handle_data *)arg;
|
struct handle_data *handle_data_arg = (struct handle_data *)arg;
|
||||||
FILE *fsockin;
|
FILE *fsockin;
|
||||||
FILE *fsockout;
|
FILE *fsockout;
|
||||||
int retcode;
|
int retcode = RIG_OK;
|
||||||
char host[NI_MAXHOST];
|
char host[NI_MAXHOST];
|
||||||
char serv[NI_MAXSERV];
|
char serv[NI_MAXSERV];
|
||||||
|
|
||||||
|
@ -784,17 +900,61 @@ void * handle_socket(void *arg)
|
||||||
goto handle_exit;
|
goto handle_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_PTHREAD
|
||||||
|
sync_callback (1);
|
||||||
|
if (!client_count++) {
|
||||||
|
retcode = rig_open (my_rig);
|
||||||
|
if (RIG_OK == retcode && verbose > 0)
|
||||||
|
{
|
||||||
|
printf("Opened rig model %d, '%s'\n",
|
||||||
|
my_rig->caps->rig_model,
|
||||||
|
my_rig->caps->model_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sync_callback (0);
|
||||||
|
#else
|
||||||
|
retcode = rig_open (my_rig);
|
||||||
|
if (RIG_OK == retcode && verbose > 0)
|
||||||
|
{
|
||||||
|
printf("Opened rig model %d, '%s'\n",
|
||||||
|
my_rig->caps->rig_model,
|
||||||
|
my_rig->caps->model_name);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
retcode = rigctl_parse(handle_data_arg->rig, fsockin, fsockout, NULL, 0);
|
retcode = rigctl_parse(handle_data_arg->rig, fsockin, fsockout, NULL, 0, sync_callback);
|
||||||
|
if (ferror(fsockin) || ferror(fsockout))
|
||||||
if (ferror(fsockin) || ferror(fsockout))
|
|
||||||
{
|
{
|
||||||
retcode = 1;
|
retcode = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (retcode == 0 || retcode == 2 || retcode == -RIG_ENAVAIL);
|
while (retcode == 0 || retcode == 2 || retcode == -RIG_ENAVAIL);
|
||||||
|
|
||||||
|
#ifdef HAVE_PTHREAD
|
||||||
|
sync_callback (1);
|
||||||
|
/* Release rig if there are no clients */
|
||||||
|
if (!--client_count) {
|
||||||
|
rig_close (my_rig);
|
||||||
|
if (verbose > 0)
|
||||||
|
{
|
||||||
|
printf("Closed rig model %d, '%s - no clients, will reopen for new clients'\n",
|
||||||
|
my_rig->caps->rig_model,
|
||||||
|
my_rig->caps->model_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sync_callback (0);
|
||||||
|
#else
|
||||||
|
rig_close (my_rig);
|
||||||
|
if (verbose > 0)
|
||||||
|
{
|
||||||
|
printf("Closed rig model %d, '%s - will reopen for new clients'\n",
|
||||||
|
my_rig->caps->rig_model,
|
||||||
|
my_rig->caps->model_name);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if ((retcode = getnameinfo((struct sockaddr const *)&handle_data_arg->cli_addr,
|
if ((retcode = getnameinfo((struct sockaddr const *)&handle_data_arg->cli_addr,
|
||||||
handle_data_arg->clilen,
|
handle_data_arg->clilen,
|
||||||
host,
|
host,
|
||||||
|
|
Ładowanie…
Reference in New Issue