-
Notifications
You must be signed in to change notification settings - Fork 0
/
g2_link.cpp
7583 lines (6632 loc) · 282 KB
/
g2_link.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* Copyright (C) 2010 by Scott Lawson KI4LKF
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* by KI4LKF */
// Version History
//
// Version 4.00 - Ramesh Dhami, VA3UV - 2015.06.07
// Ready for release
//
// Version 3.18 - Ramesh Dhami, VA3UV - 2015.06.07
// Stripped out REF linking ability
// Bug Fix to address issue where repeaters connecting to us directly were not showing the "source" in the log file and hence users
// appearing on the dashboard were not showing the source - i.e., where are they coming from
//
// Version 3.17 - Ramesh Dhami, VA3UV - 2014.08.25
// Bug fix - initialized temp_buff[] to clear out garbage
//
// Version 3.16 - Ramesh Dhami, VA3UV - 2014.07.09
//
// Version 3.14 - Ramesh Dhami, VA3UV - 2014.04.06
// Added support for 3 separate LINK_AT_STARTUP hosts - 1 per RF module
// RF_INACTIVITY_TIMERS will be bypassed as long as the RF module is connected
// to the LINK_AT_STARTUP host for that particular module
// Fixed up ONLY_LINK_UNLINK Logic - to ensure that if ONLY_LINK_UNLINK=Y then only
// named / spec'd callsigns can link/unlink - all other users are denied linking / unlinking
//
// Version 3.13 - Ramesh Dhami, VA3UV - 2014.02.18
// Added RF inactivity timer: tracing[i].last_time
// Added 3 new variables to the cfg file: RF_INACTIVITY_TIMER_A / B / C
// Create up to 3 separate files 'local_rf_use_A/B/C' so that the external persistent_link script
// can sense when the GW is being used locally. The timestamp on these 3 files is updated every time
// a local RF user transmits
//
//
//
// version 3.12 - Ramesh Dhami, VA3UV - 2013.10.09
// Added checks to make sure that users MyCALL is valid - check MyCALL against valid_users.txt
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <time.h>
#include <sys/time.h>
#include <regex.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <net/if.h>
#include <netpacket/packet.h>
#include <net/ethernet.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <pthread.h>
/* Required for Binary search trees using C++ STL */
#include <string>
#include <set>
#include <map>
#include <utility>
using namespace std;
/*** version number must be x.xx ***/
#define VERSION "4.00"
#define CALL_SIZE 8
#define IP_SIZE 15
#define QUERY_SIZE 56
#define MAXHOSTNAMELEN 64
#define TIMEOUT 50
#define LINK_CODE 'O'
#define UNLINK_CODE 'T'
#define INFO_CODE 'W'
#define DONGLE_CODE 'D'
#define FILE_REFRESH_GWYS_CODE 'F'
#define RESTORE_TIMER_CODE 'R'
#define RESET_TIMER_CODE 'Z'
/* configuration data */
static char OWNER[CALL_SIZE + 1];
static char ADMIN[CALL_SIZE + 1];
static bool ONLY_ADMIN_LOGIN = false;
static char LINK_UNLINK_USER[CALL_SIZE + 1];
static bool ONLY_LINK_UNLINK = false;
static bool unlink_token = true;
static int ONLY_LINK_UNLINK_temp = 0;
static char EXTERNAL_IF[IF_NAMESIZE + 1];
static char LISTEN_IP[IP_SIZE + 1];
static int G2_EXTERNAL_PORT = 40000;
static char INTERNAL_IF[IF_NAMESIZE + 1];
static uint16_t G2_INTERNAL_PORT = htons(20000);
static uint16_t RP2C_PORT = htons(20000);
static int RMT_XRF_PORT = 30001;
static int RMT_REF_PORT = 50001;
static int RMT_DCS_PORT = 30051;
static int COMMAND_PORT = 30003;
static bool QSO_DETAILS = false;
static char GWYS[FILENAME_MAX + 1];
static char VALID_CALLSIGNS[FILENAME_MAX + 1];
static char STATUS_FILE[FILENAME_MAX + 1];
static bool ANNOUNCE = false;
static char ANNOUNCE_DIR[FILENAME_MAX + 1];
static bool RPTR_ACK = true;
static int DELAY_BETWEEN = 18;
static int DELAY_BEFORE = 3;
static char LINK_AT_STARTUP_A[CALL_SIZE + 1];
static char LINK_AT_STARTUP_A_TMP[CALL_SIZE + 1];
static char LINK_AT_STARTUP_B[CALL_SIZE + 1];
static char LINK_AT_STARTUP_B_TMP[CALL_SIZE + 1];
static char LINK_AT_STARTUP_C[CALL_SIZE + 1];
static char LINK_AT_STARTUP_C_TMP[CALL_SIZE + 1];
static unsigned int MAX_DONGLES = 5;
static unsigned int SAVED_MAX_DONGLES = 5;
//static char REPORTS[MAXHOSTNAMELEN + 1];
//static char AUTH0[MAXHOSTNAMELEN + 1];
//static char AUTH1[MAXHOSTNAMELEN + 1];
//static char AUTH2[MAXHOSTNAMELEN + 1];
// v3.18 - no longer used static char ECHOTEST_DIR[FILENAME_MAX + 1];
// v3.18 - no longer used static int ECHOTEST_REC_TIMEOUT = 1;
static long RF_INACTIVITY_TIMER[3] = { 3, 3, 3 };
static long RF_INACTIVITY_TIMER_SAVE[3] = { 3, 3, 3};
static unsigned char REF_ACK[3] = { 3, 96, 0 };
static char RF_FLAGS_DIR[FILENAME_MAX + 1];
char my_module[2];
char dest_mod[2];
char test[9];
char rf_file[40]; /* Touch a file in the /tmp folder to mark when the repeater was last used */
char uv_mod[2]; /* Preserve the module where the RF user was last heard */
char uv_rf_module; /* Module where a user was last heard */
int uv_count_a;
int uv_count_b;
char temp_buff[10];
char temp_buff_a[11];
char temp_buff_b[11];
char temp_buff_c[11];
/*
This is the data payload in the map: inbound_list
This is for inbound dongles
*/
struct inbound
{
/* the callsign of the remote */
char call[CALL_SIZE + 1];
/* IP and port of remote */
struct sockaddr_in sin;
/* if countdown expires, the connection is terminated */
short countdown;
/* This user talked on this module */
char mod; /* A B C */
/* dvap, dvdongle, ... */
char client;
};
/* the Key in this inbound_list map is the unique IP address of the remote */
typedef map<string, inbound *> inbound_type;
static inbound_type inbound_list;
typedef set<string> admin_type;
static admin_type admin;
typedef set<string> link_unlink_user_type;
static link_unlink_user_type link_unlink_user;
#define LH_MAX_SIZE 39
typedef map<string, string> dt_lh_type;
static dt_lh_type dt_lh_list;
/*
to_remote_g2 contains the remote repeaters/reflectors
that our local bands are linked with.
The remote systems can be either:
XRF-type or REF-type or DCS-type
index 0 is from_mod=A,
index 1 is from_mod=B,
index 2 is from_mod=C
*/
static struct
{
char type; /* p or x or d */
char link_status[CALL_SIZE + 1];
char to_call[CALL_SIZE + 1];
struct sockaddr_in toDst4;
char from_mod;
char to_mod;
short countdown;
bool is_connected;
unsigned char in_streamid[2]; /* incoming from remote systems */
unsigned char out_streamid[2]; /* outgoing to remote systems */
} to_remote_g2[3];
static struct
{
unsigned char streamid[2];
uint32_t adr;
} plus_crap[3] = { { {0x00, 0x00}, 0 },
{ {0x00, 0x00}, 0 },
{ {0x00, 0x00}, 0 } };
/* broadcast for data arriving from xrf to local rptr */
static struct
{
unsigned char xrf_streamid[2]; /* streamid from xrf */
unsigned char rptr_streamid[2][2]; /* generated streamid to rptr(s) */
} brd_from_xrf;
static unsigned char from_xrf_torptr_brd[56];
static short brd_from_xrf_idx = 0;
/* broadcast for data arriving from ref to local rptr */
static struct
{
unsigned char ref_streamid[2]; /* streamid from ref */
unsigned char rptr_streamid[2][2]; /* generated streamid to rptr(s) */
} ml_from_ref;
static unsigned char from_ref_torptr_brd[58];
static short ml_from_ref_idx = 0;
/* broadcast for data arriving from local rptr */
static struct
{
unsigned char from_rptr_streamid[2];
unsigned char to_rptr_streamid[2][2];
} ml_from_rptr;
static unsigned char multilink[58];
static short ml_from_rptr_idx = 0;
/* This is for echotest */
//v3.18 static struct
//{
// time_t last_time;
// unsigned char streamid[2];
// int fd;
// char file[FILENAME_MAX + 1];
//} recd[3]; /* local module 0, 1, 2 */
//static unsigned char recbuf[100]; /* 56 or 27, max is 56 */
//static short int rec_len = 56;
//static long num_recs = 0L;
//static pthread_t echo_thread;
//static pthread_attr_t echo_attr;
/*
index 0 is local mod=A,
index 1 is local mod=B,
index 2 is local mod=C
*/
static struct
{
unsigned char streamid[2];
time_t last_time; /* last time RF user talked */
} tracing[3] = { { {0,0}, 0 },
{ {0,0}, 0 },
{ {0,0}, 0 } };
/* input from remote */
static int xrf_g2_sock = -1;
static int ref_g2_sock = -1;
static int dcs_g2_sock = -1;
static unsigned char dcs_buf[1000];
static unsigned char readBuffer2[1024];
static struct sockaddr_in fromDst4;
/*
After we receive it from remote g2,
we must feed it to our local repeater.
*/
static struct sockaddr_in toLocalg2;
/* input from our own local repeater */
static int rptr_sock = -1;
static unsigned char readBuffer[1024]; /* 58 or 29 or 32, max is 58 */
static struct sockaddr_ll sll;
static u_char *udp_payload;
static int udp_payload_len;
static uint32_t internal_daddr = 0;
/* input from command port */
static int cmd_sock = -1;
static struct sockaddr_in fromCmd;
static fd_set fdset;
static struct timeval tv;
static bool keep_running = true;
/* auth stuff */
static sockaddr_in to_reports;
static struct start_msg_to_reports
{
unsigned char codes[4];
char version[10];
char sep1;
char gw[15];
char sep2;
char time[22];
char sep3;
char type[6];
char sep4;
char mod[11];
char sep5;
unsigned char streamid[13];
char sep6;
char my[15];
char sep7;
char sfx[13];
char sep8;
char yr[15];
char sep9;
char rpt1[13];
char sep10;
char rpt2[13];
char sep11;
char msg[20];
char sep12;
char id[5];
} sm_to_r;
//v3.18 static sockaddr_in to_auth0;
//static sockaddr_in to_auth1;
//static sockaddr_in to_auth2;
/* last 4 bytes is seed */
//v3.18 static unsigned char rep_from_auth0_ok[9] = {0x09, 0x00, 0x18, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00};
/* last 4 bytes is seed */
//v3.18 static unsigned char rep_from_auth1_ok[9] = {0x09, 0x00, 0x18, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00};
/* the last 4 bytes are: "22j " */
//v3.18 static unsigned char rep_to_auth_ok[9] = {0x09, 0x00, 0x18, 0x00, 0x02, 0x32, 0x32, 0x6a, 0x20};
//v3.18 static bool auth0_linking_ok = false;
//v3.18 static bool auth1_linking_ok = false;
/* static struct auth_msg_to_auth
{
unsigned char codes[4];
char auth_type[14];
char sep1;
char proto[7];
char sep2;
char prog[10];
char sep3;
char version[12];
char sep4;
char gw[15];
char sep5;
char id[4];
char term;
} am_to_a;
*/
// v3.18 static time_t au_msg_time = 0;
/* Used to validate incoming donglers */
static regex_t preg;
const char* G2_html = "<table border=\"0\" width=\"95%\"><tr>"
"<td width=\"4%\"><img border=\"0\" src=g2ircddb.jpg></td>"
"<td width=\"96%\"><font size=\"2\">"
"<b>REPEATER</b> G2_LINK v4.00"
"</font></td>"
"</tr></table>";
/* re-transmit headers to plus on SYNC */
static struct {
unsigned char buf[58];
} regen_hdr_for_plus_refs[3];
static struct {
unsigned char buf[58];
unsigned streamid[2];
} regen_hdr_for_plus_dongles[3];
static unsigned short crc_tabccitt[256] =
{
0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf,
0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7,
0x1081,0x0108,0x3393,0x221a,0x56a5,0x472c,0x75b7,0x643e,
0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,0xf9ff,0xe876,
0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd,
0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5,
0x3183,0x200a,0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c,
0xbdcb,0xac42,0x9ed9,0x8f50,0xfbef,0xea66,0xd8fd,0xc974,
0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,0x2732,0x36bb,
0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3,
0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a,
0xdecd,0xcf44,0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72,
0x6306,0x728f,0x4014,0x519d,0x2522,0x34ab,0x0630,0x17b9,
0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,0x8a78,0x9bf1,
0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738,
0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70,
0x8408,0x9581,0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7,
0x0840,0x19c9,0x2b52,0x3adb,0x4e64,0x5fed,0x6d76,0x7cff,
0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,0xf1bf,0xe036,
0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e,
0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5,
0x2942,0x38cb,0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd,
0xb58b,0xa402,0x9699,0x8710,0xf3af,0xe226,0xd0bd,0xc134,
0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,0x5cf5,0x4d7c,
0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3,
0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb,
0xd68d,0xc704,0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232,
0x5ac5,0x4b4c,0x79d7,0x685e,0x1ce1,0x0d68,0x3ff3,0x2e7a,
0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,0x8238,0x93b1,
0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9,
0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330,
0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78
};
/* the map of the loaded entries in gwys.txt */
/* key is the callsign, data is the host and port */
typedef map<string, string> gwy_list_type;
static gwy_list_type gwy_list;
/* This is the map above, but the key is the ip */
typedef map<string, string> ip_list_type;
static ip_list_type ip_list;
/* the list of the loaded entries in valid_callsigns.txt */
typedef set<string> valid_callsigns_type;
static valid_callsigns_type valid_callsigns;
static unsigned char queryCommand[QUERY_SIZE];
/* dtmf stuff */
static char silence[9] = { 0x4e,0x8d,0x32,0x88,0x26,0x1a,0x3f,0x61,0xe8 };
static char DTMF_DIR[FILENAME_MAX + 1];
static char DTMF_FILE[FILENAME_MAX + 1];
static const int MAX_DTMF_BUF = 32;
static char dtmf_chars[17] = "147*2580369#ABCD";
static int dtmf_digit;
static FILE *dtmf_fp = NULL;
static char dtmf_buf[3][MAX_DTMF_BUF + 1] = { {""}, {""}, {""} };
static int dtmf_buf_count[3] = {0, 0, 0};
static unsigned int dtmf_counter[3] = {0, 0, 0};
static int dtmf_last_frame[3] = {0, 0, 0};
static char dtmf_mycall[3][CALL_SIZE + 1] = { {""}, {""}, {""} };
extern void dstar_dv_init();
extern int dstar_dv_decode(const unsigned char *d, int data[3]);
/* START: TEXT crap */
static bool new_group[3] = { true, true, true };
static int header_type = 0;
static bool GPS_seen[3] = { false, false, false };
unsigned char tmp_txt[3];
static char *p_tmp2 = NULL;
/* END: TEXT crap */
/* this is used for the "dashboard and QSO_DETAILS" to avoid processing multiple headers */
static struct
{
unsigned char sid[2];
} old_sid[3] = { { {0x00, 0x00} },
{ {0x00, 0x00} },
{ {0x00, 0x00} } };
static bool load_gwys(char *filename);
static bool load_valid_callsigns(char *filename);
static void calcPFCS(unsigned char *packet, int len);
static void traceit(const char *fmt,...);
static bool read_config(char *);
static bool srv_open();
static void srv_close();
static void sigCatch(int signum);
static void g2link(char from_mod, char *call, char to_mod);
static void runit();
static void print_status_file();
static void print_status_screen();
static void send_heartbeat();
static void handle_cmd(char *buf);
static bool resolve_plus();
static void link_plus(short int i);
//static void *echotest(void *arg);
static bool resolve_rmt(char *name, int type, struct sockaddr_in *addr);
static void audio_notify(char *notify_msg);
static void rptr_ack(short i);
static void *audio_notify_run(void *arg);
static void *rptr_ack_run(void *arg);
static void dv_block(char mod);
static bool df_check(char mod);
// v3.18
static bool df_check(char mod)
{
char df_s[FILENAME_MAX + 1];
FILE *df_fp = NULL;
char df_buf[256];
char msg[] = {" Linked to "};
bool ok = true;
msg[11] = mod;
strcpy(df_s, "/dstar/tmp/status");
df_fp = fopen(df_s, "r");
if (df_fp == NULL)
return true;
while (fgets(df_buf, 254, df_fp) != NULL)
{
if (strstr(df_buf, msg) != NULL)
{
traceit("%s", df_buf);
ok = false;
break;
}
}
fclose(df_fp);
return ok;
}
static void df_block(char mod)
{
char df_b[FILENAME_MAX + 1];
int fd = -1;
sprintf(df_b, "/dstar/tmp/blocklinking-%c", mod);
fd = open(df_b, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
if (fd >= 0)
{
close(fd);
fd = -1;
}
return;
}
static bool resolve_rmt(char *name, int type, struct sockaddr_in *addr)
{
struct addrinfo hints;
struct addrinfo *res;
struct addrinfo *rp;
int rc = 0;
bool found = false;
memset(&hints, 0x00, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = type;
rc = getaddrinfo(name, NULL, &hints, &res);
if (rc != 0)
{
traceit("getaddrinfo return error code %d for [%s]\n", rc, name);
return false;
}
for (rp = res; rp != NULL; rp = rp->ai_next)
{
if ((rp->ai_family == AF_INET) &&
(rp->ai_socktype == type))
{
memcpy(addr, rp->ai_addr, sizeof(struct sockaddr_in));
found = true;
break;
}
}
freeaddrinfo(res);
return found;
}
/* v3.18
static void *echotest(void *arg)
{
char *file = (char *)arg;
struct timespec req;
FILE *fp = NULL;
unsigned short rlen = 0;
size_t nread = 0;
unsigned char dstar_buf[56];
struct sigaction act;
act.sa_handler = sigCatch;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_RESTART;
if (sigaction(SIGTERM, &act, 0) != 0)
{
traceit("sigaction-TERM failed, error=%d\n", errno);
traceit("echotest thread exiting...\n");
pthread_exit(NULL);
}
if (sigaction(SIGINT, &act, 0) != 0)
{
traceit("sigaction-INT failed, error=%d\n", errno);
traceit("echotest thread exiting...\n");
pthread_exit(NULL);
}
fp = fopen(file, "rb");
if (!fp)
{
traceit("Failed to open file %s\n", file);
pthread_exit(NULL);
}
nread = fread(dstar_buf, 10, 1, fp);
if (nread != 1)
{
traceit("Cant read first 10 bytes in %s\n", file);
fclose(fp);
pthread_exit(NULL);
}
if (memcmp(dstar_buf, "DVTOOL", 6) != 0)
{
traceit("DVTOOL keyword not found in %s\n", file);
fclose(fp);
pthread_exit(NULL);
}
sleep(DELAY_BEFORE);
traceit("File to playback:[%s]\n", file);
while (keep_running)
{
nread = fread(&rlen, 2, 1, fp);
if (nread != 1)
break;
if ((rlen != 56) && (rlen != 27))
{
traceit("Expected 56 bytes or 27 bytes, found %d\n", rlen);
break;
}
nread = fread(dstar_buf, rlen, 1, fp);
if (nread == 1)
{
if (memcmp(dstar_buf, "DSVT", 4) != 0)
{
traceit("DVST keyword not found in %s\n", file);
break;
}
if (dstar_buf[8] != 0x20)
{
traceit("Not Voice type in %s\n", file);
break;
}
if ((dstar_buf[4] != 0x10) && (dstar_buf[4] != 0x20))
{
traceit("Not a valid record type in %s\n",file);
break;
}
sendto(ref_g2_sock, (char *)dstar_buf, rlen, 0,
(struct sockaddr *)&toLocalg2,sizeof(toLocalg2));
req.tv_sec = 0;
req.tv_nsec = DELAY_BETWEEN * 1000000;
nanosleep(&req, NULL);
}
}
fclose(fp);
unlink(file);
traceit("Finished playing\n");
pthread_exit(NULL);
}
*/
/* Process the shell command */
static void handle_cmd(char *buf)
{
char reply[24];
char *p = NULL;
char call[CALL_SIZE + 1];
char cmd[4];
short i,j;
char nak[5];
char *ptr_cmd = NULL;
char *ptr_call = NULL;
char temp_repeater[CALL_SIZE + 1];
const char *delim = " ";
char unlink_request[19];
char notify_msg[64];
char *space_p = 0;
char linked_remote_system[CALL_SIZE + 1];
//v3.18
char df_b[FILENAME_MAX + 1];
//
nak[0] = '\0';
p = strchr(buf, '\r');
if (p)
*p = '\0';
p = strchr(buf, '\n');
if (p)
*p = '\0';
traceit("Received command [%s] from [%s]\n", buf, inet_ntoa(fromCmd.sin_addr));
if (strlen(buf) < 2)
{
traceit("Invalid command length\n");
strcpy(nak, "NAK\n");
}
else
{
if (strcmp(buf, "sh") == 0) /* shut it down */
keep_running = false;
else
if (strcmp(buf, "qsoy") == 0) /* QSO_DETAILS yes */
QSO_DETAILS = true;
else
if (strcmp(buf, "qson") == 0) /* QSO_DETAILS no */
QSO_DETAILS = false;
else
if (strcmp(buf, "pv") == 0) /* print version */
{
snprintf(reply, 23, "%s\n", VERSION);
sendto(cmd_sock, reply, strlen(reply),
0, (struct sockaddr *)&fromCmd,
sizeof(struct sockaddr_in));
}
else
if (strcmp(buf, "ps") == 0) /* print status */
print_status_screen();
else
if (strcmp(buf, "rfr") == 0)
{
load_gwys(GWYS);
load_valid_callsigns(VALID_CALLSIGNS);
}
else
{
ptr_cmd = strtok(buf, delim);
if (ptr_cmd)
ptr_call = strtok(NULL, delim);
if (!ptr_cmd || !ptr_call)
{
traceit("Invalid command\n");
strcpy(nak, "NAK\n");
}
else
if ((strlen(ptr_cmd) > 2) || (strlen(ptr_call) > CALL_SIZE))
{
traceit("Invalid command length\n");
strcpy(nak, "NAK\n");
}
else
{
strcpy(cmd, ptr_cmd);
strcpy(call, ptr_call);
traceit("cmd=[%s], parameter=[%s]\n", cmd, call);
/*
Link command: the second parameter must be 8 characters: localMod Repeater remoteMod
Example: lm CXRF003A
Example: lm CK1XC__B (you must use _ if the callsign is less than 6)
*/
if (strcmp(cmd, "lm") == 0)
{
if (strlen(call) != CALL_SIZE)
{
traceit("Invalid parameter length\n");
strcpy(nak, "NAK\n");
}
else
{
/* replace _ with SPACE */
for (i = 0; i < CALL_SIZE; i++)
{
if (call[i] == '_')
call[i] = ' ';
}
memset(temp_repeater, ' ', CALL_SIZE);
memcpy(temp_repeater, call + 1, 6);
temp_repeater[8] = '\0';
if ((call[0] != 'A') && (call[0] != 'B') && (call[0] != 'C'))
{
traceit("Invalid local module\n");
strcpy(nak, "NAK\n");
}
else
{
i = -1;
if (call[0] == 'A')
i = 0;
else
if (call[0] == 'B')
i = 1;
else
if (call[0] == 'C')
i = 2;
// 3.18
if (strncmp(temp_repeater, "REF", 2) == 0)
{
traceit("Trying to link to an REF - that is no longer supported\n");
i = -1;
strcpy(nak, "NAK\n");
}
if (i >= 0)
{
if ((to_remote_g2[i].to_call[0] == '\0') || /* not linked */
((to_remote_g2[i].to_call[0] != '\0') && /* waiting for a link reply that may never arrive */
!to_remote_g2[i].is_connected))
g2link(call[0], temp_repeater, call[7]);
else
{
traceit("Module is active, unlink before you link\n");
strcpy(nak, "NAK\n");
}
}
}
}
}
else
if (strcmp(cmd, "in") == 0) // Info on link status
{
if (strlen(call) != 1)
{
traceit("Invalid parameter length\n");
strcpy(nak, "NAK\n");
}
else
if ((call[0] != 'A') && (call[0] != 'B') && (call[0] != 'C'))
{
traceit("Invalid local module\n");
strcpy(nak, "NAK\n");
}
else
{
i = -1;
if (call[0] == 'A')
i = 0;
else
if (call[0] == 'B')
i = 1;
else
if (call[0] == 'C')
i = 2;
if (i >= 0)
{
if (to_remote_g2[i].is_connected)
{
tracing[i].last_time = time(NULL); //VA3UV
strcpy(linked_remote_system, to_remote_g2[i].to_call);
space_p = strchr(linked_remote_system, ' ');
if (space_p)
*space_p = '\0';
sprintf(notify_msg, "%c_linked.dat_LINKED_%s_%c",
to_remote_g2[i].from_mod,
linked_remote_system,
to_remote_g2[i].to_mod);
}
else
sprintf(notify_msg, "%c_unlinked.dat_UNLINKED", call[0]);
audio_notify(notify_msg);
}
}
}
else
if (strcmp(cmd, "um") == 0)
{
if (strlen(call) != 1)
{
traceit("Invalid parameter length\n");
strcpy(nak, "NAK\n");
}
else
if ((call[0] != 'A') && (call[0] != 'B') && (call[0] != 'C'))
{
traceit("Invalid local module\n");
strcpy(nak, "NAK\n");
}
else
{
i = -1;
if (call[0] == 'A')
i = 0;
else
if (call[0] == 'B')
i = 1;
else
if (call[0] == 'C')
i = 2;
if (i >= 0)
{
if (to_remote_g2[i].to_call[0] != '\0')
{
traceit("Unlinking from [%s] mod %c\n",
to_remote_g2[i].to_call, to_remote_g2[i].to_mod);
sprintf(notify_msg, "%c_unlinked.dat_UNLINKED", to_remote_g2[i].from_mod);
// v3.18
sprintf(df_b, "/dstar/tmp/blocklinking-%c", tolower(to_remote_g2[i].from_mod));
unlink(df_b);
if (to_remote_g2[i].type == 'p')
{
queryCommand[0] = 0x05;
queryCommand[1] = 0x00;
queryCommand[2] = 0x18;
queryCommand[3] = ((to_remote_g2[i].from_mod - 'A') << 4) | (to_remote_g2[i].to_mod - 'A');
queryCommand[4] = 0x00;
for (j = 0; j < 3; j++)
sendto(ref_g2_sock,(char *)queryCommand,5,0,
(struct sockaddr *)&(to_remote_g2[i].toDst4),
sizeof(to_remote_g2[i].toDst4));
}
else
if (to_remote_g2[i].type == 'x')
{
strcpy(unlink_request, OWNER);
unlink_request[8] = to_remote_g2[i].from_mod;
unlink_request[9] = ' ';
unlink_request[10] = '\0';
for (j = 0; j < 5; j++)
sendto(xrf_g2_sock,unlink_request, CALL_SIZE + 3,0,
(struct sockaddr *)&(to_remote_g2[i].toDst4),
sizeof(to_remote_g2[i].toDst4));
}
else
if (to_remote_g2[i].type == 'd')
{
strcpy(unlink_request, OWNER);
unlink_request[8] = to_remote_g2[i].from_mod;
unlink_request[9] = ' ';
unlink_request[10] = '\0';
memcpy(unlink_request + 11, to_remote_g2[i].to_call, 8);
for (j = 0; j < 5; j++)
sendto(dcs_g2_sock,unlink_request, 19,0,
(struct sockaddr *)&(to_remote_g2[i].toDst4),
sizeof(to_remote_g2[i].toDst4));
}
/* now zero out this entry */
to_remote_g2[i].type = ' ';
to_remote_g2[i].to_call[0] = '\0';
memset(&(to_remote_g2[i].toDst4),0,sizeof(struct sockaddr_in));
to_remote_g2[i].from_mod = ' ';
to_remote_g2[i].to_mod = ' ';
to_remote_g2[i].countdown = 0;
to_remote_g2[i].is_connected = false;