diff --git a/binaries/aarch64/nfqws b/binaries/aarch64/nfqws
index 603c793..61508cf 100755
Binary files a/binaries/aarch64/nfqws and b/binaries/aarch64/nfqws differ
diff --git a/binaries/aarch64/tpws b/binaries/aarch64/tpws
index 619222c..1f3d955 100755
Binary files a/binaries/aarch64/tpws and b/binaries/aarch64/tpws differ
diff --git a/binaries/armhf/nfqws b/binaries/armhf/nfqws
index a4c934e..25a3b0d 100755
Binary files a/binaries/armhf/nfqws and b/binaries/armhf/nfqws differ
diff --git a/binaries/armhf/tpws b/binaries/armhf/tpws
index f3d5341..e2a51bb 100755
Binary files a/binaries/armhf/tpws and b/binaries/armhf/tpws differ
diff --git a/binaries/mips32r1-lsb/nfqws b/binaries/mips32r1-lsb/nfqws
index 0c32f1e..a7b3f94 100755
Binary files a/binaries/mips32r1-lsb/nfqws and b/binaries/mips32r1-lsb/nfqws differ
diff --git a/binaries/mips32r1-lsb/tpws b/binaries/mips32r1-lsb/tpws
index f6d9610..26458f4 100755
Binary files a/binaries/mips32r1-lsb/tpws and b/binaries/mips32r1-lsb/tpws differ
diff --git a/binaries/mips32r1-msb/nfqws b/binaries/mips32r1-msb/nfqws
index 412614b..f2d14bf 100755
Binary files a/binaries/mips32r1-msb/nfqws and b/binaries/mips32r1-msb/nfqws differ
diff --git a/binaries/mips32r1-msb/tpws b/binaries/mips32r1-msb/tpws
index f76aa02..55023c0 100755
Binary files a/binaries/mips32r1-msb/tpws and b/binaries/mips32r1-msb/tpws differ
diff --git a/binaries/ppc/nfqws b/binaries/ppc/nfqws
index 9b42a38..6e43fe1 100755
Binary files a/binaries/ppc/nfqws and b/binaries/ppc/nfqws differ
diff --git a/binaries/ppc/tpws b/binaries/ppc/tpws
index ae3b5da..0ea5c18 100755
Binary files a/binaries/ppc/tpws and b/binaries/ppc/tpws differ
diff --git a/binaries/x86/nfqws b/binaries/x86/nfqws
index 71da68c..b81558d 100755
Binary files a/binaries/x86/nfqws and b/binaries/x86/nfqws differ
diff --git a/binaries/x86/tpws b/binaries/x86/tpws
index 0aa1284..bbe2efb 100755
Binary files a/binaries/x86/tpws and b/binaries/x86/tpws differ
diff --git a/binaries/x86_64/nfqws b/binaries/x86_64/nfqws
index bd3d1ee..35d2595 100755
Binary files a/binaries/x86_64/nfqws and b/binaries/x86_64/nfqws differ
diff --git a/binaries/x86_64/tpws b/binaries/x86_64/tpws
index 668bcb1..0217859 100755
Binary files a/binaries/x86_64/tpws and b/binaries/x86_64/tpws differ
diff --git a/docs/compile/openwrt/package/zapret/tpws/Makefile b/docs/compile/openwrt/package/zapret/tpws/Makefile
index c3a111c..f8dc5cf 100644
--- a/docs/compile/openwrt/package/zapret/tpws/Makefile
+++ b/docs/compile/openwrt/package/zapret/tpws/Makefile
@@ -12,6 +12,7 @@ define Package/tpws
 	CATEGORY:=Network
 	TITLE:=tpws
 	SUBMENU:=Zapret
+ 	DEPENDS:=+zlib
 endef
 
 define Build/Prepare
diff --git a/docs/readme.txt b/docs/readme.txt
index 84da266..b8cbe10 100644
--- a/docs/readme.txt
+++ b/docs/readme.txt
@@ -97,6 +97,7 @@ nfqws
 Эта программа - модификатор пакетов и обработчик очереди NFQUEUE.
 Она берет следующие параметры :
  --daemon		; демонизировать прогу
+ --pidfile=<file>	; сохранить PID в файл
  --qnum=200		; номер очереди
  --wsize=4		; менять tcp window size на указанный размер
  --hostcase		; менять регистр заголовка "Host:" по умолчанию на "host:".
@@ -108,10 +109,11 @@ tpws
 -----
 
 tpws - это transparent proxy.
+ --daemon               ; демонизировать прогу
+ --pidfile=<file>	; сохранить PID в файл
+ --user=<username>	; менять uid процесса
  --bind-addr		; на каком адресе слушать. может быть ipv4 или ipv6 адрес. если не указано, то слушает на всех адресах ipv4 и ipv6
  --port=<port>		; на каком порту слушать
