#include #include #include #include #include // Standard input/output definitions #include // String function definitions #include // UNIX standard function definitions #include // File control definitions #include // Error number definitions #include // POSIX terminal control definitions #include #include #include #include #include #include #include #include "urlencode.h" #include "base64.h" #include "ssdv.h" #include "gateway.h" #include "global.h" extern int ssdv_pipe_fd[2]; extern pthread_mutex_t var; size_t write_ssdv_data( void *buffer, size_t size, size_t nmemb, void *userp ) { return size * nmemb; } void ConvertStringToHex( unsigned char *Target, unsigned char *Source, int Length ) { const char Hex[16] = "0123456789ABCDEF"; int i; for ( i = 0; i < Length; i++ ) { *Target++ = Hex[Source[i] >> 4]; *Target++ = Hex[Source[i] & 0x0F]; } *Target++ = '\0'; } void UploadImagePacket( ssdv_t * s, unsigned int packets ) { CURL *curl; CURLcode res; char curl_error[CURL_ERROR_SIZE]; char base64_data[512], json[32768], packet_json[1000]; struct curl_slist *headers = NULL; size_t base64_length; char now[32]; time_t rawtime; struct tm *tm; char url[250]; /* get a curl handle */ curl = curl_easy_init( ); if ( curl ) { // So that the response to the curl POST doesn;'t mess up my finely crafted display! curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, write_ssdv_data ); // Set the timeout curl_easy_setopt( curl, CURLOPT_TIMEOUT, 15 ); // RJH capture http errors and report curl_easy_setopt( curl, CURLOPT_FAILONERROR, 1 ); curl_easy_setopt( curl, CURLOPT_ERRORBUFFER, curl_error ); // Avoid curl library bug that happens if above timeout occurs (sigh) curl_easy_setopt( curl, CURLOPT_NOSIGNAL, 1 ); // Get formatted timestamp time( &rawtime ); tm = gmtime( &rawtime ); strftime( now, sizeof( now ), "%Y-%0m-%0dT%H:%M:%SZ", tm ); int PacketIndex; // Create json with the base64 data in hex, the tracker callsign and the current timestamp strcpy( json, "{\"type\": \"packets\",\"packets\":[" ); for (PacketIndex = 0; PacketIndex < packets; PacketIndex++) { base64_encode(s[PacketIndex].SSDV_Packet, 256, &base64_length, base64_data); base64_data[base64_length] = '\0'; sprintf(packet_json, "{\"type\": \"packet\", \"packet\": \"%s\", \"encoding\": \"base64\", \"received\": \"%s\", \"receiver\": \"%s\"}%s", base64_data, now, Config.Tracker, PacketIndex == ( packets - 1 ) ? "" : ","); strcat(json, packet_json); } strcat(json, "]}"); // LogTelemetryPacket(json); strcpy( url, "http://ssdv.habhub.org/api/v0/packets" ); // Set the headers headers = NULL; headers = curl_slist_append( headers, "Accept: application/json" ); headers = curl_slist_append( headers, "Content-Type: application/json" ); headers = curl_slist_append( headers, "charsets: utf-8" ); curl_easy_setopt( curl, CURLOPT_HTTPHEADER, headers ); curl_easy_setopt( curl, CURLOPT_URL, url ); curl_easy_setopt( curl, CURLOPT_CUSTOMREQUEST, "POST" ); curl_easy_setopt( curl, CURLOPT_POSTFIELDS, json ); // Perform the request, res will get the return code res = curl_easy_perform( curl ); /* Check for errors */ if ( res == CURLE_OK ) { } else { LogMessage( "Failed for URL '%s'\n", url ); LogMessage( "curl_easy_perform() failed: %s\n", curl_easy_strerror( res ) ); LogMessage( "error: %s\n", curl_error ); } /* always cleanup */ curl_slist_free_all( headers ); // RJH Added this from habitat.c as was missing curl_easy_cleanup( curl ); } } void *SSDVLoop( void *vars ) { if ( Config.EnableSSDV ) { const int max_packets = 51; thread_shared_vars_t *stsv; stsv = vars; ssdv_t s[max_packets]; unsigned int j = 0; unsigned int packets = 0; unsigned long total_packets = 0; // Keep looping until the parent quits and there are no more packets to // send to ssdv. while ( ( stsv->parent_status == RUNNING ) || ( packets > 0 ) ) { if ( stsv->packet_count > total_packets ) { packets = read( ssdv_pipe_fd[0], &s[j], sizeof( ssdv_t ) ); } else { packets = 0; // If we have have a rollover after processing 4294967295 packets if ( stsv->packet_count < total_packets ) total_packets = 0; } if ( packets ) { j++; total_packets++; } if ( j == 50 || ( ( packets == 0 ) && ( j > 0 ) ) ) { ChannelPrintf(s[0].Channel, 6, 16, "SSDV"); UploadImagePacket( s, j ); ChannelPrintf(s[0].Channel, 6, 16, " "); j = 0; packets = 0; } delay(100); // Don't eat too much CPU } } close( ssdv_pipe_fd[0] ); close( ssdv_pipe_fd[1] ); LogMessage( "SSDV thread closing\n" ); return NULL; }