Add multiple client support to kiss TCP ports. This only works on

Linux ( and probably other POSIX platforms ) as I don't think
Windows has select.
This commit is contained in:
Angus Ainslie 2017-01-25 14:29:31 +00:00
parent 6207e2eb3e
commit 1f9310b79e
1 changed files with 156 additions and 83 deletions

237
kissnet.c
View File

@ -2,6 +2,7 @@
// This file is part of Dire Wolf, an amateur radio packet TNC. // This file is part of Dire Wolf, an amateur radio packet TNC.
// //
// Copyright (C) 2011-2014, 2015 John Langner, WB2OSZ // Copyright (C) 2011-2014, 2015 John Langner, WB2OSZ
// Copyright (C) 2016 Angus Ainslie angus at akkea.ca, VE6GUS
// //
// This program is free software: you can redistribute it and/or modify // This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by // it under the terms of the GNU General Public License as published by
@ -128,15 +129,21 @@
#include "kiss_frame.h" #include "kiss_frame.h"
#include "xmit.h" #include "xmit.h"
// TODO: no idea how to do this on windows
#if __WIN32__
#define MAX_NET_CLIENTS 1
#else
#define MAX_NET_CLIENTS 4
#endif
static kiss_frame_t kf; /* Accumulated KISS frame and state of decoder. */ static kiss_frame_t kf[MAX_NET_CLIENTS]; /* Accumulated KISS frame and state of decoder. */
// TODO: multiple instances if multiple KISS network clients! // TODO: multiple instances if multiple KISS network clients!
static int client_sock; /* File descriptor for socket for */ static int client_sock[MAX_NET_CLIENTS]; /* File descriptor for socket for */
/* communication with client application. */ /* communication with client application. */
/* Set to -1 if not connected. */ /* Set to -1 if not connected. */
/* (Don't use SOCKET type because it is unsigned.) */ /* (Don't use SOCKET type because it is unsigned.) */
static void * connect_listen_thread (void *arg); static void * connect_listen_thread (void *arg);
@ -187,6 +194,7 @@ void kissnet_init (struct misc_config_s *mc)
#endif #endif
int e; int e;
int kiss_port = mc->kiss_port; int kiss_port = mc->kiss_port;
int i;
#if DEBUG #if DEBUG
@ -194,9 +202,10 @@ void kissnet_init (struct misc_config_s *mc)
dw_printf ("kissnet_init ( %d )\n", kiss_port); dw_printf ("kissnet_init ( %d )\n", kiss_port);
#endif #endif
memset (&kf, 0, sizeof(kf)); for( i=0; i<MAX_NET_CLIENTS; i++ ) {
client_sock[i] = -1;
client_sock = -1; memset (&kf, 0, sizeof(kf));
}
if (kiss_port == 0) { if (kiss_port == 0) {
text_color_set(DW_COLOR_INFO); text_color_set(DW_COLOR_INFO);
@ -343,8 +352,12 @@ static void * connect_listen_thread (void *arg)
while (1) { while (1) {
while (client_sock > 0) { i = 0
SLEEP_SEC(1); /* Already connected. Try again later. */ while (client_sock[i] > 0) {
if(( ++i % MAX_NET_CLIENTS ) == 0 ) {
SLEEP_SEC(1); /* All clients already connected. Try again later. */
i = 0 ;
}
} }
#define QUEUE_SIZE 5 #define QUEUE_SIZE 5
@ -359,9 +372,9 @@ static void * connect_listen_thread (void *arg)
text_color_set(DW_COLOR_INFO); text_color_set(DW_COLOR_INFO);
dw_printf("Ready to accept KISS client application on port %s ...\n", kiss_port_str); dw_printf("Ready to accept KISS client application on port %s ...\n", kiss_port_str);
client_sock = accept(listen_sock, NULL, NULL); client_sock[i] = accept(listen_sock, NULL, NULL);
if (client_sock == -1) { if (client_sock[i] == -1) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf("Accept failed with error: %d\n", WSAGetLastError()); dw_printf("Accept failed with error: %d\n", WSAGetLastError());
closesocket(listen_sock); closesocket(listen_sock);
@ -383,6 +396,7 @@ static void * connect_listen_thread (void *arg)
int kiss_port = (int)(long)arg; int kiss_port = (int)(long)arg;
int listen_sock; int listen_sock;
int bcopt = 1; int bcopt = 1;
int i;
listen_sock= socket(AF_INET,SOCK_STREAM,0); listen_sock= socket(AF_INET,SOCK_STREAM,0);
if (listen_sock == -1) { if (listen_sock == -1) {
@ -409,12 +423,12 @@ static void * connect_listen_thread (void *arg)
#endif #endif
if (bind(listen_sock,(struct sockaddr*)&sockaddr,sizeof(sockaddr)) == -1) { if (bind(listen_sock,(struct sockaddr*)&sockaddr,sizeof(sockaddr)) == -1) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf("Bind failed with error: %d\n", errno); dw_printf("Bind failed with error: %d\n", errno);
dw_printf("%s\n", strerror(errno)); dw_printf("%s\n", strerror(errno));
dw_printf("Some other application is probably already using port %d.\n", kiss_port); dw_printf("Some other application is probably already using port %d.\n", kiss_port);
dw_printf("Try using a different port number with KISSPORT in the configuration file.\n"); dw_printf("Try using a different port number with KISSPORT in the configuration file.\n");
return (NULL); return (NULL);
} }
getsockname( listen_sock, (struct sockaddr *)(&sockaddr), &sockaddr_size); getsockname( listen_sock, (struct sockaddr *)(&sockaddr), &sockaddr_size);
@ -426,8 +440,12 @@ static void * connect_listen_thread (void *arg)
while (1) { while (1) {
while (client_sock > 0) { i = 0;
SLEEP_SEC(1); /* Already connected. Try again later. */ while (client_sock[i] > 0) {
if(( ++i % MAX_NET_CLIENTS ) == 0 ) {
i = 0;
SLEEP_SEC(1); /* Already connected. Try again later. */
}
} }
#define QUEUE_SIZE 5 #define QUEUE_SIZE 5
@ -440,12 +458,12 @@ static void * connect_listen_thread (void *arg)
} }
text_color_set(DW_COLOR_INFO); text_color_set(DW_COLOR_INFO);
dw_printf("Ready to accept KISS client application on port %d ...\n", kiss_port); dw_printf("Ready to accept KISS client %d application on port %d ...\n", i, kiss_port);
client_sock = accept(listen_sock, (struct sockaddr*)(&sockaddr),&sockaddr_size); client_sock[i] = accept(listen_sock, (struct sockaddr*)(&sockaddr),&sockaddr_size);
text_color_set(DW_COLOR_INFO); text_color_set(DW_COLOR_INFO);
dw_printf("\nConnected to KISS client application ...\n\n"); dw_printf("\nConnected to KISS client %d application on fd %d...\n\n", i, client_sock[i] );
} }
#endif #endif
@ -483,64 +501,66 @@ void kissnet_send_rec_packet (int chan, unsigned char *fbuf, int flen)
int kiss_len; int kiss_len;
int j; int j;
int err; int err;
int i;
for( i = 0; i<MAX_NET_CLIENTS; i++ ) {
if (client_sock[i] == -1) {
continue;
}
if (flen < 0) {
flen = strlen((char*)fbuf);
if (kiss_debug) {
kiss_debug_print (TO_CLIENT, "Fake command prompt", fbuf, flen);
}
strlcpy ((char *)kiss_buff, (char *)fbuf, sizeof(kiss_buff));
kiss_len = strlen((char *)kiss_buff);
}
else {
if (client_sock == -1) { unsigned char stemp[AX25_MAX_PACKET_LEN + 1];
return;
}
if (flen < 0) {
flen = strlen((char*)fbuf);
if (kiss_debug) {
kiss_debug_print (TO_CLIENT, "Fake command prompt", fbuf, flen);
}
strlcpy ((char *)kiss_buff, (char *)fbuf, sizeof(kiss_buff));
kiss_len = strlen((char *)kiss_buff);
}
else {
assert (flen < sizeof(stemp));
unsigned char stemp[AX25_MAX_PACKET_LEN + 1]; stemp[0] = (chan << 4) + 0;
memcpy (stemp+1, fbuf, flen);
assert (flen < sizeof(stemp)); if (kiss_debug >= 2) {
/* AX.25 frame with the CRC removed. */
text_color_set(DW_COLOR_DEBUG);
dw_printf ("\n");
dw_printf ("Packet content before adding KISS framing and any escapes:\n");
hex_dump (fbuf, flen);
}
stemp[0] = (chan << 4) + 0; kiss_len = kiss_encapsulate (stemp, flen+1, kiss_buff);
memcpy (stemp+1, fbuf, flen);
if (kiss_debug >= 2) { /* This has the escapes and the surrounding FENDs. */
/* AX.25 frame with the CRC removed. */
text_color_set(DW_COLOR_DEBUG);
dw_printf ("\n");
dw_printf ("Packet content before adding KISS framing and any escapes:\n");
hex_dump (fbuf, flen);
}
kiss_len = kiss_encapsulate (stemp, flen+1, kiss_buff); if (kiss_debug) {
kiss_debug_print (TO_CLIENT, NULL, kiss_buff, kiss_len);
/* This has the escapes and the surrounding FENDs. */ }
}
if (kiss_debug) {
kiss_debug_print (TO_CLIENT, NULL, kiss_buff, kiss_len);
}
}
#if __WIN32__ #if __WIN32__
err = send (client_sock, (char*)kiss_buff, kiss_len, 0); err = send (client_sock[i], (char*)kiss_buff, kiss_len, 0);
if (err == SOCKET_ERROR) if (err == SOCKET_ERROR)
{ {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("\nError %d sending message to KISS client application. Closing connection.\n\n", WSAGetLastError()); dw_printf ("\nError %d sending message to KISS client application. Closing connection.\n\n", WSAGetLastError());
closesocket (client_sock); closesocket (client_sock[i]);
client_sock = -1; client_sock[i] = -1;
WSACleanup(); WSACleanup();
} }
#else #else
err = write (client_sock, kiss_buff, kiss_len); err = write (client_sock[i], kiss_buff, kiss_len);
if (err <= 0) if (err <= 0)
{ {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("\nError sending message to KISS client application. Closing connection.\n\n"); dw_printf ("\nError sending message to KISS client application. Closing connection %d.\n\n", i);
close (client_sock); close (client_sock[i]);
client_sock = -1; client_sock[i] = -1;
}
} }
#endif #endif
@ -626,20 +646,21 @@ static int read_from_socket (int fd, char *ptr, int len)
/* Return one byte (value 0 - 255) */ /* Return one byte (value 0 - 255) */
static int kiss_get (void) static int kiss_get ( int socket_id )
{ {
unsigned char ch; unsigned char ch;
int n; int n;
while (1) { while (1) {
while (client_sock <= 0) { #if __WIN32__
while (client_sock[socket_id] <= 0) {
SLEEP_SEC(1); /* Not connected. Try again later. */ SLEEP_SEC(1); /* Not connected. Try again later. */
} }
#endif
/* Just get one byte at a time. */ /* Just get one byte at a time. */
n = read_from_socket (client_sock, (char *)(&ch), 1); n = read_from_socket (client_sock[socket_id], (char *)(&ch), 1);
if (n == 1) { if (n == 1) {
#if DEBUG9 #if DEBUG9
@ -661,11 +682,13 @@ static int kiss_get (void)
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("\nError reading KISS byte from clent application. Closing connection.\n\n"); dw_printf ("\nError reading KISS byte from clent application. Closing connection.\n\n");
#if __WIN32__ #if __WIN32__
closesocket (client_sock); closesocket (client_sock[socket_id]);
#else #else
close (client_sock); close (client_sock[socket_id]);
#endif #endif
client_sock = -1; client_sock[socket_id] = -1;
return( -1 );
} }
} }
@ -674,15 +697,65 @@ static int kiss_get (void)
static void * kissnet_listen_thread (void *arg) static void * kissnet_listen_thread (void *arg)
{ {
unsigned char ch; unsigned char ch;
int i = 0;
int count;
int max_fd;
fd_set set;
struct timeval tv;
#if DEBUG #if DEBUG
text_color_set(DW_COLOR_DEBUG); text_color_set(DW_COLOR_DEBUG);
dw_printf ("kissnet_listen_thread ( socket = %d )\n", client_sock); dw_printf ("kissnet_listen_thread ( socket = %d )\n", client_sock[i]);
#endif #endif
while (1) { while (1) {
ch = kiss_get(); #if __WIN32__
kiss_rec_byte (&kf, ch, kiss_debug, kissnet_send_rec_packet); ch = kiss_get( i );
kiss_rec_byte (&kf[i], ch, kiss_debug, kissnet_send_rec_packet);
#else
FD_ZERO( &set );
for( max_fd=0, i=0; i<MAX_NET_CLIENTS; i++ )
if( client_sock[i] > 0 ) {
FD_SET( client_sock[i], &set);
if( client_sock[i] > max_fd )
max_fd = client_sock[i];
}
if( max_fd == 0 ) {
SLEEP_SEC(1);
continue;
}
else
{
tv.tv_sec = 1;
tv.tv_usec = 0;
count = select( max_fd + 1, &set, NULL, NULL, &tv );
}
if( count > 0 ) {
for( i=0; i<MAX_NET_CLIENTS; i++ ) {
if( client_sock[i] > 0 && FD_ISSET( client_sock[i], &set )) {
ch = kiss_get( i );
if( ch != -1 )
kiss_rec_byte (&kf[i], ch, kiss_debug,
kissnet_send_rec_packet);
}
}
}
else if ( count == 0 )
{
#if DEBUG
dw_printf ("kissnet_listen_thread timeout\n");
#endif
}
else
{
// TODO : Should we do something here ?
#if DEBUG
dw_printf ("kissnet_listen_thread error\n");
#endif
}
#endif
} }
return (NULL); /* to suppress compiler warning. */ return (NULL); /* to suppress compiler warning. */