- --daemon               ; демонизировать прогу
- --user=<username>	; менять uid процесса
  --split-http-req=method|host	; способ разделения http запросов на сегменты : около метода (GET,POST) или около заголовка Host
  --split-pos=<offset>	; делить все посылы на сегменты в указанной позиции. Если отсыл длинее 8Kb (размер буфера приема), то будет разделен каждый блок по 8Kb.
  --hostcase             ; менять регистр заголовка "Host:". по умолчанию на "host:".
@@ -126,6 +128,7 @@ tpws - это transparent proxy.
 			; список читается 1 раз при старте и хранится в памяти в виде иерархической структуры для быстрого поиска.
 			; для списка РКН может потребоваться система с 128 Mb памяти ! расчитывайте требование RAM для процесса как 3-5 кратный размер файла списка.
 			; по сигналу HUP список будет перечитан при следующем принятом соединении
+			; список может быть запакован в gzip. формат автоматически распознается и разжимается
 Параметры манипуляции могут сочетаться в любых комбинациях.
 Есть исключения : split-pos заменяет split-http-req. hostdot и hosttab взаимоисключающи.
 
@@ -136,7 +139,7 @@ tpws - это transparent proxy.
 На выходе получите ipset/zapret-ip-user.txt с IP адресами.
 
 2) ipset/get_reestr.sh получает список доменов от rublacklist и дальше их ресолвит в ip адреса
-в файл ipset/zapret-ip.txt. В этом списке есть готовые IP адреса, но судя во всему они там в точности в том виде,
+в файл ipset/zapret-ip.txt.gz. В этом списке есть готовые IP адреса, но судя во всему они там в точности в том виде,
 что вносит в реестр РосКомПозор. Адреса могут меняться, позор не успевает их обновлять, а провайдеры редко
 банят по IP : вместо этого они банят http запросы с "нехорошим" заголовком "Host:" вне зависимости
 от IP адреса. Поэтому скрипт ресолвит все сам, хотя это и занимает много времени.
@@ -185,7 +188,7 @@ get_reestr.sh может использовать мультипоточный 
 ----------------------------
 
 Альтернативой ipset является использование tpws со списком доменов.
-Список доменов РКН может быть получен скриптом ipset/get_hostlist.sh - кладется в ipset/zapret-hosts.txt.
+Список доменов РКН может быть получен скриптом ipset/get_hostlist.sh - кладется в ipset/zapret-hosts.txt.gz.
 Этот скрипт автоматически добавляет к списку РКН домены из zapret-hosts-user.txt.
 tpws должен запускаться без фильтрации по ipset. Весь трафик http идет через tpws, и он решает нужно ли
 применять дурение в зависимости от поля Host: в http запросе.
@@ -273,7 +276,7 @@ TPWS_OPT_HTTPS="--split-pos=3"
  systemctl enable zapret
 
 Удалить старые листы, если они были созданы ранее :
- rm /opt/zapret/ipset/zapret-ip.txt* /opt/zapret/ipset/zapret-ip-user.txt* /opt/zapret/ipset/zapret-ip-ipban.txt* /opt/zapret/ipset/zapret-ip-user-ipban.txt* /opt/zapret/ipset/zapret-hosts.txt
+ rm /opt/zapret/ipset/zapret-ip.txt* /opt/zapret/ipset/zapret-ip-user.txt* /opt/zapret/ipset/zapret-ip-ipban.txt* /opt/zapret/ipset/zapret-ip-user-ipban.txt* /opt/zapret/ipset/zapret-hosts.txt*
 По желанию прописать в /opt/zapret/ipset/zapret-hosts-user.txt свои домены.
 Выполнить скрипт обновления листа :
  /opt/zapret/ipset/get_config.sh
@@ -446,18 +449,18 @@ ipset можно выкинуть, если не будем пользовать
  rm /tmp/zapret-master.zip
 
 Если места совсем мало :
- opkg update
- opkg install netcat
- cd /tmp
- netcat -l -p 1111 >zapret.tar.gz
+ opkg update
+ opkg install netcat
+ cd /tmp
+ netcat -l -p 1111 >zapret.tar.gz
 На linux системе скачать и распаковать zapret. Оставить необходимый минимум файлов.
-Запаковать в архив zapret.tar.gz.
- md5sum zapret.tar.gz
- netcat <router_ip> 1111 <zapret.tar.gz
- <ctrl+c>
-На роутере
- md5sum zapret.tar.gz
-Проверить соответствие hash.
+Запаковать в архив zapret.tar.gz.
+ md5sum zapret.tar.gz
+ netcat <router_ip> 1111 <zapret.tar.gz
+ <ctrl+c>
+На роутере
+ md5sum zapret.tar.gz
+Проверить соответствие hash.
 
 Не стоит работать с распакованной версией zapret на windows. Потеряются ссылки и chmod.
 
