1 //
2 //    This file is part of Dire Wolf, an amateur radio packet TNC.
3 //
4 //    Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2020  John Langner, WB2OSZ
5 //
6 //    This program is free software: you can redistribute it and/or modify
7 //    it under the terms of the GNU General Public License as published by
8 //    the Free Software Foundation, either version 2 of the License, or
9 //    (at your option) any later version.
10 //
11 //    This program is distributed in the hope that it will be useful,
12 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //    GNU General Public License for more details.
15 //
16 //    You should have received a copy of the GNU General Public License
17 //    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 //
19 
20 
21 /*------------------------------------------------------------------
22  *
23  * Module:      server.c
24  *
25  * Purpose:   	Provide service to other applications via "AGW TCPIP Socket Interface".
26  *
27  * Input:
28  *
29  * Outputs:
30  *
31  * Description:	This provides a TCP socket for communication with a client application.
32  *		It implements a subset of the AGW socket interface.
33  *
34  *		Commands from application recognized:
35  *
36  *			'R'	Request for version number.
37  *				(See below for response.)
38  *
39  *			'G'	Ask about radio ports.
40  *				(See below for response.)
41  *
42  *			'g'	Capabilities of a port.  (new in 0.8)
43  *				(See below for response.)
44  *
45  *			'k'	Ask to start receiving RAW AX25 frames.
46  *
47  *			'm'	Ask to start receiving Monitor AX25 frames.
48  *				Enables sending of U, I, S, and T messages to client app.
49  *
50  *			'V'	Transmit UI data frame.
51  *
52  *			'H'	Report recently heard stations.  Not implemented yet.
53  *
54  *			'K'	Transmit raw AX.25 frame.
55  *
56  *			'X'	Register CallSign
57  *
58  *			'x'	Unregister CallSign
59  *
60  *			'y'	Ask Outstanding frames waiting on a Port   (new in 1.2)
61  *
62  *			'Y'	How many frames waiting for transmit for a particular station (new in 1.5)
63  *
64  *			'C'	Connect, Start an AX.25 Connection			(new in 1.4)
65  *
66  *			'v'	Connect VIA, Start an AX.25 circuit thru digipeaters	(new in 1.4)
67  *
68  *			'c'	Connection with non-standard PID			(new in 1.4)
69  *
70  *			'D'	Send Connected Data					(new in 1.4)
71  *
72  *			'd'	Disconnect, Terminate an AX.25 Connection		(new in 1.4)
73  *
74  *
75  *			A message is printed if any others are received.
76  *
77  *			TODO: Should others be implemented?
78  *
79  *
80  *		Messages sent to client application:
81  *
82  *			'R'	Reply to Request for version number.
83  *				Currently responds with major 1, minor 0.
84  *
85  *			'G'	Reply to Ask about radio ports.
86  *
87  *			'g'	Reply to capabilities of a port.  (new in 0.8)
88  *
89  *			'K'	Received AX.25 frame in raw format.
90  *				(Enabled with 'k' command.)
91  *
92  *			'U'	Received AX.25 "UI" frames in monitor format.
93  *				(Enabled with 'm' command.)
94  *
95  *			'I'	Received AX.25 "I" frames in monitor format.	(new in 1.6)
96  *				(Enabled with 'm' command.)
97  *
98  *			'S'	Received AX.25 "S" and "U" (other than UI) frames in monitor format.	(new in 1.6)
99  *				(Enabled with 'm' command.)
100  *
101  *			'T'	Own Transmitted AX.25 frames in monitor format.	(new in 1.6)
102  *				(Enabled with 'm' command.)
103  *
104  *			'y'	Outstanding frames waiting on a Port   (new in 1.2)
105  *
106  *			'Y'	How many frames waiting for transmit for a particular station (new in 1.5)
107  *
108  *			'C'	AX.25 Connection Received		(new in 1.4)
109  *
110  *			'D'	Connected AX.25 Data			(new in 1.4)
111  *
112  *			'd'	Disconnected				(new in 1.4)
113  *
114  *
115  *
116  * References:	AGWPE TCP/IP API Tutorial
117  *		http://uz7ho.org.ua/includes/agwpeapi.htm
118  *
119  * 		Getting Started with Winsock
120  *		http://msdn.microsoft.com/en-us/library/windows/desktop/bb530742(v=vs.85).aspx
121  *
122  *
123  * Major change in 1.1:
124  *
125  *		Formerly a single client was allowed.
126  *		Now we can have multiple concurrent clients.
127  *
128  *---------------------------------------------------------------*/
129 
130 
131 /*
132  * Native Windows:	Use the Winsock interface.
133  * Linux:		Use the BSD socket interface.
134  * Cygwin:		Can use either one.
135  */
136 
137 #include "direwolf.h"		// Sets _WIN32_WINNT for XP API level needed by ws2tcpip.h
138 
139 #if __WIN32__
140 #include <winsock2.h>
141 #include <ws2tcpip.h>  		// _WIN32_WINNT must be set to 0x0501 before including this
142 #else
143 #include <stdlib.h>
144 #include <sys/types.h>
145 #include <sys/ioctl.h>
146 #include <sys/socket.h>
147 #include <netinet/in.h>
148 #include <errno.h>
149 #endif
150 
151 #include <unistd.h>
152 #include <stdio.h>
153 #include <assert.h>
154 #include <string.h>
155 #include <time.h>
156 #include <ctype.h>
157 #include <stddef.h>
158 
159 #include "tq.h"
160 #include "ax25_pad.h"
161 #include "textcolor.h"
162 #include "audio.h"
163 #include "server.h"
164 #include "dlq.h"
165 
166 
167 
168 /*
169  * Previously, we allowed only one network connection at a time to each port.
170  * In version 1.1, we allow multiple concurrent client apps to attach with the AGW network protocol.
171  * The default is a limit of 3 client applications at the same time.
172  * You can increase the limit by changing the line below.
173  * A larger number consumes more resources so don't go crazy by making it larger than needed.
174  */
175 
176 #define MAX_NET_CLIENTS 3
177 
178 static int client_sock[MAX_NET_CLIENTS];
179 					/* File descriptor for socket for */
180 					/* communication with client application. */
181 					/* Set to -1 if not connected. */
182 					/* (Don't use SOCKET type because it is unsigned.) */
183 
184 static int enable_send_raw_to_client[MAX_NET_CLIENTS];
185 					/* Should we send received packets to client app in raw form? */
186 					/* Note that it starts as false for a new connection. */
187 					/* the client app must send a command to enable this. */
188 
189 static int enable_send_monitor_to_client[MAX_NET_CLIENTS];
190 					/* Should we send received packets to client app in monitor form? */
191 					/* Note that it starts as false for a new connection. */
192 					/* the client app must send a command to enable this. */
193 
194 
195 // TODO:  define in one place, use everywhere.
196 // TODO:  Macro to terminate thread when no point to go on.
197 
198 #if __WIN32__
199 #define THREAD_F unsigned __stdcall
200 #else
201 #define THREAD_F void *
202 #endif
203 
204 static THREAD_F connect_listen_thread (void *arg);
205 static THREAD_F cmd_listen_thread (void *arg);
206 
207 /*
208  * Message header for AGW protocol.
209  * Multibyte numeric values require rearranging for big endian cpu.
210  */
211 
212 /*
213  * With MinGW version 4.6, obviously x86.
214  * or Linux gcc version 4.9, Linux ARM.
215  *
216  *	$ gcc -E -dM - < /dev/null | grep END
217  *	#define __ORDER_LITTLE_ENDIAN__ 1234
218  *	#define __FLOAT_WORD_ORDER__ __ORDER_LITTLE_ENDIAN__
219  *	#define __ORDER_PDP_ENDIAN__ 3412
220  *	#define __ORDER_BIG_ENDIAN__ 4321
221  *	#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
222  *
223  * This is for standard OpenWRT on MIPS.
224  *
225  *	#define __ORDER_LITTLE_ENDIAN__ 1234
226  *	#define __FLOAT_WORD_ORDER__ __ORDER_BIG_ENDIAN__
227  *	#define __ORDER_PDP_ENDIAN__ 3412
228  *	#define __ORDER_BIG_ENDIAN__ 4321
229  *	#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__
230  *
231  * This was reported for an old Mac with PowerPC processor.
232  * (Newer versions have x86.)
233  *
234  *	$ gcc -E -dM - < /dev/null | grep END
235  *	#define __BIG_ENDIAN__ 1
236  *	#define _BIG_ENDIAN 1
237  */
238 
239 
240 #if defined(__BIG_ENDIAN__) || (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
241 
242 // gcc >= 4.2 has __builtin_swap32() but might not be compatible with older versions or other compilers.
243 
244 #define host2netle(x) ( (((x)>>24)&0x000000ff) | (((x)>>8)&0x0000ff00) | (((x)<<8)&0x00ff0000) | (((x)<<24)&0xff000000) )
245 #define netle2host(x) ( (((x)>>24)&0x000000ff) | (((x)>>8)&0x0000ff00) | (((x)<<8)&0x00ff0000) | (((x)<<24)&0xff000000) )
246 
247 #else
248 
249 #define host2netle(x) (x)
250 #define netle2host(x) (x)
251 
252 #endif
253 
254 
255 struct agwpe_s {
256   unsigned char portx;		/* 0 for first, 1 for second, etc. */
257   unsigned char reserved1;
258   unsigned char reserved2;
259   unsigned char reserved3;
260 
261   unsigned char datakind;	/* message type, usually written as a letter. */
262   unsigned char reserved4;
263   unsigned char pid;
264   unsigned char reserved5;
265 
266   char call_from[10];
267 
268   char call_to[10];
269 
270   int data_len_NETLE;		/* Number of data bytes following. */
271 				/* _NETLE suffix is reminder to convert for network byte order. */
272 
273   int user_reserved_NETLE;
274 };
275 
276 
277 static void send_to_client (int client, void *reply_p);
278 
279 
280 /*-------------------------------------------------------------------
281  *
282  * Name:        debug_print
283  *
284  * Purpose:     Print message to/from client for debugging.
285  *
286  * Inputs:	fromto		- Direction of message.
287  *		client		- client number, 0 .. MAX_NET_CLIENTS-1
288  *		pmsg		- Address of the message block.
289  *		msg_len		- Length of the message.
290  *
291  *--------------------------------------------------------------------*/
292 
293 static int debug_client = 0;		/* Debug option: Print information flowing from and to client. */
294 
server_set_debug(int n)295 void server_set_debug (int n)
296 {
297 	debug_client = n;
298 }
299 
hex_dump(unsigned char * p,int len)300 void hex_dump (unsigned char *p, int len)
301 {
302 	int n, i, offset;
303 
304 	offset = 0;
305 	while (len > 0) {
306 	  n = len < 16 ? len : 16;
307 	  dw_printf ("  %03x: ", offset);
308 	  for (i=0; i<n; i++) {
309 	    dw_printf (" %02x", p[i]);
310 	  }
311 	  for (i=n; i<16; i++) {
312 	    dw_printf ("   ");
313 	  }
314 	  dw_printf ("  ");
315 	  for (i=0; i<n; i++) {
316 	    dw_printf ("%c", isprint(p[i]) ? p[i] : '.');
317 	  }
318 	  dw_printf ("\n");
319 	  p += 16;
320 	  offset += 16;
321 	  len -= 16;
322 	}
323 }
324 
325 typedef enum fromto_e { FROM_CLIENT=0, TO_CLIENT=1 } fromto_t;
326 
debug_print(fromto_t fromto,int client,struct agwpe_s * pmsg,int msg_len)327 static void debug_print (fromto_t fromto, int client, struct agwpe_s *pmsg, int msg_len)
328 {
329 	char direction [10];
330 	char datakind[80];
331 	const char *prefix [2] = { "<<<", ">>>" };
332 
333 	switch (fromto) {
334 
335 	  case FROM_CLIENT:
336 	    strlcpy (direction, "from", sizeof(direction));		/* from the client application */
337 
338 	    switch (pmsg->datakind) {
339 	      case 'P': strlcpy (datakind, "Application Login",				sizeof(datakind)); break;
340 	      case 'X': strlcpy (datakind, "Register CallSign",				sizeof(datakind)); break;
341 	      case 'x': strlcpy (datakind, "Unregister CallSign",			sizeof(datakind)); break;
342 	      case 'G': strlcpy (datakind, "Ask Port Information",			sizeof(datakind)); break;
343 	      case 'm': strlcpy (datakind, "Enable Reception of Monitoring Frames",	sizeof(datakind)); break;
344 	      case 'R': strlcpy (datakind, "AGWPE Version Info",			sizeof(datakind)); break;
345 	      case 'g': strlcpy (datakind, "Ask Port Capabilities",			sizeof(datakind)); break;
346 	      case 'H': strlcpy (datakind, "Callsign Heard on a Port",			sizeof(datakind)); break;
347 	      case 'y': strlcpy (datakind, "Ask Outstanding frames waiting on a Port",	sizeof(datakind)); break;
348 	      case 'Y': strlcpy (datakind, "Ask Outstanding frames waiting for a connection", sizeof(datakind)); break;
349 	      case 'M': strlcpy (datakind, "Send UNPROTO Information",			sizeof(datakind)); break;
350 	      case 'C': strlcpy (datakind, "Connect, Start an AX.25 Connection",	sizeof(datakind)); break;
351 	      case 'D': strlcpy (datakind, "Send Connected Data",			sizeof(datakind)); break;
352 	      case 'd': strlcpy (datakind, "Disconnect, Terminate an AX.25 Connection",	sizeof(datakind)); break;
353 	      case 'v': strlcpy (datakind, "Connect VIA, Start an AX.25 circuit thru digipeaters", sizeof(datakind)); break;
354 	      case 'V': strlcpy (datakind, "Send UNPROTO VIA",				sizeof(datakind)); break;
355 	      case 'c': strlcpy (datakind, "Non-Standard Connections, Connection with PID", sizeof(datakind)); break;
356 	      case 'K': strlcpy (datakind, "Send data in raw AX.25 format",		sizeof(datakind)); break;
357 	      case 'k': strlcpy (datakind, "Activate reception of Frames in raw format", sizeof(datakind)); break;
358 	      default:  strlcpy (datakind, "**INVALID**",				sizeof(datakind)); break;
359 	    }
360 	    break;
361 
362 	  case TO_CLIENT:
363 	  default:
364 	    strlcpy (direction, "to", sizeof(direction));	/* sent to the client application. */
365 
366 	    switch (pmsg->datakind) {
367 	      case 'R': strlcpy (datakind, "Version Number",				sizeof(datakind)); break;
368 	      case 'X': strlcpy (datakind, "Callsign Registration",			sizeof(datakind)); break;
369 	      case 'G': strlcpy (datakind, "Port Information",				sizeof(datakind)); break;
370 	      case 'g': strlcpy (datakind, "Capabilities of a Port",			sizeof(datakind)); break;
371 	      case 'y': strlcpy (datakind, "Frames Outstanding on a Port",		sizeof(datakind)); break;
372 	      case 'Y': strlcpy (datakind, "Frames Outstanding on a Connection",	sizeof(datakind)); break;
373 	      case 'H': strlcpy (datakind, "Heard Stations on a Port",			sizeof(datakind)); break;
374 	      case 'C': strlcpy (datakind, "AX.25 Connection Received",			sizeof(datakind)); break;
375 	      case 'D': strlcpy (datakind, "Connected AX.25 Data",			sizeof(datakind)); break;
376 	      case 'd': strlcpy (datakind, "Disconnected",				sizeof(datakind)); break;
377 	      case 'M': strlcpy (datakind, "Monitored Connected Information",		sizeof(datakind)); break;
378 	      case 'S': strlcpy (datakind, "Monitored Supervisory Information",		sizeof(datakind)); break;
379 	      case 'U': strlcpy (datakind, "Monitored Unproto Information",		sizeof(datakind)); break;
380 	      case 'T': strlcpy (datakind, "Monitoring Own Information",		sizeof(datakind)); break;
381 	      case 'K': strlcpy (datakind, "Monitored Information in Raw Format",	sizeof(datakind)); break;
382 	      default:  strlcpy (datakind, "**INVALID**",				sizeof(datakind)); break;
383 	    }
384 	}
385 
386 	text_color_set(DW_COLOR_DEBUG);
387 	dw_printf ("\n");
388 
389 	dw_printf ("%s %s %s AGWPE client application %d, total length = %d\n",
390 			prefix[(int)fromto], datakind, direction, client, msg_len);
391 
392 	dw_printf ("\tportx = %d, datakind = '%c', pid = 0x%02x\n", pmsg->portx, pmsg->datakind, pmsg->pid);
393 	dw_printf ("\tcall_from = \"%s\", call_to = \"%s\"\n", pmsg->call_from, pmsg->call_to);
394 	dw_printf ("\tdata_len = %d, user_reserved = %d, data =\n", netle2host(pmsg->data_len_NETLE), netle2host(pmsg->user_reserved_NETLE));
395 
396 	hex_dump ((unsigned char*)pmsg + sizeof(struct agwpe_s), netle2host(pmsg->data_len_NETLE));
397 
398 	if (msg_len < 36) {
399 	  text_color_set (DW_COLOR_ERROR);
400 	  dw_printf ("AGWPE message length, %d, is shorter than minumum 36.\n", msg_len);
401 	}
402 	if (msg_len != netle2host(pmsg->data_len_NETLE) + 36) {
403 	  text_color_set (DW_COLOR_ERROR);
404 	  dw_printf ("AGWPE message length, %d, inconsistent with data length %d.\n", msg_len, netle2host(pmsg->data_len_NETLE));
405 	}
406 
407 }
408 
409 /*-------------------------------------------------------------------
410  *
411  * Name:        server_init
412  *
413  * Purpose:     Set up a server to listen for connection requests from
414  *		an application such as Xastir.
415  *
416  * Inputs:	mc->agwpe_port	- TCP port for server.
417  *				  Main program has default of 8000 but allows
418  *				  an alternative to be specified on the command line
419  *
420  *				0 means disable.  New in version 1.2.
421  *
422  * Outputs:
423  *
424  * Description:	This starts at least two threads:
425  *		  *  one to listen for a connection from client app.
426  *		  *  one or more to listen for commands from client app.
427  *		so the main application doesn't block while we wait for these.
428  *
429  *--------------------------------------------------------------------*/
430 
431 static struct audio_s *save_audio_config_p;
432 
433 
server_init(struct audio_s * audio_config_p,struct misc_config_s * mc)434 void server_init (struct audio_s *audio_config_p, struct misc_config_s *mc)
435 {
436 	int client;
437 
438 #if __WIN32__
439 	HANDLE connect_listen_th;
440 	HANDLE cmd_listen_th[MAX_NET_CLIENTS];
441 #else
442 	pthread_t connect_listen_tid;
443 	pthread_t cmd_listen_tid[MAX_NET_CLIENTS];
444 	int e;
445 #endif
446 	int server_port = mc->agwpe_port;		/* Usually 8000 but can be changed. */
447 
448 
449 #if DEBUG
450 	text_color_set(DW_COLOR_DEBUG);
451 	dw_printf ("server_init ( %d )\n", server_port);
452 	debug_a = 1;
453 #endif
454 
455 	save_audio_config_p = audio_config_p;
456 
457 	for (client=0; client<MAX_NET_CLIENTS; client++) {
458 	  client_sock[client] = -1;
459 	  enable_send_raw_to_client[client] = 0;
460 	  enable_send_monitor_to_client[client] = 0;
461 	}
462 
463 	if (server_port == 0) {
464 	  text_color_set(DW_COLOR_INFO);
465 	  dw_printf ("Disabled AGW network client port.\n");
466 	  return;
467 	}
468 
469 
470 /*
471  * This waits for a client to connect and sets an available client_sock[n].
472  */
473 #if __WIN32__
474 	connect_listen_th = (HANDLE)_beginthreadex (NULL, 0, connect_listen_thread, (void *)(ptrdiff_t)server_port, 0, NULL);
475 	if (connect_listen_th == NULL) {
476 	  text_color_set(DW_COLOR_ERROR);
477 	  dw_printf ("Could not create AGW connect listening thread\n");
478 	  return;
479 	}
480 #else
481 	e = pthread_create (&connect_listen_tid, NULL, connect_listen_thread, (void *)(ptrdiff_t)server_port);
482 	if (e != 0) {
483 	  text_color_set(DW_COLOR_ERROR);
484 	  perror("Could not create AGW connect listening thread");
485 	  return;
486 	}
487 #endif
488 
489 /*
490  * These read messages from client when client_sock[n] is valid.
491  * Currently we start up a separate thread for each potential connection.
492  * Possible later refinement.  Start one now, others only as needed.
493  */
494 	for (client = 0; client < MAX_NET_CLIENTS; client++) {
495 
496 #if __WIN32__
497 	  cmd_listen_th[client] = (HANDLE)_beginthreadex (NULL, 0, cmd_listen_thread, (void*)(ptrdiff_t)client, 0, NULL);
498 	  if (cmd_listen_th[client] == NULL) {
499 	    text_color_set(DW_COLOR_ERROR);
500 	    dw_printf ("Could not create AGW command listening thread for client %d\n", client);
501 	    return;
502 	  }
503 #else
504 	  e = pthread_create (&cmd_listen_tid[client], NULL, cmd_listen_thread, (void *)(ptrdiff_t)client);
505 	  if (e != 0) {
506 	    text_color_set(DW_COLOR_ERROR);
507 	    dw_printf ("Could not create AGW command listening thread for client %d\n", client);
508 	    // Replace add perror with better message handling.
509 	    perror("");
510 	    return;
511 	  }
512 #endif
513 	}
514 }
515 
516 
517 /*-------------------------------------------------------------------
518  *
519  * Name:        connect_listen_thread
520  *
521  * Purpose:     Wait for a connection request from an application.
522  *
523  * Inputs:	arg		- TCP port for server.
524  *				  Main program has default of 8000 but allows
525  *				  an alternative to be specified on the command line
526  *
527  * Outputs:	client_sock	- File descriptor for communicating with client app.
528  *
529  * Description:	Wait for connection request from client and establish
530  *		communication.
531  *		Note that the client can go away and come back again and
532  *		re-establish communication without restarting this application.
533  *
534  *--------------------------------------------------------------------*/
535 
connect_listen_thread(void * arg)536 static THREAD_F connect_listen_thread (void *arg)
537 {
538 #if __WIN32__
539 
540 	struct addrinfo hints;
541 	struct addrinfo *ai = NULL;
542 	int err;
543 	char server_port_str[12];
544 
545 	SOCKET listen_sock;
546 	WSADATA wsadata;
547 
548 	snprintf (server_port_str, sizeof(server_port_str), "%d", (int)(ptrdiff_t)arg);
549 #if DEBUG
550 	text_color_set(DW_COLOR_DEBUG);
551         dw_printf ("DEBUG: serverport = %d = '%s'\n", (int)(ptrdiff_t)arg, server_port_str);
552 #endif
553 	err = WSAStartup (MAKEWORD(2,2), &wsadata);
554 	if (err != 0) {
555 	    text_color_set(DW_COLOR_ERROR);
556 	    dw_printf("WSAStartup failed: %d\n", err);
557 	    return (0);
558 	}
559 
560 	if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wVersion) != 2) {
561 	  text_color_set(DW_COLOR_ERROR);
562           dw_printf("Could not find a usable version of Winsock.dll\n");
563           WSACleanup();
564 	  //sleep (1);
565           return (0);
566 	}
567 
568 	memset (&hints, 0, sizeof(hints));
569 	hints.ai_family = AF_INET;
570 	hints.ai_socktype = SOCK_STREAM;
571 	hints.ai_protocol = IPPROTO_TCP;
572 	hints.ai_flags = AI_PASSIVE;
573 
574 	err = getaddrinfo(NULL, server_port_str, &hints, &ai);
575 	if (err != 0) {
576 	    text_color_set(DW_COLOR_ERROR);
577 	    dw_printf("getaddrinfo failed: %d\n", err);
578 	    //sleep (1);
579 	    WSACleanup();
580 	    return (0);
581 	}
582 
583 	listen_sock= socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
584 	if (listen_sock == INVALID_SOCKET) {
585 	  text_color_set(DW_COLOR_ERROR);
586 	  dw_printf ("connect_listen_thread: Socket creation failed, err=%d", WSAGetLastError());
587 	  return (0);
588 	}
589 
590 #if DEBUG
591 	text_color_set(DW_COLOR_DEBUG);
592     	dw_printf("Binding to port %s ... \n", server_port_str);
593 #endif
594 
595 	err = bind( listen_sock, ai->ai_addr, (int)ai->ai_addrlen);
596 	if (err == SOCKET_ERROR) {
597 	  text_color_set(DW_COLOR_ERROR);
598           dw_printf("Bind failed with error: %d\n", WSAGetLastError());		// TODO: translate number to text?
599 	  dw_printf("Some other application is probably already using port %s.\n", server_port_str);
600 	  dw_printf("Try using a different port number with AGWPORT in the configuration file.\n");
601           freeaddrinfo(ai);
602           closesocket(listen_sock);
603           WSACleanup();
604           return (0);
605         }
606 
607 	freeaddrinfo(ai);
608 
609 #if DEBUG
610 	text_color_set(DW_COLOR_DEBUG);
611  	dw_printf("opened socket as fd (%d) on port (%s) for stream i/o\n", listen_sock, server_port_str );
612 #endif
613 
614  	while (1) {
615 
616 	  int client;
617 	  int c;
618 
619 	  client = -1;
620 	  for (c = 0; c < MAX_NET_CLIENTS && client < 0; c++) {
621 	    if (client_sock[c] <= 0) {
622 	      client = c;
623 	    }
624 	  }
625 
626 /*
627  * Listen for connection if we have not reached maximum.
628  */
629 	  if (client >= 0) {
630 
631 	    if(listen(listen_sock, MAX_NET_CLIENTS) == SOCKET_ERROR)
632 	    {
633 	      text_color_set(DW_COLOR_ERROR);
634               dw_printf("Listen failed with error: %d\n", WSAGetLastError());
635 	      return (0);
636 	    }
637 
638 	    text_color_set(DW_COLOR_INFO);
639             dw_printf("Ready to accept AGW client application %d on port %s ...\n", client, server_port_str);
640 
641             client_sock[client] = accept(listen_sock, NULL, NULL);
642 
643 	    if (client_sock[client] == -1) {
644 	      text_color_set(DW_COLOR_ERROR);
645               dw_printf("Accept failed with error: %d\n", WSAGetLastError());
646               closesocket(listen_sock);
647               WSACleanup();
648               return (0);
649             }
650 
651 	    text_color_set(DW_COLOR_INFO);
652 	    dw_printf("\nAttached to AGW client application %d ...\n\n", client);
653 
654 /*
655  * The command to change this is actually a toggle, not explicit on or off.
656  * Make sure it has proper state when we get a new connection.
657  */
658 	    enable_send_raw_to_client[client] = 0;
659 	    enable_send_monitor_to_client[client] = 0;
660 	  }
661 	  else {
662 	    SLEEP_SEC(1);	/* wait then check again if more clients allowed. */
663 	  }
664  	}
665 
666 #else		/* End of Windows case, now Linux */
667 
668 
669     	struct sockaddr_in sockaddr; /* Internet socket address stuct */
670     	socklen_t sockaddr_size = sizeof(struct sockaddr_in);
671 	int server_port = (int)(ptrdiff_t)arg;
672 	int listen_sock;
673 	int bcopt = 1;
674 
675 	listen_sock= socket(AF_INET,SOCK_STREAM,0);
676 	if (listen_sock == -1) {
677 	  text_color_set(DW_COLOR_ERROR);
678 	  perror ("connect_listen_thread: Socket creation failed");
679 	  return (NULL);
680 	}
681 
682 	/* Version 1.3 - as suggested by G8BPQ. */
683 	/* Without this, if you kill the application then try to run it */
684 	/* again quickly the port number is unavailable for a while. */
685 	/* Don't try doing the same thing On Windows; It has a different meaning. */
686 	/* http://stackoverflow.com/questions/14388706/socket-options-so-reuseaddr-and-so-reuseport-how-do-they-differ-do-they-mean-t */
687 
688         setsockopt (listen_sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&bcopt, 4);
689 
690 
691     	sockaddr.sin_addr.s_addr = INADDR_ANY;
692     	sockaddr.sin_port = htons(server_port);
693     	sockaddr.sin_family = AF_INET;
694 
695 #if DEBUG
696 	text_color_set(DW_COLOR_DEBUG);
697     	dw_printf("Binding to port %d ... \n", server_port);
698 #endif
699 
700         if (bind(listen_sock,(struct sockaddr*)&sockaddr,sizeof(sockaddr))  == -1) {
701 	  text_color_set(DW_COLOR_ERROR);
702           dw_printf("Bind failed with error: %d\n", errno);
703           dw_printf("%s\n", strerror(errno));
704 	  dw_printf("Some other application is probably already using port %d.\n", server_port);
705 	  dw_printf("Try using a different port number with AGWPORT in the configuration file.\n");
706           return (NULL);
707 	}
708 
709 	getsockname( listen_sock, (struct sockaddr *)(&sockaddr), &sockaddr_size);
710 
711 #if DEBUG
712 	text_color_set(DW_COLOR_DEBUG);
713  	dw_printf("opened socket as fd (%d) on port (%d) for stream i/o\n", listen_sock, ntohs(sockaddr.sin_port) );
714 #endif
715 
716  	while (1) {
717 
718 	  int client;
719 	  int c;
720 
721 	  client = -1;
722 	  for (c = 0; c < MAX_NET_CLIENTS && client < 0; c++) {
723 	    if (client_sock[c] <= 0) {
724 	      client = c;
725 	    }
726 	  }
727 
728 	  if (client >= 0) {
729 
730 	    if(listen(listen_sock,MAX_NET_CLIENTS) == -1)
731 	    {
732 	      text_color_set(DW_COLOR_ERROR);
733 	      perror ("connect_listen_thread: Listen failed");
734 	      return (NULL);
735 	    }
736 
737 	    text_color_set(DW_COLOR_INFO);
738             dw_printf("Ready to accept AGW client application %d on port %d ...\n", client, server_port);
739 
740             client_sock[client] = accept(listen_sock, (struct sockaddr*)(&sockaddr),&sockaddr_size);
741 
742 	    text_color_set(DW_COLOR_INFO);
743 	    dw_printf("\nAttached to AGW client application %d...\n\n", client);
744 
745 /*
746  * The command to change this is actually a toggle, not explicit on or off.
747  * Make sure it has proper state when we get a new connection.
748  */
749 	    enable_send_raw_to_client[client] = 0;
750 	    enable_send_monitor_to_client[client] = 0;
751 	  }
752 	  else {
753 	    SLEEP_SEC(1);	/* wait then check again if more clients allowed. */
754 	  }
755  	}
756 #endif
757 }
758 
759 
760 /*-------------------------------------------------------------------
761  *
762  * Name:        server_send_rec_packet
763  *
764  * Purpose:     Send a received packet to the client app.
765  *
766  * Inputs:	chan		- Channel number where packet was received.
767  *				  0 = first, 1 = second if any.
768  *
769  *		pp		- Identifier for packet object.
770  *
771  *		fbuf		- Address of raw received frame buffer.
772  *		flen		- Length of raw received frame.
773  *
774  *
775  * Description:	Send message to client if connected.
776  *		Disconnect from client, and notify user, if any error.
777  *
778  *		There are two different formats:
779  *			RAW - the original received frame.
780  *			MONITOR - human readable monitoring format.
781  *
782  *--------------------------------------------------------------------*/
783 
784 static void mon_addrs (int chan, packet_t pp, char *result, int result_size);
785 static char mon_desc (packet_t pp, char *result, int result_size);
786 
787 
server_send_rec_packet(int chan,packet_t pp,unsigned char * fbuf,int flen)788 void server_send_rec_packet (int chan, packet_t pp, unsigned char *fbuf,  int flen)
789 {
790 	struct {
791 	  struct agwpe_s hdr;
792 	  char data[1+AX25_MAX_PACKET_LEN];
793 	} agwpe_msg;
794 
795 	int err;
796 
797 /*
798  * RAW format
799  */
800 	for (int client=0; client<MAX_NET_CLIENTS; client++) {
801 
802 	  if (enable_send_raw_to_client[client] && client_sock[client] > 0){
803 
804 	    memset (&agwpe_msg.hdr, 0, sizeof(agwpe_msg.hdr));
805 
806 	    agwpe_msg.hdr.portx = chan;
807 
808 	    agwpe_msg.hdr.datakind = 'K';
809 
810 	    ax25_get_addr_with_ssid (pp, AX25_SOURCE, agwpe_msg.hdr.call_from);
811 
812 	    ax25_get_addr_with_ssid (pp, AX25_DESTINATION, agwpe_msg.hdr.call_to);
813 
814 	    agwpe_msg.hdr.data_len_NETLE = host2netle(flen + 1);
815 
816 	    /* Stick in extra byte for the "TNC" to use. */
817 
818 	    agwpe_msg.data[0] = 0;
819 	    memcpy (agwpe_msg.data + 1, fbuf, (size_t)flen);
820 
821 	    if (debug_client) {
822 	      debug_print (TO_CLIENT, client, &agwpe_msg.hdr, sizeof(agwpe_msg.hdr) + netle2host(agwpe_msg.hdr.data_len_NETLE));
823 	    }
824 
825 #if __WIN32__
826             err = SOCK_SEND (client_sock[client], (char*)(&agwpe_msg), sizeof(agwpe_msg.hdr) + netle2host(agwpe_msg.hdr.data_len_NETLE));
827 	    if (err == SOCKET_ERROR)
828 	    {
829 	      text_color_set(DW_COLOR_ERROR);
830 	      dw_printf ("\nError %d sending message to AGW client application.  Closing connection.\n\n", WSAGetLastError());
831 	      closesocket (client_sock[client]);
832 	      client_sock[client] = -1;
833 	      WSACleanup();
834 	      dlq_client_cleanup (client);
835 	    }
836 #else
837             err = SOCK_SEND (client_sock[client], &agwpe_msg, sizeof(agwpe_msg.hdr) + netle2host(agwpe_msg.hdr.data_len_NETLE));
838 	    if (err <= 0)
839 	    {
840 	      text_color_set(DW_COLOR_ERROR);
841 	      dw_printf ("\nError sending message to AGW client application.  Closing connection.\n\n");
842 	      close (client_sock[client]);
843 	      client_sock[client] = -1;
844 	      dlq_client_cleanup (client);
845 	    }
846 #endif
847 	  }
848 	}
849 
850 	// Application might want more human readable format.
851 
852 	server_send_monitored (chan, pp, 0);
853 
854 } /* end server_send_rec_packet */
855 
856 
857 
server_send_monitored(int chan,packet_t pp,int own_xmit)858 void server_send_monitored (int chan, packet_t pp, int own_xmit)
859 {
860 /*
861  * MONITOR format - 	'I' for information frames.
862  *			'U' for unnumbered information.
863  *			'S' for supervisory and other unnumbered.
864  */
865 	struct {
866 	  struct agwpe_s hdr;
867 	  char data[1+AX25_MAX_PACKET_LEN];
868 	} agwpe_msg;
869 
870 	int err;
871 
872 	for (int client=0; client<MAX_NET_CLIENTS; client++) {
873 
874 	  if (enable_send_monitor_to_client[client] && client_sock[client] > 0) {
875 
876 	    memset (&agwpe_msg.hdr, 0, sizeof(agwpe_msg.hdr));
877 
878 	    agwpe_msg.hdr.portx = chan;	// datakind is added later.
879 	    ax25_get_addr_with_ssid (pp, AX25_SOURCE, agwpe_msg.hdr.call_from);
880 	    ax25_get_addr_with_ssid (pp, AX25_DESTINATION, agwpe_msg.hdr.call_to);
881 
882 	    /* http://uz7ho.org.ua/includes/agwpeapi.htm#_Toc500723812 */
883 
884 	    /* Description mentions one CR character after timestamp but example has two. */
885 	    /* Actual observed cases have only one. */
886 	    /* Also need to add extra CR, CR, null at end. */
887 	    /* The documentation example includes these 3 extra in the Len= value */
888 	    /* but actual observed data uses only the packet info length. */
889 
890 	    // Documentation doesn't mention anything about including the via path.
891 	    // In version 1.4, we add that to match observed behaviour.
892 
893 	    // This inconsistency was reported:
894 	    // Direwolf:
895 	    // [AGWE-IN] 1:Fm ZL4FOX-8 To Q7P2U2 [08:25:07]`I1*l V>/"9<}[:Barts Tracker 3.83V X
896 	    // AGWPE:
897 	    // [AGWE-IN] 1:Fm ZL4FOX-8 To Q7P2U2 Via WIDE3-3 [08:32:14]`I0*l V>/"98}[:Barts Tracker 3.83V X
898 
899 	    // Format the channel and addresses, with leading and trailing space.
900 
901 	    mon_addrs (chan, pp, (char*)(agwpe_msg.data), sizeof(agwpe_msg.data));
902 
903 	    // Add the description with <... >
904 
905 	    char desc[80];
906 	    agwpe_msg.hdr.datakind = mon_desc (pp, desc, sizeof(desc));
907 	    if (own_xmit) {
908 	      agwpe_msg.hdr.datakind = 'T';
909 	    }
910 	    strlcat ((char*)(agwpe_msg.data), desc, sizeof(agwpe_msg.data));
911 
912 	    // Timestamp with [...]\r
913 
914 	    time_t clock = time(NULL);
915 	    struct tm *tm = localtime(&clock);		// TODO: use localtime_r ?
916 	    char ts[32];
917 	    snprintf (ts, sizeof(ts), "[%02d:%02d:%02d]\r", tm->tm_hour, tm->tm_min, tm->tm_sec);
918 	    strlcat ((char*)(agwpe_msg.data), ts, sizeof(agwpe_msg.data));
919 
920 	    // Information if any with \r\r.
921 
922 	    unsigned char *pinfo = NULL;
923 	    int info_len = ax25_get_info (pp, &pinfo);
924 	    if (info_len > 0 && pinfo != NULL) {
925 	      strlcat ((char*)(agwpe_msg.data), (char*)pinfo, sizeof(agwpe_msg.data));
926 	      strlcat ((char*)(agwpe_msg.data), "\r", sizeof(agwpe_msg.data));
927 	    }
928 
929 	    agwpe_msg.hdr.data_len_NETLE = host2netle(strlen(agwpe_msg.data) + 1) /* +1 to include terminating null */ ;
930 
931 	    if (debug_client) {
932 	      debug_print (TO_CLIENT, client, &agwpe_msg.hdr, sizeof(agwpe_msg.hdr) + netle2host(agwpe_msg.hdr.data_len_NETLE));
933 	    }
934 
935 #if __WIN32__
936             err = SOCK_SEND (client_sock[client], (char*)(&agwpe_msg), sizeof(agwpe_msg.hdr) + netle2host(agwpe_msg.hdr.data_len_NETLE));
937 	    if (err == SOCKET_ERROR)
938 	    {
939 	      text_color_set(DW_COLOR_ERROR);
940 	      dw_printf ("\nError %d sending message to AGW client application %d.  Closing connection.\n\n", WSAGetLastError(), client);
941 	      closesocket (client_sock[client]);
942 	      client_sock[client] = -1;
943 	      WSACleanup();
944 	      dlq_client_cleanup (client);
945 	    }
946 #else
947             err = SOCK_SEND (client_sock[client], &agwpe_msg, sizeof(agwpe_msg.hdr) + netle2host(agwpe_msg.hdr.data_len_NETLE));
948 	    if (err <= 0)
949 	    {
950 	      text_color_set(DW_COLOR_ERROR);
951 	      dw_printf ("\nError sending message to AGW client application %d.  Closing connection.\n\n", client);
952 	      close (client_sock[client]);
953 	      client_sock[client] = -1;
954 	      dlq_client_cleanup (client);
955 	    }
956 #endif
957 	  }
958 	}
959 
960 } /* server_send_monitored */
961 
962 
963 // Next two are broken out in case they can be reused elsewhere.
964 
965 // Format addresses in AGWPR monitoring format such as:
966 //	 1:Fm ZL4FOX-8 To Q7P2U2 Via WIDE3-3
967 
mon_addrs(int chan,packet_t pp,char * result,int result_size)968 static void mon_addrs (int chan, packet_t pp, char *result, int result_size)
969 {
970 	char src[AX25_MAX_ADDR_LEN];
971 	char dst[AX25_MAX_ADDR_LEN];
972 
973 	ax25_get_addr_with_ssid (pp, AX25_SOURCE, src);
974 	ax25_get_addr_with_ssid (pp, AX25_DESTINATION, dst);
975 	int num_digi = ax25_get_num_repeaters(pp);
976 
977 	if (num_digi > 0) {
978 
979 	  char via[AX25_MAX_REPEATERS*(AX25_MAX_ADDR_LEN+1)];
980 	  char stemp[AX25_MAX_ADDR_LEN+1];
981 	  int j;
982 
983 	  ax25_get_addr_with_ssid (pp, AX25_REPEATER_1, via);
984 	  for (j = 1; j < num_digi; j++) {
985 	    ax25_get_addr_with_ssid (pp, AX25_REPEATER_1 + j, stemp);
986 	    strlcat (via, ",", sizeof(via));
987 	    strlcat (via, stemp, sizeof(via));
988 	  }
989 	  snprintf (result, result_size, " %d:Fm %s To %s Via %s ",
990 		chan+1, src, dst, via);
991 	}
992 	else {
993 	  snprintf (result, result_size, " %d:Fm %s To %s ",
994 			chan+1, src, dst);
995 	}
996 }
997 
998 
999 // Generate frame description in AGWPE monitoring format such as
1000 //	<UI pid=F0 Len=123 >
1001 //	<I R1 S3 pid=F0 Len=123 >
1002 //	<RR P1 R5 >
1003 //
1004 // Returns:
1005 //	'I' for information frame.
1006 //	'U' for unnumbered information frame.
1007 //	'S' for supervisory and other unnumbered frames.
1008 
mon_desc(packet_t pp,char * result,int result_size)1009 static char mon_desc (packet_t pp, char *result, int result_size)
1010 {
1011 	cmdres_t cr;		// command/response.
1012 	char ignore[80];	// direwolf description.  not used here.
1013 	int pf;			// poll/final bit.
1014 	int ns;			// N(S) Send sequence number.
1015 	int nr;			// N(R) Received sequence number.
1016 	char pf_text[4];	// P or F depending on whether command or response.
1017 
1018 	ax25_frame_type_t ftype = ax25_frame_type (pp, &cr, ignore, &pf, &nr, &ns);
1019 
1020 	switch (cr) {
1021 	  case cr_cmd:	strcpy(pf_text, "P"); break;	// P only: I, SABME, SABM, DISC
1022 	  case cr_res:	strcpy(pf_text, "F"); break;	// F only: DM, UA, FRMR
1023 							// Either: RR, RNR, REJ, SREJ, UI, XID, TEST
1024 
1025 	  default:	strcpy(pf_text, "PF"); break;	// Not AX.25 version >= 2.0
1026 							// APRS is often sloppy about this but it
1027 							// is essential for connected mode.
1028 	}
1029 
1030 	unsigned char *pinfo = NULL;	// I, UI, XID, SREJ, TEST can have information part.
1031 	int info_len = ax25_get_info (pp, &pinfo);
1032 
1033 	switch (ftype) {
1034 
1035 	  case frame_type_I:		snprintf (result, result_size, "<I S%d R%d pid=0x%02X Len=%d %s=%d >",  ns, nr, ax25_get_pid(pp), info_len, pf_text, pf); return ('I');
1036 
1037 	  case frame_type_U_UI:		snprintf (result, result_size, "<UI pid=%02X Len=%d %s=%d >", 	ax25_get_pid(pp), info_len, pf_text, pf);  return ('U'); break;
1038 
1039 	  case frame_type_S_RR:		snprintf (result, result_size, "<RR R%d %s=%d >",	nr, pf_text, pf);	return ('S'); break;
1040 	  case frame_type_S_RNR:	snprintf (result, result_size, "<RNR R%d %s=%d >",	nr, pf_text, pf);	return ('S'); break;
1041 	  case frame_type_S_REJ:	snprintf (result, result_size, "<REJ R%d %s=%d >",	nr, pf_text, pf);	return ('S'); break;
1042 	  case frame_type_S_SREJ:	snprintf (result, result_size, "<SREJ R%d %s=%d Len=%d >", nr, pf_text, pf, info_len);	return ('S'); break;
1043 
1044 	  case frame_type_U_SABME:	snprintf (result, result_size, "<SABME %s=%d >",	pf_text, pf);		return ('S'); break;
1045 	  case frame_type_U_SABM:	snprintf (result, result_size, "<SABM %s=%d >", 	pf_text, pf);		return ('S'); break;
1046 	  case frame_type_U_DISC:	snprintf (result, result_size, "<DISC %s=%d >", 	pf_text, pf);		return ('S'); break;
1047 	  case frame_type_U_DM:		snprintf (result, result_size, "<DM %s=%d >", 		pf_text, pf);		return ('S'); break;
1048 	  case frame_type_U_UA:		snprintf (result, result_size, "<UA %s=%d >", 		pf_text, pf);		return ('S'); break;
1049 	  case frame_type_U_FRMR:	snprintf (result, result_size, "<FRMR %s=%d >", 	pf_text, pf);		return ('S'); break;
1050 	  case frame_type_U_XID:	snprintf (result, result_size, "<XID %s=%d Len=%d >", 	pf_text, pf, info_len);	return ('S'); break;
1051 	  case frame_type_U_TEST:	snprintf (result, result_size, "<TEST %s=%d Len=%d >", 	pf_text, pf, info_len);	return ('S'); break;
1052 	  default:
1053 	  case frame_type_U:		snprintf (result, result_size, "<U other??? >");				return ('S'); break;
1054 	}
1055 }
1056 
1057 
1058 /*-------------------------------------------------------------------
1059  *
1060  * Name:        server_link_established
1061  *
1062  * Purpose:     Send notification to client app when a link has
1063  *		been established with another station.
1064  *
1065  *		DL-CONNECT Confirm or DL-CONNECT Indication in the protocol spec.
1066  *
1067  * Inputs:	chan		- Which radio channel.
1068  *
1069  * 		client		- Which one of potentially several clients.
1070  *
1071  *		remote_call	- Callsign[-ssid] of remote station.
1072  *
1073  *		own_call	- Callsign[-ssid] of my end.
1074  *
1075  *		incoming	- true if connection was initiated from other end.
1076  *				  false if this end started it.
1077  *
1078  *--------------------------------------------------------------------*/
1079 
server_link_established(int chan,int client,char * remote_call,char * own_call,int incoming)1080 void server_link_established (int chan, int client, char *remote_call, char *own_call, int incoming)
1081 {
1082 
1083 	struct {
1084 	  struct agwpe_s hdr;
1085 	  char info[100];
1086 	} reply;
1087 
1088 
1089 	memset (&reply, 0, sizeof(reply));
1090 	reply.hdr.portx = chan;
1091 	reply.hdr.datakind = 'C';
1092 
1093 	strlcpy (reply.hdr.call_from, remote_call, sizeof(reply.hdr.call_from));
1094 	strlcpy (reply.hdr.call_to,   own_call,    sizeof(reply.hdr.call_to));
1095 
1096 	// Question:  Should the via path be provided too?
1097 
1098 	if (incoming) {
1099 	  // Other end initiated the connection.
1100 	  snprintf (reply.info, sizeof(reply.info), "*** CONNECTED To Station %s\r", remote_call);
1101 	}
1102 	else {
1103 	  // We started the connection.
1104 	  snprintf (reply.info, sizeof(reply.info), "*** CONNECTED With Station %s\r", remote_call);
1105 	}
1106 	reply.hdr.data_len_NETLE = host2netle(strlen(reply.info) + 1);
1107 
1108 	send_to_client (client, &reply);
1109 
1110 } /* end server_link_established */
1111 
1112 
1113 
1114 /*-------------------------------------------------------------------
1115  *
1116  * Name:        server_link_terminated
1117  *
1118  * Purpose:     Send notification to client app when a link with
1119  *		another station has been terminated or a connection
1120  *		attempt failed.
1121  *
1122  *		DL-DISCONNECT Confirm or DL-DISCONNECT Indication in the protocol spec.
1123  *
1124  * Inputs:	chan		- Which radio channel.
1125  *
1126  * 		client		- Which one of potentially several clients.
1127  *
1128  *		remote_call	- Callsign[-ssid] of remote station.
1129  *
1130  *		own_call	- Callsign[-ssid] of my end.
1131  *
1132  *		timeout		- true when no answer from other station.
1133  *				  How do we distinguish who asked for the
1134  *				  termination of an existing link?
1135  *
1136  *--------------------------------------------------------------------*/
1137 
server_link_terminated(int chan,int client,char * remote_call,char * own_call,int timeout)1138 void server_link_terminated (int chan, int client, char *remote_call, char *own_call, int timeout)
1139 {
1140 
1141 	struct {
1142 	  struct agwpe_s hdr;
1143 	  char info[100];
1144 	} reply;
1145 
1146 
1147 	memset (&reply, 0, sizeof(reply));
1148 	reply.hdr.portx = chan;
1149 	reply.hdr.datakind = 'd';
1150 	strlcpy (reply.hdr.call_from, remote_call, sizeof(reply.hdr.call_from));  /* right order */
1151 	strlcpy (reply.hdr.call_to,   own_call,    sizeof(reply.hdr.call_to));
1152 
1153 	if (timeout) {
1154 	  snprintf (reply.info, sizeof(reply.info), "*** DISCONNECTED RETRYOUT With %s\r", remote_call);
1155 	}
1156 	else {
1157 	  snprintf (reply.info, sizeof(reply.info), "*** DISCONNECTED From Station %s\r", remote_call);
1158 	}
1159 	reply.hdr.data_len_NETLE = host2netle(strlen(reply.info) + 1);
1160 
1161 	send_to_client (client, &reply);
1162 
1163 
1164 } /* end server_link_terminated */
1165 
1166 
1167 /*-------------------------------------------------------------------
1168  *
1169  * Name:        server_rec_conn_data
1170  *
1171  * Purpose:     Send received connected data to the application.
1172  *
1173  *		DL-DATA Indication in the protocol spec.
1174  *
1175  * Inputs:	chan		- Which radio channel.
1176  *
1177  * 		client		- Which one of potentially several clients.
1178  *
1179  *		remote_call	- Callsign[-ssid] of remote station.
1180  *
1181  *		own_call	- Callsign[-ssid] of my end.
1182  *
1183  *		pid		- Protocol ID from I frame.
1184  *
1185  *		data_ptr	- Pointer to a block of bytes.
1186  *
1187  *		data_len	- Number of bytes.  Could be zero.
1188  *
1189  *--------------------------------------------------------------------*/
1190 
server_rec_conn_data(int chan,int client,char * remote_call,char * own_call,int pid,char * data_ptr,int data_len)1191 void server_rec_conn_data (int chan, int client, char *remote_call, char *own_call, int pid, char *data_ptr, int data_len)
1192 {
1193 
1194 	struct {
1195 	  struct agwpe_s hdr;
1196 	  char info[AX25_MAX_INFO_LEN];		// I suppose there is potential for something larger.
1197 						// We'll cross that bridge if we ever come to it.
1198 	} reply;
1199 
1200 
1201 	memset (&reply.hdr, 0, sizeof(reply.hdr));
1202 	reply.hdr.portx = chan;
1203 	reply.hdr.datakind = 'D';
1204 	reply.hdr.pid = pid;
1205 
1206 	strlcpy (reply.hdr.call_from, remote_call, sizeof(reply.hdr.call_from));
1207 	strlcpy (reply.hdr.call_to,   own_call,    sizeof(reply.hdr.call_to));
1208 
1209 	if (data_len < 0) {
1210 	  text_color_set(DW_COLOR_ERROR);
1211 	  dw_printf ("Invalid length %d for connected data to client %d.\n", data_len, client);
1212 	  data_len = 0;
1213 	}
1214 	else if (data_len > AX25_MAX_INFO_LEN) {
1215 	  text_color_set(DW_COLOR_ERROR);
1216 	  dw_printf ("Invalid length %d for connected data to client %d.\n", data_len, client);
1217 	  data_len = AX25_MAX_INFO_LEN;
1218 	}
1219 
1220 	memcpy (reply.info, data_ptr, data_len);
1221 	reply.hdr.data_len_NETLE = host2netle(data_len);
1222 
1223 	send_to_client (client, &reply);
1224 
1225 } /* end server_rec_conn_data */
1226 
1227 
1228 /*-------------------------------------------------------------------
1229  *
1230  * Name:        server_outstanding_frames_reply
1231  *
1232  * Purpose:     Send 'Y' Outstanding frames for connected data to the application.
1233  *
1234  * Inputs:	chan		- Which radio channel.
1235  *
1236  * 		client		- Which one of potentially several clients.
1237  *
1238  *		own_call	- Callsign[-ssid] of my end.
1239  *
1240  *		remote_call	- Callsign[-ssid] of remote station.
1241  *
1242  *		count		- Number of frames sent from the application but
1243  *				  not yet received by the other station.
1244  *
1245  *--------------------------------------------------------------------*/
1246 
server_outstanding_frames_reply(int chan,int client,char * own_call,char * remote_call,int count)1247 void server_outstanding_frames_reply (int chan, int client, char *own_call, char *remote_call, int count)
1248 {
1249 
1250 	struct {
1251 	  struct agwpe_s hdr;
1252 	  int count_NETLE;
1253 	} reply;
1254 
1255 
1256 	memset (&reply.hdr, 0, sizeof(reply.hdr));
1257 
1258 	reply.hdr.portx = chan;
1259 	reply.hdr.datakind = 'Y';
1260 
1261 	strlcpy (reply.hdr.call_from, own_call,    sizeof(reply.hdr.call_from));
1262 	strlcpy (reply.hdr.call_to,   remote_call, sizeof(reply.hdr.call_to));
1263 
1264 	reply.hdr.data_len_NETLE = host2netle(4);
1265 	reply.count_NETLE = host2netle(count);
1266 
1267 	send_to_client (client, &reply);
1268 
1269 } /* end server_outstanding_frames_reply */
1270 
1271 
1272 /*-------------------------------------------------------------------
1273  *
1274  * Name:        read_from_socket
1275  *
1276  * Purpose:     Read from socket until we have desired number of bytes.
1277  *
1278  * Inputs:	fd		- file descriptor.
1279  *		ptr		- address where data should be placed.
1280  *		len		- desired number of bytes.
1281  *
1282  * Description:	Just a wrapper for the "read" system call but it should
1283  *		never return fewer than the desired number of bytes.
1284  *
1285  *--------------------------------------------------------------------*/
1286 
read_from_socket(int fd,char * ptr,int len)1287 static int read_from_socket (int fd, char *ptr, int len)
1288 {
1289 	int got_bytes = 0;
1290 
1291 #if DEBUG
1292 	text_color_set(DW_COLOR_DEBUG);
1293 	dw_printf ("read_from_socket (%d, %p, %d)\n", fd, ptr, len);
1294 #endif
1295 	while (got_bytes < len) {
1296 	  int n;
1297 
1298 	  n = SOCK_RECV (fd, ptr + got_bytes, len - got_bytes);
1299 
1300 #if DEBUG
1301 	  text_color_set(DW_COLOR_DEBUG);
1302 	  dw_printf ("read_from_socket: n = %d\n", n);
1303 #endif
1304 	  if (n <= 0) {
1305 	    return (n);
1306 	  }
1307 
1308 	  got_bytes += n;
1309 	}
1310 	assert (got_bytes >= 0 && got_bytes <= len);
1311 
1312 #if DEBUG
1313 	text_color_set(DW_COLOR_DEBUG);
1314 	dw_printf ("read_from_socket: return %d\n", got_bytes);
1315 #endif
1316 	return (got_bytes);
1317 }
1318 
1319 
1320 /*-------------------------------------------------------------------
1321  *
1322  * Name:        cmd_listen_thread
1323  *
1324  * Purpose:     Wait for command messages from an application.
1325  *
1326  * Inputs:	arg		- client number, 0 .. MAX_NET_CLIENTS-1
1327  *
1328  * Outputs:	client_sock[n]	- File descriptor for communicating with client app.
1329  *
1330  * Description:	Process messages from the client application.
1331  *		Note that the client can go away and come back again and
1332  *		re-establish communication without restarting this application.
1333  *
1334  *--------------------------------------------------------------------*/
1335 
1336 
send_to_client(int client,void * reply_p)1337 static void send_to_client (int client, void *reply_p)
1338 {
1339 	struct agwpe_s *ph;
1340 	int len;
1341 	int err;
1342 
1343 	ph = (struct agwpe_s *) reply_p;	// Replies are often hdr + other stuff.
1344 
1345 	len = sizeof(struct agwpe_s) + netle2host(ph->data_len_NETLE);
1346 
1347 	/* Not sure what max data length might be. */
1348 
1349 	if (netle2host(ph->data_len_NETLE) < 0 || netle2host(ph->data_len_NETLE) > 4096) {
1350 	  text_color_set(DW_COLOR_ERROR);
1351 	  dw_printf ("Invalid data length %d for AGW protocol message to client %d.\n", netle2host(ph->data_len_NETLE), client);
1352 	  debug_print (TO_CLIENT, client, ph, len);
1353 	}
1354 
1355 	if (debug_client) {
1356 	  debug_print (TO_CLIENT, client, ph, len);
1357 	}
1358 
1359 	err = SOCK_SEND (client_sock[client], (char*)(ph), len);
1360 	(void)err;
1361 }
1362 
1363 
cmd_listen_thread(void * arg)1364 static THREAD_F cmd_listen_thread (void *arg)
1365 {
1366 	int n;
1367 
1368 	struct {
1369 	  struct agwpe_s hdr;		/* Command header. */
1370 
1371 	  char data[AX25_MAX_PACKET_LEN]; /* Additional data used by some commands. */
1372 					/* Maximum for 'V': 1 + 8*10 + 256 */
1373 					/* Maximum for 'D': Info part length + 1 */
1374 	} cmd;
1375 
1376 	int client = (int)(ptrdiff_t)arg;
1377 
1378 	assert (client >= 0 && client < MAX_NET_CLIENTS);
1379 
1380 	while (1) {
1381 
1382 	  while (client_sock[client] <= 0) {
1383 	    SLEEP_SEC(1);			/* Not connected.  Try again later. */
1384 	  }
1385 
1386 	  n = read_from_socket (client_sock[client], (char *)(&cmd.hdr), sizeof(cmd.hdr));
1387 	  if (n != sizeof(cmd.hdr)) {
1388 	    text_color_set(DW_COLOR_ERROR);
1389 	    dw_printf ("\nError getting message header from AGW client application %d.\n", client);
1390 	    dw_printf ("Tried to read %d bytes but got only %d.\n", (int)sizeof(cmd.hdr), n);
1391 	    dw_printf ("Closing connection.\n\n");
1392 #if __WIN32__
1393 	    closesocket (client_sock[client]);
1394 #else
1395 	    close (client_sock[client]);
1396 #endif
1397 	    client_sock[client] = -1;
1398 	    dlq_client_cleanup (client);
1399 	    continue;
1400 	  }
1401 
1402 /*
1403  * Take some precautions to guard against bad data which could cause problems later.
1404  */
1405 	if (cmd.hdr.portx < 0 || cmd.hdr.portx >= MAX_CHANS) {
1406 	  text_color_set(DW_COLOR_ERROR);
1407 	  dw_printf ("\nInvalid port number, %d, in command '%c', from AGW client application %d.\n",
1408 			cmd.hdr.portx, cmd.hdr.datakind, client);
1409 	  cmd.hdr.portx = 0;	// avoid subscript out of bounds, try to keep going.
1410 	}
1411 
1412 /*
1413  * Call to/from fields are 10 bytes but contents must not exceeed 9 characters.
1414  * It's not guaranteed that unused bytes will contain 0 so we
1415  * don't issue error message in this case.
1416  */
1417 	  cmd.hdr.call_from[sizeof(cmd.hdr.call_from)-1] = '\0';
1418 	  cmd.hdr.call_to[sizeof(cmd.hdr.call_to)-1] = '\0';
1419 
1420 /*
1421  * Following data must fit in available buffer.
1422  * Leave room for an extra nul byte terminator at end later.
1423  */
1424 
1425 	  int data_len = netle2host(cmd.hdr.data_len_NETLE);
1426 
1427 	  if (data_len < 0 || data_len > (int)(sizeof(cmd.data) - 1)) {
1428 
1429 	    text_color_set(DW_COLOR_ERROR);
1430 	    dw_printf ("\nInvalid message from AGW client application %d.\n", client);
1431 	    dw_printf ("Data Length of %d is out of range.\n", data_len);
1432 
1433 	    /* This is a bad situation. */
1434 	    /* If we tried to read again, the header probably won't be there. */
1435 	    /* No point in trying to continue reading.  */
1436 
1437 	    dw_printf ("Closing connection.\n\n");
1438 #if __WIN32__
1439 	    closesocket (client_sock[client]);
1440 #else
1441 	    close (client_sock[client]);
1442 #endif
1443 	    client_sock[client] = -1;
1444 	    dlq_client_cleanup (client);
1445 	    return (0);
1446 	  }
1447 
1448 	  cmd.data[0] = '\0';
1449 
1450 	  if (data_len > 0) {
1451 	    n = read_from_socket (client_sock[client], cmd.data, data_len);
1452 	    if (n != data_len) {
1453 	      text_color_set(DW_COLOR_ERROR);
1454 	      dw_printf ("\nError getting message data from AGW client application %d.\n", client);
1455 	      dw_printf ("Tried to read %d bytes but got only %d.\n", data_len, n);
1456 	      dw_printf ("Closing connection.\n\n");
1457 #if __WIN32__
1458 	      closesocket (client_sock[client]);
1459 #else
1460 	      close (client_sock[client]);
1461 #endif
1462 	      client_sock[client] = -1;
1463 	      dlq_client_cleanup (client);
1464 	      return (0);
1465 	    }
1466 	    if (n >= 0) {
1467 		cmd.data[n] = '\0';	// Tidy if we print for debug.
1468 	    }
1469 	  }
1470 
1471 /*
1472  * print & process message from client.
1473  */
1474 
1475 	  if (debug_client) {
1476 	    debug_print (FROM_CLIENT, client, &cmd.hdr, sizeof(cmd.hdr) + data_len);
1477 	  }
1478 
1479 	  switch (cmd.hdr.datakind) {
1480 
1481 	    case 'R':				/* Request for version number */
1482 	      {
1483 		struct {
1484 		  struct agwpe_s hdr;
1485 	          int major_version_NETLE;
1486 	          int minor_version_NETLE;
1487 		} reply;
1488 
1489 
1490 	        memset (&reply, 0, sizeof(reply));
1491 	        reply.hdr.datakind = 'R';
1492 	        reply.hdr.data_len_NETLE = host2netle(sizeof(reply.major_version_NETLE) + sizeof(reply.minor_version_NETLE));
1493 		assert (netle2host(reply.hdr.data_len_NETLE) == 8);
1494 
1495 		// Xastir only prints this and doesn't care otherwise.
1496 		// APRSIS32 doesn't seem to care.
1497 		// UI-View32 wants on 2000.15 or later.
1498 
1499 	        reply.major_version_NETLE = host2netle(2005);
1500 	        reply.minor_version_NETLE = host2netle(127);
1501 
1502 		assert (sizeof(reply) == 44);
1503 
1504 	        send_to_client (client, &reply);
1505 
1506 	      }
1507 	      break;
1508 
1509 	    case 'G':				/* Ask about radio ports */
1510 
1511 	      {
1512 		struct {
1513 		  struct agwpe_s hdr;
1514 	 	  char info[200];
1515 		} reply;
1516 
1517 
1518 		int j, count;
1519 
1520 
1521 	        memset (&reply, 0, sizeof(reply));
1522 	        reply.hdr.datakind = 'G';
1523 
1524 
1525 		// Xastir only prints this and doesn't care otherwise.
1526 		// YAAC uses this to identify available channels.
1527 
1528 		// The interface manual wants the first to be "Port1"
1529 		// so channel 0 corresponds to "Port1."
1530 		// We can have gaps in the numbering.
1531 		// I wonder what applications will think about that.
1532 
1533 		// No other place cares about total number.
1534 
1535 		count = 0;
1536 		for (j=0; j<MAX_CHANS; j++) {
1537 	          if (save_audio_config_p->achan[j].medium == MEDIUM_RADIO ||
1538 	              save_audio_config_p->achan[j].medium == MEDIUM_IGATE ||
1539 	              save_audio_config_p->achan[j].medium == MEDIUM_NETTNC) {
1540 		    count++;
1541 		  }
1542 		}
1543 		snprintf (reply.info, sizeof(reply.info), "%d;", count);
1544 
1545 		for (j=0; j<MAX_CHANS; j++) {
1546 
1547 	          switch (save_audio_config_p->achan[j].medium) {
1548 
1549 	            case MEDIUM_RADIO:
1550 	              {
1551 		        char stemp[100];
1552 		        int a = ACHAN2ADEV(j);
1553 		        // If I was really ambitious, some description could be provided.
1554 		        static const char *names[8] = { "first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth" };
1555 
1556 		        if (save_audio_config_p->adev[a].num_channels == 1) {
1557 		          snprintf (stemp, sizeof(stemp), "Port%d %s soundcard mono;", j+1, names[a]);
1558 		          strlcat (reply.info, stemp, sizeof(reply.info));
1559 		        }
1560 		        else {
1561 		          snprintf (stemp, sizeof(stemp), "Port%d %s soundcard %s;", j+1, names[a], j&1 ? "right" : "left");
1562 		          strlcat (reply.info, stemp, sizeof(reply.info));
1563 		        }
1564 	              }
1565 	              break;
1566 
1567 	            case MEDIUM_IGATE:
1568 	              {
1569 		        char stemp[100];
1570 		        snprintf (stemp, sizeof(stemp), "Port%d Internet Gateway;", j+1);
1571 		        strlcat (reply.info, stemp, sizeof(reply.info));
1572 	              }
1573 		      break;
1574 
1575 	            case MEDIUM_NETTNC:
1576 	              {
1577 	                // could elaborate with hostname, etc.
1578 		        char stemp[100];
1579 		        snprintf (stemp, sizeof(stemp), "Port%d Network TNC;", j+1);
1580 		        strlcat (reply.info, stemp, sizeof(reply.info));
1581 	              }
1582 	              break;
1583 
1584 	            default:
1585 	              {
1586 	                // could elaborate with hostname, etc.
1587 		        char stemp[100];
1588 		        snprintf (stemp, sizeof(stemp), "Port%d INVALID CHANNEL;", j+1);
1589 		        strlcat (reply.info, stemp, sizeof(reply.info));
1590 	              }
1591 	              break;
1592 
1593 		  }  // switch
1594 		}  // for each channel
1595 
1596 	        reply.hdr.data_len_NETLE = host2netle(strlen(reply.info) + 1);
1597 
1598 	        send_to_client (client, &reply);
1599 	      }
1600 	      break;
1601 
1602 
1603 	    case 'g':				/* Ask about capabilities of a port. */
1604 
1605 	      {
1606 		struct {
1607 		  struct agwpe_s hdr;
1608 	 	  unsigned char on_air_baud_rate; 	/* 0=1200, 1=2400, 2=4800, 3=9600, ... */
1609 		  unsigned char traffic_level;		/* 0xff if not in autoupdate mode */
1610 		  unsigned char tx_delay;
1611 		  unsigned char tx_tail;
1612 		  unsigned char persist;
1613 		  unsigned char slottime;
1614 		  unsigned char maxframe;
1615 		  unsigned char active_connections;
1616 		  int how_many_bytes_NETLE;
1617 		} reply;
1618 
1619 
1620 	        memset (&reply, 0, sizeof(reply));
1621 
1622 		reply.hdr.portx = cmd.hdr.portx;	/* Reply with same port number ! */
1623 	        reply.hdr.datakind = 'g';
1624 	        reply.hdr.data_len_NETLE = host2netle(12);
1625 
1626 		// YAAC asks for this.
1627 		// Fake it to keep application happy.
1628 	        // TODO:  Supply real values instead of just faking it.
1629 
1630 	        reply.on_air_baud_rate = 0;
1631 		reply.traffic_level = 1;
1632 		reply.tx_delay = 0x19;
1633 		reply.tx_tail = 4;
1634 		reply.persist = 0xc8;
1635 		reply.slottime = 4;
1636 		reply.maxframe = 7;
1637 		reply.active_connections = 0;
1638 		reply.how_many_bytes_NETLE = host2netle(1);
1639 
1640 		assert (sizeof(reply) == 48);
1641 
1642 	        send_to_client (client, &reply);
1643 
1644 	      }
1645 	      break;
1646 
1647 
1648 	    case 'H':				/* Ask about recently heard stations on given port. */
1649 
1650 		/* This should send back 20 'H' frames for the most recently heard stations. */
1651 		/* If there are less available, empty frames are sent to make a total of 20. */
1652 		/* Each contains the first and last heard times. */
1653 
1654 	      {
1655 #if 0						/* Currently, this information is not being collected. */
1656 		struct {
1657 		  struct agwpe_s hdr;
1658 	 	  char info[100];
1659 		} reply;
1660 
1661 
1662 	        memset (&reply.hdr, 0, sizeof(reply.hdr));
1663 	        reply.hdr.datakind = 'H';
1664 
1665 		// TODO:  Implement properly.
1666 
1667 	        reply.hdr.portx = cmd.hdr.portx
1668 
1669 	        strlcpy (reply.hdr.call_from, "WB2OSZ-15 Mon,01Jan2000 01:02:03  Tue,31Dec2099 23:45:56", sizeof(reply.hdr.call_from));
1670 		// or                                                  00:00:00                00:00:00
1671 
1672 	        strlcpy (agwpe_msg.data, ..., sizeof(agwpe_msg.data));
1673 
1674 	        reply.hdr.data_len_NETLE = host2netle(strlen(reply.info));
1675 
1676 	        send_to_client (client, &reply);
1677 #endif
1678 	      }
1679 	      break;
1680 
1681 
1682 
1683 
1684 	    case 'k':				/* Ask to start receiving RAW AX25 frames */
1685 
1686 	      // Actually it is a toggle so we must be sure to clear it for a new connection.
1687 
1688 	      enable_send_raw_to_client[client] = ! enable_send_raw_to_client[client];
1689 	      break;
1690 
1691 	    case 'm':				/* Ask to start receiving Monitor frames */
1692 
1693 	      // Actually it is a toggle so we must be sure to clear it for a new connection.
1694 
1695 	      enable_send_monitor_to_client[client] = ! enable_send_monitor_to_client[client];
1696 	      break;
1697 
1698 
1699 	    case 'V':				/* Transmit UI data frame (with digipeater path) */
1700 	      {
1701 	      	// Data format is:
1702 	      	//	1 byte for number of digipeaters.
1703 	      	//	10 bytes for each digipeater.
1704 	      	//	data part of message.
1705 
1706 	      	char stemp[AX25_MAX_PACKET_LEN+2];
1707 		char *p;
1708 		int ndigi;
1709 		int k;
1710 
1711 		packet_t pp;
1712 
1713 	      	strlcpy (stemp, cmd.hdr.call_from, sizeof(stemp));
1714 	      	strlcat (stemp, ">", sizeof(stemp));
1715 	      	strlcat (stemp, cmd.hdr.call_to, sizeof(stemp));
1716 
1717 		cmd.data[data_len] = '\0';
1718 		ndigi = cmd.data[0];
1719 		p = cmd.data + 1;
1720 
1721 		for (k=0; k<ndigi; k++) {
1722 		  strlcat (stemp, ",", sizeof(stemp));
1723 		  strlcat (stemp, p, sizeof(stemp));
1724 		  p += 10;
1725 	        }
1726 		strlcat (stemp, ":", sizeof(stemp));
1727 		strlcat (stemp, p, sizeof(stemp));
1728 
1729 	        //text_color_set(DW_COLOR_DEBUG);
1730 		//dw_printf ("Transmit '%s'\n", stemp);
1731 
1732 		pp = ax25_from_text (stemp, 1);
1733 
1734 
1735 		if (pp == NULL) {
1736 	          text_color_set(DW_COLOR_ERROR);
1737 		  dw_printf ("Failed to create frame from AGW 'V' message.\n");
1738 		}
1739 		else {
1740 
1741 		  /* This goes into the low priority queue because it is an original. */
1742 
1743 		  /* Note that the protocol has no way to set the "has been used" */
1744 		  /* bits in the digipeater fields. */
1745 
1746 		  /* This explains why the digipeating option is grayed out in */
1747 		  /* xastir when using the AGW interface.  */
1748 		  /* The current version uses only the 'V' message, not 'K' for transmitting. */
1749 
1750 		  tq_append (cmd.hdr.portx, TQ_PRIO_1_LO, pp);
1751 
1752 		}
1753 	      }
1754 
1755 	      break;
1756 
1757 	    case 'K':				/* Transmit raw AX.25 frame */
1758 	      {
1759 	      	// Message contains:
1760 	      	//	port number for transmission.
1761 	      	//	data length
1762 	      	//	data which is raw ax.25 frame.
1763 		//
1764 
1765 		packet_t pp;
1766 		alevel_t alevel;
1767 
1768 		// Bug fix in version 1.1:
1769 		//
1770 		// The first byte of data is described as:
1771 		//
1772 		// 		the "TNC" to use
1773 		//		00=Port 1
1774 		//		16=Port 2
1775 		//
1776 		// I don't know what that means; we already a port number in the header.
1777 		// Anyhow, the original code here added one to cmd.data to get the
1778 		// first byte of the frame.  Unfortunately, it did not subtract one from
1779 		// cmd.hdr.data_len so we ended up sending an extra byte.
1780 
1781 		memset (&alevel, 0xff, sizeof(alevel));
1782 		pp = ax25_from_frame ((unsigned char *)cmd.data+1, data_len - 1, alevel);
1783 
1784 		if (pp == NULL) {
1785 	          text_color_set(DW_COLOR_ERROR);
1786 		  dw_printf ("Failed to create frame from AGW 'K' message.\n");
1787 		}
1788 		else {
1789 
1790 		  /* How can we determine if it is an original or repeated message? */
1791 		  /* If there is at least one digipeater in the frame, AND */
1792 		  /* that digipeater has been used, it should go out quickly thru */
1793 		  /* the high priority queue. */
1794 		  /* Otherwise, it is an original for the low priority queue. */
1795 
1796 		  if (ax25_get_num_repeaters(pp) >= 1 &&
1797 		      ax25_get_h(pp,AX25_REPEATER_1)) {
1798 		    tq_append (cmd.hdr.portx, TQ_PRIO_0_HI, pp);
1799 		  }
1800 		  else {
1801 		    tq_append (cmd.hdr.portx, TQ_PRIO_1_LO, pp);
1802 		  }
1803 		}
1804 	      }
1805 
1806 	      break;
1807 
1808 	    case 'X':				/* Register CallSign  */
1809 
1810 	      {
1811 		struct {
1812 		  struct agwpe_s hdr;
1813 		  char data;			/* 1 = success, 0 = failure */
1814 		} reply;
1815 
1816 		int ok = 1;
1817 
1818 		// The protocol spec says it is an error to register the same one more than once.
1819 	        // Too much trouble.  Report success if the channel is valid.
1820 
1821 
1822 	        int chan = cmd.hdr.portx;
1823 
1824 	        // Connected mode can only be used with internal modems.
1825 
1826 		if (chan >= 0 && chan < MAX_CHANS && save_audio_config_p->achan[chan].medium == MEDIUM_RADIO) {
1827 		  ok = 1;
1828 	          dlq_register_callsign (cmd.hdr.call_from, chan, client);
1829 	        }
1830 	        else {
1831 	          text_color_set(DW_COLOR_ERROR);
1832 	          dw_printf ("AGW protocol error.  Register callsign for invalid channel %d.\n", chan);
1833 	          ok = 0;
1834 	        }
1835 
1836 
1837 	        memset (&reply, 0, sizeof(reply));
1838 	        reply.hdr.datakind = 'X';
1839 	        reply.hdr.portx = cmd.hdr.portx;
1840 		memcpy (reply.hdr.call_from, cmd.hdr.call_from, sizeof(reply.hdr.call_from));
1841 	        reply.hdr.data_len_NETLE = host2netle(1);
1842 		reply.data = ok;
1843 	        send_to_client (client, &reply);
1844 	      }
1845 	      break;
1846 
1847 	    case 'x':				/* Unregister CallSign  */
1848 
1849 	      {
1850 
1851 	        int chan = cmd.hdr.portx;
1852 
1853 	        // Connected mode can only be used with internal modems.
1854 
1855 		if (chan >= 0 && chan < MAX_CHANS && save_audio_config_p->achan[chan].medium == MEDIUM_RADIO) {
1856 	          dlq_unregister_callsign (cmd.hdr.call_from, chan, client);
1857 	        }
1858 		else {
1859 	          text_color_set(DW_COLOR_ERROR);
1860 	          dw_printf ("AGW protocol error.  Unregister callsign for invalid channel %d.\n", chan);
1861 	        }
1862 	      }
1863 	      /* No reponse is expected. */
1864 	      break;
1865 
1866 	    case 'C':				/* Connect, Start an AX.25 Connection  */
1867 	    case 'v':	      			/* Connect VIA, Start an AX.25 circuit thru digipeaters */
1868 	    case 'c':	      			/* Connection with non-standard PID */
1869 
1870 	      {
1871 	        struct via_info {
1872 	          unsigned char num_digi;	/* Expect to be in range 1 to 7.  Why not up to 8? */
1873 		  char dcall[7][10];
1874 	        }
1875 #if 1
1876 		// October 2017.  gcc ??? complained:
1877 		//     warning: dereferencing pointer 'v' does break strict-aliasing rules
1878 		// Try adding this attribute to get rid of the warning.
1879 	        // If this upsets your compiler, take it out.
1880 	        // Let me know.  Maybe we could put in a compiler version check here.
1881 
1882 	           __attribute__((__may_alias__))
1883 #endif
1884 	                              *v = (struct via_info *)cmd.data;
1885 
1886 	        char callsigns[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN];
1887 	        int num_calls = 2;	/* 2 plus any digipeaters. */
1888 	        int pid = 0xf0;		/* normal for AX.25 I frames. */
1889 		int j;
1890 
1891 	        strlcpy (callsigns[AX25_SOURCE], cmd.hdr.call_from, sizeof(callsigns[AX25_SOURCE]));
1892 	        strlcpy (callsigns[AX25_DESTINATION], cmd.hdr.call_to, sizeof(callsigns[AX25_DESTINATION]));
1893 
1894 	        if (cmd.hdr.datakind == 'c') {
1895 	          pid = cmd.hdr.pid;		/* non standard for NETROM, TCP/IP, etc. */
1896 	        }
1897 
1898 	        if (cmd.hdr.datakind == 'v') {
1899 	          if (v->num_digi >= 1 && v->num_digi <= 7) {
1900 
1901 	            if (data_len != v->num_digi * 10 + 1 && data_len != v->num_digi * 10 + 2) {
1902 	              // I'm getting 1 more than expected from AGWterminal.
1903 	              text_color_set(DW_COLOR_ERROR);
1904 	              dw_printf ("AGW client, connect via, has data len, %d when %d expected.\n", data_len, v->num_digi * 10 + 1);
1905 	            }
1906 
1907 	            for (j = 0; j < v->num_digi; j++) {
1908 	              strlcpy (callsigns[AX25_REPEATER_1 + j], v->dcall[j], sizeof(callsigns[AX25_REPEATER_1 + j]));
1909 	              num_calls++;
1910 	            }
1911 	          }
1912 	          else {
1913 	            text_color_set(DW_COLOR_ERROR);
1914 	            dw_printf ("\n");
1915 	            dw_printf ("AGW client, connect via, has invalid number of digipeaters = %d\n", v->num_digi);
1916 	          }
1917 	        }
1918 
1919 
1920 	        dlq_connect_request (callsigns, num_calls, cmd.hdr.portx, client, pid);
1921 
1922 	      }
1923 	      break;
1924 
1925 
1926 	    case 'D': 				/* Send Connected Data */
1927 
1928 	      {
1929 	        char callsigns[2][AX25_MAX_ADDR_LEN];
1930 	        const int num_calls = 2;
1931 
1932 	        strlcpy (callsigns[AX25_SOURCE], cmd.hdr.call_from, sizeof(callsigns[AX25_SOURCE]));
1933 	        strlcpy (callsigns[AX25_DESTINATION], cmd.hdr.call_to, sizeof(callsigns[AX25_SOURCE]));
1934 
1935 	        dlq_xmit_data_request (callsigns, num_calls, cmd.hdr.portx, client, cmd.hdr.pid, cmd.data, netle2host(cmd.hdr.data_len_NETLE));
1936 
1937 	      }
1938 	      break;
1939 
1940 	    case 'd': 				/* Disconnect, Terminate an AX.25 Connection */
1941 
1942 	      {
1943 	        char callsigns[2][AX25_MAX_ADDR_LEN];
1944 	        const int num_calls = 2;
1945 
1946 	        strlcpy (callsigns[AX25_SOURCE], cmd.hdr.call_from, sizeof(callsigns[AX25_SOURCE]));
1947 	        strlcpy (callsigns[AX25_DESTINATION], cmd.hdr.call_to, sizeof(callsigns[AX25_SOURCE]));
1948 
1949 	        dlq_disconnect_request (callsigns, num_calls, cmd.hdr.portx, client);
1950 
1951 	      }
1952 	      break;
1953 
1954 
1955 	    case 'M': 				/* Send UNPROTO Information (no digipeater path) */
1956 
1957 		/*
1958 		Added in version 1.3.
1959 		This is the same as 'V' except there is no provision for digipeaters.
1960 		TODO: combine 'V' and 'M' into one case.
1961 		AGWterminal sends this for beacon or ask QRA.
1962 
1963 		<<< Send UNPROTO Information from AGWPE client application 0, total length = 253
1964 		        portx = 0, datakind = 'M', pid = 0x00
1965 		        call_from = "WB2OSZ-15", call_to = "BEACON"
1966 		        data_len = 217, user_reserved = 556, data =
1967 		  000:  54 68 69 73 20 76 65 72 73 69 6f 6e 20 75 73 65  This version use
1968 		   ...
1969 
1970 		<<< Send UNPROTO Information from AGWPE client application 0, total length = 37
1971 		        portx = 0, datakind = 'M', pid = 0x00
1972 		        call_from = "WB2OSZ-15", call_to = "QRA"
1973 		        data_len = 1, user_reserved = 31759424, data =
1974 		  000:  0d                                               .
1975                                           .
1976 
1977 		There is also a report of it coming from UISS.
1978 
1979 		<<< Send UNPROTO Information from AGWPE client application 0, total length = 50
1980 			portx = 0, port_hi_reserved = 0
1981 			datakind = 77 = 'M', kind_hi = 0
1982 			call_from = "JH4XSY", call_to = "APRS"
1983 			data_len = 14, user_reserved = 0, data =
1984 		  000:  21 22 3c 43 2e 74 71 6c 48 72 71 21 21 5f        !"<C.tqlHrq!!_
1985 		*/
1986 	      {
1987 
1988 		int pid = cmd.hdr.pid;
1989 		(void)(pid);
1990 			/* The AGW protocol spec says, */
1991 			/* "AX.25 PID 0x00 or 0xF0 for AX.25 0xCF NETROM and others" */
1992 
1993 			/* BUG: In theory, the AX.25 PID octet should be set from this. */
1994 			/* All examples seen (above) have 0. */
1995 			/* The AX.25 protocol spec doesn't list 0 as a valid value. */
1996 			/* We always send 0xf0, meaning no layer 3. */
1997 			/* Maybe we should have an ax25_set_pid function for cases when */
1998 			/* it is neither 0 nor 0xf0. */
1999 
2000 	      	char stemp[AX25_MAX_PACKET_LEN];
2001 		packet_t pp;
2002 
2003 	      	strlcpy (stemp, cmd.hdr.call_from, sizeof(stemp));
2004 	      	strlcat (stemp, ">", sizeof(stemp));
2005 	      	strlcat (stemp, cmd.hdr.call_to, sizeof(stemp));
2006 
2007 		cmd.data[data_len] = '\0';
2008 
2009 		strlcat (stemp, ":", sizeof(stemp));
2010 		strlcat (stemp, cmd.data, sizeof(stemp));
2011 
2012 	        //text_color_set(DW_COLOR_DEBUG);
2013 		//dw_printf ("Transmit '%s'\n", stemp);
2014 
2015 		pp = ax25_from_text (stemp, 1);
2016 
2017 		if (pp == NULL) {
2018 	          text_color_set(DW_COLOR_ERROR);
2019 		  dw_printf ("Failed to create frame from AGW 'M' message.\n");
2020 		}
2021 		else {
2022 		  tq_append (cmd.hdr.portx, TQ_PRIO_1_LO, pp);
2023 		}
2024 	      }
2025 	      break;
2026 
2027 
2028 	    case 'y':				/* Ask Outstanding frames waiting on a Port  */
2029 
2030 	      /* Number of frames sitting in transmit queue for specified channel. */
2031 	      {
2032 		struct {
2033 		  struct agwpe_s hdr;
2034 		  int data_NETLE;			// Little endian order.
2035 		} reply;
2036 
2037 
2038 	        memset (&reply, 0, sizeof(reply));
2039 		reply.hdr.portx = cmd.hdr.portx;	/* Reply with same port number */
2040 	        reply.hdr.datakind = 'y';
2041 	        reply.hdr.data_len_NETLE = host2netle(4);
2042 
2043 	        int n = 0;
2044 	        if (cmd.hdr.portx >= 0 && cmd.hdr.portx < MAX_CHANS) {
2045 	          // Count both normal and expedited in transmit queue for given channel.
2046 		  n = tq_count (cmd.hdr.portx, -1, "", "", 0);
2047 		}
2048 		reply.data_NETLE = host2netle(n);
2049 
2050 	        send_to_client (client, &reply);
2051 	      }
2052 	      break;
2053 
2054 	    case 'Y':				/* How Many Outstanding frames wait for tx for a particular station  */
2055 
2056 	      // This is different than the above 'y' because this refers to a specific
2057 	      // link in connected mode.
2058 
2059 	      // This would be useful for a couple different purposes.
2060 
2061 	      // When sending bulk data, we want to keep a fair amount queued up to take
2062 	      // advantage of large window sizes (MAXFRAME, EMAXFRAME).  On the other
2063 	      // hand we don't want to get TOO far ahead when transferring a large file.
2064 
2065 	      // Before disconnecting from another station, it would be good to know
2066 	      // that it actually received the last message we sent.  For this reason,
2067 	      // I think it would be good for this to include information frames that were
2068 	      // transmitted but not yet acknowleged.
2069 	      // You could say that a particular frame is still waiting to be sent even
2070 	      // if was already sent because it could be sent again if lost previously.
2071 
2072 	      // The documentation is inconsistent about the address order.
2073 	      // One place says "callfrom" is my callsign and "callto" is the other guy.
2074 	      // That would make sense.  We are asking about frames going to the other guy.
2075 
2076 	      // But another place says it depends on who initiated the connection.
2077 	      //
2078 	      //	"If we started the connection CallFrom=US and CallTo=THEM
2079 	      //	If the other end started the connection CallFrom=THEM and CallTo=US"
2080 	      //
2081 	      // The response description says nothing about the order; it just mentions two addresses.
2082 	      // If you are writing a client or server application, the order would
2083 	      // be clear but right here it could be either case.
2084 	      //
2085 	      // Another version of the documentation mentioned the source address being optional.
2086 	      //
2087 
2088 	      // The only way to get this information is from inside the data link state machine.
2089 	      // We will send a request to it and the result coming out will be used to
2090 	      // send the reply back to the client application.
2091 
2092 	      {
2093 
2094 	        char callsigns[2][AX25_MAX_ADDR_LEN];
2095 	        const int num_calls = 2;
2096 
2097 	        strlcpy (callsigns[AX25_SOURCE], cmd.hdr.call_from, sizeof(callsigns[AX25_SOURCE]));
2098 	        strlcpy (callsigns[AX25_DESTINATION], cmd.hdr.call_to, sizeof(callsigns[AX25_SOURCE]));
2099 
2100 	        // Issue 169.  Proper implementation for 'Y'.
2101 	        dlq_outstanding_frames_request (callsigns, num_calls, cmd.hdr.portx, client);
2102 
2103 	      }
2104 	      break;
2105 
2106 	    default:
2107 
2108 	      text_color_set(DW_COLOR_ERROR);
2109 	      dw_printf ("--- Unexpected Command from application %d using AGW protocol:\n", client);
2110 	      debug_print (FROM_CLIENT, client, &cmd.hdr, sizeof(cmd.hdr) + data_len);
2111 
2112 	      break;
2113 	  }
2114 	}
2115 
2116 } /* end send_to_client */
2117 
2118 
2119 /* end server.c */
2120