main.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. /*
  2. * SPDX-FileCopyrightText: 2019 Helmut Pozimski <helmut@pozimski.eu>
  3. *
  4. * SPDX-License-Identifier: GPL-2.0-only
  5. */
  6. #include <signal.h>
  7. #include <stdlib.h>
  8. #include <stdint.h>
  9. #include <unistd.h>
  10. #include <getopt.h>
  11. #include <stdio.h>
  12. #include <string.h>
  13. #include <netinet/in.h>
  14. #include <time.h>
  15. #include <sys/time.h>
  16. #include <syslog.h>
  17. #include "tcpserver.h"
  18. #include "wavfile.h"
  19. #define BUF_SIZE 1558
  20. #define MAX_PATH_LEN 255
  21. typedef struct {
  22. uint32_t sample_rate;
  23. uint32_t bits;
  24. } sync_information;
  25. typedef struct {
  26. char ack[4];
  27. sync_information sync;
  28. } sync_ack;
  29. /* global variables */
  30. char filepath[MAX_PATH_LEN + 30];
  31. uint8_t file_closed = -1;
  32. wavfile * file;
  33. int sock;
  34. /*
  35. * Function: signal_handler
  36. * ------------------------
  37. * handles TERM and INT to ensure an orderly shutdown
  38. *
  39. * signal: the number of the signal sent
  40. */
  41. static void signal_handler(int signal) {
  42. syslog(LOG_INFO, "signal %d received, shutting down\n", signal);
  43. if (!file_closed) {
  44. wavfile_close(file);
  45. }
  46. tcpserver_stop(sock);
  47. exit(EXIT_SUCCESS);
  48. }
  49. /*
  50. * Function: construct_file_path
  51. * ----------------------------------------
  52. * Constructs the file path to write a new file to
  53. *
  54. * directory: directory in which the file should be placed
  55. * file_path: pointer to the buffer to write the file path to
  56. */
  57. static void construct_file_path(char * directory, char * file_path) {
  58. time_t cur_time;
  59. struct tm local_time;
  60. char timebuffer[12];
  61. cur_time = time(NULL);
  62. local_time = (*localtime(&cur_time));
  63. strncpy(file_path, "", 1);
  64. strncat(file_path, directory, 255);
  65. strncat(file_path, "/", 2);
  66. sprintf(timebuffer, "%d", local_time.tm_year +1900);
  67. strncat(file_path, timebuffer, 12);
  68. sprintf(timebuffer, "%d", local_time.tm_mon +1);
  69. strncat(file_path, timebuffer, 12);
  70. sprintf(timebuffer, "%d", local_time.tm_mday);
  71. strncat(file_path, timebuffer, 12);
  72. sprintf(timebuffer, "%d", local_time.tm_hour);
  73. strncat(file_path, timebuffer, 12);
  74. sprintf(timebuffer, "%d", local_time.tm_min);
  75. strncat(file_path, timebuffer, 12);
  76. sprintf(timebuffer, "%d", local_time.tm_sec);
  77. strncat(file_path, timebuffer, 12);
  78. strncat(file_path, "-recording.wav", 15);
  79. }
  80. int main(int argc, char **argv) {
  81. char * ip_address = NULL;
  82. char * directory = NULL;
  83. uint16_t port = 0;
  84. int opt, bytes_received, conn;
  85. struct sockaddr_in client;
  86. unsigned int namelen;
  87. sync_information sync;
  88. uint8_t buffer[BUF_SIZE];
  89. sync_ack ack_packet;
  90. while ((opt = getopt(argc, argv, "i:p:d:")) != -1) {
  91. switch(opt) {
  92. case 'i':
  93. ip_address = optarg;
  94. break;
  95. case 'p':
  96. port = strtoul(optarg, NULL, 10);
  97. break;
  98. case 'd':
  99. directory = optarg;
  100. break;
  101. }
  102. }
  103. if (port == 0 || ip_address == NULL || directory == NULL) {
  104. printf("Usage: %s -i IPV4_ADDRESS -p PORT -d DIRECTORY\n", argv[0]);
  105. return EXIT_SUCCESS;
  106. }
  107. struct sigaction action;
  108. action.sa_handler = signal_handler;
  109. sigaction(SIGTERM, &action,NULL);
  110. sigaction(SIGINT, &action,NULL);
  111. openlog("tpr", LOG_CONS | LOG_PID, LOG_DAEMON);
  112. if ((sock = tcpserver_start(ip_address, port)) < 0 ) {
  113. syslog(LOG_ERR, "Failed to start TCP server\n");
  114. return EXIT_FAILURE;
  115. }
  116. namelen = sizeof(client);
  117. while (1) {
  118. conn = accept(sock, (struct sockaddr *)&client, &namelen);
  119. if (conn == -1) {
  120. continue;
  121. }
  122. struct timeval tv;
  123. tv.tv_sec = 3;
  124. tv.tv_usec = 0;
  125. setsockopt(conn, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
  126. recv(conn, &sync, sizeof(sync), 0);
  127. if (sync.sample_rate < 8000 || sync.sample_rate > 48000) {
  128. syslog(LOG_ERR, "Invalid sample rate received\n");
  129. continue;
  130. }
  131. construct_file_path(directory, filepath);
  132. syslog(LOG_INFO, "opening file at: %s\n", filepath);
  133. file = wavfile_create(filepath, 1, sync.sample_rate, sync.bits);
  134. file_closed = 0;
  135. strncpy(ack_packet.ack,"ACK", 4);
  136. if (file == NULL) {
  137. syslog(LOG_ERR, "Error creating new file\n");
  138. close(conn);
  139. continue;
  140. }
  141. ack_packet.sync = sync;
  142. send(conn, &ack_packet, sizeof(ack_packet), 0);
  143. while ((bytes_received = recv(conn, buffer, BUF_SIZE, 0)) != -1) {
  144. wavfile_append_data(file, buffer, bytes_received);
  145. }
  146. syslog(LOG_INFO, "closing file: %s\n", filepath);
  147. wavfile_close(file);
  148. close(conn);
  149. file_closed = 1;
  150. }
  151. return EXIT_SUCCESS;
  152. }