#include #include #include #include #include // Standard input/output definitions #include // String function definitions #include // File control definitions #include // UNIX standard function definitions #include // Error number definitions #include // POSIX terminal control definitions #include #include #include #include #include #include #include #include #include #include "server.h" #include "config.h" #include "global.h" #include "gateway.h" extern bool run; void EncryptMessage(char *Code, char *Message) { int i, Len; Len = strlen(Code); if (Len > 0) { i = 0; while (*Message) { *Message = (*Message ^ Code[i]) | 0x80; Message++; i = (i + 1) % Len; } } } void ProcessChatClientLine(int connfd, char *line) { line[strcspn(line, "\r\n")] = '\0'; // Get rid of CR LF // LogMessage("Received '%s' from CHAT client\n", line); if (strchr(line, ':') != NULL) { // Command with parameters char *command, *value, *saveptr = NULL; command = strtok_r(line, ":", &saveptr); value = strtok_r(NULL, "\n", &saveptr); if (strcasecmp(command, "send") == 0) { int channel; channel = *value != '0'; value++; LogMessage("LoRa[%d]: To send '%s'\n", channel, value); if (*Config.UplinkCode) { EncryptMessage(Config.UplinkCode, value); } // sprintf(Config.LoRaDevices[channel].UplinkMessage, "!%s,%s", Config.LoRaDevices[channel].ChatPayloadID, value); if (Config.LoRaDevices[channel].ChatMode) { // Format is [message_id],[message] sscanf(value, "%d,%[^\n]", &(Config.LoRaDevices[channel].TxMessageID), Config.LoRaDevices[channel].TxChatMessage); LogMessage("Uplink to payload [%s], message ID [%d], message [%s]\n", Config.LoRaDevices[channel].ChatPayloadID, Config.LoRaDevices[channel].TxMessageID, Config.LoRaDevices[channel].TxChatMessage); LogMessage("Uplink message is %s\n", Config.LoRaDevices[channel].UplinkMessage); } } else if (strcasecmp(command, "poll") == 0) { char Line[300]; int channel; channel = *value != '0'; // TxMessageID, Len(TxMessage), RxMessageID, RxMessage sprintf(Line, "%d,%d,%d,%s", Config.LoRaDevices[channel].TxMessageID, strlen(Config.LoRaDevices[channel].TxChatMessage), Config.LoRaDevices[channel].RxMessageID, Config.LoRaDevices[channel].RxChatMessage); send(connfd, Line, strlen(Line), MSG_NOSIGNAL); } } else { // single-word request } } void ProcessJSONClientLine(int connfd, char *line) { line[strcspn(line, "\r\n")] = '\0'; // Get rid of CR LF LogMessage("Received '%s' from JSON client\n", line); if (strchr(line, '=') != NULL) { // Setting char *setting, *value, *saveptr = NULL; setting = strtok_r(line, "=", &saveptr); value = strtok_r( NULL, "\n", &saveptr); SetConfigValue(setting, value); if (strstr(line, "frequency_0") != NULL) { Config.LoRaDevices[0].FrequencyOffset = 0; } else if (strstr(line, "frequency_1") != NULL) { Config.LoRaDevices[1].FrequencyOffset = 0; } } else if (strchr(line, ':') != NULL) { // Command with parameters char *command, *value, *saveptr = NULL; command = strtok_r(line, ":", &saveptr); value = strtok_r(NULL, "\n", &saveptr); if (strcasecmp(command, "send") == 0) { int channel; channel = *value != '0'; value++; LogMessage("LoRa[%d]: To send '%s'\n", channel, value); if (*Config.UplinkCode) { EncryptMessage(Config.UplinkCode, value+1); } strcpy(Config.LoRaDevices[channel].UplinkMessage, value); } } else { // single-word request if (strcasecmp(line, "settings") == 0) { int Index; char SettingName[64], SettingValue[256], packet[4096]; LogMessage("Responding to settings request\n"); Index = 0; packet[0] = '\0'; while (SettingAsString(Index, SettingName, sizeof(SettingName), SettingValue, sizeof(SettingValue))) { char temp[300]; sprintf(temp, "{\"class\":\"SET\",\"set\":\"%s\",\"val\":%s}\r\n", SettingName, SettingValue); if ((strlen(temp) + strlen(packet)) < sizeof(packet)) { strcat(packet, temp); } Index++; } send(connfd, packet, strlen(packet), MSG_NOSIGNAL); } else if (strcasecmp(line, "poll") == 0) { char Line[300]; sprintf(Line, "1/"); send(connfd, Line, strlen(Line), MSG_NOSIGNAL); } else if (strcasecmp(line, "save") == 0) { LogMessage("Saving Settings\n"); SaveConfigFile(); } } } int SendJSON(int connfd) { int Channel, PayloadIndex, port_closed; char sendBuff[4000], line[400]; port_closed = 0; sendBuff[0] = '\0'; // Send any packets that we've not sent yet for (PayloadIndex=0; PayloadIndexsockfd = socket( AF_INET, SOCK_STREAM, 0 ); memset( &serv_addr, '0', sizeof( serv_addr ) ); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl( INADDR_ANY ); serv_addr.sin_port = htons(ServerInfo->Port); LogMessage( "Listening on %s port %d\n", ChannelName[ServerInfo->ServerIndex], ServerInfo->Port); if (setsockopt(ServerInfo->sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < 0) { LogMessage( "setsockopt(SO_REUSEADDR) failed" ); } if (bind(ServerInfo->sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { LogMessage( "Server failed errno %d\n", errno ); exit( -1 ); } listen(ServerInfo->sockfd, 10); while (run) { static char *ChannelName[4] = {"JSON", "HAB", "DATA", "CHAT"}; int MSPerLoop=100; int ms=0; int connfd; Config.EnableDev=1; fcntl(ServerInfo->sockfd, F_SETFL, fcntl(ServerInfo->sockfd, F_GETFL) & ~O_NONBLOCK); // Blocking mode so we wait for a connection connfd = accept(ServerInfo->sockfd, ( struct sockaddr * ) NULL, NULL ); // Wait for connection LogMessage( "Connected to %s client\n", ChannelName[ServerInfo->ServerIndex]); ServerInfo->Connected = 1; fcntl(connfd, F_SETFL, fcntl(ServerInfo->sockfd, F_GETFL) | O_NONBLOCK); // Non-blocking, so we don't block on receiving any commands from client while (ServerInfo->Connected) { int bytecount; ms += MSPerLoop; // Listen part bytecount = -1; if (ServerInfo->ServerIndex == 0) { static char lines[4096]; char packet[4096]; while ((bytecount = recv(connfd, packet, sizeof(packet), 0)) > 0) { // JSON server char *lf; packet[bytecount] = 0; strcat(lines, packet); while ((lf = strchr(lines, '\n')) != NULL) { // Terminate string *lf = '\0'; // Process this line ProcessJSONClientLine(connfd, lines); // Shift any other lines over strcpy(lines, lf+1); } } if (bytecount == 0) { // -1 is no more data, 0 means port closed ServerInfo->Connected = 0; } } else if (ServerInfo->ServerIndex == 1) { char RxByte; while ((bytecount = recv(connfd, &RxByte, 1, 0)) > 0) { Config.LoRaDevices[Config.HABChannel].FromTelnetBuffer[Config.LoRaDevices[Config.HABChannel].FromTelnetBufferCount++] = RxByte; LogMessage("KEYB BUFFER %d BYTES\n", Config.LoRaDevices[Config.HABChannel].FromTelnetBufferCount); } } else if (ServerInfo->ServerIndex == 2) { char RxByte; while ((bytecount = recv(connfd, &RxByte, 1, 0)) > 0) { // Nothing as we are only sending } } else if (ServerInfo->ServerIndex == 3) { char packet[300]; while ((bytecount = recv(connfd, packet, sizeof(packet), 0)) > 0) { packet[bytecount] = 0; ProcessChatClientLine(connfd, packet); } if (bytecount == 0) { // -1 is no more data, 0 means port closed ServerInfo->Connected = 0; } } if (bytecount == 0) { // -1 is no more data, 0 means port closed LogMessage("Disconnected from %s client\n", ChannelName[ServerInfo->ServerIndex]); ServerInfo->Connected = 0; } if (ServerInfo->Connected) { // Send part if (ServerInfo->ServerIndex == 0) { // Send to JSON client static int SendDelay = 0; if ((SendDelay += MSPerLoop) >= 1000) { SendDelay = 0; if (SendJSON(connfd)) { ServerInfo->Connected = 0; } } } else if (ServerInfo->ServerIndex == 1) { // Telnet port (provides Telnet-like connection to HAB) int Channel; for (Channel=0; Channel<=1; Channel++) { if (Config.LoRaDevices[Channel].ToTelnetBufferCount > 0) { send(connfd, Config.LoRaDevices[Channel].ToTelnetBuffer, Config.LoRaDevices[Channel].ToTelnetBufferCount, 0); Config.LoRaDevices[Channel].ToTelnetBufferCount = 0; } } } else if (ServerInfo->ServerIndex == 2) { // Direct telemetry port int Channel; for (Channel=0; Channel<=1; Channel++) { if (Config.LoRaDevices[Channel].LocalDataCount > 0) { send(connfd, Config.LoRaDevices[Channel].LocalDataBuffer, Config.LoRaDevices[Channel].LocalDataCount, 0); Config.LoRaDevices[Channel].LocalDataCount = 0; } } } } delay(MSPerLoop); } close(connfd); } return NULL; }