@@ -470,7 +473,7 @@ ipset можно выкинуть, если не будем пользовать
 Настроить параметры согласно разделу "Выбор параметров".
 
 Удалить старые листы, если они были созданы ранее :
- rm /opt/zapret/ipset/zapret-ip.txt* /opt/zapret/ipset/zapret-ip-user.txt* /opt/zapret/ipset/zapret-ip-ipban.txt* /opt/zapret/ipset/zapret-ip-user-ipban.txt* /opt/zapret/ipset/zapret-hosts.txt
+ rm /opt/zapret/ipset/zapret-ip.txt* /opt/zapret/ipset/zapret-ip-user.txt* /opt/zapret/ipset/zapret-ip-ipban.txt* /opt/zapret/ipset/zapret-ip-user-ipban.txt* /opt/zapret/ipset/zapret-hosts.txt*
 По желанию прописать в /opt/zapret/ipset/zapret-hosts-user.txt свои домены.
 Выполнить скрипт обновления листа :
  /opt/zapret/ipset/get_config.sh
diff --git a/init.d/openwrt/zapret b/init.d/openwrt/zapret
index aa9a813..c25a616 100755
--- a/init.d/openwrt/zapret
+++ b/init.d/openwrt/zapret
@@ -21,7 +21,8 @@ TPPORT_HTTP=1188
 TPPORT_HTTPS=1189
 TPWS=$ZAPRET_BASE/tpws/tpws
 TPWS_USER=daemon
-TPWS_HOSTLIST=$ZAPRET_BASE/ipset/zapret-hosts.txt
+TPWS_HOSTLIST=$ZAPRET_BASE/ipset/zapret-hosts.txt.gz
+[ -f "$TPWS_HOSTLIST" ] || TPWS_HOSTLIST=$ZAPRET_BASE/ipset/zapret-hosts-user.txt
 TPWS_OPT_BASE="--user=$TPWS_USER --bind-addr=127.0.0.1"
 TPWS_OPT_BASE_HTTP="--port=$TPPORT_HTTP $TPWS_OPT_BASE"
 TPWS_OPT_BASE_HTTPS="--port=$TPPORT_HTTPS $TPWS_OPT_BASE"
diff --git a/init.d/sysv/zapret b/init.d/sysv/zapret
index 7892552..098d73b 100755
--- a/init.d/sysv/zapret
+++ b/init.d/sysv/zapret
@@ -28,7 +28,8 @@ TPPORT_HTTP=1188
 TPPORT_HTTPS=1189
 TPWS=$ZAPRET_BASE/tpws/tpws
 TPWS_USER=tpws
-TPWS_HOSTLIST=$ZAPRET_BASE/ipset/zapret-hosts.txt
+TPWS_HOSTLIST=$ZAPRET_BASE/ipset/zapret-hosts.txt.gz
+[ -f "$TPWS_HOSTLIST" ] || TPWS_HOSTLIST=$ZAPRET_BASE/ipset/zapret-hosts-user.txt
 TPWS_OPT_BASE="--user=$TPWS_USER --bind-addr=127.0.0.1"
 TPWS_OPT_BASE_HTTP="--port=$TPPORT_HTTP $TPWS_OPT_BASE"
 TPWS_OPT_BASE_HTTPS="--port=$TPPORT_HTTPS $TPWS_OPT_BASE"
diff --git a/install_easy.sh b/install_easy.sh
index 9dc0945..cf71605 100755
--- a/install_easy.sh
+++ b/install_easy.sh
@@ -283,7 +283,7 @@ check_preprequisites_linux()
 					exitp 6
 				}
 			elif [ -x "$YUM" ] ; then
