/ ddcd.cpp
ddcd.cpp
1 /* 2 This software is part of libcsdr, a set of simple DSP routines for 3 Software Defined Radio. 4 5 Copyright (c) 2014, Andras Retzler <randras@sdr.hu> 6 All rights reserved. 7 8 Redistribution and use in source and binary forms, with or without 9 modification, are permitted provided that the following conditions are met: 10 * Redistributions of source code must retain the above copyright 11 notice, this list of conditions and the following disclaimer. 12 * Redistributions in binary form must reproduce the above copyright 13 notice, this list of conditions and the following disclaimer in the 14 documentation and/or other materials provided with the distribution. 15 * Neither the name of the copyright holder nor the 16 names of its contributors may be used to endorse or promote products 17 derived from this software without specific prior written permission. 18 19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY 23 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "ddcd.h" 32 33 34 int host_port = 0; 35 char host_address[100] = "127.0.0.1"; 36 int thread_cntr = 0; 37 38 //CLI parameters 39 int decimation = 0; 40 float transition_bw = 0.05; 41 int bufsize = 1024; //! currently unused 42 int bufcnt = 1024; 43 char ddc_method_str[100] = "td"; 44 ddc_method_t ddc_method; 45 46 void sig_handler(int signo) 47 { 48 fprintf(stderr, MSG_START "signal %d caught, exiting ddcd...\n", signo); 49 fflush(stderr); 50 exit(0); 51 } 52 53 int main(int argc, char* argv[]) 54 { 55 int c; 56 for(;;) 57 { 58 int option_index = 0; 59 static struct option long_options[] = { 60 {"port", required_argument, 0, 'p' }, 61 {"address", required_argument, 0, 'a' }, 62 {"decimation", required_argument, 0, 'd' }, 63 {"bufsize", required_argument, 0, 'b' }, 64 {"bufcnt", required_argument, 0, 'n' }, 65 {"method", required_argument, 0, 'm' }, 66 {"transition", required_argument, 0, 't' } 67 }; 68 c = getopt_long(argc, argv, "p:a:d:b:n:m:t:", long_options, &option_index); 69 if(c==-1) break; 70 switch (c) 71 { 72 case 'a': 73 host_address[100-1]=0; 74 strncpy(host_address,optarg,100-1); 75 break; 76 case 'p': 77 host_port=atoi(optarg); 78 break; 79 case 'd': 80 decimation=atoi(optarg); 81 break; 82 case 'b': 83 bufsize=atoi(optarg); 84 break; 85 case 'n': 86 bufcnt=atoi(optarg); 87 break; 88 case 'm': 89 ddc_method_str[100-1]=0; 90 strncpy(ddc_method_str,optarg,100-1); 91 break; 92 case 't': 93 sscanf(optarg,"%g",&transition_bw); 94 break; 95 case 0: 96 case '?': 97 case ':': 98 default:; 99 print_exit(MSG_START "error in getopt_long()\n"); 100 } 101 } 102 103 if(!decimation) print_exit(MSG_START "missing required command line argument, --decimation.\n"); 104 if(!host_port) print_exit(MSG_START "missing required command line argument, --port.\n"); 105 if(decimation<0) print_exit(MSG_START "invalid value for --decimation (should be >0).\n"); 106 if(decimation==1) fprintf(stderr, MSG_START "decimation = 1, just copying raw samples.\n"); 107 if(transition_bw<0||transition_bw>0.5) print_exit(MSG_START "invalid value for --transition (should be between 0 and 0.5).\n"); 108 if(bufsize<0) print_exit(MSG_START "invalid value for --bufsize (should be >0)\n"); 109 if(bufcnt<0) print_exit(MSG_START "invalid value for --bufcnt (should be >0)\n"); 110 if(decimation==1); //don't do anything then //!will have to take care about this later 111 else if(!strcmp(ddc_method_str,"td")) 112 { 113 ddc_method = M_TD; 114 fprintf(stderr, MSG_START "method is M_TD (default).\n"); 115 } 116 else if (!strcmp(ddc_method_str,"fastddc")) 117 { 118 ddc_method = M_FASTDDC; 119 fprintf(stderr, MSG_START "method is M_FASTDDC.\n"); 120 } 121 else print_exit(MSG_START "invalid parameter given to --method.\n"); 122 123 //set signals 124 struct sigaction sa; 125 memset(&sa, 0, sizeof(sa)); 126 sa.sa_handler = sig_handler; 127 sigaction(SIGTERM, &sa, NULL); 128 sigaction(SIGKILL, &sa, NULL); 129 sigaction(SIGQUIT, &sa, NULL); 130 sigaction(SIGINT, &sa, NULL); 131 sigaction(SIGHUP, &sa, NULL); 132 133 struct sockaddr_in addr_host; 134 int listen_socket; 135 std::vector<client_t*> clients; 136 clients.reserve(100); 137 listen_socket=socket(AF_INET,SOCK_STREAM,0); 138 139 int sockopt = 1; 140 if( setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&sockopt, sizeof(sockopt)) == -1 ) 141 error_exit(MSG_START "cannot set SO_REUSEADDR"); //the best description on SO_REUSEADDR ever: http://stackoverflow.com/a/14388707/3182453 142 143 memset(&addr_host,'0',sizeof(addr_host)); 144 addr_host.sin_family = AF_INET; 145 addr_host.sin_port = htons(host_port); 146 addr_host.sin_addr.s_addr = INADDR_ANY; 147 148 if( (addr_host.sin_addr.s_addr=inet_addr(host_address)) == INADDR_NONE ) 149 error_exit(MSG_START "invalid host address"); 150 151 if( bind(listen_socket, (struct sockaddr*) &addr_host, sizeof(addr_host)) < 0 ) 152 error_exit(MSG_START "cannot bind() address to the socket"); 153 154 if( listen(listen_socket, 10) == -1 ) 155 error_exit(MSG_START "cannot listen() on socket"); 156 157 fprintf(stderr,MSG_START "listening on %s:%d\n", inet_ntoa(addr_host.sin_addr), host_port); 158 159 struct sockaddr_in addr_cli; 160 socklen_t addr_cli_len = sizeof(addr_cli); 161 int new_socket; 162 163 int highfd = 0; 164 FD_ZERO(&select_fds); 165 FD_SET(listen_socket, &select_fds); 166 maxfd(&highfd, listen_socket); 167 FD_SET(input_fd, &select_fds); 168 maxfd(&highfd, input_fd); 169 170 //Set stdin and listen_socket to non-blocking 171 if(set_nonblocking(input_fd) || set_nonblocking(listen_socket)) 172 error_exit(MSG_START "cannot set_nonblocking()"); 173 174 //Create tsmpool 175 tsmpool* pool = new tsmpool(bufsize, bufcnt); 176 if(!pool->ok) print_exit(MSG_START "tsmpool failed to initialize\n"); 177 178 unsigned char* current_write_buffer = pool->get_write_buffer(); 179 int index_in_current_write_buffer = 0; 180 181 182 for(;;) 183 { 184 //Let's wait until there is any new data to read, or any new connection! 185 select(highfd, &select_fds, NULL, NULL, NULL); 186 187 //Is there a new client connection? 188 if( (new_socket = accept(listen_socket, (struct sockaddr*)&addr_cli, &addr_cli_len)) != -1) 189 { 190 clients_close_all_finished(); 191 if(pthread_create(&new_client->thread, NULL, client_thread , (void*)&new_client)<0) 192 { 193 //We're the parent 194 client_t* new_client = new client_t; 195 new_client->error = 0; 196 memcpy(&new_client->addr, &addr_cli, sizeof(new_client->addr)); 197 new_client->socket = new_socket; 198 new_client->status = CS_CREATED; 199 clients.push_back(new_client); 200 fprintf(stderr, MSG_START "pthread_create() done, clients now: %d\n", clients.size()); 201 } 202 else fprintf(stderr, MSG_START "pthread_create() failed.\n"); 203 } 204 205 if(index_in_current_write_buffer >= bufsize) 206 { 207 current_write_buffer = pool->get_write_buffer(); 208 index_in_current_write_buffer = 0; 209 } 210 int retval = read(input_fd, current_write_buffer + index_in_current_write_buffer, bufsize - index_in_current_write_buffer); 211 if(retval>0) 212 { 213 index_in_current_write_buffer += retval; 214 } 215 else if(retval==0) 216 { 217 //!end of input stream, close clients and exit 218 print_exit(MSG_START "end of input, exiting.\n") 219 } 220 } 221 } 222 223 #if 0 224 for (int i=0; i<clients.size(); i++) 225 { 226 if(write(clients[i]->pipefd[1], buf, retval)==-1) 227 { 228 229 if(!clients[i]->error) 230 { 231 print_client(clients[i], "lost buffer, failed to write pipe."); 232 clients[i]->error=1; 233 } 234 //fprintf(stderr, MSG_START "errno is %d\n", errno); //usually 11 235 //int wpstatus; 236 //int wpresult = waitpid(clients[i]->pid, &wpstatus, WNOHANG); 237 //fprintf(stderr, MSG_START "pid is %d\n",clients[i]->pid); 238 //perror("somethings wrong"); 239 //if(wpresult == -1) print_client(clients[i], "error while waitpid()!"); 240 //else if(wpresult == 0) 241 waitpid(clients[i]->pid, NULL, WNOHANG); 242 if(!proc_exists(clients[i]->pid)) 243 { 244 //Client exited! 245 print_client(clients[i], "closing client from main process."); 246 close(clients[i]->pipefd[1]); 247 close(clients[i]->socket); 248 delete clients[i]; 249 clients.erase(clients.begin()+i); 250 fprintf(stderr, MSG_START "done closing client from main process.\n"); 251 } 252 } 253 else { if(clients[i]->error) print_client(clients[i], "pipe okay again."); clients[i]->error=0; } 254 } 255 } 256 //TODO: at the end, server closes pipefd[1] for client 257 #endif 258 259 void clients_close_all_finished() 260 { 261 for(int i=0;i<clients.size();i++) 262 { 263 if(clients[i]->status == CS_THREAD_FINISHED) clients.erase(i); 264 } 265 } 266 267 void client_parser_push(char c) 268 { //!TODO 269 command_t cmd; 270 char* commands_cstr = commands.c_str(); 271 int newline_index = -1; 272 273 for(int i=0;commands_cstr[i];i++) if(commands_cstr[i]=='\n') newline_index = i; 274 if(newline_index == -1) 275 276 char param_name[101]; 277 char param_value[101]; 278 for(int i=0;i<100;commands_csdr 279 280 } 281 282 void* client_thread (void* param) //!TODO 283 { 284 client_t* me_the_client = (client_t*)param; 285 me_the_client->status = CS_THREAD_RUNNING; 286 char ctl_data_buffer; 287 int retval; 288 tsmpool* p1_temp; 289 tsmpool* p2_temp; 290 const int num_client_buffers = 20; 291 if(ddc_method == M_TD) 292 { 293 p1_temp = new tsmpool(bufsize, ) 294 } 295 296 for(;;) 297 { 298 do 299 { 300 retval = recv(me_the_client->socket, &ctl_data_buffer, 1, 0); 301 if(client_parser_push(ctl_data_buffer)) break; 302 } while (retval); 303 304 305 //read control data from socket 306 //process control data 307 //run shift 308 //run decimation 309 //have an exit condition (??) 310 if(ddc_method == M_TD) 311 { 312 313 } 314 } 315 me_the_client->status = CS_THREAD_FINISHED; 316 pthread_exit(NULL); 317 return NULL; 318 } 319 320 void error_exit(const char* why) 321 { 322 perror(why); //do we need a \n at the end of (why)? 323 exit(1); 324 } 325 326 void print_exit(const char* why) 327 { 328 fprintf(stderr, "%s", why); 329 exit(1); 330 } 331 332 void maxfd(int* maxfd, int fd) 333 { 334 if(fd>=*maxfd) *maxfd=fd+1; 335 }