diff --git a/AUTHORS b/AUTHORS
index 52850562..e4688ed5 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,2 +1,3 @@
 Steve Markgraf <steve@steve-m.de>
 Dimitri Stolnikov <horiz0n@gmx.net>
+Hoernchen <la@tfc-server.de>
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index ffb09273..0ce6f6bf 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 be402aaa..f9023cd5 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 00000000..007482ee
--- /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 <steve@steve-m.de>
+ * Copyright (C) 2012 by Hoernchen <la@tfc-server.de>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#ifndef _WIN32
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <fcntl.h>
+#endif
+
+#include <pthread.h>
+#include <libusb.h>
+
+#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;
+}