-			"$YUM" -y install curl ipset daemonize || {
+			"$YUM" -y install curl ipset || {
 				echo could not install prerequisites
 				exitp 6
 			}
@@ -366,7 +366,8 @@ download_list()
 
 		# can be txt or txt.gz
 		rm -f "$EXEDIR/ipset/zapret-ip.txt"* "$EXEDIR/ipset/zapret-ip-user.txt"* \
-			"$EXEDIR/ipset/zapret-ip-ipban.txt"* "$EXEDIR/ipset/zapret-ip-user-ipban.txt"*
+			"$EXEDIR/ipset/zapret-ip-ipban.txt"* "$EXEDIR/ipset/zapret-ip-user-ipban.txt"* \
+			"$EXEDIR/ipset/zapret-hosts.txt"*
 		"$GET_LIST" || {
 			echo could not download ip list
 			exitp 25
diff --git a/ipset/get_hostlist.sh b/ipset/get_hostlist.sh
index f37dfc4..b912cc9 100755
--- a/ipset/get_hostlist.sh
+++ b/ipset/get_hostlist.sh
@@ -20,7 +20,7 @@ if test $dlsize -lt 204800; then
  echo list file is too small. can be bad.
  exit 2
 fi
-(cut -s -f2 -d';' "$ZREESTR" | grep -a . | sed -re 's/^\*\.(.+)$/\1/' | awk '{ print tolower($0) }' ; cat "$ZUSERLIST" ) | sort -u >"$ZHOSTLIST"
+(cut -s -f2 -d';' "$ZREESTR" | grep -a . | sed -re 's/^\*\.(.+)$/\1/' | awk '{ print tolower($0) }' ; cat "$ZUSERLIST" ) | sort -u | zz "$ZHOSTLIST"
 rm -f "$ZREESTR"
 
 # force tpws to reload if its running
diff --git a/ipset/zapret-hosts.txt b/ipset/zapret-hosts.txt
deleted file mode 100644
index e69de29..0000000
diff --git a/nfq/nfqws.c b/nfq/nfqws.c
index 61ffaae..0395996 100644
--- a/nfq/nfqws.c
+++ b/nfq/nfqws.c
@@ -366,6 +366,46 @@ bool droproot(uid_t uid, gid_t gid)
    return true;
 }
 
+void daemonize()
+{
+	int pid;
+
+	pid = fork();
+	if (pid == -1)
+	{
+		perror("fork: ");
+		exit(2);
+	}
+	else if (pid != 0)
+		exit(0);
+
+	if (setsid() == -1)
+		exit(2);
+	if (chdir("/") == -1)
+		exit(2);
+	close(STDIN_FILENO);
+	close(STDOUT_FILENO);
+	close(STDERR_FILENO);
+	/* redirect fd's 0,1,2 to /dev/null */
+	open("/dev/null", O_RDWR);
+	/* stdin */
+	dup(0);
+	/* stdout */
+	dup(0);
+	/* stderror */
+}
+
+bool writepid(const char *filename)
+{
+	FILE *F;
+	if (!(F=fopen(filename,"w")))
+		return false;
+	fprintf(F,"%d",getpid());
+	fclose(F);
+	return true;
+}
+
+
 void exithelp()
 {
 	printf(
@@ -375,6 +415,7 @@ void exithelp()
           " --hostspell\t\t; exact spelling of \"Host\" header. must be 4 chars. default is \"host\"\n"
           " --hostnospace\t\t; remove space after Host: and add it to User-Agent: to preserve packet size\n"
           " --daemon\t\t; daemonize\n"
+	  " --pidfile=<filename>\t; write pid to file\n"
         );
 	exit(1);
 }
@@ -392,10 +433,12 @@ int main(int argc, char **argv)
 	bool daemon=false;
 	uid_t uid=0;
 	gid_t gid;
+	char pidfile[256];
 
 	memset(&cbdata,0,sizeof(cbdata));
 	memcpy(cbdata.hostspell,"host",4); // default hostspell
-	
+	*pidfile = 0;
+
 	const struct option long_options[] = {
     	    {"qnum",required_argument,0,0},	// optidx=0
     	    {"daemon",no_argument,0,0},		// optidx=1
@@ -404,6 +447,7 @@ int main(int argc, char **argv)
     	    {"hostspell",required_argument,0,0}, // optidx=4
     	    {"hostnospace",no_argument,0,0},	// optidx=5
     	    {"user",required_argument,0,0},	// optidx=6
+    	    {"pidfile",required_argument,0,0},	// optidx=7
     	    {NULL,0,NULL,0}
 	};
 	if (argc<2) exithelp();
@@ -458,64 +502,55 @@ int main(int argc, char **argv)
 			gid = pwd->pw_gid;
 			break;
 	    	}
+		case 7: /* pidfile */
+		    strncpy(pidfile,optarg,sizeof(pidfile));
+		    pidfile[sizeof(pidfile)-1]='\0';
+		    break;
 	    }
 	}
 
