/* by KI4LKF */ #include <stdio.h> #include <fcntl.h> #include <string.h> #include <ctype.h> #include <stdlib.h> #include <stdarg.h> #include <signal.h> #include <errno.h> #include <sys/stat.h> #include <sys/types.h> #include <netinet/in.h> #include <netdb.h> #include <time.h> #include <regex.h> static regex_t preg; #include <unistd.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <arpa/inet.h> /* Required for Binary search trees using C++ STL */ #include <string> #include <map> #include <set> #include <utility> using namespace std; #include <pthread.h> #define VERSION "3.08" #define OWNER_SIZE 8 #define IP_SIZE 15 #define MAXHOSTNAMELEN 64 #define CALL_SIZE 8 /* Timeout is 30 seconds. If after 30 seconds, we have not received the KEEPALIVE, we drop that station */ static short TIMEOUT = 60; static char STATUS_FILE[FILENAME_MAX + 1]; /* configuration data */ /* Put that in a structure, later */ static char OWNER[OWNER_SIZE + 1]; static char ADMIN[CALL_SIZE + 1]; static char LISTEN_IP[IP_SIZE + 1]; static int LISTEN_PORT = 30001; static int COMMAND_PORT = 30002; /* max number of XRF repeaters */ static unsigned int MAX_USERS = 10; /* max number of dvap/dvtool dongles */ static unsigned int MAX_OTHER_USERS=10; static bool QSO_DETAILS = false; static char USERS[FILENAME_MAX + 1]; static char BLOCKS[FILENAME_MAX + 1]; // Input from XRF repeaters static int srv_sock = -1; // Input from admin commands static int cmd_sock = -1; // Input from dvap, dvtool dongles static int ref_sock = -1; /* ACK back to dvap, dvtool users */ static unsigned char REF_ACK[3] = { 3, 96, 0 }; /*** for replying with DASHBOARD information ***/ #define LH_MAX_SIZE 39 typedef map<string, string> dt_lh_type; static dt_lh_type dt_lh_list; /* inbound dongles(dvap, dvtool, ...) on port 20001 */ struct inbound { /* the callsign of the remote */ char call[CALL_SIZE + 1]; /* if true, packets from this call are dropped */ bool isMute; time_t connect_time; /* 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 D E*/ bool is_ref; char links[5]; /* The index is the local module: 0=A, 1=B, 2=C, 3=D, 4=E The value is the remote module Example: links[1] = 'C' That means that our local module B is linked to remote module C The remote system is identified by inbound->call */ /* the serial number of the dongle */ char serial[9]; }; /* the Key in this inbound_list map is the unique IP-port address of the remote, example: x.x.x.x-20001 */ typedef map<string, inbound *> inbound_type; static inbound_type inbound_list; /* Just before we send data to dvtool/dvap users, we save the header here, for re-transmit later */ static struct { uint32_t s_addr; unsigned char hdr[58]; } temp_r[5]; /* inbound repeaters on port 30001 */ struct a_user { /* callsign of the connected repeater */ char call[CALL_SIZE + 1]; /* if true, packets from this call are dropped */ bool isMute; /* is this another XRF reflector */ bool is_xrf; time_t connect_time; /* The first index identifies the local reflector module index 0 identifies reflector module A index 1 identifies reflector module B index 2 identifies reflector module C index 3 identifies reflector module D index 4 identifies reflector module E The second index identifies the remote repeater band. from 0 to 3 which is from A...D Example: rpt_mods[1][2] = 'C' rpt_mods[1][3] = 'D' Explanation: Reflector module B is linked to repeater module C Reflector module B is linked to repeater module D This means that the remote repeater has linked both repeater bands C and D to our reflector module B */ char rpt_mods[5][4]; /* time link was established */ time_t link_time[5][4]; /* IP address and UDP port of connected station */ /* For easy access to the connected station */ struct sockaddr_in sin; /* if countdown expires, the connection is terminated */ short countdown; /* This user talked on this module */ char mod; /* A B C D E */ }; /* The BST/map of connected users */ /* The KEY is the unique IP address string of ip[IP_SIZE + 1] */ /* The data is a pointer to struct a_user */ typedef map<string, struct a_user *> a_user_list_type; static a_user_list_type a_user_list; /* Just before we send the data to XRF repeaters we save the header here for re-transmit later */ static struct { uint32_t s_addr; unsigned char hdr[56]; unsigned char old_sid[2]; } temp_x[5]; /* the map of which reflectors we can link to */ typedef map<string,string> call_ip_type; static call_ip_type call_ip_map; /* The BST/set of blocked callsigns. The KEY is the unique blocked callsign. There is no data in the set. Blocked callsigns added by the administrator of the reflector. */ typedef set<string> blocks_type; static blocks_type blocks; /* socket descriptor set */ static fd_set fdset; /* 20 ms delay */ static struct timeval tv; static time_t tNow = 0; /* timing for XRF users */ static time_t HBinterStart = 0; /* timing for dvtool/dvap users */ static time_t inboundStart = 0; /* Variables used by more than one function */ static const short READBUFFER_SIZE = 1024; static unsigned char readBuffer[READBUFFER_SIZE]; static struct sockaddr_in fromUser; static struct sockaddr_in fromCmd; /* dvap, dvtool input buffer */ static unsigned char refbuf[READBUFFER_SIZE]; static struct sockaddr_in fromInbound; /* log file for tracing data */ static FILE *logfp = NULL; /* status file */ static FILE *statusfp = NULL; /*** rcd data ***/ static pthread_t playback_thread; pthread_attr_t attr; /* 30 users recording at the same time */ static const unsigned short int MAX_RCD_USERS = 30; /* each user can record 750 packets = 15 seconds of recorded audio */ static const unsigned short int MAX_RCD_DATA = 750; struct rcd { bool locked; time_t ts; struct sockaddr_in sin; short int recvlen; unsigned short idx; /*** index into data ***/ unsigned char data[MAX_RCD_DATA][58]; /*** 10 seconds ***/ }; /* key is streamid */ typedef map<string, struct rcd *> rcd_list_type; static rcd_list_type rcd_list; static struct rcd *an_rcd; static rcd_list_type::iterator rcd_pos; static pair<rcd_list_type::iterator,bool> rcd_insert_pair; static char an_rcd_streamid[32]; static time_t check_rcd_time = 0; static bool keep_running = true; static u_int16_t streamid_raw = 0; /* The reflector uses these functions only */ static void check_heartbeat(); static void print_users(); static void print_version(); static void mute_users(bool mute); static bool mute_call(char *call, bool mute); static void print_blocks(); static void print_links_file(); static void print_links_screen(); static bool get_ip(char *call, char *ip); static void handle_cmd(char *buf); static void runit(); static void traceit(const char *fmt,...); static int read_config(char *); static int srv_open(); static int cmd_open(); static void sigCatch(int signum); static int open_users(char *filename); static int open_blocks(char *filename); static bool resolve_rmt(char *name, int type, struct sockaddr_in *addr); static void *playback(void *arg); /* dvap, dongles, ... */ static void send_heartbeat(); static int ref_open(); static int link_to_ref(char *call); static int link_to_xrf(char local_mod, char *ref, char remote_mod, char *IP); 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; } static int link_to_xrf(char local_mod, char *ref, char remote_mod, char *IP) { short counter; char request[CALL_SIZE + 3]; struct sockaddr_in sin; a_user_list_type::iterator user_pos; if (remote_mod == 'X') remote_mod = ' '; /* unlink request */ else { user_pos = a_user_list.find(IP); if (user_pos != a_user_list.end()) { /* It already exists */ traceit("Remote reflector [%s] ip=%s already linked, unlink first\n", ref, IP); return 0; } } /* send the request to the remote XRF reflector */ strcpy(request, OWNER); request[8] = local_mod; request[9] = remote_mod; request[10] = '\0'; memset(&sin,0,sizeof(struct sockaddr_in)); sin.sin_family = AF_INET; sin.sin_port = htons(LISTEN_PORT); sin.sin_addr.s_addr = inet_addr(IP); traceit("Sending request [%s] to reflector %s\n", request, ref); for (counter = 0; counter < 5; counter++) sendto(srv_sock, request, CALL_SIZE + 3, 0,(struct sockaddr *)&sin, sizeof(struct sockaddr_in)); return 0; } static int link_to_ref(char *call) { char payload[MAXHOSTNAMELEN + 1]; /* IP-port */ char search_value[MAXHOSTNAMELEN + 7]; inbound_type::iterator inbound_pos; inbound *inbound_ptr; pair<inbound_type::iterator,bool> inbound_insert_pair; struct sockaddr_in sin; unsigned char queryCommand[56]; unsigned short j; char local_mod = ' '; char ref[CALL_SIZE + 1]; char remote_mod = ' '; local_mod = call[0]; if ((local_mod != 'A') && (local_mod != 'B') && (local_mod != 'C') && (local_mod != 'D')) { traceit("Invalid local module %c for linking\n", local_mod); return -1; } memset(ref, ' ', sizeof(ref)); memcpy(ref, call + 1, 6); ref[8] = '\0'; /* Is it blocked ? */ if (blocks.find(ref) != blocks.end()) return -1; if ((memcmp(ref, "REF", 3) != 0) && (memcmp(ref, "XRF", 3) != 0)) { traceit("XRF or REF only\n"); return -1; } if (strcmp(ref, OWNER) == 0) { traceit("Can not link to itself\n"); return -1; } remote_mod = call[7]; if ((remote_mod != 'A') && (remote_mod != 'B') && (remote_mod != 'C') && (remote_mod != 'D') && (remote_mod != 'X')) { traceit("Invalid remote module %c\n", remote_mod); return -1; } payload[0] = '\0'; /* get the IP address from database */ if (!get_ip(ref, payload)) return -1; /* No IP in db? */ if (payload[0] == '\0') { traceit("No host or IP address for %s\n", ref); return -1; } if (strcmp(payload, "0.0.0.0") == 0) { traceit("Invalid IP in db\n"); return -1; } if (memcmp(ref, "XRF", 3) == 0) { return link_to_xrf(local_mod, ref, remote_mod, payload); } /* Is it already linked? */ sprintf(search_value, "%s-20001", payload); inbound_pos = inbound_list.find(search_value); if (inbound_pos != inbound_list.end()) { inbound_ptr = (inbound *)inbound_pos->second; if (!inbound_ptr->is_ref) { traceit("This connection is not a reflector\n"); return -1; } /* update the links */ if (remote_mod == 'X') remote_mod = ' '; else if ((inbound_ptr->links[0] == remote_mod) || (inbound_ptr->links[1] == remote_mod) || (inbound_ptr->links[2] == remote_mod) || (inbound_ptr->links[3] == remote_mod) || (inbound_ptr->links[4] == remote_mod)) { traceit ("Already set or duplicate assignment\n"); return 0; } if (local_mod == 'A') inbound_ptr->links[0] = remote_mod; else if (local_mod == 'B') inbound_ptr->links[1] = remote_mod; else if (local_mod == 'C') inbound_ptr->links[2] = remote_mod; else if (local_mod == 'D') inbound_ptr->links[3] = remote_mod; else inbound_ptr->links[4] = remote_mod; if ((inbound_ptr->links[0] == ' ') && (inbound_ptr->links[1] == ' ') && (inbound_ptr->links[2] == ' ') && (inbound_ptr->links[3] == ' ') && (inbound_ptr->links[4] == ' ')) { /* all links removed, disconnect from remote system */ traceit("All links removed, disconnecting from %s\n", inbound_ptr->call); refbuf[0] = 5; refbuf[1] = 0; refbuf[2] = 24; refbuf[3] = 0; refbuf[4] = 0; sendto(ref_sock,(char *)refbuf,5,0, (struct sockaddr *)&(inbound_ptr->sin), sizeof(struct sockaddr_in)); free(inbound_pos->second); inbound_pos->second = NULL; inbound_list.erase(inbound_pos); } print_links_file(); return 0; } if (remote_mod == 'X') { traceit("X can not be used, there is no connection to unlink\n"); return -1; } if ((inbound_list.size() + 1) > MAX_OTHER_USERS) { traceit("Over the MAX_OTHER_USERS limit of %d\n", MAX_OTHER_USERS); return -1; } sin.sin_family = AF_INET; sin.sin_addr.s_addr = inet_addr(payload); sin.sin_port = htons(20001); /* assume that we will be ok */ inbound_ptr = (inbound *)malloc(sizeof(inbound)); if (inbound_ptr) { inbound_ptr->countdown = TIMEOUT; memcpy((char *)&(inbound_ptr->sin),(char *)&sin, sizeof(struct sockaddr_in)); strcpy(inbound_ptr->call, ref); time(&(inbound_ptr->connect_time)); inbound_ptr->isMute = false; inbound_ptr->mod = ' '; inbound_ptr->is_ref = true; inbound_ptr->links[0] = inbound_ptr->links[1] = inbound_ptr->links[2] = inbound_ptr->links[3] = inbound_ptr->links[4] = ' '; if (local_mod == 'A') inbound_ptr->links[0] = remote_mod; else if (local_mod == 'B') inbound_ptr->links[1] = remote_mod; else if (local_mod == 'C') inbound_ptr->links[2] = remote_mod; else if (local_mod == 'D') inbound_ptr->links[3] = remote_mod; else inbound_ptr->links[4] = remote_mod; strcpy(inbound_ptr->serial, "REF "); inbound_insert_pair = inbound_list.insert(pair<string, inbound *>(search_value, inbound_ptr)); if (inbound_insert_pair.second) { traceit("new CALL=%s,REPEATER,ip=%s, users=%d\n", inbound_ptr->call,search_value,inbound_list.size() + a_user_list.size()); /* request to connect */ queryCommand[0] = 5; queryCommand[1] = 0; queryCommand[2] = 24; queryCommand[3] = 0; queryCommand[4] = 1; for (j = 0; j < 2; j++) sendto(ref_sock,(char *)queryCommand,5,0, (struct sockaddr *)&(inbound_ptr->sin), sizeof(struct sockaddr_in)); print_links_file(); } else { traceit("failed to add CALL=%s,ip=%s\n",inbound_ptr->call,search_value); free(inbound_ptr); inbound_ptr = NULL; return -1; } } else { traceit("malloc() failed for call=%s,ip=%s\n",ref,search_value); return -1; } return 0; } /* send keepalive to dvap, dongles, ... */ static void send_heartbeat() { inbound_type::iterator pos; inbound_type::iterator temp_pos = inbound_list.end(); inbound *inbound_ptr; blocks_type::iterator block_pos; char dropped = ' '; for (pos = inbound_list.begin(); pos != inbound_list.end(); pos++) { inbound_ptr = (inbound *)pos->second; block_pos = blocks.find(inbound_ptr->call); if (block_pos == blocks.end()) /* not blocked */ { sendto(ref_sock,(char *)REF_ACK,3,0, (struct sockaddr *)&(inbound_ptr->sin), sizeof(struct sockaddr_in)); if (inbound_ptr->countdown >= 0) inbound_ptr->countdown --; if (inbound_ptr->countdown < 0) { dropped = 't'; // timeout temp_pos = pos; } } else { dropped = 'b'; // blocked temp_pos = pos; } } if (temp_pos != inbound_list.end()) { inbound_ptr = (inbound *)temp_pos->second; traceit("call=%s %s, removing %s\n", inbound_ptr->call, (dropped == 't')?"timeout":"blocked", temp_pos->first.c_str()); if (dropped == 'b') { /* disconnect */ refbuf[0] = 5; refbuf[1] = 0; refbuf[2] = 24; refbuf[3] = 0; refbuf[4] = 0; sendto(ref_sock,(char *)refbuf,5,0, (struct sockaddr *)&(inbound_ptr->sin), sizeof(struct sockaddr_in)); } free(temp_pos->second); temp_pos->second = NULL; inbound_list.erase(temp_pos); print_links_file(); } } static int open_blocks(char *filename) { FILE *fp = NULL; char inbuf[512]; char *p = NULL; blocks_type::iterator pos; short int i; char *call_ptr; char call[9]; const char *delim = " \t"; fp = fopen(filename, "r"); if (!fp) { traceit("Failed to open file %s\n", filename); return 1; } blocks.clear(); traceit("Reading from file: [%s]\n", filename); while (fgets(inbuf, 511, fp) != NULL) { inbuf[511] = '\0'; p = strchr(inbuf, '\r'); if (p) *p = '\0'; p = strchr(inbuf, '\n'); if (p) *p = '\0'; call_ptr = strtok(inbuf, delim); if (call_ptr) { if (strlen(call_ptr) <= 8) { memset(call, ' ', 9); call[8] = '\0'; memcpy(call, call_ptr, strlen(call_ptr)); for (i = 0; i < CALL_SIZE; i++) { if (call[i] == '_') call[i] = ' '; } blocks.insert(call); } } } fclose(fp); traceit("BEGIN listing blocked callsigns...%d calls blocked\n", blocks.size()); for (pos = blocks.begin(); pos != blocks.end(); pos++) traceit("--->[%s]\n", pos->c_str()); traceit("END listing blocked callsigns\n"); return 0; } static int open_users(char *filename) { FILE *fp = NULL; char inbuf[512]; char *p = NULL; char *gwy_ptr; char gwy[9]; char *host_ptr; const char *delim = " \t"; call_ip_type::iterator pos; fp = fopen(filename, "r"); if (!fp) { traceit("Failed to open file %s\n", filename); return 1; } call_ip_map.clear(); traceit("Reading from file: [%s]\n", filename); while (fgets(inbuf, 511, fp) != NULL) { inbuf[511] = '\0'; p = strchr(inbuf, '\r'); if (p) *p = '\0'; p = strchr(inbuf, '\n'); if (p) *p = '\0'; gwy_ptr = strtok(inbuf, delim); host_ptr = strtok(NULL, delim); if (gwy_ptr && host_ptr) { if (strlen(gwy_ptr) <= 8) { memset(gwy, ' ', 9); gwy[8] = '\0'; memcpy(gwy, gwy_ptr, strlen(gwy_ptr)); call_ip_map[gwy] = host_ptr; } } } fclose(fp); for (pos = call_ip_map.begin(); pos != call_ip_map.end(); pos++) traceit("[%s],[%s]\n", pos->first.c_str(), pos->second.c_str()); traceit("Loaded %d entries\n", call_ip_map.size()); return 0; } /* trace data to the log */ static void traceit(const char *fmt,...) { time_t ltime; struct tm tm; const short BFSZ = 512; char buf[BFSZ]; time(<ime); localtime_r(<ime,&tm); snprintf(buf,BFSZ - 1,"%02d%02d%02d at %02d:%02d:%02d:", tm.tm_mon+1,tm.tm_mday,tm.tm_year % 100, tm.tm_hour,tm.tm_min,tm.tm_sec); va_list args; va_start(args,fmt); vsnprintf(buf + strlen(buf), BFSZ - strlen(buf) -1, fmt, args); va_end(args); fprintf(logfp, "%s",buf); return; } /* Search for that host */ static bool get_ip(char *call, char *ip) { bool ok = false; call_ip_type::iterator pos; struct sockaddr_in a_net_addr; pos = call_ip_map.find(call); if (pos == call_ip_map.end()) { traceit("Callsign [%s] not found in database\n", call); return false; // not found } ok = resolve_rmt((char *)pos->second.c_str(), SOCK_DGRAM, &(a_net_addr)); if (!ok) { traceit("Failed to resolve [%s] for callsign [%s]\n", pos->second.c_str(), call); return false; } if (ip) strcpy(ip, inet_ntoa(a_net_addr.sin_addr)); return true; } /* Process the configuration file */ static int read_config(char *cfgFile) { short int valid_params = 11; short int params = 0; FILE *cnf = NULL; char inbuf[1024]; char *p; char *ptr = NULL; unsigned short int i; unsigned short int j; cnf = fopen(cfgFile, "r"); if (!cnf) { traceit("Failed to open file %s\n", cfgFile); return 1; } traceit("Reading file %s\n", cfgFile); while (fgets(inbuf, 1020, cnf) != NULL) { if (strchr(inbuf, '#')) continue; p = strchr(inbuf, '\r'); if (p) *p = '\0'; p = strchr(inbuf, '\n'); if (p) *p = '\0'; p = strchr(inbuf, '='); if (!p) continue; *p = '\0'; if (strcmp(inbuf,"OWNER") == 0) { memset(OWNER,' ', sizeof(OWNER)); OWNER[OWNER_SIZE] = '\0'; ptr = strchr(p + 1, ' '); if (ptr) *ptr = '\0'; if (strlen(p + 1) != OWNER_SIZE - 2) traceit("OWNER value %s invalid, length must be exactly %d\n", p + 1, OWNER_SIZE - 2); else { memcpy(OWNER, p + 1, OWNER_SIZE - 2); for (i = 0; i < strlen(OWNER); i++) OWNER[i] = toupper(OWNER[i]); if ((memcmp(OWNER, "XRF", 3) != 0) || !isdigit(OWNER[3]) || !isdigit(OWNER[4]) || !isdigit(OWNER[5])) traceit("Reflector names must be XRFzzz where zzz are digits from 1 thru 9\n"); else { traceit("OWNER=%s\n",OWNER); params ++; } } } else if (strcmp(inbuf,"ADMIN") == 0) { memset(ADMIN,' ', sizeof(ADMIN)); ADMIN[CALL_SIZE] = '\0'; /* no spaces after the equal sign */ if (p[1] == ' ') traceit("ADMIN: no spaces after the equal sign\n"); else { /* take up to 8 characters, throw away the rest */ p[CALL_SIZE + 1] = '\0'; /* valid length? */ if ((strlen(p + 1) < 3) || (strlen(p + 1) > CALL_SIZE)) traceit("ADMIN value [%s] invalid\n", p + 1); else { memcpy(ADMIN, p + 1, strlen(p + 1)); /* uppercase it */ for (j = 0; j < CALL_SIZE; j++) ADMIN[j] = toupper(ADMIN[j]); traceit("ADMIN=[%s]\n",ADMIN); params ++; } } } else if (strcmp(inbuf,"LISTEN_IP") == 0) { ptr = strchr(p + 1, ' '); if (ptr) *ptr = '\0'; if (strlen(p + 1) < 1) traceit("LISTEN_IP value %s invalid\n", p + 1); else { memset(LISTEN_IP, '\0', sizeof(LISTEN_IP)); strncpy(LISTEN_IP, p + 1, IP_SIZE); traceit("LISTEN_IP=%s\n",LISTEN_IP); params ++; } } else if (strcmp(inbuf,"LISTEN_PORT") == 0) { LISTEN_PORT = atoi(p + 1); traceit("LISTEN_PORT=%d\n",LISTEN_PORT); params ++; } else if (strcmp(inbuf,"COMMAND_PORT") == 0) { COMMAND_PORT = atoi(p + 1); traceit("COMMAND_PORT=%d\n",COMMAND_PORT); params ++; } else if (strcmp(inbuf,"MAX_USERS") == 0) { MAX_USERS = atoi(p + 1); traceit("MAX_USERS=%d\n",MAX_USERS); params ++; } else if (strcmp(inbuf,"MAX_OTHER_USERS") == 0) { MAX_OTHER_USERS = atoi(p + 1); traceit("MAX_OTHER_USERS=%d\n",MAX_OTHER_USERS); params ++; } else if (strcmp(inbuf,"STATUS_FILE") == 0) { memset(STATUS_FILE, '\0', sizeof(STATUS_FILE)); strncpy(STATUS_FILE, p + 1,FILENAME_MAX); traceit("STATUS_FILE=%s\n",STATUS_FILE); params ++; } else if (strcmp(inbuf,"USERS") == 0) { memset(USERS, '\0', sizeof(USERS)); strncpy(USERS, p + 1, FILENAME_MAX); traceit("USERS=%s\n",USERS); params ++; } else if (strcmp(inbuf,"BLOCKS") == 0) { memset(BLOCKS, '\0', sizeof(BLOCKS)); strncpy(BLOCKS, p + 1, FILENAME_MAX); traceit("BLOCKS=%s\n",BLOCKS); params ++; } else if (strcmp(inbuf,"QSO_DETAILS") == 0) { if (*(p + 1) == 'Y') QSO_DETAILS = true; else QSO_DETAILS = false; traceit("QSO_DETAILS=%c\n", *(p + 1)); params ++; } } fclose(cnf); if (params != valid_params) { traceit("Configuration file %s invalid\n",cfgFile); return 1; } if (COMMAND_PORT == LISTEN_PORT) { traceit("Error: COMMAND_PORT must be different from LISTEN_PORT\n"); return 1; } return 0; } /* Send heartbeat to repeaters, ... */ static void check_heartbeat() { a_user_list_type::iterator pos; a_user_list_type::iterator temp_pos = a_user_list.end(); struct a_user *a_user_ptr; blocks_type::iterator block_pos; char dropped = ' '; for (pos = a_user_list.begin(); pos != a_user_list.end(); pos++) { a_user_ptr = (struct a_user *)pos->second; block_pos = blocks.find(a_user_ptr->call); if (block_pos == blocks.end()) /* not blocked */ { sendto(srv_sock, OWNER, strlen(OWNER) + 1, 0,(struct sockaddr *)&(a_user_ptr->sin), sizeof(struct sockaddr_in)); if (a_user_ptr->countdown >= 0) a_user_ptr->countdown --; if (a_user_ptr->countdown < 0) { dropped = 't'; // timeout temp_pos = pos; } } else { dropped = 'b'; // blocked temp_pos = pos; } } if (temp_pos != a_user_list.end()) { a_user_ptr = (struct a_user *)temp_pos->second; traceit("call=%s %s, removing %s\n", a_user_ptr->call, (dropped == 't')?"timeout":"blocked", temp_pos->first.c_str()); free(temp_pos->second); temp_pos->second = NULL; a_user_list.erase(temp_pos); print_links_file(); } return; } static void print_version() { char buf[24]; snprintf(buf, 23, "%s\n", VERSION); sendto(cmd_sock, buf, strlen(buf), 0, (struct sockaddr *)&fromCmd, sizeof(struct sockaddr_in)); } /* Print connected users */ static void print_users() { a_user_list_type::iterator pos; struct a_user *a_user_ptr; inbound_type::iterator pos2; inbound *inbound_ptr; struct tm tm; char buf[256]; for (pos = a_user_list.begin(); pos != a_user_list.end(); pos++) { a_user_ptr = (struct a_user *)pos->second; localtime_r(&(a_user_ptr->connect_time),&tm); snprintf(buf, 255, "%s,%s,REPEATER,%02d%02d%02d,%02d:%02d:%02d,%s\n", a_user_ptr->call, pos->first.c_str(), tm.tm_mon+1,tm.tm_mday,tm.tm_year % 100, tm.tm_hour,tm.tm_min,tm.tm_sec, a_user_ptr->isMute?"Muted":"notMuted"); sendto(cmd_sock, buf, strlen(buf), 0, (struct sockaddr *)&fromCmd, sizeof(struct sockaddr_in)); } for (pos2 = inbound_list.begin(); pos2 != inbound_list.end(); pos2++) { inbound_ptr = (inbound *)pos2->second; localtime_r(&(inbound_ptr->connect_time),&tm); snprintf(buf, 255, "%s,%s,%s(%.8s),%02d%02d%02d,%02d:%02d:%02d,%s\n", inbound_ptr->call, pos2->first.c_str(), inbound_ptr->is_ref?"REPEATER":"DONGLE", inbound_ptr->serial, tm.tm_mon+1,tm.tm_mday,tm.tm_year % 100, tm.tm_hour,tm.tm_min,tm.tm_sec, inbound_ptr->isMute?"Muted":"notMuted"); sendto(cmd_sock, buf, strlen(buf), 0, (struct sockaddr *)&fromCmd, sizeof(struct sockaddr_in)); } return; } /* Mute or unmute all users */ static void mute_users(bool mute) { a_user_list_type::iterator pos; struct a_user *a_user_ptr; inbound_type::iterator pos2; inbound *inbound_ptr; for (pos = a_user_list.begin(); pos != a_user_list.end(); pos++) { a_user_ptr = (struct a_user *)pos->second; a_user_ptr->isMute = mute; } for (pos2 = inbound_list.begin(); pos2 != inbound_list.end(); pos2++) { inbound_ptr = (inbound *)pos2->second; inbound_ptr->isMute = mute; } return; } /* mute or unmute a user by callsign */ static bool mute_call(char *call, bool mute) { bool found = false; a_user_list_type::iterator pos; struct a_user *a_user_ptr; inbound_type::iterator pos2; inbound *inbound_ptr; for (pos = a_user_list.begin(); pos != a_user_list.end(); pos++) { a_user_ptr = (struct a_user *)pos->second; if (strcmp(a_user_ptr->call, call) == 0) { found = true; a_user_ptr->isMute = mute; } } for (pos2 = inbound_list.begin(); pos2 != inbound_list.end(); pos2++) { inbound_ptr = (inbound *)pos2->second; if (strcmp(inbound_ptr->call, call) == 0) { found = true; inbound_ptr->isMute = mute; } } return found; } /* print the links on the screen */ static void print_links_screen() { char buf[256]; struct tm tm; inbound_type::iterator inbound_pos; inbound *inbound_ptr; a_user_list_type::iterator pos; struct a_user *a_user_ptr; short int i, j; char from_mod = ' '; for (pos = a_user_list.begin(); pos != a_user_list.end(); pos++) { a_user_ptr = (struct a_user *)pos->second; for (i = 0; i < 5; i++) { for (j = 0; j < 4; j++) { if (a_user_ptr->rpt_mods[i][j] != '\0') { if (i == 0) from_mod = 'A'; else if (i == 1) from_mod = 'B'; else if (i == 2) from_mod = 'C'; else if (i == 3) from_mod = 'D'; else if (i == 4) from_mod = 'E'; localtime_r(&(a_user_ptr->link_time[i][j]),&tm); snprintf(buf, 255, "%c,%s,%c,%s,%02d%02d%02d,%02d:%02d:%02d\n", from_mod, a_user_ptr->call, a_user_ptr->rpt_mods[i][j], pos->first.c_str(), tm.tm_mon+1,tm.tm_mday,tm.tm_year % 100, tm.tm_hour,tm.tm_min,tm.tm_sec); sendto(cmd_sock, buf, strlen(buf), 0, (struct sockaddr *)&fromCmd, sizeof(struct sockaddr_in)); } } } } for (inbound_pos = inbound_list.begin(); inbound_pos != inbound_list.end(); inbound_pos++) { inbound_ptr = (inbound *)inbound_pos->second; for (i = 0; i < 5; i++) { if (inbound_ptr->links[i] != ' ') { if (i == 0) from_mod = 'A'; else if (i == 1) from_mod = 'B'; else if (i == 2) from_mod = 'C'; else if (i == 3) from_mod = 'D'; else from_mod = 'E'; localtime_r(&(inbound_ptr->connect_time), &tm); snprintf(buf, 255, "%c,%s,%c,%s,%02d%02d%02d,%02d:%02d:%02d\n", from_mod, inbound_ptr->call, inbound_ptr->links[i], inbound_pos->first.c_str(), tm.tm_mon+1,tm.tm_mday,tm.tm_year % 100, tm.tm_hour,tm.tm_min,tm.tm_sec); sendto(cmd_sock, buf, strlen(buf), 0, (struct sockaddr *)&fromCmd, sizeof(struct sockaddr_in)); } } } } /* Print links into the STATUS file */ static void print_links_file() { inbound_type::iterator inbound_pos; inbound *inbound_ptr; a_user_list_type::iterator pos; struct a_user *a_user_ptr; struct tm tm; short int i, j; char from_mod = ' '; statusfp = fopen(STATUS_FILE, "w"); if (!statusfp) traceit("Failed to create status file %s\n", STATUS_FILE); else { setvbuf(statusfp, (char *)NULL, _IOLBF, 0); for (pos = a_user_list.begin(); pos != a_user_list.end(); pos++) { a_user_ptr = (struct a_user *)pos->second; for (i = 0; i < 5; i++) { for (j = 0; j < 4; j++) { if (a_user_ptr->rpt_mods[i][j] != '\0') { if (i == 0) from_mod = 'A'; else if (i == 1) from_mod = 'B'; else if (i == 2) from_mod = 'C'; else if (i == 3) from_mod = 'D'; else from_mod = 'E'; localtime_r(&(a_user_ptr->link_time[i][j]),&tm); fprintf(statusfp, "%c,%s,%c,%s,%02d%02d%02d,%02d:%02d:%02d\n", from_mod, a_user_ptr->call, a_user_ptr->rpt_mods[i][j], pos->first.c_str(), tm.tm_mon+1,tm.tm_mday,tm.tm_year % 100, tm.tm_hour,tm.tm_min,tm.tm_sec); } } } } for (inbound_pos = inbound_list.begin(); inbound_pos != inbound_list.end(); inbound_pos++) { inbound_ptr = (inbound *)inbound_pos->second; for (i = 0; i < 5; i++) { if (inbound_ptr->links[i] != ' ') { if (i == 0) from_mod = 'A'; else if (i == 1) from_mod = 'B'; else if (i == 2) from_mod = 'C'; else if (i == 3) from_mod = 'D'; else from_mod = 'E'; localtime_r(&(inbound_ptr->connect_time), &tm); fprintf(statusfp, "%c,%s,%c,%s,%02d%02d%02d,%02d:%02d:%02d\n", from_mod, inbound_ptr->call, inbound_ptr->links[i], inbound_pos->first.c_str(), tm.tm_mon+1,tm.tm_mday,tm.tm_year % 100, tm.tm_hour,tm.tm_min,tm.tm_sec); } } } fclose(statusfp); } } /* print blocked users */ static void print_blocks() { blocks_type::iterator pos; char buf[32]; for (pos = blocks.begin(); pos != blocks.end(); pos++) { snprintf(buf, 31, "[%s]\n", pos->c_str()); sendto(cmd_sock, buf, strlen(buf), 0, (struct sockaddr *)&fromCmd, sizeof(struct sockaddr_in)); } } /* signal catching function */ static void sigCatch(int signum) { /* do NOT do any serious work here */ /* Just get out of its processing loop */ if ((signum == SIGTERM) || (signum == SIGINT)) keep_running = false; return; } /* Open server socket for dvap, dvtool ... */ static int ref_open() { struct sockaddr_in sin; ref_sock = socket(PF_INET,SOCK_DGRAM,0); if (ref_sock == -1) { traceit("Failed to create ref socket,errno=%d\n",errno); return 1; } memset(&sin,0,sizeof(struct sockaddr_in)); sin.sin_family = AF_INET; sin.sin_port = htons(20001); sin.sin_addr.s_addr = inet_addr(LISTEN_IP); if (bind(ref_sock,(struct sockaddr *)&sin,sizeof(struct sockaddr_in)) != 0) { traceit("Failed to bind ref socket on IP %s, port 20001, errno=%d\n", LISTEN_IP, errno); close(ref_sock); ref_sock = -1; return 1; } fcntl(ref_sock,F_SETFL,O_NONBLOCK); return 0; } /* Open server socket for connected stations */ static int srv_open() { struct sockaddr_in sin; srv_sock = socket(PF_INET,SOCK_DGRAM,0); if (srv_sock == -1) { traceit("Failed to create server socket,errno=%d\n",errno); return 1; } memset(&sin,0,sizeof(struct sockaddr_in)); sin.sin_family = AF_INET; sin.sin_port = htons(LISTEN_PORT); sin.sin_addr.s_addr = inet_addr(LISTEN_IP); if (bind(srv_sock,(struct sockaddr *)&sin,sizeof(struct sockaddr_in)) != 0) { traceit("Failed to bind server socket on IP %s, port %d, errno=%d\n", LISTEN_IP, LISTEN_PORT,errno); close(srv_sock); srv_sock = -1; return 1; } fcntl(srv_sock,F_SETFL,O_NONBLOCK); return 0; } /* Open command socket for handling commands from the shell. Use netcat as a client to send commands to this reflector */ static int cmd_open() { struct sockaddr_in sin; cmd_sock = socket(PF_INET,SOCK_DGRAM,0); if (cmd_sock == -1) { traceit("Failed to create cmd socket,errno=%d\n",errno); return 1; } memset(&sin,0,sizeof(struct sockaddr_in)); sin.sin_family = AF_INET; sin.sin_port = htons(COMMAND_PORT); sin.sin_addr.s_addr = inet_addr(LISTEN_IP); if (bind(cmd_sock,(struct sockaddr *)&sin,sizeof(struct sockaddr_in)) != 0) { traceit("Failed to bind cmd socket on IP %s, port %d, errno=%d\n", LISTEN_IP, COMMAND_PORT,errno); close(cmd_sock); cmd_sock = -1; return 1; } fcntl(cmd_sock,F_SETFL,O_NONBLOCK); return 0; } /* Process the shell command */ static void handle_cmd(char *buf) { char *p = NULL; char call[CALL_SIZE + 1]; char cmd[4]; unsigned short i; char nak[5]; char *ptr_cmd = NULL; char *ptr_call = NULL; const char *delim = " "; blocks_type::iterator pos; int rc = -1; nak[0] = '\0'; p = strchr(buf, '\r'); if (p) *p = '\0'; p = strchr(buf, '\n'); if (p) *p = '\0'; if (strlen(buf) < 2) return; traceit("Received command [%s] from [%s]\n", buf, inet_ntoa(fromCmd.sin_addr)); if (strcmp(buf, "sh") == 0) /* shutdown reflector */ keep_running = false; else if (strcmp(buf, "mu") == 0) /* mute users */ mute_users(true); else if (strcmp(buf, "uu") == 0) /* un-mute users */ mute_users(false); else if (strcmp(buf, "qsoy") == 0) /* QSO_DETAILS yes */ QSO_DETAILS = true; else if (strcmp(buf, "qson") == 0) QSO_DETAILS = false; /* QSO_DETAILS no */ else if (strcmp(buf, "pu") == 0) /* print users */ print_users(); else if (strcmp(buf, "pv") == 0) /* print version */ print_version(); else if (strcmp(buf, "pb") == 0) /* print blocked users */ print_blocks(); else if (strcmp(buf, "pl") == 0) /* print links */ print_links_screen(); else if (strcmp(buf, "upd") == 0) /* reaload the database */ { rc = open_users(USERS); if (rc != 0) traceit("Failed to reload %s\n", USERS); } else { ptr_cmd = strtok(buf, delim); ptr_call = strtok(NULL, delim); if (!ptr_cmd || !ptr_call) { traceit("Missing command parameters\n"); strcpy(nak, "NAK\n"); } else if (strlen(ptr_cmd) > 3) { traceit("Invalid command length\n"); strcpy(nak, "NAK\n"); } else { strcpy(cmd, ptr_cmd); if (strlen(ptr_call) <= CALL_SIZE) { strcpy(call, ptr_call); if (strlen(call) < CALL_SIZE) { for (i = strlen(call); i < CALL_SIZE; i++) call[i] = ' '; call[CALL_SIZE] = '\0'; } for (i = 0; i < CALL_SIZE; i++) { if (call[i] == '_') call[i] = ' '; } if (strcmp(cmd, "ab") == 0) /* ab <CALLSIGN> this will block the callsign */ { pos = blocks.find(call); if (pos != blocks.end()) { traceit("Call %s already blocked\n", call); strcpy(nak, "NAK\n"); } else if (blocks.insert(call).second) traceit("call %s is now blocked\n", call); else { traceit("Failed to block call %s\n",call); strcpy(nak, "NAK\n"); } } else if (strcmp(cmd, "rb") == 0) /* rb <CALLSIGN> this will remove the block on the callsign */ { if (blocks.erase(call) > 0) traceit("call %s is now unblocked\n", call); else { traceit("Could not find blocked call %s\n", call); strcpy(nak, "NAK\n"); } } else if (strcmp(cmd, "mc") == 0) /* mute a user by callsign */ { if (!mute_call(call, true)) strcpy(nak, "NAK\n"); } else if (strcmp(cmd, "uc") == 0) /* un-mute a user by callsign */ { if (!mute_call(call, false)) strcpy(nak, "NAK\n"); } else if (strcmp(cmd, "lrf") == 0) /* link to ref */ { rc = link_to_ref(call); if (rc != 0) strcpy(nak, "NAK\n"); } else { traceit("Unknown command or bad parameter\n", cmd); strcpy(nak, "NAK\n"); } } } } if (nak[0] == '\0') strcpy(nak, "OK\n"); sendto(cmd_sock,nak,4, 0, (struct sockaddr *)&fromCmd, sizeof(struct sockaddr_in)); return; } /* Reflector is running here */ static void runit() { short i,j,k,n; int recvlen; int recvlen2; int recvlen3; socklen_t fromlen; char *p = NULL; int call_valid = REG_NOERROR; bool allowed_to_connect = true; char search_value[MAXHOSTNAMELEN + 7]; char a_call[CALL_SIZE + 1]; char a_call2[CALL_SIZE + 1]; char an_ip[IP_SIZE + 1]; char a_port[7]; call_ip_type::iterator pos; struct a_user *a_user_ptr; a_user_list_type::iterator user_pos; struct a_user *a_user_ptr2; a_user_list_type::iterator user_pos2; pair<a_user_list_type::iterator,bool> user_insert_pair; blocks_type::iterator block_pos; inbound *inbound_ptr; inbound_type::iterator inbound_pos; inbound *inbound_ptr2; inbound_type::iterator inbound_pos2; pair<inbound_type::iterator,bool> inbound_insert_pair; bool found = false; char source_mod = ' '; int max_nfds = 0; char tmp1[CALL_SIZE + 1]; char tmp2[32]; // 8 for rpt1 + 24 for time_t in string format dt_lh_type::iterator dt_lh_pos; dt_lh_type::reverse_iterator r_dt_lh_pos; int rc; char reply_to_xrf[11]; /* faster select */ if (srv_sock > max_nfds) max_nfds = srv_sock; if (cmd_sock > max_nfds) max_nfds = cmd_sock; if (ref_sock > max_nfds) max_nfds = ref_sock; traceit("srv=%d, cmd=%d, ref=%d, MAX+1=%d\n", srv_sock,cmd_sock,ref_sock, max_nfds + 1); time(&HBinterStart); time(&inboundStart); time(&check_rcd_time); while (keep_running) { /* send heartbeat to connected dvap, dvtool ... */ time(&tNow); if ((tNow - inboundStart) > 0) { send_heartbeat(); inboundStart = tNow; } /* send a heartbeat to linked gateways */ time(&tNow); if ((tNow - HBinterStart) > 0) { check_heartbeat(); HBinterStart = tNow; } time(&tNow); if ((tNow - check_rcd_time) > 3) { for (rcd_pos = rcd_list.begin(); rcd_pos != rcd_list.end(); rcd_pos ++) { an_rcd = (struct rcd *)rcd_pos->second; if (!an_rcd->locked) { if ((tNow - an_rcd->ts) > 1) { /*** if (an_rcd->recvlen == 56) traceit("Removing playback streamid %d,%d\n", an_rcd->data[0][12], an_rcd->data[0][13]); else traceit("Removing playback streamid %d,%d\n", an_rcd->data[0][14], an_rcd->data[0][15]); ***/ free(rcd_pos->second); rcd_pos->second = NULL; rcd_list.erase(rcd_pos); } } } check_rcd_time = tNow; } /* wait 20 ms max */ FD_ZERO(&fdset); FD_SET(srv_sock,&fdset); FD_SET(cmd_sock,&fdset); FD_SET(ref_sock,&fdset); tv.tv_sec = 0; tv.tv_usec = 20000; /* 20 ms */ (void)select(max_nfds + 1,&fdset,0,0,&tv); /* process shell commands */ if (FD_ISSET(cmd_sock, &fdset)) { fromlen = sizeof(struct sockaddr_in); recvlen2 = recvfrom(cmd_sock,(char *)readBuffer,READBUFFER_SIZE, 0,(struct sockaddr *)&fromCmd,&fromlen); if (recvlen2 > 0) { readBuffer[recvlen2 - 1] = '\0'; handle_cmd((char *)readBuffer); } FD_CLR (cmd_sock,&fdset); } /* process input from dvap, dvtool */ if (FD_ISSET(ref_sock, &fdset)) { fromlen = sizeof(struct sockaddr_in); recvlen3 = recvfrom(ref_sock,(char *)refbuf,READBUFFER_SIZE, 0,(struct sockaddr *)&fromInbound,&fromlen); strncpy(an_ip, inet_ntoa(fromInbound.sin_addr),IP_SIZE); an_ip[IP_SIZE] = '\0'; snprintf(a_port, 6, "%d", ntohs(fromInbound.sin_port)); a_port[5] = '\0'; /* LH */ if ((recvlen3 == 4) && (refbuf[0] == 4) && (refbuf[1] == 192) && (refbuf[2] == 7) && (refbuf[3] == 0)) { unsigned short j_idx = 0; unsigned short k_idx = 0; unsigned char tmp[2]; sprintf(search_value, "%s-%s", an_ip, a_port); inbound_pos = inbound_list.find(search_value); if (inbound_pos != inbound_list.end()) { /* header is 10 bytes */ /* reply type */ refbuf[2] = 7; refbuf[3] = 0; time(&tNow); memcpy((char *)refbuf + 6, (char *)&tNow, sizeof(time_t)); for (r_dt_lh_pos = dt_lh_list.rbegin(); r_dt_lh_pos != dt_lh_list.rend(); r_dt_lh_pos++) { /* each entry has 24 bytes */ /* start at position 10 to bypass the header */ strcpy((char *)refbuf + 10 + (24 * j_idx), r_dt_lh_pos->second.c_str()); p = strchr((char *)r_dt_lh_pos->first.c_str(), '='); if (p) { memcpy((char *)refbuf + 18 + (24 * j_idx), p + 1, 8); *p = '\0'; tNow = atol(r_dt_lh_pos->first.c_str()); *p = '='; memcpy((char *)refbuf + 26 + (24 * j_idx), &tNow, sizeof(time_t)); } else { memcpy((char *)refbuf + 18 + (24 * j_idx), "ERROR ", 8); time(&tNow); memcpy((char *)refbuf + 26 + (24 * j_idx), &tNow, sizeof(time_t)); } refbuf[30 + (24 * j_idx)] = 0; refbuf[31 + (24 * j_idx)] = 0; refbuf[32 + (24 * j_idx)] = 0; refbuf[33 + (24 * j_idx)] = 0; j_idx++; /* process 39 entries at a time */ if (j_idx == 39) { /* 39 * 24 = 936 + 10 header = 946 */ refbuf[0] = 0xb2; refbuf[1] = 0xc3; /* 39 entries */ refbuf[4] = 0x27; refbuf[5] = 0x00; sendto(ref_sock,(char *)refbuf,946,0, (struct sockaddr *)&fromInbound, sizeof(struct sockaddr_in)); j_idx = 0; } } if (j_idx != 0) { k_idx = 10 + (j_idx * 24); memcpy(tmp, (char *)&k_idx, 2); refbuf[0] = tmp[0]; refbuf[1] = tmp[1] | 0xc0; memcpy(tmp, (char *)&j_idx, 2); refbuf[4] = tmp[0]; refbuf[5] = tmp[1]; sendto(ref_sock,(char *)refbuf, k_idx, 0, (struct sockaddr *)&fromInbound, sizeof(struct sockaddr_in)); } } } else /* linked repeaters request */ if ((recvlen3 == 4) && (refbuf[0] == 4) && (refbuf[1] == 192) && (refbuf[2] == 5) && (refbuf[3] == 0)) { unsigned short i_idx = 0; unsigned short j_idx = 0; unsigned short k_idx = 0; short module_idx; unsigned char tmp[2]; unsigned short total = 0; sprintf(search_value, "%s-%s", an_ip, a_port); inbound_pos = inbound_list.find(search_value); if (inbound_pos != inbound_list.end()) { /* header is 8 bytes */ /* reply type */ refbuf[2] = 5; refbuf[3] = 1; total = a_user_list.size(); memcpy(tmp, (char *)&total, 2); refbuf[6] = tmp[0]; refbuf[7] = tmp[1]; for (user_pos = a_user_list.begin(), i_idx = 0; user_pos != a_user_list.end(); user_pos++, i_idx++) { /* each entry has 20 bytes */ a_user_ptr = (struct a_user *)user_pos->second; for (module_idx = 0; module_idx < 5; module_idx++) { for (k = 0; k < 4; k++) { if (a_user_ptr->rpt_mods[module_idx][k] != '\0') { if (module_idx == 0) refbuf[8 + (20 * j_idx)] = 'A'; else if (module_idx == 1) refbuf[8 + (20 * j_idx)] = 'B'; else if (module_idx == 2) refbuf[8 + (20 * j_idx)] = 'C'; else if (module_idx == 3) refbuf[8 + (20 * j_idx)] = 'D'; else if (module_idx == 4) refbuf[8 + (20 * j_idx)] = 'E'; strcpy((char *)refbuf + 9 + (20 * j_idx), a_user_ptr->call); refbuf[16 + (20 * j_idx)] = a_user_ptr->rpt_mods[module_idx][k]; refbuf[17 + (20 * j_idx)] = 0; refbuf[18 + (20 * j_idx)] = 0; refbuf[19 + (20 * j_idx)] = 0; refbuf[20 + (20 * j_idx)] = 0x50; refbuf[21 + (20 * j_idx)] = 0x04; refbuf[22 + (20 * j_idx)] = 0x32; refbuf[23 + (20 * j_idx)] = 0x4d; refbuf[24 + (20 * j_idx)] = 0x9f; refbuf[25 + (20 * j_idx)] = 0xdb; refbuf[26 + (20 * j_idx)] = 0x0e; refbuf[27 + (20 * j_idx)] = 0; j_idx++; if (j_idx == 39) { /* 20 bytes for each user, so 39 * 20 = 780 bytes + 8 bytes header = 788 */ refbuf[0] = 0x14; refbuf[1] = 0xc3; k_idx = i_idx - 38; memcpy(tmp, (char *)&k_idx, 2); refbuf[4] = tmp[0]; refbuf[5] = tmp[1]; sendto(ref_sock,(char *)refbuf,788,0, (struct sockaddr *)&fromInbound, sizeof(struct sockaddr_in)); j_idx = 0; } } } } } if (j_idx != 0) { k_idx = 8 + (j_idx * 20); memcpy(tmp, (char *)&k_idx, 2); refbuf[0] = tmp[0]; refbuf[1] = tmp[1] | 0xc0; if (i_idx > j_idx) k_idx = i_idx - j_idx; else k_idx = 0; mempcpy(tmp, (char *)&k_idx, 2); refbuf[4] = tmp[0]; refbuf[5] = tmp[1]; sendto(ref_sock,(char *)refbuf, 8 + (j_idx * 20), 0, (struct sockaddr *)&fromInbound, sizeof(struct sockaddr_in)); } i_idx = 0; j_idx = 0; k_idx = 0; for (inbound_pos = inbound_list.begin(), i_idx = 0; inbound_pos != inbound_list.end(); inbound_pos++, i_idx++) { /* each entry has 20 bytes */ inbound_ptr = (inbound *)inbound_pos->second; if (inbound_ptr->is_ref) { for (module_idx = 0; module_idx < 5; module_idx++) { if (inbound_ptr->links[module_idx] != ' ') { if (module_idx == 0) refbuf[8 + (20 * j_idx)] = 'A'; else if (module_idx == 1) refbuf[8 + (20 * j_idx)] = 'B'; else if (module_idx == 2) refbuf[8 + (20 * j_idx)] = 'C'; else if (module_idx == 3) refbuf[8 + (20 * j_idx)] = 'D'; else if (module_idx == 4) refbuf[8 + (20 * j_idx)] = 'E'; strcpy((char *)refbuf + 9 + (20 * j_idx), inbound_ptr->call); refbuf[16 + (20 * j_idx)] = inbound_ptr->links[module_idx]; refbuf[17 + (20 * j_idx)] = 0; refbuf[18 + (20 * j_idx)] = 0; refbuf[19 + (20 * j_idx)] = 0; refbuf[20 + (20 * j_idx)] = 0x50; refbuf[21 + (20 * j_idx)] = 0x04; refbuf[22 + (20 * j_idx)] = 0x32; refbuf[23 + (20 * j_idx)] = 0x4d; refbuf[24 + (20 * j_idx)] = 0x9f; refbuf[25 + (20 * j_idx)] = 0xdb; refbuf[26 + (20 * j_idx)] = 0x0e; refbuf[27 + (20 * j_idx)] = 0; j_idx++; if (j_idx == 39) { /* 20 bytes for each user, so 39 * 20 = 780 bytes + 8 bytes header = 788 */ refbuf[0] = 0x14; refbuf[1] = 0xc3; k_idx = i_idx - 38; memcpy(tmp, (char *)&k_idx, 2); refbuf[4] = tmp[0]; refbuf[5] = tmp[1]; sendto(ref_sock,(char *)refbuf,788,0, (struct sockaddr *)&fromInbound, sizeof(struct sockaddr_in)); j_idx = 0; } } } } } if (j_idx != 0) { k_idx = 8 + (j_idx * 20); memcpy(tmp, (char *)&k_idx, 2); refbuf[0] = tmp[0]; refbuf[1] = tmp[1] | 0xc0; if (i_idx > j_idx) k_idx = i_idx - j_idx; else k_idx = 0; mempcpy(tmp, (char *)&k_idx, 2); refbuf[4] = tmp[0]; refbuf[5] = tmp[1]; sendto(ref_sock,(char *)refbuf, 8 + (j_idx * 20), 0, (struct sockaddr *)&fromInbound, sizeof(struct sockaddr_in)); } } } else /* connected user list request */ if ((recvlen3 == 4) && (refbuf[0] == 4) && (refbuf[1] == 192) && (refbuf[2] == 6) && (refbuf[3] == 0)) { unsigned short i_idx = 0; unsigned short j_idx = 0; unsigned short k_idx = 0; unsigned char tmp[2]; unsigned short total = 0; sprintf(search_value, "%s-%s", an_ip, a_port); inbound_pos = inbound_list.find(search_value); if (inbound_pos != inbound_list.end()) { /* header is 8 bytes */ /* reply type */ refbuf[2] = 6; refbuf[3] = 0; /* total connected users */ total = inbound_list.size(); memcpy(tmp, (char *)&total, 2); refbuf[6] = tmp[0]; refbuf[7] = tmp[1]; for (inbound_pos = inbound_list.begin(), i_idx = 0; inbound_pos != inbound_list.end(); inbound_pos++, i_idx++) { /* each entry has 20 bytes */ inbound_ptr = (inbound *)inbound_pos->second; if (!inbound_ptr->is_ref) { refbuf[8 + (20 * j_idx)] = inbound_ptr->mod; strcpy((char *)refbuf + 9 + (20 * j_idx), inbound_ptr->call); /* 11 bytes here */ refbuf[17 + (20 * j_idx)] = 0; /* refbuf[18 + (20 * j_idx)] = 0; */ if (memcmp(inbound_ptr->serial, "AP", 2) == 0) refbuf[18 + (20 * j_idx)] = 'A'; /* dvap */ else if (memcmp(inbound_ptr->serial, "DV019999", 8) == 0) refbuf[18 + (20 * j_idx)] = 'H'; /* spot */ else refbuf[18 + (20 * j_idx)] = 'D'; /* dongle */ refbuf[19 + (20 * j_idx)] = 0; refbuf[20 + (20 * j_idx)] = 0x0d; refbuf[21 + (20 * j_idx)] = 0x4d; refbuf[22 + (20 * j_idx)] = 0x37; refbuf[23 + (20 * j_idx)] = 0x4d; refbuf[24 + (20 * j_idx)] = 0x6f; refbuf[25 + (20 * j_idx)] = 0x98; refbuf[26 + (20 * j_idx)] = 0x04; refbuf[27 + (20 * j_idx)] = 0; j_idx++; if (j_idx == 39) { /* 20 bytes for each user, so 39 * 20 = 788 bytes + 8 bytes header = 788 */ refbuf[0] = 0x14; refbuf[1] = 0xc3; k_idx = i_idx - 38; memcpy(tmp, (char *)&k_idx, 2); refbuf[4] = tmp[0]; refbuf[5] = tmp[1]; sendto(ref_sock,(char *)refbuf,788,0, (struct sockaddr *)&fromInbound, sizeof(struct sockaddr_in)); j_idx = 0; } } } if (j_idx != 0) { k_idx = 8 + (j_idx * 20); memcpy(tmp, (char *)&k_idx, 2); refbuf[0] = tmp[0]; refbuf[1] = tmp[1] | 0xc0; if (i_idx > j_idx) k_idx = i_idx - j_idx; else k_idx = 0; mempcpy(tmp, (char *)&k_idx, 2); refbuf[4] = tmp[0]; refbuf[5] = tmp[1]; sendto(ref_sock,(char *)refbuf, 8 + (j_idx * 20), 0, (struct sockaddr *)&fromInbound, sizeof(struct sockaddr_in)); } } } else /* date request */ if ((recvlen3 == 4) && (refbuf[0] == 4) && (refbuf[1] == 192) && (refbuf[2] == 8) && (refbuf[3] == 0)) { time_t ltime; struct tm tm; sprintf(search_value, "%s-%s", an_ip, a_port); inbound_pos = inbound_list.find(search_value); if (inbound_pos != inbound_list.end()) { time(<ime); localtime_r(<ime,&tm); refbuf[0] = 34; refbuf[1] = 192; refbuf[2] = 8; refbuf[3] = 0; refbuf[4] = 0xb5; refbuf[5] = 0xae; refbuf[6] = 0x37; refbuf[7] = 0x4d; snprintf((char *)refbuf + 8, READBUFFER_SIZE - 1, "20%02d/%02d/%02d %02d:%02d:%02d %5.5s", tm.tm_year % 100, tm.tm_mon+1,tm.tm_mday, tm.tm_hour,tm.tm_min,tm.tm_sec, (tzname[0] == NULL)?" ":tzname[0]); sendto(ref_sock,(char *)refbuf,34,0, (struct sockaddr *)&fromInbound, sizeof(struct sockaddr_in)); } } else /* version request */ if ((recvlen3 == 4) && (refbuf[0] == 4) && (refbuf[1] == 192) && (refbuf[2] == 3) && (refbuf[3] == 0)) { sprintf(search_value, "%s-%s", an_ip, a_port); inbound_pos = inbound_list.find(search_value); if (inbound_pos != inbound_list.end()) { refbuf[0] = 9; refbuf[1] = 192; refbuf[2] = 3; refbuf[3] = 0; strncpy((char *)refbuf + 4, VERSION, 4); refbuf[8] = 0; sendto(ref_sock,(char *)refbuf,9,0, (struct sockaddr *)&fromInbound, sizeof(struct sockaddr_in)); } } else /* dvap, dvtool disconnects */ if ((recvlen3 == 5) && (refbuf[0] == 5) && (refbuf[1] == 0) && (refbuf[2] == 24) && (refbuf[3] == 0) && (refbuf[4] == 0)) { sprintf(search_value, "%s-%s", an_ip, a_port); inbound_pos = inbound_list.find(search_value); if (inbound_pos != inbound_list.end()) { /* reply with the same DISCONNECT */ sendto(ref_sock,(char *)refbuf,5,0, (struct sockaddr *)&fromInbound, sizeof(struct sockaddr_in)); inbound_ptr = (inbound *)inbound_pos->second; if (memcmp(inbound_ptr->call, "1NFO", 4) != 0) traceit("Call %s disconnected\n", inbound_ptr->call); free(inbound_pos->second); inbound_pos->second = NULL; inbound_list.erase(inbound_pos); } else traceit("Disconnect received from %s-%s\n", an_ip, a_port); } else if ((recvlen3 == 5) && (refbuf[0] == 5) && (refbuf[1] == 0) && (refbuf[2] == 24) && (refbuf[3] == 0) && (refbuf[4] == 1)) { /* If we already have this ip, that means that we already requested a link to ref */ sprintf(search_value, "%s-%s", an_ip, a_port); inbound_pos = inbound_list.find(search_value); if (inbound_pos != inbound_list.end()) { traceit("Connect request accepted from %s-%s, sending login\n", an_ip, a_port); /* send a login */ refbuf[0] = 28; refbuf[1] = 192; refbuf[2] = 4; refbuf[3] = 0; memcpy(refbuf + 4, ADMIN, CALL_SIZE); for (j = 11; j > 3; j--) { if (refbuf[j] == ' ') refbuf[j] = '\0'; else break; } memset(refbuf + 12, '\0', 8); memcpy(refbuf + 20, "DV019999", 8); sendto(ref_sock,(char *)refbuf,28,0, (struct sockaddr *)&fromInbound, sizeof(fromInbound)); } else /* They want to connect with our reflector */ { if ((inbound_list.size() + 1) > MAX_OTHER_USERS) traceit("Inbound connection from %s-%s but over the MAX_OTHER_USERS limit of %d\n", an_ip, a_port, inbound_list.size()); else sendto(ref_sock,(char *)refbuf,5,0, (struct sockaddr *)&fromInbound, sizeof(fromInbound)); } } else if ((recvlen3 == 8) && /* this is a response to our login request */ (refbuf[0] == 8) && (refbuf[1] == 192) && (refbuf[2] == 4) && (refbuf[3] == 0)) { /* we should already have the ip address in our list */ if ((refbuf[4] == 79) && (refbuf[5] == 75) && (refbuf[6] == 82)) traceit("Login OK to %s\n", an_ip); else traceit("Login to %s failed\n", an_ip); } else if ((recvlen3 == 28) && /* they want to login to our reflector */ (refbuf[0] == 28) && (refbuf[1] == 192) && (refbuf[2] == 4) && (refbuf[3] == 0)) { /* verify callsign */ memcpy(a_call, refbuf + 4, CALL_SIZE); a_call[CALL_SIZE] = '\0'; for (i = 7; i > 0; i--) { if (a_call[i] == '\0') a_call[i] = ' '; else break; } /*** if (memcmp(a_call, "1NFO", 4) != 0) traceit("Possible new connection: %s, ip=%s, DV=%.8s\n", a_call, an_ip, refbuf + 20); ***/ strcpy(a_call2, a_call); a_call2[7] = ' '; call_valid = regexec(&preg, a_call, 0, NULL, 0); if ((call_valid != REG_NOERROR) || (blocks.find(a_call2) != blocks.end()) || /* BLOCKED a_call */ (memcmp(a_call, OWNER, OWNER_SIZE) == 0)) /* a_call can NOT be our reflector */ { traceit("Invalid(or blocked) CALL=%s(%s),ip=%s,%s\n", a_call, a_call2, an_ip, a_port); refbuf[0] = 8; refbuf[4] = 70; refbuf[5] = 65; refbuf[6] = 73; refbuf[7] = 76; sendto(ref_sock,(char *)refbuf,8,0, (struct sockaddr *)&fromInbound, sizeof(fromInbound)); } else { if ((inbound_list.size() + 1) > MAX_OTHER_USERS) { traceit("Inbound connection from %s,%s but over the MAX_OTHER_USERS limit of %d\n", an_ip, a_port, inbound_list.size()); refbuf[0] = 8; refbuf[4] = 70; refbuf[5] = 65; refbuf[6] = 73; refbuf[7] = 76; sendto(ref_sock,(char *)refbuf,8,0, (struct sockaddr *)&fromInbound, sizeof(fromInbound)); } else { /* add the dongle to the inbound list */ inbound_ptr = (inbound *)malloc(sizeof(inbound)); if (inbound_ptr) { inbound_ptr->countdown = TIMEOUT; memcpy((char *)&(inbound_ptr->sin),(char *)&fromInbound, sizeof(struct sockaddr_in)); strcpy(inbound_ptr->call, a_call); time(&(inbound_ptr->connect_time)); inbound_ptr->isMute = false; inbound_ptr->mod = ' '; inbound_ptr->is_ref = false; inbound_ptr->links[0] = inbound_ptr->links[1] = inbound_ptr->links[2] = inbound_ptr->links[3] = inbound_ptr->links[4] = ' '; memcpy(inbound_ptr->serial, refbuf + 20, 8); inbound_ptr->serial[8] = '\0'; sprintf(search_value, "%s-%s", an_ip, a_port); inbound_insert_pair = inbound_list.insert(pair<string, inbound *>(search_value, inbound_ptr)); if (inbound_insert_pair.second) { if (memcmp(inbound_ptr->call, "1NFO", 4) != 0) traceit("new CALL=%s,DONGLE,ip=%s-%s, DV=%.8s, users=%d\n", inbound_ptr->call,an_ip, a_port, refbuf + 20, inbound_list.size() + a_user_list.size()); refbuf[0] = 8; refbuf[4] = 79; refbuf[5] = 75; refbuf[6] = 82; refbuf[7] = 87; sendto(ref_sock,(char *)refbuf,8,0, (struct sockaddr *)&fromInbound, sizeof(fromInbound)); } else { traceit("failed to add CALL=%s,ip=%s,%s\n",inbound_ptr->call,an_ip,a_port); free(inbound_ptr); inbound_ptr = NULL; refbuf[0] = 8; refbuf[4] = 70; refbuf[5] = 65; refbuf[6] = 73; refbuf[7] = 76; sendto(ref_sock,(char *)refbuf,8,0, (struct sockaddr *)&fromInbound, sizeof(fromInbound)); } } else { traceit("malloc() failed for call=%s,ip=%s,%s\n",a_call,an_ip,a_port); refbuf[0] = 8; refbuf[4] = 70; refbuf[5] = 65; refbuf[6] = 73; refbuf[7] = 76; sendto(ref_sock,(char *)refbuf,8,0, (struct sockaddr *)&fromInbound, sizeof(fromInbound)); } } } } else if ((recvlen3 == 3) && (memcmp(refbuf, REF_ACK, 3) == 0)) /* keepalive */ { sprintf(search_value, "%s-%s", an_ip, a_port); inbound_pos = inbound_list.find(search_value); if (inbound_pos != inbound_list.end()) { inbound_ptr = (inbound *)inbound_pos->second; inbound_ptr->countdown = TIMEOUT; } } else if ( ((recvlen3 == 58) || (recvlen3 == 29) || (recvlen3 == 32)) && (memcmp(refbuf + 2, "DSVT", 4) == 0) && ((refbuf[6] == 0x10) || (refbuf[6] == 0x20)) && (refbuf[10] == 0x20)) { found = false; sprintf(search_value, "%s-%s", an_ip, a_port); inbound_pos = inbound_list.find(search_value); if (inbound_pos != inbound_list.end()) { inbound_ptr = (inbound *)inbound_pos->second; inbound_ptr->countdown = TIMEOUT; /* We drop audio from muted stations */ if (!inbound_ptr->isMute) found = true; if (recvlen3 == 58) { memcpy(a_call, refbuf + 44, CALL_SIZE); a_call[CALL_SIZE] = '\0'; call_valid = regexec(&preg, a_call, 0, NULL, 0); if (call_valid != REG_NOERROR) { traceit("User callsign [%s] not valid, audio from [%s] will not be transmitted\n", a_call, search_value); found = false; } else { a_call[7] = ' '; if (blocks.find(a_call) != blocks.end()) { traceit("User callsign [%s] blocked, audio from [%s] will not be transmitted\n", a_call, search_value); found = false; } } } } if (found) { sprintf(an_rcd_streamid,"%s-%d,%d", an_ip,refbuf[14],refbuf[15]); if (recvlen3 == 58) { if (QSO_DETAILS) { if (!inbound_ptr->is_ref) source_mod = ' '; else { if (refbuf[35] == 'G') source_mod = refbuf[27]; else if (refbuf[27] == 'G') source_mod = refbuf[35]; else source_mod = refbuf[27]; } traceit("START user: streamID=%d,%d, my=%.8s, sfx=%.4s, ur=%.8s, rpt1=%.8s, rpt2=%.8s, %d bytes fromIP=%s, src=%.8s %c\n", refbuf[14],refbuf[15],&refbuf[44], &refbuf[52], &refbuf[36], &refbuf[20], &refbuf[28], recvlen3, an_ip, inbound_ptr->call, source_mod); } /* the crazy shit */ /* replace the rpt1 name and rpt2 name with our callsign */ /* leave the module of the remote system untouched */ if (refbuf[35] == 'G') /* dongle, */ { memcpy(refbuf + 20, OWNER, 7); memcpy(refbuf + 28, OWNER, 7); } else if (refbuf[27] == 'G') /* RF user thru local repeater ---> reflector */ { refbuf[27] = refbuf[35]; refbuf[35] = 'G'; memcpy(refbuf + 20, OWNER, 7); memcpy(refbuf + 28, OWNER, 7); } else /* dvap */ { memcpy(refbuf + 20, OWNER, 7); memcpy(refbuf + 28, OWNER, 7); refbuf[35] = 'G'; } } else { if ((refbuf[16] & 0x40) != 0) { if (QSO_DETAILS) traceit("END user: streamID=%d,%d, %d bytes from IP=%s\n", refbuf[14],refbuf[15],recvlen3, an_ip); } } /* send the data to repeaters */ if (recvlen3 == 58) { source_mod = ' '; if (inbound_ptr->is_ref) { for (i = 0; i < 5; i++) { /* if the remote module matches */ if ((inbound_ptr->links[i] == refbuf[27]) && (refbuf[27] != ' ')) { if (i == 0) refbuf[27] = 'A'; else if (i == 1) refbuf[27] = 'B'; else if (i == 2) refbuf[27] = 'C'; else if (i == 3) refbuf[27] = 'D'; else refbuf[27] = 'E'; source_mod = refbuf[27]; if (refbuf[27] == 'E') { rcd_pos = rcd_list.find(an_rcd_streamid); if (rcd_pos == rcd_list.end()) { if (rcd_list.size() < MAX_RCD_USERS) { an_rcd = (struct rcd *)malloc(sizeof(struct rcd)); if (an_rcd) { an_rcd->locked = false; time(&(an_rcd->ts)); /* stamp it */ memcpy((char *)&(an_rcd->sin), (char *)&fromInbound, sizeof(struct sockaddr_in)); memcpy(an_rcd->data[0], refbuf, recvlen3); an_rcd->recvlen = recvlen3; an_rcd->idx = 1; rcd_insert_pair = rcd_list.insert(pair<string, struct rcd *>(an_rcd_streamid, an_rcd)); if (rcd_insert_pair.second) ; // traceit("Started recording for user %.8s, streamid=%d,%d\n", // refbuf + 44, refbuf[14],refbuf[15]); else { traceit("failed to add user %.8s, streamid=%d,%d, for recording...\n", refbuf + 44, refbuf[14],refbuf[15]); free(an_rcd); an_rcd = NULL; } } else traceit("Failed to allocate for recording on user %.8s, streamid=%d,%d\n", refbuf + 44, refbuf[14],refbuf[15]); } else traceit("Reached maximum concurrent users for recording\n"); } } /* This user is talking on this module */ inbound_ptr->mod = refbuf[27]; // put user into tmp1 memcpy(tmp1, refbuf + 44, 8); tmp1[8] = '\0'; // delete the user if exists for (dt_lh_pos = dt_lh_list.begin(); dt_lh_pos != dt_lh_list.end(); dt_lh_pos++) { if (strcmp((char *)dt_lh_pos->second.c_str(), tmp1) == 0) { dt_lh_list.erase(dt_lh_pos); break; } } /* Limit?, delete oldest user */ if (dt_lh_list.size() == LH_MAX_SIZE) { dt_lh_pos = dt_lh_list.begin(); dt_lh_list.erase(dt_lh_pos); } /* add user */ time(&tNow); sprintf(tmp2, "%ld=%.7s%c", tNow, inbound_ptr->call, refbuf[27]); dt_lh_list[tmp2] = tmp1; if (rcd_list.find(an_rcd_streamid) == rcd_list.end()) { /*************** REPLACEMENT to send_a_pkt_to_all **************************************/ /* send header to repeaters */ if (refbuf[27] == 'A') k = 0; else if (refbuf[27] == 'B') k = 1; else if (refbuf[27] == 'C') k = 2; else if (refbuf[27] == 'D') k = 3; else k = -1; if (k >= 0) { temp_x[k].old_sid[0] = refbuf[14]; temp_x[k].old_sid[1] = refbuf[15]; streamid_raw = (refbuf[14] * 256U) + refbuf[15]; streamid_raw ++; if (streamid_raw == 0) streamid_raw ++; memcpy(temp_x[k].hdr, refbuf + 2, 56); temp_x[k].hdr[12] = streamid_raw / 256U; temp_x[k].hdr[13] = streamid_raw % 256U; temp_x[k].s_addr = fromInbound.sin_addr.s_addr; for (user_pos = a_user_list.begin(); user_pos != a_user_list.end(); user_pos++) { a_user_ptr = (struct a_user *)user_pos->second; if ((a_user_ptr->rpt_mods[k][0] != '\0') || (a_user_ptr->rpt_mods[k][1] != '\0') || (a_user_ptr->rpt_mods[k][2] != '\0') || (a_user_ptr->rpt_mods[k][3] != '\0')) sendto(srv_sock, (char *)temp_x[k].hdr, 56, 0,(struct sockaddr *)&(a_user_ptr->sin), sizeof(struct sockaddr_in)); } } /*********************************************************************************************/ } break; } } } else if (refbuf[27] != ' ') { source_mod = refbuf[27]; if (refbuf[27] == 'E') { rcd_pos = rcd_list.find(an_rcd_streamid); if (rcd_pos == rcd_list.end()) { if (rcd_list.size() < MAX_RCD_USERS) { an_rcd = (struct rcd *)malloc(sizeof(struct rcd)); if (an_rcd) { an_rcd->locked = false; time(&(an_rcd->ts)); /* stamp it */ memcpy((char *)&(an_rcd->sin), (char *)&fromInbound, sizeof(struct sockaddr_in)); memcpy(an_rcd->data[0], refbuf, recvlen3); an_rcd->recvlen = recvlen3; an_rcd->idx = 1; rcd_insert_pair = rcd_list.insert(pair<string, struct rcd *>(an_rcd_streamid, an_rcd)); if (rcd_insert_pair.second) ; // traceit("Started recording for user %.8s, streamid=%d,%d\n", // refbuf + 44, refbuf[14],refbuf[15]); else { traceit("failed to add user %.8s, streamid=%d,%d, for recording...\n", refbuf + 44, refbuf[14],refbuf[15]); free(an_rcd); an_rcd = NULL; } } else traceit("Failed to allocate for recording on user %.8s, streamid=%d,%d\n", refbuf + 44, refbuf[14],refbuf[15]); } else traceit("Reached maximum concurrent users for recording\n"); } } /* This user is talking on this module */ inbound_ptr->mod = refbuf[27]; // put user into tmp1 memcpy(tmp1, refbuf + 44, 8); tmp1[8] = '\0'; // delete the user if exists for (dt_lh_pos = dt_lh_list.begin(); dt_lh_pos != dt_lh_list.end(); dt_lh_pos++) { if (strcmp((char *)dt_lh_pos->second.c_str(), tmp1) == 0) { dt_lh_list.erase(dt_lh_pos); break; } } /* Limit?, delete oldest user */ if (dt_lh_list.size() == LH_MAX_SIZE) { dt_lh_pos = dt_lh_list.begin(); dt_lh_list.erase(dt_lh_pos); } time(&tNow); sprintf(tmp2, "%ld=%.7s%c", tNow, inbound_ptr->call, refbuf[27]); dt_lh_list[tmp2] = tmp1; if (rcd_list.find(an_rcd_streamid) == rcd_list.end()) { /********************** REPLACEMENT to send_a_pkt_to_all ***********************************************/ /* send header to repeaters */ if (refbuf[27] == 'A') k = 0; else if (refbuf[27] == 'B') k = 1; else if (refbuf[27] == 'C') k = 2; else if (refbuf[27] == 'D') k = 3; else k = -1; if (k >= 0) { temp_x[k].old_sid[0] = refbuf[14]; temp_x[k].old_sid[1] = refbuf[15]; streamid_raw = (refbuf[14] * 256U) + refbuf[15]; streamid_raw ++; if (streamid_raw == 0) streamid_raw ++; memcpy(temp_x[k].hdr, refbuf + 2, 56); temp_x[k].hdr[12] = streamid_raw / 256U; temp_x[k].hdr[13] = streamid_raw % 256U; temp_x[k].s_addr = fromInbound.sin_addr.s_addr; for (user_pos = a_user_list.begin(); user_pos != a_user_list.end(); user_pos++) { a_user_ptr = (struct a_user *)user_pos->second; if ((a_user_ptr->rpt_mods[k][0] != '\0') || (a_user_ptr->rpt_mods[k][1] != '\0') || (a_user_ptr->rpt_mods[k][2] != '\0') || (a_user_ptr->rpt_mods[k][3] != '\0')) sendto(srv_sock, (char *)temp_x[k].hdr, 56, 0,(struct sockaddr *)&(a_user_ptr->sin), sizeof(struct sockaddr_in)); } } /**********************************************************************************************************/ } } } else { rcd_pos = rcd_list.find(an_rcd_streamid); if (rcd_pos != rcd_list.end()) { an_rcd = (struct rcd *)rcd_pos->second; time(&(an_rcd->ts)); /* stamp it */ if ((an_rcd->idx < MAX_RCD_DATA) && !(an_rcd->locked)) { memcpy(an_rcd->data[an_rcd->idx], refbuf, recvlen3); an_rcd->idx ++; } if (((refbuf[16] & 0x40) != 0) && !(an_rcd->locked)) { /*** traceit("Finished recording for user %.8s, streamid=%d,%d\n", &(an_rcd->data[0][44]), refbuf[14], refbuf[15]); ***/ /*** start playback */ an_rcd->locked = true; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); rc = pthread_create(&playback_thread,&attr,playback,(void *)rcd_pos->second); if (rc != 0) { traceit("Failed to start the playback thread for streamid=%d,%d\n", refbuf[14], refbuf[15]); free(rcd_pos->second); rcd_pos->second = NULL; rcd_list.erase(rcd_pos); } pthread_attr_destroy(&attr); } } else { /******************************* REPLACEMENT to send_a_pkt_to_all **********************************/ for (user_pos = a_user_list.begin(); user_pos != a_user_list.end(); user_pos++) { a_user_ptr = (struct a_user *)user_pos->second; /* source must NOT be a reflector */ if (!(inbound_ptr->is_ref)) { if ((refbuf[26] == 0x55) && (refbuf[27] == 0x2d) && (refbuf[28] == 0x16)) { for (k = 0; k < 4; k++) { if ((refbuf[14] == temp_x[k].old_sid[0]) && (refbuf[15] == temp_x[k].old_sid[1]) && (fromInbound.sin_addr.s_addr == temp_x[k].s_addr) && ((a_user_ptr->rpt_mods[k][0] != '\0') || /* module is linked */ (a_user_ptr->rpt_mods[k][1] != '\0') || (a_user_ptr->rpt_mods[k][2] != '\0') || (a_user_ptr->rpt_mods[k][3] != '\0'))) { sendto(srv_sock, (char *)temp_x[k].hdr, 56, 0, (struct sockaddr *)&(a_user_ptr->sin), sizeof(struct sockaddr_in)); break; } } } } for (k = 0; k < 4; k++) { if ((refbuf[14] == temp_x[k].old_sid[0]) && (refbuf[15] == temp_x[k].old_sid[1]) && (fromInbound.sin_addr.s_addr == temp_x[k].s_addr) && ((a_user_ptr->rpt_mods[k][0] != '\0') || /* module is linked */ (a_user_ptr->rpt_mods[k][1] != '\0') || (a_user_ptr->rpt_mods[k][2] != '\0') || (a_user_ptr->rpt_mods[k][3] != '\0'))) { refbuf[14] = temp_x[k].hdr[12]; refbuf[15] = temp_x[k].hdr[13]; sendto(srv_sock, (char *)(refbuf + 2), 27, 0,(struct sockaddr *)&(a_user_ptr->sin), sizeof(struct sockaddr_in)); refbuf[14] = temp_x[k].old_sid[0]; refbuf[15] = temp_x[k].old_sid[1]; break; } } } /***************************************************************************************************/ } } /* At this point, if this is a header, it contains our reflector info */ /* save the header for re-transmit */ if (recvlen3 == 58) { i = -1; if (source_mod == 'A') i = 0; else if (source_mod == 'B') i = 1; else if (source_mod == 'C') i = 2; else if (source_mod == 'D') i = 3; if (i >= 0) { temp_r[i].s_addr = fromInbound.sin_addr.s_addr; memcpy(temp_r[i].hdr, refbuf, 58); } } /* send the data to dvap, dvtool stations */ if (rcd_list.find(an_rcd_streamid) == rcd_list.end()) { for (inbound_pos2 = inbound_list.begin(); inbound_pos2 != inbound_list.end(); inbound_pos2++) { if (strcmp(inbound_pos2->first.c_str(), inbound_pos->first.c_str()) != 0) { inbound_ptr2 = (inbound *)inbound_pos2->second; if (recvlen3 == 58) { /* if it is a reflector, we must send its own call */ if (inbound_ptr2->is_ref) { if (i >= 0) { if (inbound_ptr2->links[i] != ' ') { memcpy(refbuf + 20, inbound_ptr2->call, 7); refbuf[27] = inbound_ptr2->links[i]; memcpy(refbuf + 28, inbound_ptr2->call, 7); sendto(ref_sock, (char *)refbuf, recvlen3, 0, (struct sockaddr *)&(inbound_ptr2->sin), sizeof(struct sockaddr_in)); } } } else { if (i >= 0) { memcpy(refbuf + 20, OWNER, 7); refbuf[27] = source_mod; memcpy(refbuf + 28, OWNER, 7); sendto(ref_sock, (char *)refbuf, recvlen3, 0, (struct sockaddr *)&(inbound_ptr2->sin), sizeof(struct sockaddr_in)); } } } else { if ((refbuf[26] == 0x55) && (refbuf[27] == 0x2d) && (refbuf[28] == 0x16)) { if ((!inbound_ptr2->is_ref) && (!inbound_ptr->is_ref)) { for (i = 0; i < 4; i++) { if ((refbuf[14] == temp_r[i].hdr[14]) && (refbuf[15] == temp_r[i].hdr[15]) && (fromInbound.sin_addr.s_addr == temp_r[i].s_addr)) { sendto(ref_sock, (char *)temp_r[i].hdr, 58, 0, (struct sockaddr *)&(inbound_ptr2->sin), sizeof(struct sockaddr_in)); break; } } } } /* if it is a regular dongle, send it */ if (!inbound_ptr2->is_ref) sendto(ref_sock, (char *)refbuf, recvlen3, 0, (struct sockaddr *)&(inbound_ptr2->sin), sizeof(struct sockaddr_in)); else { /* treat the remote reflector with resepct */ /* send it only if the module matches */ for (i = 0; i < 4; i++) { if ((refbuf[14] == temp_r[i].hdr[14]) && (refbuf[15] == temp_r[i].hdr[15]) && (fromInbound.sin_addr.s_addr == temp_r[i].s_addr) && (inbound_ptr2->links[i] != ' ')) { sendto(ref_sock, (char *)refbuf, recvlen3, 0, (struct sockaddr *)&(inbound_ptr2->sin), sizeof(struct sockaddr_in)); break; } } } } } } } } } FD_CLR (ref_sock,&fdset); } /* process input from repeaters */ if (FD_ISSET(srv_sock, &fdset)) { fromlen = sizeof(struct sockaddr_in); recvlen = recvfrom(srv_sock,(char *)readBuffer,READBUFFER_SIZE, 0,(struct sockaddr *)&fromUser,&fromlen); strncpy(an_ip, inet_ntoa(fromUser.sin_addr),IP_SIZE); an_ip[IP_SIZE] = '\0'; a_user_ptr = NULL; if ((recvlen == (CALL_SIZE + 1)) || (recvlen == (CALL_SIZE + 3))) { readBuffer[(recvlen - 1)] = '\0'; strncpy(a_call, (char *)readBuffer,CALL_SIZE); a_call[CALL_SIZE] = '\0'; /* is this a new user? */ user_pos = a_user_list.find(an_ip); if (user_pos != a_user_list.end()) { /* We found it */ /* point to the data of the connected user */ a_user_ptr = (struct a_user *)user_pos->second; /* update its countdown */ a_user_ptr->countdown = TIMEOUT; /* repeater request, an un-link request arrived ? Example: DB0SAT space space B space NULL This means that repeater DB0SAT wants to unlink its module B from reflector */ if (recvlen == (CALL_SIZE + 3)) { // traceit("Possible new link/unlink request: %.*s\n", recvlen - 1, readBuffer); /* remote repeater band */ if ((readBuffer[8] == 'A') || (readBuffer[8] == 'B') || (readBuffer[8] == 'C') || (readBuffer[8] == 'D')) { /* local reflector module */ if (readBuffer[9] == ' ') { traceit("Call %s mod %c drops the link\n", a_call, readBuffer[8]); /* this is the the remote repeater band */ if (readBuffer[8] == 'A') k = 0; else if (readBuffer[8] == 'B') k = 1; else if (readBuffer[8] == 'C') k = 2; else k = 3; /* for all the reflector modules, zero out the repeater band */ for (i = 0; i < 5; i++) { /*** inform the remote XRF reflector: start ***/ if (a_user_ptr->is_xrf) { if (a_user_ptr->rpt_mods[i][k] != '\0') { memcpy(reply_to_xrf, OWNER, 8); if (i == 0) reply_to_xrf[8] = 'A'; else if (i == 1) reply_to_xrf[8] = 'B'; else if (i == 2) reply_to_xrf[8] = 'C'; else if (i == 3) reply_to_xrf[8] = 'D'; else reply_to_xrf[8] = 'E'; reply_to_xrf[9] = ' '; reply_to_xrf[10] = '\0'; for (j = 0; j < 5; j++) sendto(srv_sock, reply_to_xrf, CALL_SIZE + 3, 0,(struct sockaddr *)&(a_user_ptr->sin), sizeof(struct sockaddr_in)); } } /*** inform the remote XRF reflector: end ***/ a_user_ptr->rpt_mods[i][k] = '\0'; a_user_ptr->link_time[i][k] = 0; } print_links_file(); /* if this repeater has unlinked everything, disconnect it */ for (i = 0; i < 5; i++) { for (k = 0; k < 4; k++) { if (a_user_ptr->rpt_mods[i][k] != '\0') break; } if (k < 4) break; } if (i == 5) { /* All linked modules have been unlinked, disconnect the repeater */ traceit("All linked modules from %s have been unlinked, disconnecting...\n", a_call); free(user_pos->second); a_user_ptr = user_pos->second = NULL; a_user_list.erase(user_pos); traceit("User %s ip=%s removed\n", a_call, an_ip); } } else { /* A link request from remote repeater Example: DB0SAT space space BC NULL This means that repeater DB0SAT wants to link its module B to our reflector module C */ /* local reflector module */ if ((readBuffer[9] == 'A') || (readBuffer[9] == 'B') || (readBuffer[9] == 'C') || (readBuffer[9] == 'D') || (readBuffer[9] == 'E')) { /* local reflector module */ if (readBuffer[9] == 'A') i = 0; else if (readBuffer[9] == 'B') i = 1; else if (readBuffer[9] == 'C') i = 2; else if (readBuffer[9] == 'D') i = 3; else i = 4; /* remote repeater band */ if (readBuffer[8] == 'A') k = 0; else if (readBuffer[8] == 'B') k = 1; else if (readBuffer[8] == 'C') k = 2; else k = 3; for (j = 0; j < 5; j++) { if (i == j) { /*** inform the remote XRF reflector: start ***/ if (a_user_ptr->is_xrf) { if (a_user_ptr->rpt_mods[i][k] != readBuffer[8]) { memcpy(reply_to_xrf, OWNER, 8); reply_to_xrf[8] = readBuffer[9]; reply_to_xrf[9] = readBuffer[8]; reply_to_xrf[10] = '\0'; for (n = 0; n < 5; n++) sendto(srv_sock, reply_to_xrf, CALL_SIZE + 3, 0,(struct sockaddr *)&(a_user_ptr->sin), sizeof(struct sockaddr_in)); } } /*** inform the remote XRF reflector: end ***/ a_user_ptr->rpt_mods[i][k] = readBuffer[8]; time(&a_user_ptr->link_time[i][k]); } else { a_user_ptr->rpt_mods[j][k] = '\0'; a_user_ptr->link_time[j][k] = 0; } } /*** traceit("Link established from %s mod %c ---> mod %c\n", a_user_ptr->call, readBuffer[8], readBuffer[9]); ***/ print_links_file(); if (!a_user_ptr->is_xrf) { memcpy(readBuffer + 10, "ACK", 4); sendto(srv_sock, readBuffer, CALL_SIZE + 6, 0,(struct sockaddr *)&(a_user_ptr->sin), sizeof(struct sockaddr_in)); } } } } } } else { allowed_to_connect = true; // traceit("Possible new connection: %.*s ip=%s\n", recvlen - 1, readBuffer, an_ip); do { /* ONWER can not connect to itself */ if (memcmp(a_call,OWNER,CALL_SIZE) == 0) { allowed_to_connect = false; break; } /* reached capacity */ if (a_user_list.size() + 1 > MAX_USERS) { // traceit("Reached MAX_USERS capacity\n"); allowed_to_connect = false; break; } /* Is this callsign blocked? */ block_pos = blocks.find(a_call); if (block_pos != blocks.end()) { // traceit("Callsign is blocked\n"); allowed_to_connect = false; break; } /* if it is XRF, do we want to accept it? */ if (memcmp(a_call, "XRF", 3) == 0) { pos = call_ip_map.find(a_call); if (pos == call_ip_map.end()) { allowed_to_connect = false; break; } } } while (false); if (allowed_to_connect) { /* do we have a repeater in the database? */ call_valid = regexec(&preg, a_call, 0, NULL, 0); if (recvlen == (CALL_SIZE + 3)) { if ((call_valid != REG_NOERROR) && (memcmp(a_call, "XRF", 3) != 0)) { // traceit("Received link information from %s %s but call is not valid\n", a_call, an_ip); allowed_to_connect = false; } else { /* reflector module */ if ((readBuffer[9] != 'A') && (readBuffer[9] != 'B') && (readBuffer[9] != 'C') && (readBuffer[9] != 'D') && (readBuffer[9] != 'E')) allowed_to_connect = false; else /* repeater band */ if ((readBuffer[8] != 'A') && (readBuffer[8] != 'B') && (readBuffer[8] != 'C') && (readBuffer[8] != 'D')) allowed_to_connect = false; } } else allowed_to_connect = false; } if (allowed_to_connect) { /* about to add the new user to the BST/map */ a_user_ptr = (struct a_user *)malloc(sizeof(struct a_user)); if (a_user_ptr) { /* Initialize the data for the new user */ a_user_ptr->countdown = TIMEOUT; memcpy((char *)&(a_user_ptr->sin), (char *)&fromUser, sizeof(struct sockaddr_in)); strncpy(a_user_ptr->call, a_call, CALL_SIZE); a_user_ptr->call[CALL_SIZE] = '\0'; a_user_ptr->isMute = false; time(&(a_user_ptr->connect_time)); if (memcmp(a_user_ptr->call, "XRF", 3) == 0) a_user_ptr->is_xrf = true; else a_user_ptr->is_xrf = false; a_user_ptr->sin.sin_port = htons(LISTEN_PORT); /* Initialize links */ for (i = 0; i < 5; i++) { for (k = 0; k < 4; k++) { a_user_ptr->rpt_mods[i][k] = '\0'; a_user_ptr->link_time[i][k] = 0; } } a_user_ptr->mod = ' '; if (recvlen == (CALL_SIZE + 3)) { /* A repeater requesting a specific link. set the link corrrectly. */ /* local reflector module */ if (readBuffer[9] == 'A') i = 0; else if (readBuffer[9] == 'B') i = 1; else if (readBuffer[9] == 'C') i = 2; else if (readBuffer[9] == 'D') i = 3; else i = 4; /* remote repeater band */ if (readBuffer[8] == 'A') k = 0; else if (readBuffer[8] == 'B') k = 1; else if (readBuffer[8] == 'C') k = 2; else k = 3; a_user_ptr->rpt_mods[i][k] = readBuffer[8]; time(&a_user_ptr->link_time[i][k]); } /* Add new user to the connected list */ user_insert_pair = a_user_list.insert(pair<string, struct a_user *>(an_ip, a_user_ptr)); if (user_insert_pair.second) { traceit("new CALL=%s,REPEATER,ip=%s,users=%d, link from remote mod %c ---> local mod %c\n", a_call, an_ip, a_user_list.size() + inbound_list.size(), readBuffer[8], readBuffer[9]); print_links_file(); if (!a_user_ptr->is_xrf) { memcpy(readBuffer + 10, "ACK", 4); sendto(srv_sock, readBuffer, CALL_SIZE + 6, 0,(struct sockaddr *)&(a_user_ptr->sin), sizeof(struct sockaddr_in)); } else { /*** inform the remote XRF reflector: start ***/ memcpy(reply_to_xrf, OWNER, 8); reply_to_xrf[8] = readBuffer[9]; reply_to_xrf[9] = readBuffer[8]; reply_to_xrf[10] = '\0'; for (n = 0; n < 5; n++) sendto(srv_sock, reply_to_xrf, CALL_SIZE + 3, 0,(struct sockaddr *)&(a_user_ptr->sin), sizeof(struct sockaddr_in)); /*** inform the remote XRF reflector: end ***/ } } else { traceit("Failed to add CALL=%s,ip=%s\n",a_call,an_ip); /* If it was a link request, send back a NAK */ memcpy(readBuffer + 10, "NAK", 4); sendto(srv_sock, readBuffer, CALL_SIZE + 6, 0,(struct sockaddr *)&(a_user_ptr->sin), sizeof(struct sockaddr_in)); free(a_user_ptr); a_user_ptr = NULL; } } else { traceit("malloc() failed for call=%s,ip=%s\n",a_call, an_ip); /* If it was a link request, send back a NAK */ if (recvlen == (CALL_SIZE + 3)) { memcpy(readBuffer + 10, "NAK", 4); fromUser.sin_port = htons(LISTEN_PORT); sendto(srv_sock, readBuffer, CALL_SIZE + 6, 0,(struct sockaddr *)&fromUser, sizeof(struct sockaddr_in)); } } } else { /* If it was a link request, send back a NAK. If it was an unlink request, do nothing */ if (recvlen == (CALL_SIZE + 3)) { if ((readBuffer[8] != ' ') && (readBuffer[9] == ' ')) ; else { memcpy(readBuffer + 10, "NAK", 4); fromUser.sin_port = htons(LISTEN_PORT); sendto(srv_sock, readBuffer, CALL_SIZE + 6, 0,(struct sockaddr *)&fromUser, sizeof(struct sockaddr_in)); } } } } } else if ((recvlen == 56) || (recvlen == 27)) { found = false; user_pos = a_user_list.find(an_ip); if (user_pos != a_user_list.end()) { a_user_ptr = (struct a_user *)user_pos->second; a_user_ptr->countdown = TIMEOUT; if (!a_user_ptr->isMute) found = true; if (recvlen == 56) { memcpy(a_call, readBuffer + 42, CALL_SIZE); a_call[CALL_SIZE] = '\0'; call_valid = regexec(&preg, a_call, 0, NULL, 0); if (call_valid != REG_NOERROR) { traceit("User callsign [%s] not valid, audio from [%s] will not be transmitted\n", a_call, an_ip); found = false; } else { a_call[7] = ' '; if (blocks.find(a_call) != blocks.end()) { traceit("User callsign [%s] blocked, audio from [%s] will not be transmitted\n", a_call, an_ip); found = false; } } /* last check, to make sure audio is from a valid linked source band */ if (found) { // source band must be one of: A B C D source_mod = '?'; // assume bad source module if (a_user_ptr->is_xrf) { /* a remote reflector sends its own data */ /* remote band of reflector */ if (readBuffer[25] == 'A') k = 0; else if (readBuffer[25] == 'B') k = 1; else if (readBuffer[25] == 'C') k = 2; else if (readBuffer[25] == 'D') k = 3; else k = -1; if (k >= 0) { // find our local module for (i = 0; i < 5; i++) { if (a_user_ptr->rpt_mods[i][k] == readBuffer[25]) { source_mod = readBuffer[25]; // band of remote reflector /* set rpt2 */ memcpy(readBuffer + 26, OWNER, OWNER_SIZE); readBuffer[33] = 'G'; /* set rpt1 */ memcpy(readBuffer + 18, OWNER, 7); // set our local module if (i == 0) readBuffer[25] = 'A'; else if (i == 1) readBuffer[25] = 'B'; else if (i == 2) readBuffer[25] = 'C'; else if (i == 3) readBuffer[25] = 'D'; else readBuffer[25] = 'E'; break; } } } } else { /* A remote repeater sends our data. rpt1 contains our reflector module, we can NOT use that, we have to find the band of the repeater. Since a repeater may have more than one band linked to our reflector module, we will use byte 11 as incoming source band. If the repeater did not use g2_link to link to our reflector, then that repeater must be modified to support the new XRF features of multilinking, */ if ((readBuffer[11] >= 'A') && (readBuffer[11] <= 'D')) source_mod = readBuffer[11]; // band of remote repeater else { /* repeater is not using g2_link, try this */ /* byte 25 is our reflector mod */ if (readBuffer[25] == 'A') i = 0; else if (readBuffer[25] == 'B') i = 1; else if (readBuffer[25] == 'C') i = 2; else if (readBuffer[25] == 'D') i = 3; else if (readBuffer[25] == 'E') i = 4; else i = -1; /* now find the first band of the remote repeater linked to our reflector mod */ if (i >= 0) { for (k = 0; k < 4; k++) { if (a_user_ptr->rpt_mods[i][k] != '\0') { source_mod = a_user_ptr->rpt_mods[i][k]; /* we found it */ if (readBuffer[33] == 'G') { memcpy(readBuffer + 18, OWNER, 7); memcpy(readBuffer + 26, OWNER, 7); } else if (readBuffer[25] == 'G') { readBuffer[25] = readBuffer[33]; readBuffer[33] = 'G'; memcpy(readBuffer + 18, OWNER, 7); memcpy(readBuffer + 26, OWNER, 7); } else { memcpy(readBuffer + 18, OWNER, 7); memcpy(readBuffer + 26, OWNER, 7); readBuffer[33] = 'G'; } break; } } } } } if ((source_mod >= 'A') && (source_mod <= 'D')) ; else { if (QSO_DETAILS) traceit("Invalid streamID: %d,%d, my=%.8s, rpt1=%.8s, rpt2=%.8s, %d bytes fromIP=%s\n", readBuffer[12],readBuffer[13], &readBuffer[42], &readBuffer[18], &readBuffer[26], recvlen, an_ip); found = false; } } } } if (found) { sprintf(an_rcd_streamid,"%s-%d,%d", an_ip, readBuffer[12], readBuffer[13]); if (recvlen == 56) { if (QSO_DETAILS) traceit("START user: streamID=%d,%d, my=%.8s, sfx=%.4s, ur=%.8s, rpt1=%.8s, rpt2=%.8s, %d bytes fromIP=%s, src=%.8s %c\n", readBuffer[12],readBuffer[13],&readBuffer[42], &readBuffer[50], &readBuffer[34], &readBuffer[18], &readBuffer[26], recvlen, an_ip, a_user_ptr->call, source_mod); memcpy(tmp1, readBuffer + 42, 8); tmp1[8] = '\0'; // delete the user if exists for (dt_lh_pos = dt_lh_list.begin(); dt_lh_pos != dt_lh_list.end(); dt_lh_pos++) { if (strcmp((char *)dt_lh_pos->second.c_str(), tmp1) == 0) { dt_lh_list.erase(dt_lh_pos); break; } } /* Limit?, delete oldest user */ if (dt_lh_list.size() == LH_MAX_SIZE) { dt_lh_pos = dt_lh_list.begin(); dt_lh_list.erase(dt_lh_pos); } time(&tNow); sprintf(tmp2, "%ld=%.6s%c%c", tNow, a_user_ptr->call, source_mod, readBuffer[25]); dt_lh_list[tmp2] = tmp1; /* This user is talking on this module */ a_user_ptr->mod = readBuffer[25]; if (readBuffer[25] == 'E') { rcd_pos = rcd_list.find(an_rcd_streamid); if (rcd_pos == rcd_list.end()) { if (rcd_list.size() < MAX_RCD_USERS) { an_rcd = (struct rcd *)malloc(sizeof(struct rcd)); if (an_rcd) { an_rcd->locked = false; time(&(an_rcd->ts)); /* stamp it */ memcpy((char *)&(an_rcd->sin), (char *)&(a_user_ptr->sin), sizeof(struct sockaddr_in)); memcpy(an_rcd->data[0], readBuffer, recvlen); an_rcd->recvlen = recvlen; an_rcd->idx = 1; rcd_insert_pair = rcd_list.insert(pair<string, struct rcd *>(an_rcd_streamid, an_rcd)); if (rcd_insert_pair.second) ; // traceit("Started recording for user %.8s, streamid=%d,%d\n", // readBuffer + 42, readBuffer[12], readBuffer[13]); else { traceit("failed to add user %.8s, streamid=%d,%d, for recording...\n", readBuffer + 42, readBuffer[12], readBuffer[13]); free(an_rcd); an_rcd = NULL; } } else traceit("Failed to allocate for recording on user %.8s, streamid=%d,%d\n", readBuffer + 42, readBuffer[12], readBuffer[13]); } else traceit("Reached maximum concurrent users for recording\n"); } } } else { if ((readBuffer[14] & 0x40) != 0) { if (QSO_DETAILS) traceit("END user: streamID=%d,%d, %d bytes from IP=%s\n", readBuffer[12],readBuffer[13],recvlen, an_ip); } rcd_pos = rcd_list.find(an_rcd_streamid); if (rcd_pos != rcd_list.end()) { an_rcd = (struct rcd *)rcd_pos->second; time(&(an_rcd->ts)); /* stamp it */ if ((an_rcd->idx < MAX_RCD_DATA) && !(an_rcd->locked)) { memcpy(an_rcd->data[an_rcd->idx], readBuffer, recvlen); an_rcd->idx ++; } if (((readBuffer[14] & 0x40) != 0) && !(an_rcd->locked)) { /*** traceit("Finished recording for user %.8s, streamid=%d,%d\n", &(an_rcd->data[0][42]), readBuffer[12], readBuffer[13]); ***/ /*** start playback */ an_rcd->locked = true; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); rc = pthread_create(&playback_thread,&attr,playback,(void *)rcd_pos->second); if (rc != 0) { traceit("Failed to start the playback thread for streamid=%d,%d\n", readBuffer[12], readBuffer[13]); free(rcd_pos->second); rcd_pos->second = NULL; rcd_list.erase(rcd_pos); } pthread_attr_destroy(&attr); } } } /* prepare to send the data to dvap, dvtool stations */ refbuf[0] = (unsigned char)((recvlen + 2) & 0xFF); refbuf[1] = (unsigned char)((recvlen + 2) >> 8 & 0x1F); refbuf[1] = (unsigned char)(refbuf[1] | 0xFFFFFF80); memcpy(refbuf + 2, readBuffer, recvlen); /* At this point, if this is a header, it contains our reflector info */ /* save the header for re-transmit */ if (recvlen == 56) { /* save it */ source_mod = refbuf[27]; i = -1; if (refbuf[27] == 'A') i = 0; else if (refbuf[27] == 'B') i = 1; else if (refbuf[27] == 'C') i = 2; else if (refbuf[27] == 'D') i = 3; if (i >= 0) { temp_r[i].s_addr = fromUser.sin_addr.s_addr; memcpy(temp_r[i].hdr, refbuf, 58); } } /* send the data to dvap, dvtool stations */ if ((inbound_list.size() > 0) && (rcd_list.find(an_rcd_streamid) == rcd_list.end())) { for (inbound_pos2 = inbound_list.begin(); inbound_pos2 != inbound_list.end(); inbound_pos2++) { inbound_ptr2 = (inbound *)inbound_pos2->second; if (recvlen == 56) { if (inbound_ptr2->is_ref) { if (i >= 0) { if (inbound_ptr2->links[i] != ' ') { memcpy(refbuf + 20, inbound_ptr2->call, 7); refbuf[27] = inbound_ptr2->links[i]; memcpy(refbuf + 28, inbound_ptr2->call, 7); sendto(ref_sock, (char *)refbuf, recvlen + 2, 0, (struct sockaddr *)&(inbound_ptr2->sin), sizeof(struct sockaddr_in)); } } } else { /* reset it */ memcpy(refbuf + 20, OWNER, 7); refbuf[27] = source_mod; memcpy(refbuf + 28, OWNER, 7); if (i >= 0) sendto(ref_sock, (char *)refbuf, recvlen + 2, 0, (struct sockaddr *)&(inbound_ptr2->sin), sizeof(struct sockaddr_in)); } } else { if ((refbuf[26] == 0x55) && (refbuf[27] == 0x2d) && (refbuf[28] == 0x16)) { if (!inbound_ptr2->is_ref) { for (i = 0; i < 4; i++) { if ((refbuf[14] == temp_r[i].hdr[14]) && (refbuf[15] == temp_r[i].hdr[15]) && (fromUser.sin_addr.s_addr == temp_r[i].s_addr)) { sendto(ref_sock, (char *)temp_r[i].hdr, 58, 0, (struct sockaddr *)&(inbound_ptr2->sin), sizeof(struct sockaddr_in)); break; } } } } /* if it is a regular dongle, send it */ if (!inbound_ptr2->is_ref) sendto(ref_sock, (char *)refbuf, recvlen + 2, 0, (struct sockaddr *)&(inbound_ptr2->sin), sizeof(struct sockaddr_in)); else { /* treat the remote reflector with resepct */ /* send it only if the module matches */ for (i = 0; i < 4; i++) { if ((refbuf[14] == temp_r[i].hdr[14]) && (refbuf[15] == temp_r[i].hdr[15]) && (fromUser.sin_addr.s_addr == temp_r[i].s_addr) && (inbound_ptr2->links[i] != ' ')) { sendto(ref_sock, (char *)refbuf, recvlen + 2, 0, (struct sockaddr *)&(inbound_ptr2->sin), sizeof(struct sockaddr_in)); break; } } } } } } if (rcd_list.find(an_rcd_streamid) == rcd_list.end()) { /****************************** REPLACEMENT to send_a_pkt_to_all ****************************************************/ if (recvlen == 56) { if (readBuffer[25] == 'A') k = 0; else if (readBuffer[25] == 'B') k = 1; else if (readBuffer[25] == 'C') k = 2; else if (readBuffer[25] == 'D') k = 3; else k = -1; if (k >= 0) { temp_x[k].old_sid[0] = readBuffer[12]; temp_x[k].old_sid[1] = readBuffer[13]; streamid_raw = (readBuffer[12] * 256U) + readBuffer[13]; streamid_raw ++; if (streamid_raw == 0) streamid_raw ++; memcpy(temp_x[k].hdr, readBuffer, 56); temp_x[k].hdr[12] = streamid_raw / 256U; temp_x[k].hdr[13] = streamid_raw % 256U; temp_x[k].s_addr = fromUser.sin_addr.s_addr; for (user_pos2 = a_user_list.begin(); user_pos2 != a_user_list.end(); user_pos2++) { a_user_ptr2 = (struct a_user *)user_pos2->second; if (fromUser.sin_addr.s_addr != a_user_ptr2->sin.sin_addr.s_addr) { if ((a_user_ptr2->rpt_mods[k][0] != '\0') || (a_user_ptr2->rpt_mods[k][1] != '\0') || (a_user_ptr2->rpt_mods[k][2] != '\0') || (a_user_ptr2->rpt_mods[k][3] != '\0')) sendto(srv_sock, (char *)temp_x[k].hdr, recvlen, 0,(struct sockaddr *)&(a_user_ptr2->sin), sizeof(struct sockaddr_in)); } } } } else { for (user_pos2 = a_user_list.begin(); user_pos2 != a_user_list.end(); user_pos2++) { a_user_ptr2 = (struct a_user *)user_pos2->second; if (fromUser.sin_addr.s_addr != a_user_ptr2->sin.sin_addr.s_addr) { /* source must NOT be a reflector */ if (!(a_user_ptr->is_xrf)) { if ((readBuffer[24] == 0x55) && (readBuffer[25] == 0x2d) && (readBuffer[26] == 0x16)) { for (i = 0; i < 4; i++) { if ((readBuffer[12] == temp_x[i].old_sid[0]) && (readBuffer[13] == temp_x[i].old_sid[1]) && (fromUser.sin_addr.s_addr == temp_x[i].s_addr) && ((a_user_ptr2->rpt_mods[i][0] != '\0') || /* module is linked */ (a_user_ptr2->rpt_mods[i][1] != '\0') || (a_user_ptr2->rpt_mods[i][2] != '\0') || (a_user_ptr2->rpt_mods[i][3] != '\0'))) { sendto(srv_sock, (char *)temp_x[i].hdr, 56, 0, (struct sockaddr *)&(a_user_ptr2->sin), sizeof(struct sockaddr_in)); break; } } } } for (i = 0; i < 4; i++) { if ((readBuffer[12] == temp_x[i].old_sid[0]) && (readBuffer[13] == temp_x[i].old_sid[1]) && (fromUser.sin_addr.s_addr == temp_x[i].s_addr) && ((a_user_ptr2->rpt_mods[i][0] != '\0') || /* module is linked */ (a_user_ptr2->rpt_mods[i][1] != '\0') || (a_user_ptr2->rpt_mods[i][2] != '\0') || (a_user_ptr2->rpt_mods[i][3] != '\0'))) { readBuffer[12] = temp_x[i].hdr[12]; readBuffer[13] = temp_x[i].hdr[13]; sendto(srv_sock, (char *)readBuffer, recvlen, 0,(struct sockaddr *)&(a_user_ptr2->sin), sizeof(struct sockaddr_in)); readBuffer[12] = temp_x[i].old_sid[0]; readBuffer[13] = temp_x[i].old_sid[1]; break; } } } } } /********************************************************************************************************************/ } } } FD_CLR (srv_sock,&fdset); } } } static void *playback(void *arg) { struct rcd *temp_rcd = (struct rcd *)arg; struct sigaction act; unsigned short int j; unsigned short int i; struct timespec nanos; 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); keep_running = false; pthread_exit(NULL); } if (sigaction(SIGINT, &act, 0) != 0) { traceit("sigaction-INT failed, error=%d\n", errno); keep_running = false; pthread_exit(NULL); } /* delay 5 seconds here */ sleep(5); /*** if (temp_rcd->recvlen == 56) traceit("playback started for user=%.8s, streamid %d,%d\n", &(temp_rcd->data[0][42]), temp_rcd->data[0][12], temp_rcd->data[0][13]); else traceit("playback started for user=%.8s, streamid %d,%d\n", &(temp_rcd->data[0][44]), temp_rcd->data[0][14], temp_rcd->data[0][15]); ***/ /* first packet is header */ /*** MUST CHANGE rpt1 and rpt2 if temp_rcd->recvlen is 58 ***/ for (j = 0; j < 5; j++) sendto(ref_sock, (char *)temp_rcd->data[0], temp_rcd->recvlen, 0, (struct sockaddr *)&(temp_rcd->sin), sizeof(struct sockaddr_in)); /*** header sent ***/ i = 1; while ((keep_running) && (i < temp_rcd->idx)) { time(&(temp_rcd->ts)); sendto(ref_sock, (char *)temp_rcd->data[i], (temp_rcd->recvlen == 56)?27:29, /*** ? 32 ***/ 0,(struct sockaddr *)&(temp_rcd->sin), sizeof(struct sockaddr_in)); i ++; nanos.tv_sec = 0; nanos.tv_nsec = 17000000; nanosleep(&nanos,0); } /*** if (temp_rcd->recvlen == 56) traceit("Finished playback for user=%.8s, streamid %d,%d\n", &(temp_rcd->data[0][42]), temp_rcd->data[0][12], temp_rcd->data[0][13]); else traceit("Finished playback for user=%.8s, streamid %d,%d\n", &(temp_rcd->data[0][44]), temp_rcd->data[0][14], temp_rcd->data[0][15]); ***/ temp_rcd->locked = false; pthread_exit(NULL); } int main(int argc, char **argv) { int rc = 0; struct sigaction act; inbound_type::iterator inbound_pos; inbound *inbound_ptr; short int i; if (argc != 3) { printf("Usage: dxrfd <configFile> <logFile>\n"); printf("Example: dxrfd dxrfd.cfg dxrfd.log\n"); return 1; } if (access(argv[2], F_OK) == 0) { printf("Log file %s exists, is dxrfd already running?, if not running, remove log file and restart\n", argv[2]); return 1; } rc = regcomp(&preg, "^(([1-9][A-Z])|([A-Z][0-9])|([A-Z][A-Z][0-9]))[0-9A-Z]*[A-Z][ ]*[ A-RT-Z]$", REG_EXTENDED | REG_NOSUB); if (rc != REG_NOERROR) { traceit("The regular expression is NOT valid\n"); return 1; } /* Open log file */ logfp = fopen(argv[2], "a"); if (!logfp) { printf("Cant create log file %s, error=%d\n", argv[2],errno); return 1; } tzset(); /* line buffering only */ setvbuf(logfp, (char *)NULL, _IOLBF, 0); 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); return 1; } if (sigaction(SIGINT, &act, 0) != 0) { traceit("sigaction-INT failed, error=%d\n", errno); return 1; } do { /* process configuration file */ rc = read_config(argv[1]); if (rc != 0) { traceit("Failed to process config file %s\n", argv[1]); break; } /* Open DB */ rc = open_users(USERS); if (rc != 0) { traceit("Failed to open %s\n", USERS); break; } rc = open_blocks(BLOCKS); if (rc != 0) { traceit("Failed to open %s\n", BLOCKS); break; } /* get ready to accept incoming connections */ rc = srv_open(); if (rc != 0) { traceit("srv_open() failed\n"); break; } /* get ready to accept shell commands from netcat */ rc = cmd_open(); if (rc != 0) { traceit("cmd_open() failed\n"); break; } rc = ref_open(); if (rc != 0) { traceit("ref_open() failed\n"); break; } for (i = 0; i < 5; i++) { temp_x[i].s_addr = 0; memset(temp_x[i].hdr, 0, 56); temp_r[i].s_addr = 0; memset(temp_r[i].hdr, 0, 58); } traceit("dxrfd %s initialized...entering processing loop\n", VERSION); print_links_file(); runit(); traceit("Leaving processing loop...\n"); } while (false); /* Close all handles */ if (srv_sock != -1) close(srv_sock); if (cmd_sock != -1) close(cmd_sock); /* notify dvap, dvtool ... */ if (ref_sock != -1) { refbuf[0] = 5; refbuf[1] = 0; refbuf[2] = 24; refbuf[3] = 0; refbuf[4] = 0; for (inbound_pos = inbound_list.begin(); inbound_pos != inbound_list.end(); inbound_pos++) { inbound_ptr = (inbound *)inbound_pos->second; sendto(ref_sock,(char *)refbuf,5,0, (struct sockaddr *)&(inbound_ptr->sin), sizeof(struct sockaddr_in)); } inbound_list.clear(); close(ref_sock); } /* Empty out the status file */ statusfp = fopen(STATUS_FILE, "w"); if (statusfp) fclose(statusfp); else traceit("Failed to empty out status file %s\n", STATUS_FILE); traceit("dxrfd exiting\n"); fclose(logfp); return rc; }