From d55b491c43f88aff775eb1f1cb9f85c63624a6db Mon Sep 17 00:00:00 2001 From: Hoernchen Date: Thu, 19 Apr 2012 17:46:52 +0200 Subject: [PATCH] add initial version of tcp server --- AUTHORS | 1 + src/CMakeLists.txt | 8 +- src/Makefile.am | 5 +- src/rtl_tcp.c | 474 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 486 insertions(+), 2 deletions(-) create mode 100644 src/rtl_tcp.c diff --git a/AUTHORS b/AUTHORS index 5285056..e4688ed 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,2 +1,3 @@ Steve Markgraf Dimitri Stolnikov +Hoernchen diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ffb0927..0ce6f6b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -58,18 +58,24 @@ endif() # Build utility ######################################################################## add_executable(rtl_sdr main.c) +add_executable(rtl_tcp rtl_tcp.c) target_link_libraries(rtl_sdr rtlsdr_static ${LIBUSB_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ) +target_link_libraries(rtl_tcp rtlsdr_static + ${LIBUSB_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} +) if(WIN32) set_property(TARGET rtl_sdr APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" ) +set_property(TARGET rtl_tcp APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" ) endif() ######################################################################## # Install built library files & utilities ######################################################################## -install(TARGETS rtlsdr_shared rtlsdr_static rtl_sdr +install(TARGETS rtlsdr_shared rtlsdr_static rtl_sdr rtl_tcp LIBRARY DESTINATION lib${LIB_SUFFIX} # .so/.dylib file ARCHIVE DESTINATION lib${LIB_SUFFIX} # .lib file RUNTIME DESTINATION bin # .dll file diff --git a/src/Makefile.am b/src/Makefile.am index be402aa..f9023cd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -10,6 +10,9 @@ lib_LTLIBRARIES = librtlsdr.la librtlsdr_la_SOURCES = rtl-sdr.c tuner_e4000.c tuner_fc0012.c tuner_fc0013.c tuner_fc2580.c librtlsdr_la_LDFALGS = -version-info $(LIBVERSION) -bin_PROGRAMS = rtl_sdr +bin_PROGRAMS = rtl_sdr rtl_tcp rtl_sdr_SOURCES = main.c rtl_sdr_LDADD = librtlsdr.la + +rtl_tcp_SOURCES = rtl_tcp.c +rtl_tcp_LDADD = librtlsdr.la diff --git a/src/rtl_tcp.c b/src/rtl_tcp.c new file mode 100644 index 0000000..007482e --- /dev/null +++ b/src/rtl_tcp.c @@ -0,0 +1,474 @@ +/* + * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver + * Copyright (C) 2012 by Steve Markgraf + * Copyright (C) 2012 by Hoernchen + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#ifndef _WIN32 +#include +#include +#include +#include +#include +#include +#include +#endif + +#include +#include + +#include "rtl-sdr.h" + +#ifdef _WIN32 +#pragma comment(lib, "ws2_32.lib") +#else +#define closesocket close +#define SOCKADDR struct sockaddr +#define SOCKET int +#define SOCKET_ERROR -1 +#endif + +static SOCKET s; + +static pthread_t tcp_worker_thread; +static pthread_t command_thread; +static pthread_cond_t exit_cond; +static pthread_mutex_t exit_cond_lock; +static volatile int dead[2] = {0, 0}; + +static pthread_mutex_t ll_mutex; +static pthread_cond_t cond; + +struct llist { + char *data; + size_t len; + struct llist *next; +}; + +static rtlsdr_dev_t *dev = NULL; + +int global_numq = 0; +static struct llist *ll_buffers = 0; + +static int do_exit = 0; + +void usage(void) +{ + #ifdef _WIN32 + printf("rtl-sdr, an I/Q recorder for RTL2832 based USB-sticks\n\n" + "Usage:\t rtl-sdr-win.exe [listen addr] [listen port] " + "[samplerate in kHz] [frequency in hz]\n"); + #else + printf("rtl-sdr, an I/Q recorder for RTL2832 based USB-sticks\n\n" + "Usage:\t -a listen address\n" + "\t[-p listen port (default: 1234)\n" + "\t -f frequency to tune to [Hz]\n" + "\t[-s samplerate in kHz (default: 2048 kHz)]\n" + "\toutput filename\n"); + #endif + exit(1); +} + +#ifdef _WIN32 +int gettimeofday(struct timeval *tv, void* ignored) +{ + FILETIME ft; + unsigned __int64 tmp = 0; + if (NULL != tv) { + GetSystemTimeAsFileTime(&ft); + tmp |= ft.dwHighDateTime; + tmp <<= 32; + tmp |= ft.dwLowDateTime; + tmp /= 10; + tmp -= 11644473600000000Ui64; + tv->tv_sec = (long)(tmp / 1000000UL); + tv->tv_usec = (long)(tmp % 1000000UL); + } + return 0; +} + +BOOL WINAPI +sighandler(int signum) +{ + if (CTRL_C_EVENT == signum) { + fprintf(stderr, "Signal caught, exiting!\n"); + do_exit = 1; + rtlsdr_cancel_async(dev); + return TRUE; + } + return FALSE; +} +#else +static void sighandler(int signum) +{ + fprintf(stderr, "Signal caught, exiting!\n"); + do_exit = 1; + rtlsdr_cancel_async(dev); +} +#endif + +void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx) +{ + if(!do_exit) { + struct llist *rpt = (struct llist*)malloc(sizeof(struct llist)); + rpt->data = (char*)malloc(len); + memcpy(rpt->data, buf, len); + rpt->len = len; + rpt->next = NULL; + + pthread_mutex_lock(&ll_mutex); + + if (ll_buffers == NULL) { + ll_buffers = rpt; + } else { + struct llist *cur = ll_buffers; + int num_queued = 0; + + while (cur->next != NULL) { + cur = cur->next; + num_queued++; + } + cur->next = rpt; + + if (num_queued > global_numq) + printf("ll+, now %d\n", num_queued); + else if (num_queued < global_numq) + printf("ll-, now %d\n", num_queued); + + global_numq = num_queued; + } + pthread_cond_signal(&cond); + pthread_mutex_unlock(&ll_mutex); + } +} + +static void *tcp_worker(void *arg) +{ + struct llist *curelem,*prev; + int bytesleft,bytessent, index; + struct timeval tv= {1,0}; + struct timespec ts; + struct timeval tp; + fd_set writefds; + int r = 0; + + while(1) { + if(do_exit) + pthread_exit(0); + + pthread_mutex_lock(&ll_mutex); + gettimeofday(&tp, NULL); + ts.tv_sec = tp.tv_sec+1; + ts.tv_nsec = tp.tv_usec * 1000; + r = pthread_cond_timedwait(&cond, &ll_mutex, &ts); + if(r == ETIMEDOUT) { + pthread_mutex_unlock(&ll_mutex); + printf("worker cond timeout\n"); + sighandler(0); + dead[0]=1; + pthread_exit(NULL); + } + + curelem = ll_buffers; + ll_buffers = 0; + pthread_mutex_unlock(&ll_mutex); + + while(curelem != 0) { + bytesleft = curelem->len; + index = 0; + bytessent = 0; + while(bytesleft > 0) { + FD_ZERO(&writefds); + FD_SET(s, &writefds); + r = select(0+1, NULL, &writefds, NULL, &tv); + if(r) { + bytessent = send(s, &curelem->data[index], bytesleft, 0); + if (bytessent == SOCKET_ERROR || do_exit) { + printf("worker socket error\n"); + sighandler(0); + dead[0]=1; + pthread_exit(NULL); + } else { + bytesleft -= bytessent; + index += bytessent; + } + } else if(do_exit) { + printf("worker socket bye\n"); + sighandler(0); + dead[0]=1; + pthread_exit(NULL); + } + } + prev = curelem; + curelem = curelem->next; + free(prev->data); + free(prev); + } + } +} + +#ifdef _WIN32 +#define __attribute__(x) +#pragma pack(push, 1) +#endif +struct command{ + unsigned char cmd; + unsigned int param; +}__attribute__((packed)); +#ifdef _WIN32 +#pragma pack(pop) +#endif +static void *command_worker(void *arg) +{ + int left, received; + fd_set readfds; + struct command cmd={0, 0}; + struct timeval tv= {1, 0}; + int r =0; + while(1) { + left=sizeof(cmd); + while(left >0) { + FD_ZERO(&readfds); + FD_SET(s, &readfds); + r = select(0+1, &readfds, NULL, NULL, &tv); + if(r) { + received = recv(s, (char*)&cmd+(sizeof(cmd)-left), left, 0); + if(received == SOCKET_ERROR || do_exit){ + printf("comm recv socket error\n"); + sighandler(0); + dead[1]=1; + pthread_exit(NULL); + } else { + left -= received; + } + } else if(do_exit) { + printf("comm recv bye\n"); + sighandler(0); + dead[1] = 1; + pthread_exit(NULL); + } + } + switch(cmd.cmd) { + case 0x01: + printf("set freq %d\n", cmd.param); + rtlsdr_set_center_freq(dev, cmd.param); + break; + default: + break; + } + cmd.cmd = 0xff; + } +} + +int main(int argc, char **argv) +{ + int r, opt, i; + char* addr; + int port = 1234; + uint32_t frequency = 0, samp_rate = 2048000; + struct sockaddr_in local, remote; + int device_count; + uint32_t dev_index = 0, gain = 5; + struct llist *curelem,*prev; + pthread_attr_t attr; + void *status; + struct timeval tv = {1,0}; + struct linger ling = {1,0}; + SOCKET listensocket; + fd_set readfds; + u_long blockmode = 1; +#ifdef _WIN32 + WSADATA wsd; + i = WSAStartup(MAKEWORD(2,2), &wsd); +#endif +#ifndef _WIN32 + struct sigaction sigact; + while ((opt = getopt(argc, argv, "a:p:f:s:")) != -1) { + switch (opt) { + case 'f': + frequency = atoi(optarg); + break; + case 's': + samp_rate = atoi(optarg); + break; + case 'a': + addr = optarg; + break; + case 'p': + port = atoi(optarg); + break; + default: + usage(); + break; + } + } + + if (argc <= optind) + usage(); + +#else + if(argc < 6) + usage(); + dev_index = atoi(argv[5]); + frequency = atoi(argv[4]); + samp_rate = atoi(argv[3])*1000; + port = atoi(argv[2]); + addr = argv[1]; +#endif + + printf("listen addr %s:%d\n", addr, port); + device_count = rtlsdr_get_device_count(); + if (!device_count) { + fprintf(stderr, "No supported devices found.\n"); + exit(1); + } + + printf("Found %d device(s).\n", device_count); + + rtlsdr_open(&dev, dev_index); + if (NULL == dev) { + fprintf(stderr, "Failed to open rtlsdr device #%d.\n", dev_index); + exit(1); + } + + printf("Using %s\n", rtlsdr_get_device_name(dev_index)); +#ifndef _WIN32 + sigact.sa_handler = sighandler; + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + sigaction(SIGINT, &sigact, NULL); + sigaction(SIGTERM, &sigact, NULL); + sigaction(SIGQUIT, &sigact, NULL); +#else + SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE ); +#endif + /* Set the sample rate */ + r = rtlsdr_set_sample_rate(dev, samp_rate); + if (r < 0) + fprintf(stderr, "WARNING: Failed to set sample rate.\n"); + + /* Set the frequency */ + r = rtlsdr_set_center_freq(dev, frequency); + if (r < 0) + fprintf(stderr, "WARNING: Failed to set center freq.\n"); + else + fprintf(stderr, "Tuned to %i Hz.\n", frequency); + + r = rtlsdr_set_tuner_gain(dev, gain); + if (r < 0) + fprintf(stderr, "WARNING: Failed to set tuner gain.\n"); + else + fprintf(stderr, "Tuner gain set to %i dB.\n", gain); + + /* Reset endpoint before we start reading from it (mandatory) */ + r = rtlsdr_reset_buffer(dev); + if (r < 0) + fprintf(stderr, "WARNING: Failed to reset buffers.\n"); + + + pthread_mutex_init(&exit_cond_lock, NULL); + pthread_mutex_init(&ll_mutex, NULL); + pthread_mutex_init(&exit_cond_lock, NULL); + pthread_cond_init(&cond, NULL); + pthread_cond_init(&exit_cond, NULL); + + memset(&local,0,sizeof(local)); + local.sin_family = AF_INET; + local.sin_port = htons(port); + local.sin_addr.s_addr = inet_addr(addr); + + listensocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + r = 1; + setsockopt(listensocket, SOL_SOCKET, SO_REUSEADDR, (char *)&r, sizeof(int)); + setsockopt(listensocket, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling)); + bind(listensocket,(struct sockaddr *)&local,sizeof(local)); + + #ifdef _WIN32 + ioctlsocket(listensocket, FIONBIO, &blockmode); + #else + r = fcntl(listensocket, F_GETFL, 0); + fcntl(listensocket, F_SETFL, r | O_NONBLOCK); + #endif + + while(1) { + printf("listening...\n"); + listen(listensocket,1); + + while(1) { + FD_ZERO(&readfds); + FD_SET(listensocket, &readfds); + r = select(0+1, &readfds, NULL, NULL, &tv); + if(do_exit) { + goto out; + } else if(r) { + r=sizeof(remote); + s = accept(listensocket,(struct sockaddr *)&remote, &r); + break; + } + } + + setsockopt(s, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling)); + + printf("client accepted!\n"); + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + r = pthread_create(&tcp_worker_thread, &attr, tcp_worker, NULL); + r = pthread_create(&command_thread, &attr, command_worker, NULL); + pthread_attr_destroy(&attr); + + rtlsdr_wait_async(dev, rtlsdr_callback, (void *)0); + + closesocket(s); + if(!dead[0]){ + pthread_join(tcp_worker_thread, &status); + } + if(!dead[1]){ + pthread_join(command_thread, &status); + } + + printf("all threads dead..\n"); + curelem = ll_buffers; + ll_buffers = 0; + while(curelem != 0) { + prev = curelem; + curelem = curelem->next; + free(prev->data); + free(prev); + + } + + do_exit = 0; + global_numq = 0; + } + +out: + rtlsdr_close(dev); + closesocket(listensocket); + closesocket(s); + #ifdef _WIN32 + WSACleanup(); + #endif + printf("bye!\n"); + return r >= 0 ? r : -r; +}