-	if (daemon)
+	
+	if (daemon) daemonize();
+	
+	h = NULL;
+	qh = NULL;
+	
+	if (*pidfile && !writepid(pidfile))
 	{
-	    int pid;
-	    
-            pid = fork();
-            if (pid == -1)
-                return -1;
-            else if (pid != 0)
-        	return 0;
-            if (setsid() == -1)
-                return -1;  
-            if (chdir ("/") == -1)  
-                return -1;
-	    close(STDIN_FILENO);
-	    close(STDOUT_FILENO);
-	    close(STDERR_FILENO);                
-	    /* redirect fd's 0,1,2 to /dev/null */  
-            open ("/dev/null", O_RDWR);  
-            /* stdin */
-            dup(0);  
-            /* stdout */
-            dup(0);  
-            /* stderror */
+		fprintf(stderr,"could not write pidfile\n");
+		goto exiterr;
 	}
 	
 	printf("opening library handle\n");
 	h = nfq_open();
 	if (!h) {
 		fprintf(stderr, "error during nfq_open()\n");
-		exit(1);
+		goto exiterr;
 	}
 
 	printf("unbinding existing nf_queue handler for AF_INET (if any)\n");
 	if (nfq_unbind_pf(h, AF_INET) < 0) {
 		fprintf(stderr, "error during nfq_unbind_pf()\n");
-		exit(1);
+		goto exiterr;
 	}
 
 	printf("binding nfnetlink_queue as nf_queue handler for AF_INET\n");
 	if (nfq_bind_pf(h, AF_INET) < 0) {
 		fprintf(stderr, "error during nfq_bind_pf()\n");
-		exit(1);
+		goto exiterr;
 	}
 
 	printf("binding this socket to queue '%u'\n", cbdata.qnum);
 	qh = nfq_create_queue(h, cbdata.qnum, &cb, &cbdata);
 	if (!qh) {
 		fprintf(stderr, "error during nfq_create_queue()\n");
-		exit(1);
+		goto exiterr;
 	}
 
 	printf("setting copy_packet mode\n");
 	if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) {
 		fprintf(stderr, "can't set packet_copy mode\n");
-		exit(1);
+		goto exiterr;
 	}
 
 	fd = nfq_fd(h);
@@ -542,5 +577,10 @@ int main(int argc, char **argv)
 	printf("closing library handle\n");
 	nfq_close(h);
 
-	exit(0);
+	return 0;
+	
+exiterr:
+	if (qh) nfq_destroy_queue(qh);
+	if (h) nfq_close(h);
+	return 1;
 }
diff --git a/tpws/Makefile b/tpws/Makefile
index a0cc861..d48ed0b 100644
--- a/tpws/Makefile
+++ b/tpws/Makefile
@@ -1,6 +1,6 @@
 CC ?= gcc
 CFLAGS += -s -O3
-LIBS = 
+LIBS = -lz
 SRC_FILES = *.c
 
 all: tpws
diff --git a/tpws/gzip.c b/tpws/gzip.c
new file mode 100644
index 0000000..e0f1d83
--- /dev/null
+++ b/tpws/gzip.c
@@ -0,0 +1,75 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "gzip.h"
+
+#define ZCHUNK 16384
+#define BUFMIN 128
+#define BUFCHUNK (1024*128)
+
+int z_readfile(FILE *F,char **buf,size_t *size)
+{
+ z_stream zs;
+ int r;
+ unsigned char in[ZCHUNK];
+ size_t bufsize;
+ void *newbuf;
+
+ memset(&zs,0,sizeof(zs));
+
+ *buf = NULL;
+ bufsize=*size=0;
+
+ r=inflateInit2(&zs,47);
+ if (r != Z_OK)  return r; 
+
+ do
+ {
+   zs.avail_in = fread(in, 1, sizeof(in), F);
+   if (ferror(F))
+   {
+     r = Z_ERRNO;
+     goto zerr;
+   }
+   if (!zs.avail_in) break;
+   zs.next_in = in;
+   do
+   {
+     if ((bufsize-*size)<BUFMIN)
+     {
+       bufsize += BUFCHUNK;
+       newbuf = *buf ? realloc(*buf,bufsize) : malloc(bufsize);
+       if (newbuf==*buf)
+       if (!newbuf)
+       {
+         r = Z_MEM_ERROR;
+         goto zerr;
+       }
+       *buf = newbuf;
+     }
+     zs.avail_out = bufsize - *size;
+     zs.next_out = (unsigned char*)(*buf + *size);
+     r = inflate(&zs, Z_NO_FLUSH);
+     if (r!=Z_OK && r!=Z_STREAM_END) goto zerr;
+     *size = bufsize - zs.avail_out;
+   } while (r==Z_OK && zs.avail_in);
+ } while (r==Z_OK);
+ 
+ if (*size<bufsize)
+ {
+   // free extra space
+   if (newbuf = realloc(*buf,*size)) *buf=newbuf;
+ }
+
+ inflateEnd(&zs);
+ return Z_OK;
+
+zerr:
+ inflateEnd(&zs);
+ if (*buf)
+ {
+   free(*buf);
+   *buf = NULL;
+ }
+ return r;
+}
diff --git a/tpws/gzip.h b/tpws/gzip.h
new file mode 100644
index 0000000..75c3d87
--- /dev/null
+++ b/tpws/gzip.h
@@ -0,0 +1,6 @@
+#pragma once
+
+#include <stdio.h>
+#include <zlib.h>
+
+int z_readfile(FILE *F,char **buf,size_t *size);
diff --git a/tpws/hostlist.c b/tpws/hostlist.c
new file mode 100644
index 0000000..553d7d2
--- /dev/null
+++ b/tpws/hostlist.c
@@ -0,0 +1,82 @@
+#include <stdio.h>
+#include "hostlist.h"
+#include "gzip.h"
+
+
+static bool addpool(strpool **hostlist, char **s, char *end)
+{
+	char *p;
+	
+	// advance until eol lowering all chars
+	for (p = *s; p<end && *p && *p!='\r' && *p != '\n'; p++) *p=tolower(*p);
+	if (!StrPoolAddStrLen(hostlist, *s, p-*s))
+	{
+		StrPoolDestroy(hostlist);
+		*hostlist = NULL;
+		return false;
+	}
+	// advance to the next line
+	for (; p<end && (!*p || *p=='\r' || *p=='\n') ; p++);
+	*s = p;
+	return true;
+}
+
+
+bool LoadHostList(strpool **hostlist, char *filename)
+{
+	char *p, *e, s[256], *zbuf;
+	size_t zsize;
+	int ct = 0;
+	FILE *F;
+	
+	if (*hostlist)
+	{
+		StrPoolDestroy(hostlist);
+		*hostlist = NULL;
+	}
+	
+	if (!(F = fopen(filename, "rb")))
+	{
+		fprintf(stderr, "Could not open %s\n", filename);
+		return false;
+	}
+	if (z_readfile(F,&zbuf,&zsize)==Z_OK)
+	{
+	
+		printf("libz compression detected. uncompressed size : %zu\n", zsize);
+		fclose(F);
+		
+		p = zbuf;
+		e = zbuf + zsize;
+		while(p<e)
+		{
+			if (!addpool(hostlist,&p,e))
+			{
+				fprintf(stderr, "Not enough memory to store host list : %s\n", filename);
+				free(zbuf);
+				return false;
+			}
+			ct++;
+		}
+		free(zbuf);
+	}
+	else
+	{
+		fseek(F,0,SEEK_SET);
+
+		while (fgets(s, 256, F))
+		{
+			p = s;
+			if (!addpool(hostlist,&p,p+strlen(p)))
+			{
+				fprintf(stderr, "Not enough memory to store host list : %s\n", filename);
+				fclose(F);
+				return false;
+			}
+			ct++;
+		}
+		fclose(F);
+	}
+	printf("Loaded %d hosts from %s\n", ct, filename);
+	return true;
+}
diff --git a/tpws/hostlist.h b/tpws/hostlist.h
new file mode 100644
index 0000000..186eabd
--- /dev/null
+++ b/tpws/hostlist.h
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "strpool.h"
+
+bool LoadHostList(strpool **hostlist, char *filename);
diff --git a/tpws/strpool.c b/tpws/strpool.c
index dc1ecbf..4ffeb8a 100644
--- a/tpws/strpool.c
+++ b/tpws/strpool.c
@@ -11,6 +11,7 @@ static void ut_oom_recover(strpool *elem)
  oom=true;
 }
 
+// for zero terminated strings
 bool StrPoolAddStr(strpool **pp,const char *s)
 {
  strpool *elem;
@@ -31,6 +32,30 @@ bool StrPoolAddStr(strpool **pp,const char *s)
  }
  return true;
 }
+// for not zero terminated strings
+bool StrPoolAddStrLen(strpool **pp,const char *s,size_t slen)
+{
+ strpool *elem;
+ if (!(elem = (strpool*)malloc(sizeof(strpool))))
+  return false;
+ if (!(elem->str = malloc(slen+1)))
+ {
+  free(elem);
+  return false;
+ }
+ memcpy(elem->str,s,slen);
+ elem->str[slen]=0;
+ oom = false;
+ HASH_ADD_KEYPTR( hh, *pp, elem->str, strlen(elem->str), elem );
+ if (oom)
+ {
+  free(elem->str);
+  free(elem);
+  return false;
+ }
+ return true;
+}
+
 bool StrPoolCheckStr(strpool *p,const char *s)
 {
  strpool *elem;
diff --git a/tpws/strpool.h b/tpws/strpool.h
index 4579d77..5932ba3 100644
--- a/tpws/strpool.h
+++ b/tpws/strpool.h
@@ -15,4 +15,5 @@ typedef struct strpool {
 
 void StrPoolDestroy(strpool **p);
 bool StrPoolAddStr(strpool **pp,const char *s);
+bool StrPoolAddStrLen(strpool **pp,const char *s,size_t slen);
 bool StrPoolCheckStr(strpool *p,const char *s);
diff --git a/tpws/tpws.c b/tpws/tpws.c
index 4bddf45..8bd7095 100644
--- a/tpws/tpws.c
+++ b/tpws/tpws.c
@@ -24,38 +24,7 @@
 
 #include "tpws.h"
 #include "tpws_conn.h"
-#include "strpool.h"
-
-bool LoadHostList(strpool **hostlist, char *filename)
-{
-	char *p, s[256];
-	FILE *F = fopen(filename, "rt");
-	int ct = 0;
-
-	*hostlist = NULL;
-	if (!F)
-	{
-		fprintf(stderr, "Could not open %s\n", filename);
-		return false;
-	}
-	while (fgets(s, 256, F))
-	{
-		for (p = s + strlen(s) - 1; p >= s && (*p == '\r' || *p == '\n'); p--) *p = 0;
-		for (p = s; *p; p++) *p=tolower(*p);
-		if (!StrPoolAddStr(hostlist, s))
-		{
-			StrPoolDestroy(hostlist);
-			*hostlist = NULL;
-			fprintf(stderr, "Not enough memory to store host list : %s\n", filename);
-			fclose(F);
-			return false;
-		}
-		ct++;
-	}
-	fclose(F);
-	printf("Loaded %d hosts from %s\n", ct, filename);
-	return true;
-}
+#include "hostlist.h"
 
 enum splithttpreq { split_none = 0, split_method, split_host };
 
@@ -72,6 +41,7 @@ struct params_s
 	int split_pos;
 	int maxconn;
 	char hostfile[256];
+	char pidfile[256];
 	strpool *hostlist;
 };
 
@@ -104,7 +74,6 @@ void dohup()
  {
   if (params.hostlist)
   {
-   StrPoolDestroy(&params.hostlist);
    if (!LoadHostList(&params.hostlist, params.hostfile))
 	exit(1);
   }
@@ -547,11 +516,29 @@ void exithelp()
 		" --methodeol\t\t; add end-of-line before method\n"
 		" --unixeol\t\t; replace 0D0A to 0A\n"
 		" --daemon\t\t; daemonize\n"
+		" --pidfile=<filename>\t; write pid to file\n"
 		" --user=<username>\t; drop root privs\n"
 	);
 	exit(1);
 }
-
+void cleanup_params()
+{
+	if (params.hostlist)
+	{
+		StrPoolDestroy(&params.hostlist);
+		params.hostlist = NULL;
+	}
+}
+void exithelp_clean()
+{
+	cleanup_params();
+	exithelp();
+}
+void exit_clean(int code)
+{
+	cleanup_params();
+	exit(code);
+}
 void parse_params(int argc, char *argv[])
 {
 	int option_index = 0;
@@ -580,16 +567,17 @@ void parse_params(int argc, char *argv[])
 		{ "hosttab",no_argument,0,0 },// optidx=15
 		{ "unixeol",no_argument,0,0 },// optidx=16
 		{ "hostlist",required_argument,0,0 },// optidx=17
+		{ "pidfile",required_argument,0,0 },// optidx=18
 		{ NULL,0,NULL,0 }
 	};
 	while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1)
 	{
-		if (v) exithelp();
+		if (v) exithelp_clean();
 		switch (option_index)
 		{
 		case 0:
 		case 1:
-			exithelp();
+			exithelp_clean();
 			break;
 		case 2: /* bind-addr */
 			strncpy(params.bindaddr, optarg, sizeof(params.bindaddr));
@@ -600,7 +588,7 @@ void parse_params(int argc, char *argv[])
 			if (i <= 0 || i > 65535)
 			{
 				fprintf(stderr, "bad port number\n");
-				exit(1);
+				exit_clean(1);
 			}
 			params.port = (uint16_t)i;
 			break;
@@ -613,7 +601,7 @@ void parse_params(int argc, char *argv[])
 			if (!pwd)
 			{
 				fprintf(stderr, "non-existent username supplied\n");
-				exit(1);
+				exit_clean(1);
 			}
 			params.uid = pwd->pw_uid;
 			params.gid = pwd->pw_gid;
@@ -624,7 +612,7 @@ void parse_params(int argc, char *argv[])
 			if (params.maxconn <= 0)
 			{
 				fprintf(stderr, "bad maxconn\n");
-				exit(1);
+				exit_clean(1);
 			}
 			break;
 		case 7: /* hostcase */
@@ -634,7 +622,7 @@ void parse_params(int argc, char *argv[])
 			if (strlen(optarg) != 4)
 			{
 				fprintf(stderr, "hostspell must be exactly 4 chars long\n");
-				exit(1);
+				exit_clean(1);
 			}
 			params.hostcase = true;
 			memcpy(params.hostspell, optarg, 4);
@@ -653,7 +641,7 @@ void parse_params(int argc, char *argv[])
 			else
 			{
 				fprintf(stderr, "Invalid argument for split-http-req\n");
-				exit(1);
+				exit_clean(1);
 			}
 			break;
 		case 12: /* split-pos */
@@ -663,7 +651,7 @@ void parse_params(int argc, char *argv[])
 			else
 			{
 				fprintf(stderr, "Invalid argument for split-pos\n");
-				exit(1);
+				exit_clean(1);
 			}
 			break;
 		case 13: /* methodspace */
@@ -680,16 +668,20 @@ void parse_params(int argc, char *argv[])
 			break;
 		case 17: /* hostlist */
 			if (!LoadHostList(&params.hostlist, optarg))
-				exit(1);
+				exit_clean(1);
 			strncpy(params.hostfile,optarg,sizeof(params.hostfile));
 			params.hostfile[sizeof(params.hostfile)-1]='\0';
 			break;
+		case 18: /* pidfile */
+			strncpy(params.pidfile,optarg,sizeof(params.pidfile));
+			params.pidfile[sizeof(params.pidfile)-1]='\0';
+			break;
 		}
 	}
 	if (!params.port)
 	{
 		fprintf(stderr, "Need port number\n");
-		exit(1);
+		exit_clean(1);
 	}
 }
 
@@ -740,8 +732,18 @@ bool droproot()
 	return true;
 }
 
+bool writepid(const char *filename)
+{
+	FILE *F;
+	if (!(F=fopen(filename,"w")))
+		return false;
+	fprintf(F,"%d",getpid());
+	fclose(F);
+	return true;
+}
+
 int main(int argc, char *argv[]) {
-	int listen_fd = 0;
+	int listen_fd = -1;
 	int yes = 1, retval = 0;
 	int r;
 	struct sockaddr_storage salisten;
@@ -769,7 +771,7 @@ int main(int argc, char *argv[]) {
 		else
 		{
 			printf("bad bind addr\n");
-			exit(1);
+			goto exiterr;
 		}
 	}
 	else
@@ -783,29 +785,32 @@ int main(int argc, char *argv[]) {
 
 	if (params.daemon) daemonize();
 
+	if (*params.pidfile && !writepid(params.pidfile))
+	{
+		fprintf(stderr,"could not write pidfile\n");
+		goto exiterr;
+	}
+
 	if ((listen_fd = socket(salisten.ss_family, SOCK_STREAM, 0)) == -1) {
 		perror("socket: ");
-		exit(EXIT_FAILURE);
+		goto exiterr;
 	}
 
 	if ((salisten.ss_family == AF_INET6) && setsockopt(listen_fd, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6_only, sizeof(ipv6_only)) == -1)
 	{
 		perror("setsockopt (IPV6_ONLY): ");
-		close(listen_fd);
-		exit(EXIT_FAILURE);
+		goto exiterr;
 	}
 
 	if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1)
 	{
 		perror("setsockopt (SO_REUSEADDR): ");
-		close(listen_fd);
-		exit(EXIT_FAILURE);
+		goto exiterr;
 	}
 	if (setsockopt(listen_fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes)) == -1)
 	{
 		perror("setsockopt (SO_KEEPALIVE): ");
-		close(listen_fd);
-		exit(EXIT_FAILURE);
+		goto exiterr;
 	}
 
 	//Mark that this socket can be used for transparent proxying
@@ -813,26 +818,22 @@ int main(int argc, char *argv[]) {
 	if (setsockopt(listen_fd, SOL_IP, IP_TRANSPARENT, &yes, sizeof(yes)) == -1)
 	{
 		perror("setsockopt (IP_TRANSPARENT): ");
-		close(listen_fd);
-		exit(EXIT_FAILURE);
+		goto exiterr;
 	}
 
 	if (!droproot())
 	{
-		close(listen_fd);
-		exit(EXIT_FAILURE);
+		goto exiterr;
 	}
 
 	if (bind(listen_fd, (struct sockaddr *)&salisten, salisten_len) == -1) {
 		perror("bind: ");
-		close(listen_fd);
-		exit(EXIT_FAILURE);
+		goto exiterr;
 	}
 
 	if (listen(listen_fd, BACKLOG) == -1) {
 		perror("listen: ");
-		close(listen_fd);
-		exit(EXIT_FAILURE);
+		goto exiterr;
 	}
 
 	//splice() causes the process to receive the SIGPIPE-signal if one part (for
@@ -840,8 +841,7 @@ int main(int argc, char *argv[]) {
 	//fail and return -1, so blocking SIGPIPE.
 	if (block_sigpipe() == -1) {
 		fprintf(stderr, "Could not block SIGPIPE signal\n");
-		close(listen_fd);
-		exit(EXIT_FAILURE);
+		goto exiterr;
 	}
 
 	fprintf(stderr, "Will listen to port %d\n", params.port);
@@ -849,14 +849,16 @@ int main(int argc, char *argv[]) {
 	signal(SIGHUP, onhup); 
 
 	retval = event_loop(listen_fd);
+	
 	close(listen_fd);
-
-	if (params.hostlist) StrPoolDestroy(&params.hostlist);
+	cleanup_params();
 
 	fprintf(stderr, "Will exit\n");
 
-	if (retval < 0)
-		exit(EXIT_FAILURE);
-	else
-		exit(EXIT_SUCCESS);
+	return retval < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+	
+exiterr:
+	if (listen_fd!=-1) close(listen_fd);
+	cleanup_params();
+	return EXIT_FAILURE;
 }