[SCM] pd-iemnet/master: Imported Upstream version 0.2

umlaeute at users.alioth.debian.org umlaeute at users.alioth.debian.org
Thu Sep 3 19:45:43 UTC 2015


The following commit has been merged in the master branch:
commit 00c1578a7e48a04cc2b2fc18a29d275940195f4d
Author: IOhannes m zmölnig <zmoelnig at umlautQ.umlaeute.mur.at>
Date:   Thu Sep 3 15:50:22 2015 +0200

    Imported Upstream version 0.2

diff --git a/AUTHORS b/AUTHORS
deleted file mode 100644
index bc50100..0000000
--- a/AUTHORS
+++ /dev/null
@@ -1,5 +0,0 @@
-Roman Häfeli
-Olaf Matthes
-Martin Peach
-Miller Puckette
-IOhannes m zmölnig
diff --git a/ChangeLog b/ChangeLog
index 2802724..1e2bdab 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2015-09-01 12:00  zmoelnig
+
+	* iemnet-v0.2
+
+	  got rid of threaded receiver
+	   - simplifies code
+	   - fixes a couple of stability bugs
+	   - compiles again on W32
+	  one-true-brace-style
+	  reproducible build
+
 2010-10-11 16:04  zmoelnig
 
 	* tcpreceive.c, udpreceive.c: use SO_REUSEPORT (if available during
@@ -199,7 +210,7 @@
 
 2010-08-09 09:22  zmoelnig
 
-	* iemnet_data.c: allow to resize NULL-floatlists
+	* iemnet_data.c: allow resizing of NULL-floatlists
 	  
 	  trying to resize a NULL-floatlist, will create a new one with the
 	  required size
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..d8cf7d4
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,280 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
diff --git a/Makefile b/Makefile
index 7b49ef5..64b19ff 100644
--- a/Makefile
+++ b/Makefile
@@ -1,39 +1,48 @@
-# To use this Makefile for your project, first put the name of your library in
-# LIBRARY_NAME variable. The folder for your project should have the same name
-# as your library.
+## Pd library template version 1.0.11
+# For instructions on how to use this template, see:
+#  http://puredata.info/docs/developer/MakefileTemplate
 LIBRARY_NAME = iemnet
-LIBRARY_VERSION = 0.1
 
-# Next, add your .c source files to the SOURCES variable.  The help files will
-# be included automatically
+# add your .c source files, one object per file, to the SOURCES
+# variable, help files will be included automatically, and for GUI
+# objects, the matching .tcl file too
 SOURCES = tcpserver.c tcpclient.c tcpsend.c tcpreceive.c udpreceive.c udpsend.c udpclient.c udpserver.c
-#SOURCES = tcpclient.c  tcpreceive.c  tcpsend.c  tcpserver.c  udpreceive~.c  udpreceive.c  udpsend~.c  udpsend.c
-
-# For objects that only build on certain platforms, add those to the SOURCES
-# line for the right platforms.
-SOURCES_android = 
-SOURCES_cygwin = 
-SOURCES_macosx = 
-SOURCES_iphoneos = 
-SOURCES_linux = 
-SOURCES_windows = 
-
-# .c source files that will be statically linked to _all_ objects
-HELPERSOURCES = iemnet.c iemnet_data.c  iemnet_receiver.c  iemnet_sender.c
 
+SHARED_SOURCES = iemnet.c iemnet_data.c  iemnet_receiver.c  iemnet_sender.c
+SHARED_HEADERS = iemnet_data.h  iemnet.h
 
 # list all pd objects (i.e. myobject.pd) files here, and their helpfiles will
 # be included automatically
-PDOBJECTS = 
+PDOBJECTS = udpsndrcv.pd
+
+# example patches and related files, in the 'examples' subfolder
+#EXAMPLES = bothtogether.pd
+
+# manuals and related files, in the 'manual' subfolder
+#MANUAL = manual.txt
 
 # if you want to include any other files in the source and binary tarballs,
-# list them here.  This can be anything from header files, READMEs, example
-# patches, documentation, etc.
-EXTRA_DIST = 
+# list them here.  This can be anything from header files, test patches,
+# documentation, etc.  README.txt and LICENSE.txt are required and therefore
+# automatically included
+EXTRA_DIST = ChangeLog FEATURES.txt NOTES.txt
+
+LIBS_windows=-lpthread
+
+#overriding the datestring
+# run `make CPPFLAGS="-DBUILD_DATE='\"somewhen in August\"'"`
+
+
+#------------------------------------------------------------------------------#
+#
+# things you might need to edit if you are using other C libraries
+#
+#------------------------------------------------------------------------------#
 
-# to enable debugging set this to "-DDEBUG"
-# you can slo just run make as "make DEBUG_CFLAGS='-DDEBUG'"
-DEBUG_CFLAGS =
+ALL_CFLAGS = -I"$(PD_INCLUDE)"
+ALL_LDFLAGS =  
+SHARED_LDFLAGS =
+ALL_LIBS = 
 
 
 #------------------------------------------------------------------------------#
@@ -42,33 +51,43 @@ DEBUG_CFLAGS =
 #
 #------------------------------------------------------------------------------#
 
-# where Pd lives
-PD_PATH = ../../../pd
-# where to install the library
+# these can be set from outside without (usually) breaking the build
+CFLAGS = -Wall -Wno-unused -W -g
+LDFLAGS =
+LIBS =
+
+# get library version from meta file
+LIBRARY_VERSION = $(shell sed -n 's|^\#X text [0-9][0-9]* [0-9][0-9]* VERSION \(.*\);|\1|p' $(LIBRARY_NAME)-meta.pd)
+
+ALL_CFLAGS += -DPD -DVERSION='"$(LIBRARY_VERSION)"'
+
+PD_INCLUDE = $(PD_PATH)/include/pd
+# where to install the library, overridden below depending on platform
 prefix = /usr/local
 libdir = $(prefix)/lib
 pkglibdir = $(libdir)/pd-externals
 objectsdir = $(pkglibdir)
 
-
 INSTALL = install
-INSTALL_FILE    = $(INSTALL) -p -m 644
-INSTALL_LIB     = $(INSTALL) -p -m 644 -s
+INSTALL_PROGRAM = $(INSTALL) -p -m 644
+INSTALL_DATA = $(INSTALL) -p -m 644
 INSTALL_DIR     = $(INSTALL) -p -m 755 -d
 
-CFLAGS = -DPD -DLIBRARY_VERSION=\"$(LIBRARY_VERSION)\" -I$(PD_PATH)/src -Wall -W -Wno-unused -g 
-LDFLAGS =  
-LIBS = 
 ALLSOURCES := $(SOURCES) $(SOURCES_android) $(SOURCES_cygwin) $(SOURCES_macosx) \
 	         $(SOURCES_iphoneos) $(SOURCES_linux) $(SOURCES_windows)
 
+DISTDIR=$(LIBRARY_NAME)-$(LIBRARY_VERSION)
+ORIGDIR=pd-$(LIBRARY_NAME:~=)_$(LIBRARY_VERSION)
+
 UNAME := $(shell uname -s)
 ifeq ($(UNAME),Darwin)
   CPU := $(shell uname -p)
   ifeq ($(CPU),arm) # iPhone/iPod Touch
-    SOURCES += $(SOURCES_macosx)
+    SOURCES += $(SOURCES_iphoneos)
     EXTENSION = pd_darwin
+    SHARED_EXTENSION = dylib
     OS = iphoneos
+    PD_PATH = /Applications/Pd-extended.app/Contents/Resources
     IPHONE_BASE=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin
     CC=$(IPHONE_BASE)/gcc
     CPP=$(IPHONE_BASE)/cpp
@@ -76,173 +95,335 @@ ifeq ($(UNAME),Darwin)
     ISYSROOT = -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk
     IPHONE_CFLAGS = -miphoneos-version-min=3.0 $(ISYSROOT) -arch armv6
     OPT_CFLAGS = -fast -funroll-loops -fomit-frame-pointer
-	CFLAGS := $(IPHONE_CFLAGS) $(OPT_CFLAGS) $(CFLAGS) \
-      -I/Applications/Pd-extended.app/Contents/Resources/include
-    LDFLAGS += -arch armv6 -bundle -undefined dynamic_lookup $(ISYSROOT)
-    LIBS += -lc 
+    ALL_CFLAGS := $(IPHONE_CFLAGS) $(ALL_CFLAGS)
+    ALL_LDFLAGS += -arch armv6 -bundle -undefined dynamic_lookup $(ISYSROOT)
+    SHARED_LDFLAGS += -arch armv6 -dynamiclib -undefined dynamic_lookup $(ISYSROOT)
+    ALL_LIBS += -lc $(LIBS_iphoneos)
     STRIP = strip -x
-    DISTDIR=$(LIBRARY_NAME)-$(LIBRARY_VERSION)
     DISTBINDIR=$(DISTDIR)-$(OS)
   else # Mac OS X
     SOURCES += $(SOURCES_macosx)
     EXTENSION = pd_darwin
+    SHARED_EXTENSION = dylib
     OS = macosx
-    OPT_CFLAGS = -ftree-vectorize -ftree-vectorizer-verbose=0 -fast
-    FAT_FLAGS = -arch i386 -arch ppc -mmacosx-version-min=10.4
-    CFLAGS += $(FAT_FLAGS) -fPIC -I/sw/include \
-      -I/Applications/Pd-extended.app/Contents/Resources/include
-    LDFLAGS += $(FAT_FLAGS) -bundle -undefined dynamic_lookup -L/sw/lib
-    LIBS += -lc 
+    PD_PATH = /Applications/Pd-extended.app/Contents/Resources
+    OPT_CFLAGS = -ftree-vectorize
+# build universal 32-bit on 10.4 and 32/64 on newer
+    ifeq ($(shell uname -r | sed 's|\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*|\1|'), 8)
+      FAT_FLAGS = -arch ppc -arch i386 -mmacosx-version-min=10.4
+    else
+      FAT_FLAGS = -arch i386 -arch x86_64 -mmacosx-version-min=10.4
+      SOURCES += $(SOURCES_iphoneos)
+    endif
+    ALL_CFLAGS += $(FAT_FLAGS) -fPIC
+ifneq ($(strip $(realpath /sw/include)),)
+    ALL_CFLAGS += -I/sw/include
+endif
+    # if the 'pd' binary exists, check the linking against it to aid with stripping
+    BUNDLE_LOADER = $(shell test ! -e $(PD_PATH)/bin/pd || echo -bundle_loader $(PD_PATH)/bin/pd)
+    ALL_LDFLAGS += $(FAT_FLAGS) -bundle $(BUNDLE_LOADER) -undefined dynamic_lookup
+ifneq ($(strip $(realpath /sw/lib)),)
+    ALL_LDFLAGS += -L/sw/lib
+endif
+    SHARED_LDFLAGS += $(FAT_FLAGS) -dynamiclib -undefined dynamic_lookup \
+	-install_name @loader_path/$(SHARED_LIB) -compatibility_version 1 -current_version 1.0
+    ALL_LIBS += -lc $(LIBS_macosx)
     STRIP = strip -x
-    DISTDIR=$(LIBRARY_NAME)-$(LIBRARY_VERSION)
     DISTBINDIR=$(DISTDIR)-$(OS)
+# install into ~/Library/Pd on Mac OS X since /usr/local isn't used much
+    pkglibdir=$(HOME)/Library/Pd
   endif
 endif
+# Tho Android uses Linux, we use this fake uname to provide an easy way to
+# setup all this things needed to cross-compile for Android using the NDK
+ifeq ($(UNAME),ANDROID)
+  CPU := arm
+  SOURCES += $(SOURCES_android)
+  EXTENSION = pd_linux
+  SHARED_EXTENSION = so
+  OS = android
+  PD_PATH = /usr
+  NDK_BASE := /usr/local/android-ndk
+  NDK_PLATFORM_VERSION := 5
+  NDK_SYSROOT=$(NDK_BASE)/platforms/android-$(NDK_PLATFORM_VERSION)/arch-arm
+  NDK_UNAME := $(shell uname -s | tr '[A-Z]' '[a-z]')
+  NDK_TOOLCHAIN_BASE=$(NDK_BASE)/toolchains/arm-linux-androideabi-4.4.3/prebuilt/$(NDK_UNAME)-x86
+  CC := $(NDK_TOOLCHAIN_BASE)/bin/arm-linux-androideabi-gcc --sysroot=$(NDK_SYSROOT)
+  OPT_CFLAGS = -O2 -funroll-loops -fomit-frame-pointer
+  CFLAGS += 
+  LDFLAGS += -rdynamic -shared
+  SHARED_LDFLAGS += -Wl,-soname,$(SHARED_LIB) -shared
+  LIBS += -lc $(LIBS_android)
+  STRIP := $(NDK_TOOLCHAIN_BASE)/bin/arm-linux-androideabi-strip \
+	--strip-unneeded -R .note -R .comment
+  DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m)
+endif
 ifeq ($(UNAME),Linux)
+  CPU := $(shell uname -m)
   SOURCES += $(SOURCES_linux)
   EXTENSION = pd_linux
+  SHARED_EXTENSION = so
   OS = linux
-  OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer
-  CFLAGS += -fPIC
-  LDFLAGS += -Wl,--export-dynamic  -shared -fPIC
-  LIBS += -lc
+  PD_PATH = /usr
+  OPT_CFLAGS = -O2 -funroll-loops -fomit-frame-pointer
+  ALL_CFLAGS += -fPIC
+  ALL_LDFLAGS += -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags
+  SHARED_LDFLAGS += -Wl,-soname,$(SHARED_LIB) -shared
+  ALL_LIBS += -lc $(LIBS_linux)
+  STRIP = strip --strip-unneeded -R .note -R .comment
+  DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m)
+endif
+ifeq ($(UNAME),GNU)
+  # GNU/Hurd, should work like GNU/Linux for basically all externals
+  CPU := $(shell uname -m)
+  SOURCES += $(SOURCES_linux)
+  EXTENSION = pd_linux
+  SHARED_EXTENSION = so
+  OS = linux
+  PD_PATH = /usr
+  OPT_CFLAGS = -O2 -funroll-loops -fomit-frame-pointer
+  ALL_CFLAGS += -fPIC
+  ALL_LDFLAGS += -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags
+  SHARED_LDFLAGS += -shared -Wl,-soname,$(SHARED_LIB)
+  ALL_LIBS += -lc $(LIBS_linux)
+  STRIP = strip --strip-unneeded -R .note -R .comment
+  DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m)
+endif
+ifeq ($(UNAME),GNU/kFreeBSD)
+  # Debian GNU/kFreeBSD, should work like GNU/Linux for basically all externals
+  CPU := $(shell uname -m)
+  SOURCES += $(SOURCES_linux)
+  EXTENSION = pd_linux
+  SHARED_EXTENSION = so
+  OS = linux
+  PD_PATH = /usr
+  OPT_CFLAGS = -O2 -funroll-loops -fomit-frame-pointer
+  ALL_CFLAGS += -fPIC
+  ALL_LDFLAGS += -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags
+  SHARED_LDFLAGS += -shared -Wl,-soname,$(SHARED_LIB)
+  ALL_LIBS += -lc $(LIBS_linux)
   STRIP = strip --strip-unneeded -R .note -R .comment
-  DISTDIR=$(LIBRARY_NAME)-$(LIBRARY_VERSION)
   DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m)
 endif
 ifeq (CYGWIN,$(findstring CYGWIN,$(UNAME)))
+  CPU := $(shell uname -m)
   SOURCES += $(SOURCES_cygwin)
   EXTENSION = dll
+  SHARED_EXTENSION = dll
   OS = cygwin
-  OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer
-  CFLAGS += 
-  LDFLAGS += -Wl,--export-dynamic -shared -L$(PD_PATH)/src
-  LIBS += -lc -lpd
+  PD_PATH = $(shell cygpath $$PROGRAMFILES)/pd
+  OPT_CFLAGS = -O2 -funroll-loops -fomit-frame-pointer
+  ALL_CFLAGS += 
+  ALL_LDFLAGS += -rdynamic -shared -L"$(PD_PATH)/src" -L"$(PD_PATH)/bin"
+  SHARED_LDFLAGS += -shared -Wl,-soname,$(SHARED_LIB) -L"$(PD_PATH)/src" -L"$(PD_PATH)/bin"
+  ALL_LIBS += -lc -lpd $(LIBS_cygwin)
   STRIP = strip --strip-unneeded -R .note -R .comment
-  DISTDIR=$(LIBRARY_NAME)-$(LIBRARY_VERSION)
   DISTBINDIR=$(DISTDIR)-$(OS)
 endif
 ifeq (MINGW,$(findstring MINGW,$(UNAME)))
+  CPU := $(shell uname -m)
   SOURCES += $(SOURCES_windows)
   EXTENSION = dll
+  SHARED_EXTENSION = dll
   OS = windows
+  PD_PATH = $(shell cd "$$PROGRAMFILES/pd" && pwd)
+  # MinGW doesn't seem to include cc so force gcc
+  CC=gcc
   OPT_CFLAGS = -O3 -funroll-loops -fomit-frame-pointer
-  WINDOWS_HACKS = -D'O_NONBLOCK=1'
-  CFLAGS += -mms-bitfields $(WINDOWS_HACKS)
-  LDFLAGS += -s -shared -Wl,--enable-auto-import
-  LIBS += -L$(PD_PATH)/src -L$(PD_PATH)/bin -L$(PD_PATH)/obj -lpd -lwsock32 -lkernel32 -luser32 -lgdi32
+  ALL_CFLAGS += -mms-bitfields
+  ALL_LDFLAGS += -s -shared -Wl,--enable-auto-import -L"$(PD_PATH)/src" -L"$(PD_PATH)/bin" -L"$(PD_PATH)/obj"
+  SHARED_LDFLAGS += -shared -L"$(PD_PATH)/src" -L"$(PD_PATH)/bin" -L"$(PD_PATH)/obj"
+  ALL_LIBS += -lpd -lwsock32 -lkernel32 -luser32 -lgdi32 $(LIBS_windows)
   STRIP = strip --strip-unneeded -R .note -R .comment
-  DISTDIR=$(LIBRARY_NAME)-$(LIBRARY_VERSION)
   DISTBINDIR=$(DISTDIR)-$(OS)
 endif
 
-CFLAGS += $(OPT_CFLAGS)
-CFLAGS += $(DEBUG_CFLAGS)
+-include Makefile.local
+
+# in case somebody manually set the HELPPATCHES above
+HELPPATCHES ?= $(SOURCES:.c=-help.pd) $(PDOBJECTS:.pd=-help.pd)
+
+ALL_CFLAGS := $(CPPFLAGS) $(ALL_CFLAGS) $(OPT_CFLAGS) $(CFLAGS)
+ALL_LDFLAGS := $(ALL_LDFLAGS) $(LDFLAGS)
+ALL_LIBS := $(ALL_LIBS) $(LIBS)
 
+SHARED_SOURCES ?= $(shell test ! -e lib$(LIBRARY_NAME).c || \
+	echo lib$(LIBRARY_NAME).c )
+SHARED_HEADERS ?= $(shell test ! -e $(LIBRARY_NAME).h || echo $(LIBRARY_NAME).h)
+SHARED_LIB ?= lib$(LIBRARY_NAME:=.$(SHARED_EXTENSION))
 
-.PHONY = install libdir_install single_install install-doc install-exec clean dist etags
+.PHONY = all clean distclean install dist \
+        etags dpkg-source showsetup \
+        libdir_install install-objects \
+        single_install install-libobject \
+        install-doc install-examples install-manual \
+        libdir $(LIBRARY_NAME)
 
-all: $(SOURCES:.c=.$(EXTENSION))
+all: $(SOURCES:.c=.$(EXTENSION)) $(SHARED_LIB)
 
-%.o: %.c
-	$(CC) $(CFLAGS) -o "$@" -c "$<"
+%.o: %.c $(SHARED_HEADERS)
+	$(CC) $(ALL_CFLAGS) -o $@ -c $<
 
-%.$(EXTENSION): %.o $(HELPERSOURCES:.c=.o)
-	$(CC) $(LDFLAGS) -o "$@" $^  $(LIBS)
-	chmod a-x "$*.$(EXTENSION)"
+%.$(EXTENSION): %.o $(SHARED_LIB)
+	$(CC) $(ALL_LDFLAGS) -o $@ $^  $(ALL_LIBS)
+	chmod a-x $@
 
 # this links everything into a single binary file
-$(LIBRARY_NAME): $(SOURCES:.c=.o) $(LIBRARY_NAME).o $(HELPERSOURCES:.c=.o)
-	$(CC) $(LDFLAGS) -o $@.$(EXTENSION) $^ $(LIBS)
-	chmod a-x $@.$(EXTENSION)
+$(LIBRARY_NAME): $(LIBRARY_NAME).$(EXTENSION)
 
+$(LIBRARY_NAME).$(EXTENSION): $(SOURCES:.c=.o) $(LIBRARY_NAME).o
+	$(CC) $(ALL_LDFLAGS) -o $@ $^ $(ALL_LIBS)
+	chmod a-x $@
+
+$(SHARED_LIB): $(SHARED_SOURCES:.c=.o)
+	$(CC) $(SHARED_LDFLAGS) -o $@ $^ $(ALL_LIBS)
 
 install: libdir_install
 
 # The meta and help files are explicitly installed to make sure they are
 # actually there.  Those files are not optional, then need to be there.
-libdir_install: $(SOURCES:.c=.$(EXTENSION)) install-doc
+install-objects: $(SOURCES:.c=.$(EXTENSION)) $(SHARED_LIB) $(PDOBJECTS) $(SHARED_TCL_LIB)
 	$(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
-	$(INSTALL_FILE) $(LIBRARY_NAME)-meta.pd \
+	$(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd \
 		$(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
-	test -z "$(SOURCES)" || \
-		$(INSTALL_LIB) $(SOURCES:.c=.$(EXTENSION)) \
-			$(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
-	test -z "$(PDOBJECTS)" || \
-		$(INSTALL_LIB) $(OBJECTS) \
+	$(INSTALL_DATA) $^ \
+		$(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+	test -z "$(strip $(wildcard $(SOURCES:.c=.tcl)))" || \
+		$(INSTALL_DATA) $(wildcard $(SOURCES:.c=.tcl)) \
 			$(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+libdir_install: install-objects install-doc install-examples install-manual
 
 # install library linked as single binary
-single_install: $(LIBRARY_NAME) install-doc install-exec
+install-libobject: $(LIBRARY_NAME).$(EXTENSION)
 	$(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
-	$(INSTALL_FILE) $(LIBRARY_NAME).$(EXTENSION) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
-	$(STRIP) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/$(LIBRARY_NAME).$(EXTENSION)
+	$(INSTALL_PROGRAM) $^ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+	-$(STRIP) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/$(LIBRARY_NAME).$(EXTENSION)
+
+single_install: install-libobject install-doc install-examples install-manual
 
 install-doc:
 	$(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
-	test -z "$(SOURCES)" || \
-		$(INSTALL_FILE) $(SOURCES:.c=-help.pd) \
-			$(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
-	test -z "$(PDOBJECTS)" || \
-		$(INSTALL_FILE) $(PDOBJECTS:.pd=-help.pd) \
+	test -z "$(strip $(SOURCES) $(PDOBJECTS))" || \
+		$(INSTALL_DATA) $(HELPPATCHES) \
 			$(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
-	$(INSTALL_FILE) README.txt $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/README.txt
-	$(INSTALL_FILE) VERSION.txt $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/VERSION.txt
-	$(INSTALL_FILE) CHANGES.txt $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/CHANGES.txt
+	$(INSTALL_DATA) README.txt $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/README.txt
+	$(INSTALL_DATA) LICENSE.txt $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/LICENSE.txt
+	$(INSTALL_DATA) ChangeLog $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/CHANGES.txt
+
+install-examples:
+	test -z "$(strip $(EXAMPLES))" || \
+		$(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples && \
+		for file in $(EXAMPLES); do \
+			$(INSTALL_DATA) examples/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples; \
+		done
+
+install-manual:
+	test -z "$(strip $(MANUAL))" || \
+		$(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/manual && \
+		for file in $(MANUAL); do \
+			$(INSTALL_DATA) manual/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/manual; \
+		done
 
 
 clean:
-	-rm -f -- $(SOURCES:.c=.o) $(HELPERSOURCES:.c=.o)
+	-rm -f -- $(SOURCES:.c=.o) $(SOURCES_LIB:.c=.o) $(SHARED_SOURCES:.c=.o)
 	-rm -f -- $(SOURCES:.c=.$(EXTENSION))
+	-rm -f -- $(LIBRARY_NAME).o
 	-rm -f -- $(LIBRARY_NAME).$(EXTENSION)
+	-rm -f -- $(SHARED_LIB)
 
 distclean: clean
-	-rm -f *~ *.o *.$(EXTENSION)
 	-rm -f -- $(DISTBINDIR).tar.gz
 	-rm -rf -- $(DISTBINDIR)
 	-rm -f -- $(DISTDIR).tar.gz
 	-rm -rf -- $(DISTDIR)
+	-rm -f -- $(ORIGDIR).tar.gz
+	-rm -rf -- $(ORIGDIR)
 
 
 $(DISTBINDIR):
 	$(INSTALL_DIR) $(DISTBINDIR)
 
 libdir: all $(DISTBINDIR)
-	$(INSTALL_FILE) $(LIBRARY_NAME)-meta.pd  $(DISTBINDIR)
-	$(INSTALL_FILE) $(SOURCES)  $(DISTBINDIR)
-	$(INSTALL_FILE) $(SOURCES:.c=-help.pd) $(DISTBINDIR)
-	test -z "$(EXTRA_DIST)" || \
-		$(INSTALL_FILE) $(EXTRA_DIST)    $(DISTBINDIR)
+	$(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd  $(DISTBINDIR)
+	$(INSTALL_DATA) $(SOURCES) $(SHARED_SOURCES) $(SHARED_HEADERS) $(DISTBINDIR)
+	$(INSTALL_DATA) $(HELPPATCHES) $(DISTBINDIR)
+	test -z "$(strip $(EXTRA_DIST))" || \
+		$(INSTALL_DATA) $(EXTRA_DIST)    $(DISTBINDIR)
 #	tar --exclude-vcs -czpf $(DISTBINDIR).tar.gz $(DISTBINDIR)
 
 $(DISTDIR):
 	$(INSTALL_DIR) $(DISTDIR)
 
+$(ORIGDIR):
+	$(INSTALL_DIR) $(ORIGDIR)
+
 dist: $(DISTDIR)
-	$(INSTALL_FILE) Makefile  $(DISTDIR)
-	$(INSTALL_FILE) $(LIBRARY_NAME)-meta.pd  $(DISTDIR)
-	test -z "$(ALLSOURCES)" || \
-		$(INSTALL_FILE) $(ALLSOURCES)  $(DISTDIR)
-	test -z "$(ALLSOURCES)" || \
-		$(INSTALL_FILE) $(ALLSOURCES:.c=-help.pd) $(DISTDIR)
-	test -z "$(PDOBJECTS)" || \
-		$(INSTALL_FILE) $(PDOBJECTS)  $(DISTDIR)
-	test -z "$(PDOBJECTS)" || \
-		$(INSTALL_FILE) $(PDOBJECTS:.pd=-help.pd) $(DISTDIR)
-	test -z "$(EXTRA_DIST)" || \
-		$(INSTALL_FILE) $(EXTRA_DIST)    $(DISTDIR)
+	$(INSTALL_DATA) Makefile  $(DISTDIR)
+	$(INSTALL_DATA) README.txt $(DISTDIR)
+	$(INSTALL_DATA) LICENSE.txt $(DISTDIR)
+	$(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd  $(DISTDIR)
+	test -z "$(strip $(ALLSOURCES))" || \
+		$(INSTALL_DATA) $(ALLSOURCES)  $(DISTDIR)
+	test -z "$(strip $(wildcard $(ALLSOURCES:.c=.tcl)))" || \
+		$(INSTALL_DATA) $(wildcard $(ALLSOURCES:.c=.tcl))  $(DISTDIR)
+	test -z "$(strip $(SHARED_HEADERS))" || \
+		$(INSTALL_DATA) $(SHARED_HEADERS)  $(DISTDIR)
+	test -z "$(strip $(SHARED_SOURCES))" || \
+		$(INSTALL_DATA) $(SHARED_SOURCES)  $(DISTDIR)
+	test -z "$(strip $(PDOBJECTS))" || \
+		$(INSTALL_DATA) $(PDOBJECTS)  $(DISTDIR)
+	test -z "$(strip $(HELPPATCHES))" || \
+		$(INSTALL_DATA) $(HELPPATCHES) $(DISTDIR)
+	test -z "$(strip $(EXTRA_DIST))" || \
+		$(INSTALL_DATA) $(EXTRA_DIST)    $(DISTDIR)
+	test -z "$(strip $(EXAMPLES))" || \
+		$(INSTALL_DIR) $(DISTDIR)/examples && \
+		for file in $(EXAMPLES); do \
+			$(INSTALL_DATA) examples/$$file $(DISTDIR)/examples; \
+		done
+	test -z "$(strip $(MANUAL))" || \
+		$(INSTALL_DIR) $(DISTDIR)/manual && \
+		for file in $(MANUAL); do \
+			$(INSTALL_DATA) manual/$$file $(DISTDIR)/manual; \
+		done
 	tar --exclude-vcs -czpf $(DISTDIR).tar.gz $(DISTDIR)
 
+# make a Debian source package
+dpkg-source:
+	debclean
+	make distclean dist
+	mv $(DISTDIR) $(ORIGDIR)
+	tar --exclude-vcs -czpf ../$(ORIGDIR).orig.tar.gz $(ORIGDIR)
+	rm -f -- $(DISTDIR).tar.gz
+	rm -rf -- $(DISTDIR) $(ORIGDIR)
+	cd .. && dpkg-source -b $(LIBRARY_NAME)
 
 etags:
 	etags *.h $(SOURCES) ../../pd/src/*.[ch] /usr/include/*.h /usr/include/*/*.h
 
-showpaths:
+showsetup:
+	@echo "CC: $(CC)"
+	@echo "CFLAGS: $(CFLAGS)"
+	@echo "LDFLAGS: $(LDFLAGS)"
+	@echo "LIBS: $(LIBS)"
+	@echo "ALL_CFLAGS: $(ALL_CFLAGS)"
+	@echo "ALL_LDFLAGS: $(ALL_LDFLAGS)"
+	@echo "ALL_LIBS: $(ALL_LIBS)"
+	@echo "PD_INCLUDE: $(PD_INCLUDE)"
 	@echo "PD_PATH: $(PD_PATH)"
 	@echo "objectsdir: $(objectsdir)"
 	@echo "LIBRARY_NAME: $(LIBRARY_NAME)"
+	@echo "LIBRARY_VERSION: $(LIBRARY_VERSION)"
 	@echo "SOURCES: $(SOURCES)"
+	@echo "SHARED_HEADERS: $(SHARED_HEADERS)"
+	@echo "SHARED_SOURCES: $(SHARED_SOURCES)"
+	@echo "SHARED_LIB: $(SHARED_LIB)"
+	@echo "PDOBJECTS: $(PDOBJECTS)"
 	@echo "ALLSOURCES: $(ALLSOURCES)"
+	@echo "ALLSOURCES TCL: $(wildcard $(ALLSOURCES:.c=.tcl))"
 	@echo "UNAME: $(UNAME)"
 	@echo "CPU: $(CPU)"
-
+	@echo "pkglibdir: $(pkglibdir)"
+	@echo "DISTDIR: $(DISTDIR)"
+	@echo "ORIGDIR: $(ORIGDIR)"
diff --git a/NEWS b/NEWS
deleted file mode 100644
index a7d7414..0000000
--- a/NEWS
+++ /dev/null
@@ -1,10 +0,0 @@
-what's new in iemnet?
-
-0.1
-
-- forked away from mrpeach/net
-- one thread for each socket
-- default-target concept: either send to all clients, a single client or all-but
-  a single client
-- getting rid of cruft either not related to networking (e.g. file-handling) or
-  workarounds for bugs/design problems
diff --git a/NOTES.txt b/NOTES.txt
index 1a4f2d2..9e5becd 100644
--- a/NOTES.txt
+++ b/NOTES.txt
@@ -3,24 +3,25 @@ scratchpad for the development of iemnet
 
 speed & syslocks
 ================
-one bottleneck right now is the synchronisation with Pd's 
-main thread to register a clock callback.
-doing a sys_lock() whenever a package arrives will slow down things immensely.
-
-alternatives:
- no sys_lock(): will eventually crash Pd (no option)
- use sys_trylock(): this might eventually fail to notify Pd of newly arrived 
-                    packets (bad for throughput)
- external polling: no syslock needed at all, but more complicated
- keep track of clock_callback: "notified" flag tells us, whether we have already
-           sent a notification which has not yet been handled...no need to notify again
-
- #4 looks most promising
-
+setting Pd's clocks is not thread-safe, but calling sys_lock() will slow
+the entire process down to unusability.
+therefore, we use a (per-receiver) thread, that get's waits on a pthread_cond_t
+and will syslock if needed.
+LATER there should only be one of these clock-threads (per RTE, in case we
+finally can run multiple Pd's in a single applications), that maintains it's own
+list of callbacks+data.
 
 tests for tcpclient/server:
 	client disconnects -> server should get notified
 	server disconnects -> client should get notified
 	client crashes -> server should disconnect
 	server crashes -> client should disconnect
-	
+
+known BUGS:
+
+[tcpclient] now does all the actual connect/disconnect work in a helper-thread.
+unfortunately, iemnet__receiver_destroy() assumes that it is called from the
+main-thread and will outlet_list the remaining bytes in the dtor.
+however, outlet_list is not threadsafe.
+possible solution: see speed&syslocks for a leightweight thread-safe callback
+framework.
diff --git a/README.txt b/README.txt
index 191818a..385578e 100644
--- a/README.txt
+++ b/README.txt
@@ -25,9 +25,8 @@ time), easy DoS (each thread uses one in a limited number of thread handles),
 and abandons determinism (nobody guarantees that parallel threads are executed
 "in order"; thus a message in a later-spawned thread might be delivered to the
 socket earlier than older messages - effectively circumventing one of the
-promises of TCP/IP: that all packets will reappear in order; i haven't seen this
-behaviour of mrpeach/net in real life yet; however i don't see any
-countermeasurements either)
+promises of TCP/IP: that all packets will reappear in order; users have already
+reported this behaviour, which makes using those objects a bit unreliable)
 
 on the long run compatibility with the upstream library is intended.
 (though probably not for all the cruft that is in there)
@@ -51,7 +50,7 @@ _heavy_ load. most do both.
 iemnet wants to provide objects whih allow you to saturate the network
 connection and still keep Pd reactive.
 (sidenote: saturating even a 100MBit network with Pd might lead to audio
-dropouts; this is not necessarily related to the network but rather to the 
+dropouts; this is not necessarily related to the network but rather to the
 amount of data processed by Pd...)
 
 easy to use:
diff --git a/build/w32-vs2003/iemnet.sln b/build/w32-vs2003/iemnet.sln
deleted file mode 100644
index 00e86c1..0000000
--- a/build/w32-vs2003/iemnet.sln
+++ /dev/null
@@ -1,18 +0,0 @@
-Microsoft Visual Studio Solution File, Format Version 8.00
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iemnet", "iemnet.vcproj", "{6B55773B-3FF5-4F09-B538-2A7007DEC4DB}"
-	ProjectSection(ProjectDependencies) = postProject
-	EndProjectSection
-EndProject
-Global
-	GlobalSection(SolutionConfiguration) = preSolution
-		Release = Release
-	EndGlobalSection
-	GlobalSection(ProjectConfiguration) = postSolution
-		{6B55773B-3FF5-4F09-B538-2A7007DEC4DB}.Release.ActiveCfg = Release|Win32
-		{6B55773B-3FF5-4F09-B538-2A7007DEC4DB}.Release.Build.0 = Release|Win32
-	EndGlobalSection
-	GlobalSection(ExtensibilityGlobals) = postSolution
-	EndGlobalSection
-	GlobalSection(ExtensibilityAddIns) = postSolution
-	EndGlobalSection
-EndGlobal
diff --git a/build/w32-vs2003/iemnet.vcproj b/build/w32-vs2003/iemnet.vcproj
deleted file mode 100644
index bef546f..0000000
--- a/build/w32-vs2003/iemnet.vcproj
+++ /dev/null
@@ -1,134 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
-	ProjectType="Visual C++"
-	Version="7.10"
-	Name="iemnet"
-	ProjectGUID="{6B55773B-3FF5-4F09-B538-2A7007DEC4DB}"
-	RootNamespace="iemnet"
-	SccProjectName=""
-	SccLocalPath="">
-	<Platforms>
-		<Platform
-			Name="Win32"/>
-	</Platforms>
-	<Configurations>
-		<Configuration
-			Name="Release|Win32"
-			OutputDirectory="."
-			IntermediateDirectory=".\obj"
-			ConfigurationType="2"
-			UseOfMFC="0"
-			ATLMinimizesCRunTimeLibraryUsage="FALSE">
-			<Tool
-				Name="VCCLCompilerTool"
-				Optimization="4"
-				AdditionalIncludeDirectories="..\..\..\pd\src;"$(ProgramFiles)\pd\src""
-				PreprocessorDefinitions="__WIN32__;_WIN32"
-				RuntimeLibrary="0"
-				StructMemberAlignment="5"
-				UsePrecompiledHeader="0"
-				PrecompiledHeaderFile=".\obj/$(ProjectName).pch"
-				AssemblerListingLocation=".\obj/"
-				ObjectFile=".\obj/"
-				ProgramDataBaseFileName=".\obj/"
-				BrowseInformation="1"
-				WarningLevel="3"
-				SuppressStartupBanner="TRUE"
-				CompileAs="0"/>
-			<Tool
-				Name="VCCustomBuildTool"/>
-			<Tool
-				Name="VCLinkerTool"
-				AdditionalDependencies="wsock32.lib libc.lib oldnames.lib pd.lib pthreadVC.lib"
-				OutputFile="$(ProjectName).dll"
-				LinkIncremental="1"
-				SuppressStartupBanner="TRUE"
-				AdditionalLibraryDirectories="..\..\..\pd\bin;"$(ProgramFiles)\pd\bin""
-				IgnoreAllDefaultLibraries="TRUE"
-				ProgramDatabaseFile="./$(ProjectName).pdb"
-				ImportLibrary="./$(ProjectName).lib"
-				TargetMachine="1"/>
-			<Tool
-				Name="VCMIDLTool"
-				SuppressStartupBanner="TRUE"
-				TargetEnvironment="1"
-				TypeLibraryName="./zexy.tlb"
-				HeaderFileName=""/>
-			<Tool
-				Name="VCPostBuildEventTool"/>
-			<Tool
-				Name="VCPreBuildEventTool"/>
-			<Tool
-				Name="VCPreLinkEventTool"/>
-			<Tool
-				Name="VCResourceCompilerTool"
-				Culture="3079"/>
-			<Tool
-				Name="VCWebServiceProxyGeneratorTool"/>
-			<Tool
-				Name="VCXMLDataGeneratorTool"/>
-			<Tool
-				Name="VCWebDeploymentTool"/>
-			<Tool
-				Name="VCManagedWrapperGeneratorTool"/>
-			<Tool
-				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
-		</Configuration>
-	</Configurations>
-	<References>
-	</References>
-	<Files>
-		<Filter
-			Name="objectclasses"
-			Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
-			<File
-				RelativePath="..\..\tcpclient.c">
-			</File>
-			<File
-				RelativePath="..\..\tcpreceive.c">
-			</File>
-			<File
-				RelativePath="..\..\tcpsend.c">
-			</File>
-			<File
-				RelativePath="..\..\tcpserver.c">
-			</File>
-			<File
-				RelativePath="..\..\udpclient.c">
-			</File>
-			<File
-				RelativePath="..\..\udpreceive.c">
-			</File>
-			<File
-				RelativePath="..\..\udpsend.c">
-			</File>
-			<File
-				RelativePath="..\..\udpserver.c">
-			</File>
-		</Filter>
-		<Filter
-			Name="lib"
-			Filter="">
-			<File
-				RelativePath="..\..\iemnet.c">
-			</File>
-			<File
-				RelativePath="..\..\iemnet.h">
-			</File>
-			<File
-				RelativePath="..\..\iemnet_data.c">
-			</File>
-			<File
-				RelativePath="..\..\iemnet_data.h">
-			</File>
-			<File
-				RelativePath="..\..\iemnet_receiver.c">
-			</File>
-			<File
-				RelativePath="..\..\iemnet_sender.c">
-			</File>
-		</Filter>
-	</Files>
-	<Globals>
-	</Globals>
-</VisualStudioProject>
diff --git a/iemnet-meta.pd b/iemnet-meta.pd
index cf00c23..26b2760 100644
--- a/iemnet-meta.pd
+++ b/iemnet-meta.pd
@@ -4,7 +4,7 @@
 Music and Acoustics (IEM) \, University of Music and Performing Arts
 \, Graz \, Austria;
 #N canvas 25 49 420 300 META 0;
-#X text 10 10 VERSION 0.1;
+#X text 10 10 VERSION 0.2;
 #X text 10 30 AUTHOR IOhannes m zmoelnig <zmoelnig at iem.at>;
 #X text 10 50 NAME iemnet;
 #X text 10 70 LICENSE GPL-2;
diff --git a/iemnet.c b/iemnet.c
index 5922f29..90e39d0 100644
--- a/iemnet.c
+++ b/iemnet.c
@@ -1,20 +1,62 @@
 /* iemnet
- *  copyright (c) 2010 IOhannes m zmölnig, IEM
+ * this file provides core infrastructure for the iemnet-objects
+ *
+ *  copyright © 2010-2015 IOhannes m zmölnig, IEM
  */
 
+/* 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/                                             */
+/*                                                                              */
+
 #define DEBUGLEVEL
 
 #include "iemnet.h"
 #include <stdlib.h>
-void iemnet__addrout(t_outlet*status_outlet, t_outlet*address_outlet, 
-		     long address, unsigned short port) {
+
+#include <pthread.h>
+
+/* close a socket properly */
+void iemnet__closesocket(int sockfd, int verbose)
+{
+  if(sockfd >=0) {
+#ifndef SHUT_RDWR
+# define SHUT_RDWR 2
+#endif
+    int how=SHUT_RDWR;
+    int err = shutdown(sockfd,
+                       how); /* needed on linux, since the recv won't shutdown on sys_closesocket() alone */
+    if(verbose && err) {
+      perror("iemnet:socket-shutdown");
+    }
+    sys_closesocket(sockfd);
+  }
+}
+
+
+/* various functions to send data to output in a uniform way */
+void iemnet__addrout(t_outlet*status_outlet, t_outlet*address_outlet,
+                     long address, unsigned short port)
+{
 
   static t_atom addr[5];
   static int firsttime=1;
 
   if(firsttime) {
     int i=0;
-    for(i=0; i<5; i++)SETFLOAT(addr+i, 0);
+    for(i=0; i<5; i++) {
+      SETFLOAT(addr+i, 0);
+    }
     firsttime=0;
   }
 
@@ -24,29 +66,48 @@ void iemnet__addrout(t_outlet*status_outlet, t_outlet*address_outlet,
   addr[3].a_w.w_float = (address & 0x0FF);
   addr[4].a_w.w_float = port;
 
-  if(status_outlet )outlet_anything(status_outlet , gensym("address"), 5, addr);
-  if(address_outlet)outlet_list    (address_outlet, gensym("list"   ), 5, addr);
+  if(status_outlet ) {
+    outlet_anything(status_outlet , gensym("address"), 5, addr);
+  }
+  if(address_outlet) {
+    outlet_list    (address_outlet, gensym("list"   ), 5, addr);
+  }
 }
 
-void iemnet__numconnout(t_outlet*status_outlet, t_outlet*numcon_outlet, int numconnections) {
+void iemnet__numconnout(t_outlet*status_outlet, t_outlet*numcon_outlet,
+                        int numconnections)
+{
   t_atom atom[1];
   SETFLOAT(atom, numconnections);
 
-  if(status_outlet)outlet_anything(status_outlet , gensym("connections"), 1, atom);
-  if(numcon_outlet)outlet_float   (numcon_outlet, numconnections);
+  if(status_outlet) {
+    outlet_anything(status_outlet , gensym("connections"), 1, atom);
+  }
+  if(numcon_outlet) {
+    outlet_float   (numcon_outlet, numconnections);
+  }
 }
 
-void iemnet__socketout(t_outlet*status_outlet, t_outlet*socket_outlet, int socketfd) {
+void iemnet__socketout(t_outlet*status_outlet, t_outlet*socket_outlet,
+                       int socketfd)
+{
   t_atom atom[1];
   SETFLOAT(atom, socketfd);
 
-  if(status_outlet)outlet_anything(status_outlet , gensym("socket"), 1, atom);
-  if(socket_outlet)outlet_float   (socket_outlet, socketfd);
+  if(status_outlet) {
+    outlet_anything(status_outlet , gensym("socket"), 1, atom);
+  }
+  if(socket_outlet) {
+    outlet_float   (socket_outlet, socketfd);
+  }
 }
 
 
-void iemnet__streamout(t_outlet*outlet, int argc, t_atom*argv, int stream) {
-  if(NULL==outlet)return;
+void iemnet__streamout(t_outlet*outlet, int argc, t_atom*argv, int stream)
+{
+  if(NULL==outlet) {
+    return;
+  }
 
   if(stream) {
     while(argc-->0) {
@@ -63,7 +124,8 @@ typedef struct _names {
   struct _names*next;
 } t_iemnet_names;
 static t_iemnet_names*namelist=0;
-static int iemnet__nametaken(const char*namestring) {
+static int iemnet__nametaken(const char*namestring)
+{
   t_symbol*name=gensym(namestring);
   t_iemnet_names*curname=namelist;
   t_iemnet_names*lastname=curname;
@@ -80,22 +142,30 @@ static int iemnet__nametaken(const char*namestring) {
   curname->name=name;
   curname->next=0;
 
-  if(lastname)
+  if(lastname) {
     lastname->next=curname;
-  else
+  } else {
     namelist=curname;
+  }
 
   return 0;
 }
 
-int iemnet__register(const char*name) {
-  if(iemnet__nametaken(name))return 0;
+#ifndef BUILD_DATE
+# define BUILD_DATE "on " __DATE__ " at " __TIME__
+#endif
+
+int iemnet__register(const char*name)
+{
+  if(iemnet__nametaken(name)) {
+    return 0;
+  }
   post("iemnet - networking with Pd: [%s]", name);
-#ifdef LIBRARY_VERSION
-  post("        version "LIBRARY_VERSION"");
+#ifdef VERSION
+  post("        version "VERSION"");
 #endif
-  post("        compiled on "__DATE__" at " __TIME__"");
-  post("        copyright (c) 2010 IOhannes m zmoelnig, IEM");
+  post("        compiled "BUILD_DATE"");
+  post("        copyright © 2010-2015 IOhannes m zmoelnig, IEM");
   post("        based on mrpeach/net, based on maxlib");
   return 1;
 }
@@ -115,23 +185,81 @@ void udpsend_setup(void);
 void udpserver_setup(void);
 #endif
 
-int debuglevel=0;
-void iemnet_debuglevel(void*x, t_float f) {
-  debuglevel=(int)f;
-}
+static int iemnet_debuglevel_=0;
+static pthread_mutex_t debug_mtx = PTHREAD_MUTEX_INITIALIZER;
+
+void iemnet_debuglevel(void*x, t_float f)
+{
+  static int firsttime=1;
+#ifdef IEMNET_HAVE_DEBUG
+  int debuglevel=(int)f;
+
+  pthread_mutex_lock(&debug_mtx);
+  iemnet_debuglevel_=debuglevel;
+  pthread_mutex_unlock(&debug_mtx);
 
+  post("iemnet: setting debuglevel to %d", debuglevel);
+#else
+  if(firsttime) {
+    error("iemnet compiled without debug!");
+  }
+#endif
+  firsttime=0;
+}
 
+int iemnet_debug(int debuglevel, const char*file, unsigned int line,
+                 const char*function)
+{
+#ifdef IEMNET_HAVE_DEBUG
+  int debuglevel_=0;
+  pthread_mutex_lock(&debug_mtx);
+  debuglevel_=iemnet_debuglevel_;
+  pthread_mutex_unlock(&debug_mtx);
+  if(debuglevel_ & debuglevel) {
+    startpost("[%s[%d]:%s#%d] ", file, line, function, debuglevel);
+    return 1;
+  }
+#endif
+  return 0;
+}
 
-IEMNET_EXTERN void iemnet_setup(void) {
+IEMNET_EXTERN void iemnet_setup(void)
+{
 #ifdef _MSC_VER
- tcpclient_setup();
- tcpreceive_setup();
- tcpsend_setup();
- tcpserver_setup();
-
- udpclient_setup();
- udpreceive_setup();
- udpsend_setup();
- udpserver_setup();
+  tcpclient_setup();
+  tcpreceive_setup();
+  tcpsend_setup();
+  tcpserver_setup();
+
+  udpclient_setup();
+  udpreceive_setup();
+  udpsend_setup();
+  udpserver_setup();
+#endif
+}
+
+#include <stdarg.h>
+#include <string.h>
+#include <m_imp.h>
+
+void iemnet_log(const void *object, const t_iemnet_loglevel level, const char *fmt, ...)
+{
+  t_pd*x=(t_pd*)object;
+  const char*name=(x && (*x) && ((*x)->c_name))?((*x)->c_name->s_name):"iemnet";
+  char buf[MAXPDSTRING];
+  va_list ap;
+  t_int arg[8];
+  va_start(ap, fmt);
+  vsnprintf(buf, MAXPDSTRING-1, fmt, ap);
+  va_end(ap);
+  strcat(buf, "\0");
+#if (defined PD_MINOR_VERSION) && (PD_MINOR_VERSION >= 43)
+  logpost(x, level, "[%s]: %s", name, buf);
+#else
+  if(level>1) {
+    post("[%s]: %s", name, buf);
+  } else {
+    pd_error(x, "[%s]: %s", name, buf);
+  }
 #endif
 }
diff --git a/iemnet.h b/iemnet.h
index 528b800..7a379cb 100644
--- a/iemnet.h
+++ b/iemnet.h
@@ -2,7 +2,7 @@
  * iemnet
  *     networking for Pd
  *
- *  (c) 2010 IOhannes m zmölnig
+ *  (c) 2010 IOhannes m zmölnig
  *           Institute of Electronic Music and Acoustics (IEM)
  *           University of Music and Dramatic Arts (KUG), Graz, Austria
  *
@@ -23,8 +23,8 @@
 /* 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, write to the Free Software                  */
-/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.  */
+/* along with this program; if not, see                                         */
+/*     http://www.gnu.org/licenses/                                             */
 /*                                                                              */
 
 /* ---------------------------------------------------------------------------- */
@@ -66,27 +66,42 @@ typedef struct _iemnet_sender t_iemnet_sender;
 EXTERN_STRUCT _iemnet_sender;
 
 /**
+ * user provided send function
+ * (defaults to just using send)
+ * this function is guaranteed to be called with a valid 'chunk',
+ * and the 'userdata' and 'sockfd' provided at sender-creation
+ */
+typedef int (*t_iemnet_sendfunction)(const void*userdata, int sockfd,
+                                     t_iemnet_chunk*chunk);
+
+/**
  * create a sender to a given socket
  *
  * \param sock a previously opened socket
+ * \param sendfun a send()-implementation (or NULL, to use the default send/sendto based implementation)
+ * \param userdata pointer to optional userdata to be passsed to `sendfun`
+ * \param bool indicating whether this function is called from a subthread (1) or the mainthread (0)
  * \return pointer to a sender object
  * \note the socket must be writeable
  */
-t_iemnet_sender*iemnet__sender_create(int sock);
+t_iemnet_sender*iemnet__sender_create(int sock,
+                                      t_iemnet_sendfunction sendfun, const void*userdata,
+                                      int);
 /**
  * destroy a sender to a given socket
  * destroying a sender will free all resources of the sender
  *
  * \param pointer to a sender object to be destroyed
+ * \param bool indicating whether this function is called from a subthread (1) or the mainthread (0)
  *
  * \note  it will also close() the socket
  */
-void iemnet__sender_destroy(t_iemnet_sender*);
+void iemnet__sender_destroy(t_iemnet_sender*, int);
 
 /**
  * send data over a socket
  *
- * \param pointer to a sender object 
+ * \param pointer to a sender object
  * \param pointer to a chunk of data to be sent
  * \return the current fill state of the send buffer
  *
@@ -97,7 +112,7 @@ int iemnet__sender_send(t_iemnet_sender*, t_iemnet_chunk*);
 /**
  * query the fill state of the send buffer
  *
- * \param pointer to a sender object 
+ * \param pointer to a sender object
  * \return the current fill state of the send buffer
  */
 int iemnet__sender_getsize(t_iemnet_sender*);
@@ -113,9 +128,11 @@ EXTERN_STRUCT _iemnet_receiver;
 /**
  * callback function for receiving
  * whenever data arrives at the socket, a callback will be called synchronously
+ * if rawdata is NULL, this signifies that the socket has been closed
  */
-typedef void (*t_iemnet_receivecallback)(void*userdata, 
-					 t_iemnet_chunk*rawdata);
+typedef void (*t_iemnet_receivecallback)(void*userdata
+    , t_iemnet_chunk*rawdata
+                                        );
 
 /**
  * create a receiver object
@@ -125,33 +142,42 @@ typedef void (*t_iemnet_receivecallback)(void*userdata,
  * \param sock the (readable) socket to receive from
  * \param data user data to be passed to callback
  * \param callback a callback function that is called on the caller's side
+ * \param subthread bool indicating whether this function is called from a subthread (1) or the mainthread (0)
  *
  * \note the callback will be scheduled in the caller's thread with clock_delay()
  */
-t_iemnet_receiver*iemnet__receiver_create(int sock, void*data, t_iemnet_receivecallback callback);
+t_iemnet_receiver*iemnet__receiver_create(int sock, void*data,
+    t_iemnet_receivecallback callback, int subthread);
 /**
  * destroy a receiver at a given socket
  * destroying a receiver will free all resources of the receiver
  *
  * \param pointer to a receiver object to be destroyed
+ * \param bool indicating whether this function is called from a subthread (1) or the mainthread (0)
  *
  * \note  it will also close() the socket
  */
-void iemnet__receiver_destroy(t_iemnet_receiver*);
+void iemnet__receiver_destroy(t_iemnet_receiver*, int subthread);
 
 /**
  * query the fill state of the receive buffer
  *
- * \param pointer to a receiver object 
+ * \param pointer to a receiver object
  * \return the current fill state of the receive buffer
  */
 int iemnet__receiver_getsize(t_iemnet_receiver*);
 
 
-
 /* convenience functions */
 
 /**
+ * properly close a socket fd
+ *
+ * \param sock socket to close
+ */
+void iemnet__closesocket(int fd, int verbose);
+
+/**
  * output the address  (IP, port)
  * the given address is first output through the status_outlet as a "host" message
  * and then as a list through the address_outlet
@@ -163,7 +189,8 @@ int iemnet__receiver_getsize(t_iemnet_receiver*);
  *
  * \note the address will be output as a 5 element list, with the 1st 4 elements denoting the quads of the IP address (as bytes) and the last element the port
  */
-void iemnet__addrout(t_outlet*status_outlet, t_outlet*address_outlet, long address, unsigned short port);
+void iemnet__addrout(t_outlet*status_outlet, t_outlet*address_outlet,
+                     long address, unsigned short port);
 
 /**
  * output the socket we received data from
@@ -174,7 +201,8 @@ void iemnet__addrout(t_outlet*status_outlet, t_outlet*address_outlet, long addre
  * \param socket_outlet outlet for sockets only
  * \param sockfd the socket
  */
-void iemnet__socketout(t_outlet*status_outlet, t_outlet*socket_outlet, int sockfd);
+void iemnet__socketout(t_outlet*status_outlet, t_outlet*socket_outlet,
+                       int sockfd);
 
 /**
  * output the number of connections
@@ -185,7 +213,8 @@ void iemnet__socketout(t_outlet*status_outlet, t_outlet*socket_outlet, int sockf
  * \param address_outlet outlet for numconnections only
  * \param numconnections the number of connections
  */
-void iemnet__numconnout(t_outlet*status_outlet, t_outlet*numconn_outlet, int numconnections);
+void iemnet__numconnout(t_outlet*status_outlet, t_outlet*numconn_outlet,
+                        int numconnections);
 
 /**
  * output a list as a stream (serialize)
@@ -228,32 +257,46 @@ int iemnet__register(const char*name);
   static void autoinit__ ## f(void) { f(); }
 #endif
 
-
+typedef enum {
+  IEMNET_FATAL   = 0,
+  IEMNET_ERROR   = 1,
+  IEMNET_NORMAL  = 2,
+  IEMNET_VERBOSE = 3,
+  IEMNET_DEBUG   = 4
+} t_iemnet_loglevel;
+void iemnet_log(const void *object, const t_iemnet_loglevel level, const char *fmt, ...);
 /**
  * \fn void DEBUG(const char* format,...);
  *
  * \brief debug output
  * \note this will only take effect if DEBUG is not undefined
  */
+#ifdef IEMNET_HAVE_DEBUG
+# undef IEMNET_HAVE_DEBUG
+#endif
 
 #ifdef DEBUG
 # define IEMNET_HAVE_DEBUG 1
 #endif
 
-#ifdef IEMNET_HAVE_DEBUG
-# undef IEMNET_HAVE_DEBUG
-#endif
-extern int debuglevel;
 void iemnet_debuglevel(void*,t_float);
+int iemnet_debug(int debuglevel, const char*file, unsigned int line,
+                 const char*function);
 #define DEBUGMETHOD(c) class_addmethod(c, (t_method)iemnet_debuglevel, gensym("debug"), A_FLOAT, 0)
 
+
+
 #ifdef DEBUG
 # undef DEBUG
-# define DEBUG if(debuglevel&DEBUGLEVEL)startpost("[%s:%d]", __FUNCTION__, __LINE__); if(debuglevel&DEBUGLEVEL)post
+# define DEBUG if(iemnet_debug(DEBUGLEVEL, __FILE__, __LINE__, __FUNCTION__))post
 #else
-static void debug_dummy(const char *format, ...)  {;}
+static void debug_dummy(const char *format, ...)
+{
+  ;
+}
 # define DEBUG debug_dummy
 #endif
+#define MARK() post("%s:%d [%s]",  __FILE__, __LINE__, __FUNCTION__)
 
 
 #endif /* INCLUDE_IEMNET_H_ */
diff --git a/iemnet_data.c b/iemnet_data.c
index 0fceed9..e894bed 100644
--- a/iemnet_data.c
+++ b/iemnet_data.c
@@ -1,11 +1,27 @@
 /* iemnet
+ *
  * data handling code
  *  - wrappers for data "chunks"
  *  - queues
  *
- *  copyright (c) 2010 IOhannes m zmölnig, IEM
+ *  copyright © 2010-2015 IOhannes m zmölnig, IEM
  */
 
+/* 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/                                             */
+/*                                                                              */
+
 #define DEBUGLEVEL 8
 
 #include "iemnet.h"
@@ -27,18 +43,27 @@
 
 /* data handling */
 
-t_iemnet_floatlist*iemnet__floatlist_init(t_iemnet_floatlist*cl) {
+t_iemnet_floatlist*iemnet__floatlist_init(t_iemnet_floatlist*cl)
+{
   unsigned int i;
-  if(NULL==cl)return NULL;
-  for(i=0; i<cl->size; i++)
+  if(NULL==cl) {
+    return NULL;
+  }
+  for(i=0; i<cl->size; i++) {
     SETFLOAT((cl->argv+i), 0.f);
+  }
 
   return cl;
 }
 
-void iemnet__floatlist_destroy(t_iemnet_floatlist*cl) {
-  if(NULL==cl)return;
-  if(cl->argv) free(cl->argv);
+void iemnet__floatlist_destroy(t_iemnet_floatlist*cl)
+{
+  if(NULL==cl) {
+    return;
+  }
+  if(cl->argv) {
+    free(cl->argv);
+  }
   cl->argv=NULL;
   cl->argc=0;
   cl->size=0;
@@ -46,9 +71,13 @@ void iemnet__floatlist_destroy(t_iemnet_floatlist*cl) {
   free(cl);
 }
 
-t_iemnet_floatlist*iemnet__floatlist_create(unsigned int size) {
-  t_iemnet_floatlist*result=(t_iemnet_floatlist*)malloc(sizeof(t_iemnet_floatlist));
-  if(NULL==result)return NULL;
+t_iemnet_floatlist*iemnet__floatlist_create(unsigned int size)
+{
+  t_iemnet_floatlist*result=(t_iemnet_floatlist*)malloc(sizeof(
+                              t_iemnet_floatlist));
+  if(NULL==result) {
+    return NULL;
+  }
 
   result->argv = (t_atom*)malloc(size*sizeof(t_atom));
   if(NULL==result->argv) {
@@ -64,7 +93,9 @@ t_iemnet_floatlist*iemnet__floatlist_create(unsigned int size) {
   return result;
 }
 
-t_iemnet_floatlist*iemnet__floatlist_resize(t_iemnet_floatlist*cl, unsigned int size) {
+t_iemnet_floatlist*iemnet__floatlist_resize(t_iemnet_floatlist*cl,
+    unsigned int size)
+{
   t_atom*tmp;
   if (NULL==cl) {
     return iemnet__floatlist_create(size);
@@ -76,7 +107,9 @@ t_iemnet_floatlist*iemnet__floatlist_resize(t_iemnet_floatlist*cl, unsigned int
   }
 
   tmp=(t_atom*)malloc(size*sizeof(t_atom));
-  if(NULL==tmp) return NULL;
+  if(NULL==tmp) {
+    return NULL;
+  }
 
   free(cl->argv);
 
@@ -88,10 +121,15 @@ t_iemnet_floatlist*iemnet__floatlist_resize(t_iemnet_floatlist*cl, unsigned int
   return cl;
 }
 
-void iemnet__chunk_destroy(t_iemnet_chunk*c) {
-  if(NULL==c)return;
+void iemnet__chunk_destroy(t_iemnet_chunk*c)
+{
+  if(NULL==c) {
+    return;
+  }
 
-  if(c->data)free(c->data);
+  if(c->data) {
+    free(c->data);
+  }
 
   c->data=NULL;
   c->size=0;
@@ -99,11 +137,30 @@ void iemnet__chunk_destroy(t_iemnet_chunk*c) {
   free(c);
 }
 
-t_iemnet_chunk* iemnet__chunk_create_empty(int size) {
-  t_iemnet_chunk*result=(t_iemnet_chunk*)malloc(sizeof(t_iemnet_chunk));
+
+void iemnet__chunk_print(t_iemnet_chunk*c)
+{
+  unsigned int i=0;
+  startpost("chunk[%p:%d]", c, c?c->size:0);
+  if(!c) {
+    return;
+  }
+  for(i=0; i<c->size; i++) {
+    startpost(" %d", c->data[i]);
+  }
+  endpost();
+}
+
+t_iemnet_chunk* iemnet__chunk_create_empty(int size)
+{
+  t_iemnet_chunk*result=NULL;
+  if(size<1) {
+    return NULL;
+  }
+  result=(t_iemnet_chunk*)malloc(sizeof(t_iemnet_chunk));
   if(result) {
     result->size=size;
-    result->data=(unsigned char*)malloc(sizeof(unsigned char)*size); 
+    result->data=(unsigned char*)malloc(sizeof(unsigned char)*size);
 
     if(NULL == result->data) {
       result->size=0;
@@ -115,12 +172,14 @@ t_iemnet_chunk* iemnet__chunk_create_empty(int size) {
 
     result->addr=0L;
     result->port=0;
+    result->family=AF_INET;
 
   }
   return result;
 }
 
-t_iemnet_chunk* iemnet__chunk_create_data(int size, unsigned char*data) {
+t_iemnet_chunk* iemnet__chunk_create_data(int size, unsigned char*data)
+{
   t_iemnet_chunk*result=iemnet__chunk_create_empty(size);
   if(result) {
     memcpy(result->data, data, result->size);
@@ -128,21 +187,26 @@ t_iemnet_chunk* iemnet__chunk_create_data(int size, unsigned char*data) {
   return result;
 }
 
-t_iemnet_chunk* iemnet__chunk_create_dataaddr(int size, 
-					      unsigned char*data,
-					      struct sockaddr_in*addr) {
+t_iemnet_chunk* iemnet__chunk_create_dataaddr(int size,
+    unsigned char*data,
+    struct sockaddr_in*addr)
+{
   t_iemnet_chunk*result=iemnet__chunk_create_data(size, data);
-  if(addr) {
+  if(result && addr) {
     result->addr = ntohl(addr->sin_addr.s_addr);
     result->port = ntohs(addr->sin_port);
+    result->family = addr->sin_family;
   }
   return result;
 }
 
-t_iemnet_chunk* iemnet__chunk_create_list(int argc, t_atom*argv) {
+t_iemnet_chunk* iemnet__chunk_create_list(int argc, t_atom*argv)
+{
   int i;
   t_iemnet_chunk*result=iemnet__chunk_create_empty(argc);
-  if(NULL==result)return NULL;
+  if(NULL==result) {
+    return NULL;
+  }
 
   for(i=0; i<argc; i++) {
     unsigned char c = atom_getint(argv);
@@ -153,22 +217,32 @@ t_iemnet_chunk* iemnet__chunk_create_list(int argc, t_atom*argv) {
   return result;
 }
 
-t_iemnet_chunk*iemnet__chunk_create_chunk(t_iemnet_chunk*c) {
+t_iemnet_chunk*iemnet__chunk_create_chunk(t_iemnet_chunk*c)
+{
   t_iemnet_chunk*result=NULL;
-  if(NULL==c)return NULL;
+  if(NULL==c) {
+    return NULL;
+  }
   result=iemnet__chunk_create_data(c->size, c->data);
-  result->addr=c->addr;
-  result->port=c->port;
-
+  if(result) {
+    result->addr=c->addr;
+    result->port=c->port;
+  }
   return result;
 }
 
 
-t_iemnet_floatlist*iemnet__chunk2list(t_iemnet_chunk*c, t_iemnet_floatlist*dest) {
+t_iemnet_floatlist*iemnet__chunk2list(t_iemnet_chunk*c,
+                                      t_iemnet_floatlist*dest)
+{
   unsigned int i;
-  if(NULL==c)return NULL;
+  if(NULL==c) {
+    return NULL;
+  }
   dest=iemnet__floatlist_resize(dest, c->size);
-  if(NULL==dest)return NULL;
+  if(NULL==dest) {
+    return NULL;
+  }
 
   for(i=0; i<c->size; i++) {
     dest->argv[i].a_w.w_float = c->data[i];
@@ -201,26 +275,48 @@ struct _iemnet_queue {
 
   int done; // in cleanup state
   int size;
+
+  pthread_mutex_t usedmtx;
+  pthread_cond_t usedcond;
+  int used; // use counter, so queue_finish can wait for blocking accesses to finish
 };
 
+static void queue_use_increment(t_iemnet_queue* _this)
+{
+  pthread_mutex_lock(&_this->usedmtx);
+  _this->used++;
+  pthread_mutex_unlock(&_this->usedmtx);
+}
+static void queue_use_decrement(t_iemnet_queue* _this)
+{
+  pthread_mutex_lock(&_this->usedmtx);
+  _this->used--;
+  pthread_cond_signal(&_this->usedcond);
+  pthread_mutex_unlock(&_this->usedmtx);
+}
 
 /* push a  chunk into the queue
  * this will return the current queue size
  */
 int queue_push(
-	       t_iemnet_queue* const _this,
-	       t_iemnet_chunk* const data
-	       ) {
+  t_iemnet_queue* const _this,
+  t_iemnet_chunk* const data
+)
+{
   t_node* tail;
   t_node* n=NULL;
   int size=-1;
-  if(NULL == _this)return size;
+  if(NULL == _this) {
+    return size;
+  }
 
   pthread_mutex_lock(&_this->mtx);
   size=_this->size;
   pthread_mutex_unlock(&_this->mtx);
 
-  if(NULL == data) return size;
+  if(NULL == data) {
+    return size;
+  }
 
   n=(t_node*)malloc(sizeof(t_node));
 
@@ -247,28 +343,33 @@ int queue_push(
 
 
 /* pop a chunk from the queue
- * if the queue is empty, this will block until 
+ * if the queue is empty, this will block until
  *    something has been pushed
  *   OR the queue is "done" (in which case NULL is returned)
  */
 t_iemnet_chunk* queue_pop_block(
-				t_iemnet_queue* const _this
-				) {
+  t_iemnet_queue* const _this
+)
+{
 
   t_node* head=0;
   t_iemnet_chunk*data=0;
-  if(NULL == _this)return NULL;
+  if(NULL == _this) {
+    return NULL;
+  }
 
+  queue_use_increment(_this);
   pthread_mutex_lock(&_this->mtx);
 
   /* if the queue is empty, wait */
-  if(NULL == _this->head) {
+  while(NULL == _this->head) {
     pthread_cond_wait(&_this->cond, &_this->mtx);
     /* somebody signaled us, that we should do some work
      * either the queue has been filled, or we are done...
      */
     if(_this->done) {
       pthread_mutex_unlock(&_this->mtx);
+      queue_use_decrement(_this);
       return NULL;
     }
   }
@@ -276,11 +377,13 @@ t_iemnet_chunk* queue_pop_block(
   head = _this->head;
 
   /* update _this */
-  if (! (_this->head = head->next)) {
-    _this->tail = 0;
-  }
-  if(head && head->data) {
-    _this->size-=head->data->size;
+  if(head) {
+    if (! (_this->head = head->next)) {
+      _this->tail = 0;
+    }
+    if(head->data) {
+      _this->size-=head->data->size;
+    }
   }
 
   pthread_mutex_unlock(&_this->mtx);
@@ -290,23 +393,29 @@ t_iemnet_chunk* queue_pop_block(
     free(head);
     head=NULL;
   }
+  queue_use_decrement(_this);
   return data;
 }
 /* pop a chunk from the queue
  * if the queue is empty, this will immediately return NULL
- * (note that despite of the name this does block for synchronization) 
+ * (note that despite of the name this does block for synchronization)
  */
 t_iemnet_chunk* queue_pop_noblock(
-				  t_iemnet_queue* const _this
-				  ) {
+  t_iemnet_queue* const _this
+)
+{
   t_node* head=0;
   t_iemnet_chunk*data=0;
-  if(NULL == _this)return NULL;
+  if(NULL == _this) {
+    return NULL;
+  }
 
+  queue_use_increment(_this);
   pthread_mutex_lock(&_this->mtx);
   if (! (head = _this->head)) {
     // empty head
     pthread_mutex_unlock(&_this->mtx);
+    queue_use_decrement(_this);
     return NULL;
   }
 
@@ -324,14 +433,17 @@ t_iemnet_chunk* queue_pop_noblock(
     free(head);
     head=NULL;
   }
+  queue_use_decrement(_this);
   return data;
 }
 
-t_iemnet_chunk* queue_pop(t_iemnet_queue* const _this) {
+t_iemnet_chunk* queue_pop(t_iemnet_queue* const _this)
+{
   return queue_pop_block(_this);
 }
 
-int queue_getsize(t_iemnet_queue* const _this) {
+int queue_getsize(t_iemnet_queue* const _this)
+{
   int size=-1;
   if(_this) {
     pthread_mutex_lock(&_this->mtx);
@@ -340,9 +452,12 @@ int queue_getsize(t_iemnet_queue* const _this) {
   }
   return size;
 }
-void queue_finish(t_iemnet_queue* q) {
+void queue_finish(t_iemnet_queue* q)
+{
   DEBUG("queue_finish: %x", q);
-  if(NULL==q) return;
+  if(NULL==q) {
+    return;
+  }
 
   pthread_mutex_lock(&q->mtx);
   q->done=1;
@@ -350,13 +465,23 @@ void queue_finish(t_iemnet_queue* q) {
   pthread_cond_signal(&q->cond);
   DEBUG("queue signaled: %x", q);
   pthread_mutex_unlock(&q->mtx);
+
+  /* wait until queue is no longer used */
+  pthread_mutex_lock(&q->usedmtx);
+  while(q->used) {
+    pthread_cond_wait(&q->usedcond, &q->usedmtx);
+  }
+  pthread_mutex_unlock(&q->usedmtx);
+
   DEBUG("queue_finished: %x", q);
 }
 
-void queue_destroy(t_iemnet_queue* q) {
+void queue_destroy(t_iemnet_queue* q)
+{
   t_iemnet_chunk*c=NULL;
-  if(NULL==q) 
+  if(NULL==q) {
     return;
+  }
   DEBUG("queue destroy %x", q);
 
   queue_finish(q);
@@ -372,18 +497,24 @@ void queue_destroy(t_iemnet_queue* q) {
   pthread_mutex_destroy(&q->mtx);
   pthread_cond_destroy(&q->cond);
 
+  pthread_mutex_destroy(&q->usedmtx);
+  pthread_cond_destroy(&q->usedcond);
+
   free(q);
   q=NULL;
   DEBUG("queue destroyed %x", q);
 }
 
-t_iemnet_queue* queue_create(void) {
+t_iemnet_queue* queue_create(void)
+{
   static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
   static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
 
   t_iemnet_queue*q=(t_iemnet_queue*)malloc(sizeof(t_iemnet_queue));
   DEBUG("queue create %x", q);
-  if(NULL==q)return NULL;
+  if(NULL==q) {
+    return NULL;
+  }
 
   q->head = NULL;
   q->tail = NULL;
@@ -391,8 +522,12 @@ t_iemnet_queue* queue_create(void) {
   memcpy(&q->cond, &cond, sizeof(pthread_cond_t));
   memcpy(&q->mtx , &mtx, sizeof(pthread_mutex_t));
 
+  memcpy(&q->usedcond, &cond, sizeof(pthread_cond_t));
+  memcpy(&q->usedmtx , &mtx, sizeof(pthread_mutex_t));
+
   q->done = 0;
   q->size = 0;
+  q->used = 0;
   DEBUG("queue created %x", q);
   return q;
 }
diff --git a/iemnet_data.h b/iemnet_data.h
index 0039e43..80a8eed 100644
--- a/iemnet_data.h
+++ b/iemnet_data.h
@@ -2,7 +2,7 @@
  * iemnet
  *     networking for Pd
  *
- *  (c) 2010 IOhannes m zmölnig
+ *  (c) 2010 IOhannes m zmölnig
  *           Institute of Electronic Music and Acoustics (IEM)
  *           University of Music and Dramatic Arts (KUG), Graz, Austria
  *
@@ -23,8 +23,8 @@
 /* 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, write to the Free Software                  */
-/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.  */
+/* along with this program; if not, see                                         */
+/*     http://www.gnu.org/licenses/                                             */
 /*                                                                              */
 
 /* ---------------------------------------------------------------------------- */
@@ -66,6 +66,7 @@ typedef struct _iemnet_chunk {
 
   long addr;
   unsigned short port;
+  short family; // AF_INET, AF_INET6
 } t_iemnet_chunk;
 
 /**
@@ -74,6 +75,11 @@ typedef struct _iemnet_chunk {
 void iemnet__chunk_destroy(t_iemnet_chunk*);
 
 /**
+ * print a "chunk" to the pd-console
+ */
+void iemnet__chunk_print(t_iemnet_chunk*c);
+
+/**
  * initialize a "chunk" (allocate memory,...) of fixed size
  * receiver address will be set to 0
  *
@@ -97,7 +103,8 @@ t_iemnet_chunk*iemnet__chunk_create_data(int size, unsigned char*data);
  * \param addr originating address (can be NULL)
  * \return a new chunk that holds a copy of data
  */
-t_iemnet_chunk*iemnet__chunk_create_dataaddr(int size, unsigned char*data, struct sockaddr_in*addr);
+t_iemnet_chunk*iemnet__chunk_create_dataaddr(int size, unsigned char*data,
+    struct sockaddr_in*addr);
 /**
  * initialize a "chunk" (allocate memory,...) with given data
  * receiver address will be set to 0
@@ -120,11 +127,12 @@ t_iemnet_chunk*iemnet__chunk_create_chunk(t_iemnet_chunk*source);
  * convert a data chunk to a Pd-list of A_FLOATs
  * the destination list will eventually be resized if it is too small to hold the chunk
  *
- * \param c the chunk to convert 
+ * \param c the chunk to convert
  * \param dest the destination list
  * \return the destination list if all went well, else NULL
  */
-t_iemnet_floatlist*iemnet__chunk2list(t_iemnet_chunk*c, t_iemnet_floatlist*dest);
+t_iemnet_floatlist*iemnet__chunk2list(t_iemnet_chunk*c,
+                                      t_iemnet_floatlist*dest);
 
 
 /**
@@ -146,7 +154,7 @@ int queue_push(t_iemnet_queue* const q, t_iemnet_chunk* const d);
 /**
  * \brief pop data from the FIFO (queue), blocking
  *
- *  pops data from the stack; 
+ *  pops data from the stack;
  *  if the stack is empty, this function will block until data is pushed to the stack
  *  if the queue is finalized, this function will return immediately with NULL
  *
diff --git a/iemnet_receiver.c b/iemnet_receiver.c
index bd81d45..5fb41bd 100644
--- a/iemnet_receiver.c
+++ b/iemnet_receiver.c
@@ -1,289 +1,139 @@
 /* iemnet
- *  copyright (c) 2010 IOhannes m zmölnig, IEM
+ *
+ * receiver
+ *   receives data "chunks" from a socket
+ *
+ *  copyright © 2010-2015 IOhannes m zmölnig, IEM
  */
 
+/* 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/                                             */
+/*                                                                              */
+
 #define DEBUGLEVEL 4
 
 #include "iemnet.h"
 #include "iemnet_data.h"
 
-#include <string.h>
-#include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
 
-#include <pthread.h>
-
 #define INBUFSIZE 65536L /* was 4096: size of receiving data buffer */
 
-
 struct _iemnet_receiver {
-  pthread_t thread;
   int sockfd; /* owned outside; you must call iemnet__receiver_destroy() before freeing socket yourself */
   void*userdata;
-  t_iemnet_chunk*data;
   t_iemnet_receivecallback callback;
-  t_iemnet_queue*queue;
-  t_clock *clock;
-
-
-  int newdataflag;
-  int running;
-  int keepreceiving;
-
-  pthread_mutex_t newdata_mtx, running_mtx, keeprec_mtx;
 };
 
-/* notifies Pd that there is new data to fetch */
-static void iemnet_signalNewData(t_iemnet_receiver*x) {
-  int already=0;
-  int trylock=0;
-  pthread_mutex_lock(&x->newdata_mtx);
-   already=x->newdataflag;
-   x->newdataflag=1;
-
-   /* don't schedule ticks at the end of life */
-   if(x->sockfd<0)already=1;
-
-  pthread_mutex_unlock(&x->newdata_mtx);
-
-  if(already) {
-    return;
-  }
-
-  /*
-   * try to lock Pd's main mutex
-   *  this is bound to deadlock if this function is called from within Pd's mainthread
-   *  (which happens when we destroy the receiver and signalNewData is called on cleanup)
-   *
-   * - shan't we check whether sys_trylock() returns EBUSY ?
-   */
-  trylock=sys_trylock();
-  switch(trylock) {
-  case 0:
-  case EBUSY:
-    if(x->clock)clock_delay(x->clock, 0);
-    if(0==trylock)sys_unlock();
-  default:
-    break;
-  }
-}
-
-
-/* the workhorse of the family */
-static void*iemnet__receiver_readthread(void*arg) {
-  unsigned int i=0;
-  int result = 0;
-  t_iemnet_receiver*receiver=(t_iemnet_receiver*)arg;
 
-  int sockfd=receiver->sockfd;
-  t_iemnet_queue*q=receiver->queue;
+static void pollfun(void*z, int fd)
+{
+  // read data from socket and call callback
+  t_iemnet_receiver*rec=(t_iemnet_receiver*)z;
 
   unsigned char data[INBUFSIZE];
   unsigned int size=INBUFSIZE;
+  t_iemnet_chunk*chunk=NULL;
+  int result = 0;
+  int local_errno = 0;
 
   struct sockaddr_in  from;
   socklen_t           fromlen = sizeof(from);
 
   int recv_flags=0;
-
-  struct timeval timout;
-  fd_set readset;
-  FD_ZERO(&readset);
-  FD_SET(sockfd, &readset);
-
-  for(i=0; i<size; i++)data[i]=0;
-  pthread_mutex_lock(&receiver->running_mtx);
-   receiver->running=1;
-  pthread_mutex_unlock(&receiver->running_mtx);
-
-  while(1) {
-    t_iemnet_chunk*c=NULL;
-
-    pthread_mutex_lock(&receiver->keeprec_mtx);
-     if(!receiver->keepreceiving) {
-      pthread_mutex_unlock(&receiver->keeprec_mtx);
-      break;
-     }
-    pthread_mutex_unlock(&receiver->keeprec_mtx);
-
-    fromlen = sizeof(from);
-    fd_set rs=readset;
-    timout.tv_sec=0;
-    timout.tv_usec=1000;
-
-    recv_flags|=MSG_DONTWAIT;
-    select(sockfd+1, &rs, NULL, NULL,
-           &timout);
-    if (!FD_ISSET(sockfd, &rs))continue;
-
-    DEBUG("select can read");
-
-    //fprintf(stderr, "reading %d bytes...\n", size);
-    //result = recv(sockfd, data, size, 0);
-
-    result = recvfrom(sockfd, data, size, recv_flags, (struct sockaddr *)&from, &fromlen);
-    //fprintf(stderr, "read %d bytes...\n", result);
-    DEBUG("recfrom %d bytes", result);
-    if(result<=0)break;
-    c= iemnet__chunk_create_dataaddr(result, data, &from);
-    DEBUG("pushing");  
-    queue_push(q, c);
-    DEBUG("signalling");  
-    iemnet_signalNewData(receiver);
-    DEBUG("rereceive");  
-  }
-  // oha
-  DEBUG("readthread loop termination: %d", result);
-  //if(result>=0)iemnet_signalNewData(receiver);
-
-  pthread_mutex_lock(&receiver->running_mtx);
-   receiver->running=0;
-  pthread_mutex_unlock(&receiver->running_mtx);
-
-  DEBUG("read thread terminated");
-  return NULL;
+#ifdef MSG_DONTWAIT
+  recv_flags|=MSG_DONTWAIT;
+#endif
+  errno=0;
+  result = recvfrom(rec->sockfd, data, size, recv_flags,
+                    (struct sockaddr *)&from, &fromlen);
+  local_errno=errno;
+  //fprintf(stderr, "read %d bytes...\n", result);
+  DEBUG("recvfrom %d bytes: %d %p %d", result, rec->sockfd, data, size);
+  DEBUG("errno=%d", local_errno);
+  chunk = iemnet__chunk_create_dataaddr(result, (result>0)?data:NULL, &from);
+
+  // call the callback with a NULL-chunk to signal a disconnect event.
+  (rec->callback)(rec->userdata, chunk);
+
+  iemnet__chunk_destroy(chunk);
 }
 
-/* callback from Pd's main thread to fetch queued data */
-static void iemnet__receiver_tick(t_iemnet_receiver *x)
+t_iemnet_receiver*iemnet__receiver_create(int sock, void*userdata,
+    t_iemnet_receivecallback callback, int subthread)
 {
-  int running=0, keepreceiving=0;
-  // received data
-  t_iemnet_chunk*c=queue_pop_noblock(x->queue);
-	DEBUG("tick got chunk %p", c);
-
-  while(NULL!=c) {
-    (x->callback)(x->userdata, c);
-    iemnet__chunk_destroy(c);
-    c=queue_pop_noblock(x->queue);
-  }
-	DEBUG("tick cleanup");
-  pthread_mutex_lock(&x->newdata_mtx);
-   x->newdataflag=0;
-  pthread_mutex_unlock(&x->newdata_mtx);
+  t_iemnet_receiver*rec=(t_iemnet_receiver*)malloc(sizeof(
+                          t_iemnet_receiver));
 
-  pthread_mutex_lock(&x->running_mtx);
-   running = x->running;
-  pthread_mutex_unlock(&x->running_mtx);
-
-	DEBUG("tick running %d", running);
-  if(!running) {
-    // read terminated
-    pthread_mutex_lock(&x->keeprec_mtx);
-     keepreceiving=x->keepreceiving;
-    pthread_mutex_unlock(&x->keeprec_mtx);
-
-    /* keepreceiving is set, if receiver is not yet in shutdown mode */
-    if(keepreceiving) 
-      x->callback(x->userdata, NULL);
-  }
-	DEBUG("tick DONE");
-}
-
-int iemnet__receiver_getsize(t_iemnet_receiver*x) {
-  int size=-1;
-  if(x && x->queue)
-    size=queue_getsize(x->queue);
-
-  return size;
-}
-
-
-t_iemnet_receiver*iemnet__receiver_create(int sock, void*userdata, t_iemnet_receivecallback callback) {
-  static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
-  t_iemnet_receiver*rec=(t_iemnet_receiver*)malloc(sizeof(t_iemnet_receiver));
   DEBUG("create new receiver for 0x%X:%d", userdata, sock);
   //fprintf(stderr, "new receiver for %d\t%x\t%x\n", sock, userdata, callback);
   if(rec) {
-    t_iemnet_chunk*data=NULL;
-    int res=0;
-
-    data=iemnet__chunk_create_empty(INBUFSIZE);
-    if(NULL==data) {
-      iemnet__receiver_destroy(rec);
-      DEBUG("create receiver failed");
-      return NULL;
-    }
-
-    rec->keepreceiving=1;
     rec->sockfd=sock;
     rec->userdata=userdata;
-    rec->data=data;
     rec->callback=callback;
 
-    memcpy(&rec->newdata_mtx , &mtx, sizeof(pthread_mutex_t));
-    memcpy(&rec->running_mtx , &mtx, sizeof(pthread_mutex_t));
-    memcpy(&rec->keeprec_mtx , &mtx, sizeof(pthread_mutex_t));
-    rec->newdataflag=0;
-    rec->running=1;
-
-    rec->queue = queue_create();
-    rec->clock = clock_new(rec, (t_method)iemnet__receiver_tick);
+    if(subthread) {
+      sys_lock();
+    }
+    sys_addpollfn(sock, pollfun, rec);
+    if(subthread) {
+      sys_unlock();
+    }
 
-    res=pthread_create(&rec->thread, 0, iemnet__receiver_readthread, rec);
   }
   //fprintf(stderr, "new receiver created\n");
 
   return rec;
 }
-
-void iemnet__receiver_destroy(t_iemnet_receiver*rec) {
-  static int instance=0;
-  int inst=instance++;
-
+void iemnet__receiver_destroy(t_iemnet_receiver*rec, int subthread)
+{
   int sockfd;
-  DEBUG("[%d] destroy receiver %x", inst, rec);
-  if(NULL==rec)return;
-  pthread_mutex_lock(&rec->keeprec_mtx);
-   if(!rec->keepreceiving) {
-    pthread_mutex_unlock(&rec->keeprec_mtx);
+  if(NULL==rec) {
     return;
-   }
-   rec->keepreceiving=0;
-  pthread_mutex_unlock(&rec->keeprec_mtx);
+  }
 
   sockfd=rec->sockfd;
 
-  DEBUG("joining thread");
-  pthread_join(rec->thread, NULL);
-
-  DEBUG("[%d] really destroying receiver %x -> %d", inst, rec, sockfd);
-
-  if(sockfd>=0) {
-    /* this doesn't alway make recvfrom() return!
-     * - try polling
-     * - try sending a signal with pthread_kill() ?
-     */
-
-    shutdown(sockfd, 2); /* needed on linux, since the recv won't shutdown on sys_closesocket() alone */
-    sys_closesocket(sockfd); 
+  if(subthread) {
+    sys_lock();
   }
-  DEBUG("[%d] closed socket %d", inst, sockfd);
-
-  rec->sockfd=-1;
+  sys_rmpollfn(rec->sockfd);
 
-  // empty the queue
-  DEBUG("[%d] tick %d", inst, rec->running);
-  iemnet__receiver_tick(rec);
-  queue_destroy(rec->queue);  
-  DEBUG("[%d] tack", inst);
+  // FIXXME: read any remaining bytes from the socket
 
-  if(rec->data)iemnet__chunk_destroy(rec->data);
-
-  pthread_mutex_destroy(&rec->newdata_mtx);
-  pthread_mutex_destroy(&rec->running_mtx);
-  pthread_mutex_destroy(&rec->keeprec_mtx);
+  if(subthread) {
+    sys_unlock();
+  }
 
-  clock_free(rec->clock);
-  rec->clock=NULL;
+  DEBUG("[%p] really destroying receiver %d", sockfd);
+  DEBUG("[%p] closed socket %d", rec, sockfd);
 
+  rec->sockfd=-1;
   rec->userdata=NULL;
-  rec->data=NULL;
   rec->callback=NULL;
-	rec->queue=NULL;
 
   free(rec);
   rec=NULL;
-  DEBUG("[%d] destroyed receiver", inst);
+}
+
+
+/* just dummy, since we don't maintain a queue any more */
+int iemnet__receiver_getsize(t_iemnet_receiver*x)
+{
+  if(x) {
+    return 0;
+  }
+  return -1;
 }
diff --git a/iemnet_sender.c b/iemnet_sender.c
index 715bdff..287cbb5 100644
--- a/iemnet_sender.c
+++ b/iemnet_sender.c
@@ -4,9 +4,24 @@
  *   sends data "chunks" to a socket
  *   possibly threaded
  *
- *  copyright (c) 2010 IOhannes m zmölnig, IEM
+ *  copyright © 2010-2015 IOhannes m zmölnig, IEM
  */
 
+/* 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/                                             */
+/*                                                                              */
+
 #define DEBUGLEVEL 2
 
 #include "iemnet.h"
@@ -31,18 +46,18 @@
 
 #if IEMNET_HAVE_DEBUG
 static int debug_lockcount=0;
-# define LOCK(x) do {pthread_mutex_lock(x);debug_lockcount++;  if(debuglevel&DEBUGLEVEL)post("  LOCK %d (@%s:%d)", debug_lockcount, __FILE__, __LINE__); } while(0)
-# define UNLOCK(x) do {debug_lockcount--;if(debuglevel&DEBUGLEVEL)post("UNLOCK %d (@%s:%d)", debug_lockcount, __FILE__, __LINE__);pthread_mutex_unlock(x);}while(0)
+# define LOCK(x) do {if(iemnet_debug(DEBUGLEVEL, __FILE__, __LINE__, __FUNCTION__))post("  LOCKing %p", x); pthread_mutex_lock(x);debug_lockcount++;  if(iemnet_debug(DEBUGLEVEL, __FILE__, __LINE__, __FUNCTION__))post("  LOCKed  %p[%d]", x, debug_lockcount); } while(0)
+# define UNLOCK(x) do {debug_lockcount--;if(iemnet_debug(DEBUGLEVEL, __FILE__, __LINE__, __FUNCTION__))post("  UNLOCK %p [%d]", x, debug_lockcount); pthread_mutex_unlock(x);}while(0)
 #else
 # define LOCK(x) pthread_mutex_lock(x)
 # define UNLOCK(x) pthread_mutex_unlock(x)
 #endif
 
- /* draft:
-  *   - there is a sender thread for each open connection
-  *   - the main thread just adds chunks to each sender threads processing queue
-  *   - the sender thread tries to send the queue as fast as possible
-  */
+/* draft:
+ *   - there is a sender thread for each open connection
+ *   - the main thread just adds chunks to each sender threads processing queue
+ *   - the sender thread tries to send the queue as fast as possible
+ */
 
 struct _iemnet_sender {
   pthread_t thread;
@@ -52,65 +67,103 @@ struct _iemnet_sender {
   int keepsending; // indicates whether we want to thread to continue or to terminate
   int isrunning;
 
+  const void*userdata; /* user provided data */
+  t_iemnet_sendfunction sendfun; /* user provided send function */
+
   pthread_mutex_t mtx; /* mutex to protect isrunning,.. */
 };
 
 /* the workhorse of the family */
 
-static int iemnet__sender_dosend(int sockfd, t_iemnet_queue*q) {
+
+static int iemnet__sender_defaultsend(const void*x, int sockfd,
+                                      t_iemnet_chunk*c)
+{
+  int result=-1;
+
   struct sockaddr_in  to;
   socklen_t           tolen = sizeof(to);
 
-  t_iemnet_chunk*c=queue_pop_block(q);
-  if(c) {
-    unsigned char*data=c->data;
-    unsigned int size=c->size;
-    
-    int result=-1;
+  unsigned char*data=c->data;
+  unsigned int size=c->size;
 
-    //    fprintf(stderr, "sending %d bytes at %x to %d\n", size, data, sockfd);
-    if(c->port) {
-      DEBUG("sending %d bytes to %x:%d", size, c->addr, c->port);
+  int flags = 0;
+#ifdef __linux__
+  flags |= MSG_NOSIGNAL;
+#endif
 
-      to.sin_addr.s_addr=htonl(c->addr);
-      to.sin_port       =htons(c->port);
 
-      result = sendto(sockfd, data, size, 0, (struct sockaddr *)&to, tolen);
-    } else {
-      DEBUG("sending %d bytes", size);
-      result = send(sockfd, data, size, 0);
-    }
-    if(result<0) {
-      // broken pipe
-      return 0;
-    }
+  //    fprintf(stderr, "sending %d bytes at %x to %d\n", size, data, sockfd);
+  if(c->port) {
+    DEBUG("sending %d bytes to %x:%d @%d", size, c->addr, c->port, c->family);
 
-    // shouldn't we do something with the result here?
-    DEBUG("sent %d bytes", result);
-    iemnet__chunk_destroy(c);
+    to.sin_addr.s_addr=htonl(c->addr);
+    to.sin_port       =htons(c->port);
+    to.sin_family     =c->family;
+    result = sendto(sockfd,
+                    data, size, /* DATA */
+                    flags,      /* FLAGS */
+                    (struct sockaddr *)&to, tolen); /* DESTADDR */
   } else {
+    DEBUG("sending %d bytes", size);
+    result = send(sockfd,
+                  data, size, /* DATA */
+                  flags);     /* FLAGS */
+  }
+  if(result<0) {
+    // broken pipe
     return 0;
   }
+
+  // shouldn't we do something with the result here?
+  DEBUG("sent %d bytes", result);
   return 1;
 }
 
-static void*iemnet__sender_sendthread(void*arg) {
+static void*iemnet__sender_sendthread(void*arg)
+{
   t_iemnet_sender*sender=(t_iemnet_sender*)arg;
 
-  int sockfd=sender->sockfd;
-  t_iemnet_queue*q=sender->queue;
+  int sockfd=-1;
+  t_iemnet_queue*q=NULL;
+  t_iemnet_chunk*c=NULL;
+  t_iemnet_sendfunction dosend=iemnet__sender_defaultsend;
+  const void*userdata=NULL;
+
+  LOCK(&sender->mtx);
+  q=sender->queue;
+  userdata=sender->userdata;
+  if(NULL!=sender->sendfun) {
+    dosend=sender->sendfun;
+  }
+
+  sockfd=sender->sockfd;
+
 
   while(sender->keepsending) {
-    if(!iemnet__sender_dosend(sockfd, q))break;
+    UNLOCK(&sender->mtx);
+
+    c=queue_pop_block(q);
+    if(c) {
+      if(!dosend(userdata, sockfd, c)) {
+        iemnet__chunk_destroy(c);
+
+        LOCK(&sender->mtx);
+        break;
+      }
+      iemnet__chunk_destroy(c);
+      c=NULL;
+    }
+    LOCK(&sender->mtx);
   }
-  LOCK (&sender->mtx);
   sender->isrunning=0;
   UNLOCK (&sender->mtx);
   DEBUG("send thread terminated");
   return NULL;
 }
 
-int iemnet__sender_send(t_iemnet_sender*s, t_iemnet_chunk*c) {
+int iemnet__sender_send(t_iemnet_sender*s, t_iemnet_chunk*c)
+{
   t_iemnet_queue*q=0;
   int size=-1;
   LOCK (&s->mtx);
@@ -127,10 +180,11 @@ int iemnet__sender_send(t_iemnet_sender*s, t_iemnet_chunk*c) {
   return size;
 }
 
-void iemnet__sender_destroy(t_iemnet_sender*s) {
+void iemnet__sender_destroy(t_iemnet_sender*s, int subthread)
+{
   int sockfd=-1;
   /* simple protection against recursive calls:
-   * s->keepsending is only set to "0" in here, 
+   * s->keepsending is only set to "0" in here,
    * so if it is false, we know that we are already being called
    */
   DEBUG("destroy sender %x with queue %x (%d)", s, s->queue, s->keepsending);
@@ -143,16 +197,19 @@ void iemnet__sender_destroy(t_iemnet_sender*s) {
     return;
   }
   s->keepsending=0;
+
+  while(s->isrunning) {
+    s->keepsending=0;
+    queue_finish(s->queue);
+    UNLOCK (&s->mtx);
+    LOCK (&s->mtx);
+  }
+
   UNLOCK (&s->mtx);
 
   queue_finish(s->queue);
   DEBUG("queue finished");
 
-  if(sockfd>=0) {
-    int err=shutdown(sockfd, 2); /* needed on linux, since the recv won't shutdown on sys_closesocket() alone */
-    sys_closesocket(sockfd); 
-  }
-
   pthread_join(s->thread, NULL);
   DEBUG("thread joined");
   queue_destroy(s->queue);
@@ -160,18 +217,23 @@ void iemnet__sender_destroy(t_iemnet_sender*s) {
   pthread_mutex_destroy (&s->mtx);
 
   memset(s, 0, sizeof(t_iemnet_sender));
+  s->sockfd = -1;
   free(s);
   s=NULL;
   DEBUG("destroyed sender");
 }
 
 
-t_iemnet_sender*iemnet__sender_create(int sock) {
+t_iemnet_sender*iemnet__sender_create(int sock,
+                                      t_iemnet_sendfunction sendfun, const void*userdata,
+                                      int subthread)
+{
   static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
-  t_iemnet_sender*result=(t_iemnet_sender*)malloc(sizeof(t_iemnet_sender));
+  t_iemnet_sender*result=(t_iemnet_sender*)calloc(1,
+                         sizeof(t_iemnet_sender));
   int res=0;
   DEBUG("create sender %x", result);
-  if(NULL==result){
+  if(NULL==result) {
     DEBUG("create sender failed");
     return NULL;
   }
@@ -180,23 +242,28 @@ t_iemnet_sender*iemnet__sender_create(int sock) {
   result->sockfd = sock;
   result->keepsending =1;
   result->isrunning=1;
+  result->sendfun=sendfun;
+  result->userdata=userdata;
   DEBUG("create_sender queue=%x", result->queue);
 
   memcpy(&result->mtx , &mtx, sizeof(pthread_mutex_t));
   res=pthread_create(&result->thread, 0, iemnet__sender_sendthread, result);
 
   if(0==res) {
-
   } else {
     // something went wrong
+    queue_destroy(result->queue);
+    free(result);
+    return NULL;
   }
 
   DEBUG("created sender");
   return result;
 }
 
-int iemnet__sender_getlasterror(t_iemnet_sender*x) {
-  x=NULL;
+/* coverity[param_set_but_not_used]: as x is there for potentially more specific implentations in the future */
+int iemnet__sender_getlasterror(t_iemnet_sender*x)
+{
 #ifdef _WIN32
   return WSAGetLastError();
 #endif
@@ -204,27 +271,35 @@ int iemnet__sender_getlasterror(t_iemnet_sender*x) {
 }
 
 
-int iemnet__sender_getsockopt(t_iemnet_sender*s, int level, int optname, void      *optval, socklen_t*optlen) {
+int iemnet__sender_getsockopt(t_iemnet_sender*s, int level, int optname,
+                              void      *optval, socklen_t*optlen)
+{
   int result=getsockopt(s->sockfd, level, optname, optval, optlen);
   if(result!=0) {
-    post("%s: getsockopt returned %d", __FUNCTION__, iemnet__sender_getlasterror(s));
+    error("iemnet::sender: getsockopt returned %d",
+         iemnet__sender_getlasterror(s));
   }
   return result;
 }
-int iemnet__sender_setsockopt(t_iemnet_sender*s, int level, int optname, const void*optval, socklen_t optlen) {
+int iemnet__sender_setsockopt(t_iemnet_sender*s, int level, int optname,
+                              const void*optval, socklen_t optlen)
+{
   int result=setsockopt(s->sockfd, level, optname, optval, optlen);
   if(result!=0) {
-    post("%s: setsockopt returned %d", __FUNCTION__, iemnet__sender_getlasterror(s));
+    error("iemnet::sender: setsockopt returned %d",
+         iemnet__sender_getlasterror(s));
   }
   return result;
 }
 
 
 
-int iemnet__sender_getsize(t_iemnet_sender*x) {
+int iemnet__sender_getsize(t_iemnet_sender*x)
+{
   int size=-1;
-  if(x && x->queue)
+  if(x && x->queue) {
     size=queue_getsize(x->queue);
+  }
 
   return size;
 }
diff --git a/tcpclient.c b/tcpclient.c
index c613d34..cf0bc18 100644
--- a/tcpclient.c
+++ b/tcpclient.c
@@ -1,5 +1,5 @@
 /* tcpclient.c
- * copyright (c) 2010 IOhannes m zmölnig, IEM
+ * copyright © 2010-2015 IOhannes m zmölnig, IEM
  * copyright (c) 2006-2010 Martin Peach
  * copyright (c) 2004 Olaf Matthes
  */
@@ -18,8 +18,8 @@
 /* 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, write to the Free Software                  */
-/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.  */
+/* along with this program; if not, see                                         */
+/*     http://www.gnu.org/licenses/                                             */
 /*                                                                              */
 
 /* ---------------------------------------------------------------------------- */
@@ -28,14 +28,11 @@
 #include "iemnet.h"
 #include <string.h>
 
-#include <pthread.h>
-
 static t_class *tcpclient_class;
 static char objName[] = "tcpclient";
 
 
-typedef struct _tcpclient
-{
+typedef struct _tcpclient {
   t_object        x_obj;
   t_clock         *x_clock;
   t_outlet        *x_msgout;
@@ -54,11 +51,8 @@ typedef struct _tcpclient
   int             x_port; // port we're connected to
   long            x_addr; // address we're connected to as 32bit int
 
-  /* multithread stuff */
-  pthread_t       x_threadid; /* id of child thread */
-  pthread_attr_t  x_threadattr; /* attributes of child thread */
 
-	t_iemnet_floatlist         *x_floatlist;
+  t_iemnet_floatlist         *x_floatlist;
 } t_tcpclient;
 
 
@@ -90,114 +84,134 @@ static void tcpclient_info(t_tcpclient *x)
 }
 
 /* connection handling */
-
-static void *tcpclient_child_connect(void *w)
+static int tcpclient_do_disconnect(int fd, t_iemnet_sender*sender,
+                                   t_iemnet_receiver*receiver)
+{
+  if(sender) {
+    iemnet__sender_destroy(sender, 0);
+    sender=NULL;
+  }
+  if(receiver) {
+    iemnet__receiver_destroy(receiver, 0);
+    receiver=NULL;
+  }
+  if (fd >= 0) {
+    iemnet__closesocket(fd, 1);
+    return 1;
+  }
+  return 0;
+}
+static int tcpclient_do_connect(const char*host, unsigned short port,
+                                t_tcpclient*x,
+                                t_iemnet_sender**senderOUT, t_iemnet_receiver**receiverOUT, long*addrOUT)
 {
-  t_tcpclient         *x = (t_tcpclient*) w;
   struct sockaddr_in  server;
   struct hostent      *hp;
-  int                 sockfd;
-
-  t_iemnet_sender*sender;
+  int                 sockfd=-1;
+  t_iemnet_sender*  sender;
   t_iemnet_receiver*receiver;
 
-  if (x->x_fd >= 0)
-    {
-      error("%s_connect: already connected", objName);
-      return (x);
-    }
-
-  /* create a socket */
-  sockfd = socket(AF_INET, SOCK_STREAM, 0);
-  DEBUG("send socket %d\n", sockfd);
-  if (sockfd < 0)
-    {
-      sys_sockerror("tcpclient: socket");
-      return (x);
-    }
   /* connect socket using hostname provided in command line */
+  memset(&server, 0, sizeof(server));
   server.sin_family = AF_INET;
-  hp = gethostbyname(x->x_hostname);
-  if (hp == 0)
-    {
-      sys_sockerror("tcpclient: bad host?\n");
-      return (x);
-    }
+  hp = gethostbyname(host);
+  if (hp == 0) {
+    iemnet_log(x, IEMNET_ERROR, "bad host '%s'?", host);
+    return (-1);
+  }
   memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
 
+  sockfd = socket(AF_INET, SOCK_STREAM, 0);
+  if (sockfd < 0) {
+    iemnet_log(x, IEMNET_ERROR, "unable to open socket");
+    sys_sockerror("socket");
+    return (sockfd);
+  }
+
   /* assign client port number */
-  server.sin_port = htons((u_short)x->x_port);
+  server.sin_port = htons((u_short)port);
 
   /* try to connect */
-  if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0)
-    {
-      sys_sockerror("tcpclient: connecting stream socket");
-      sys_closesocket(sockfd);
-      return (x);
-    }
-
-  sender=iemnet__sender_create(sockfd);
-  receiver=iemnet__receiver_create(sockfd, x,  tcpclient_receive_callback);
-
-  /* update the tcpclient-object (thread safe) */
-  sys_lock();
-  x->x_fd = sockfd;
-  x->x_addr = ntohl(*(long *)hp->h_addr);
-
-  x->x_sender=sender;
-  x->x_receiver=receiver;
+  if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) {
+    iemnet_log(x, IEMNET_ERROR, "unable to connect to stream socket");
+    sys_sockerror("connect");
+    iemnet__closesocket(sockfd, 1);
+    return (-1);
+  }
 
-  x->x_connectstate = 1;
+  sender=iemnet__sender_create(sockfd, NULL, NULL, 0);
+  receiver=iemnet__receiver_create(sockfd, x,  tcpclient_receive_callback,
+                                   0);
 
-  /* use callback to set outlet in main thread */
-  clock_delay(x->x_clock, 0);
-  sys_unlock();
-  return (x);
+  if(addrOUT) {
+    *addrOUT= ntohl(*(long *)hp->h_addr);
+  }
+  if(senderOUT) {
+    *senderOUT=sender;
+  }
+  if(receiverOUT) {
+    *receiverOUT=receiver;
+  }
+  return sockfd;
 }
+
 static void tcpclient_tick(t_tcpclient *x)
 {
-    outlet_float(x->x_connectout, 1);
+  outlet_float(x->x_connectout, 1);
 }
 
 
 static void tcpclient_disconnect(t_tcpclient *x);
 
-static void tcpclient_connect(t_tcpclient *x, t_symbol *hostname, t_floatarg fportno)
+static void tcpclient_connect(t_tcpclient *x, t_symbol *hostname,
+                              t_floatarg fportno)
 {
-  if(x->x_fd>=0)tcpclient_disconnect(x);
+  long addr=0;
+  int state;
+
+  // first disconnect any active connection
+  if(x->x_hostname || x->x_port) {
+    state=tcpclient_do_disconnect(x->x_fd, x->x_sender, x->x_receiver);
+    if(state) {
+      outlet_float(x->x_connectout, 0);
+    }
+  }
+
   /* we get hostname and port and pass them on
      to the child thread that establishes the connection */
   x->x_hostname = hostname->s_name;
   x->x_port = fportno;
-  x->x_connectstate = 0;
-  /* start child thread */
-  if(pthread_create(&x->x_threadid, &x->x_threadattr, tcpclient_child_connect, x) < 0)
-    error("%s: could not create new thread", objName);
+
+
+  state=tcpclient_do_connect(x->x_hostname, x->x_port, x,
+                             &x->x_sender, &x->x_receiver,
+                             &x->x_addr);
+  x->x_connectstate=(state>0);
+  x->x_fd=state;
+  if(state>0) {
+    outlet_float(x->x_connectout, 1);
+  }
 }
 
 static void tcpclient_disconnect(t_tcpclient *x)
 {
-  if (x->x_fd >= 0)
-    {
-      int fd=x->x_fd;
-      x->x_fd = -1;
+  if(x->x_hostname || x->x_port) {
+    int state=tcpclient_do_disconnect(x->x_fd, x->x_sender, x->x_receiver);
 
-      DEBUG("disconnecting %x", x);
-      if(x->x_sender)iemnet__sender_destroy(x->x_sender); x->x_sender=NULL;
-      if(x->x_receiver)iemnet__receiver_destroy(x->x_receiver); x->x_receiver=NULL;
-      DEBUG("disconnect cleaning up %x", x);
-      sys_closesocket(fd);
-
-
-      x->x_connectstate = 0;
-      outlet_float(x->x_connectout, 0);
+    if(!state && !x->x_port) {
+      iemnet_log(x, IEMNET_ERROR, "not connected");
     }
-  else pd_error(x, "%s: not connected", objName);
+  }
+  outlet_float(x->x_connectout, 0);
+
+  x->x_port=0;
+  x->x_hostname=NULL;
 }
 
 /* sending/receiving */
 
-static void tcpclient_send(t_tcpclient *x, t_symbol *s, int argc, t_atom *argv)
+static void tcpclient_send(t_tcpclient *x, t_symbol *s, int argc,
+                           t_atom *argv)
 {
   int size=0;
   t_atom output_atom;
@@ -210,41 +224,70 @@ static void tcpclient_send(t_tcpclient *x, t_symbol *s, int argc, t_atom *argv)
   iemnet__chunk_destroy(chunk);
 
   SETFLOAT(&output_atom, size);
-  outlet_anything( x->x_statusout, gensym("sent"), 1, &output_atom);
+  outlet_anything( x->x_statusout, gensym("sendbuffersize"), 1,
+                   &output_atom);
   if(size<0) {
     tcpclient_disconnect(x);
   }
 }
 
-static void tcpclient_receive_callback(void*y, t_iemnet_chunk*c) {
+static void tcpclient_receive_callback(void*y, t_iemnet_chunk*c)
+{
   t_tcpclient *x=(t_tcpclient*)y;
 
   if(c) {
     iemnet__addrout(x->x_statusout, x->x_addrout, x->x_addr, x->x_port);
-	  x->x_floatlist=iemnet__chunk2list(c, x->x_floatlist); // get's destroyed in the dtor
-    iemnet__streamout(x->x_msgout, x->x_floatlist->argc, x->x_floatlist->argv, x->x_serialize);
+    x->x_floatlist=iemnet__chunk2list(c,
+                                      x->x_floatlist); // get's destroyed in the dtor
+    iemnet__streamout(x->x_msgout, x->x_floatlist->argc, x->x_floatlist->argv,
+                      x->x_serialize);
   } else {
     // disconnected
     tcpclient_disconnect(x);
   }
 }
 
-static void tcpclient_serialize(t_tcpclient *x, t_floatarg doit) {
+static void tcpclient_serialize(t_tcpclient *x, t_floatarg doit)
+{
   x->x_serialize=doit;
 }
 
 
 /* constructor/destructor */
+static void tcpclient_free_simple(t_tcpclient *x)
+{
+  if(x->x_clock) {
+    clock_free(x->x_clock);
+  }
+  x->x_clock=NULL;
+  if(x->x_floatlist) {
+    iemnet__floatlist_destroy(x->x_floatlist);
+  }
+  x->x_floatlist=NULL;
+
+  if(x->x_msgout) {
+    outlet_free(x->x_msgout);
+  }
+  if(x->x_addrout) {
+    outlet_free(x->x_addrout);
+  }
+  if(x->x_connectout) {
+    outlet_free(x->x_connectout);
+  }
+  if(x->x_statusout) {
+    outlet_free(x->x_statusout);
+  }
+}
 
 static void *tcpclient_new(void)
 {
-  int i;
-
   t_tcpclient *x = (t_tcpclient *)pd_new(tcpclient_class);
   x->x_msgout = outlet_new(&x->x_obj, 0);	/* received data */
   x->x_addrout = outlet_new(&x->x_obj, gensym("list"));
-  x->x_connectout = outlet_new(&x->x_obj, gensym("float"));	/* connection state */
-  x->x_statusout = outlet_new(&x->x_obj, 0);/* last outlet for everything else */
+  x->x_connectout = outlet_new(&x->x_obj,
+                               gensym("float"));	/* connection state */
+  x->x_statusout = outlet_new(&x->x_obj,
+                              0);/* last outlet for everything else */
 
   x->x_serialize=1;
 
@@ -259,36 +302,34 @@ static void *tcpclient_new(void)
   x->x_clock = clock_new(x, (t_method)tcpclient_tick);
   x->x_floatlist=iemnet__floatlist_create(1024);
 
-  /* prepare child thread */
-  if(pthread_attr_init(&x->x_threadattr) < 0)
-    error("%s: warning: could not prepare child thread", objName);
-  if(pthread_attr_setdetachstate(&x->x_threadattr, PTHREAD_CREATE_DETACHED) < 0)
-    error("%s: warning: could not prepare child thread", objName);
-    
-
   return (x);
 }
 
 static void tcpclient_free(t_tcpclient *x)
 {
   tcpclient_disconnect(x);
-  if(x->x_clock)clock_free(x->x_clock);x->x_clock=NULL;
-	if(x->x_floatlist)iemnet__floatlist_destroy(x->x_floatlist);x->x_floatlist=NULL;
+  tcpclient_free_simple(x);
 }
 
 IEMNET_EXTERN void tcpclient_setup(void)
 {
-  if(!iemnet__register(objName))return;
+  if(!iemnet__register(objName)) {
+    return;
+  }
   tcpclient_class = class_new(gensym(objName), (t_newmethod)tcpclient_new,
                               (t_method)tcpclient_free,
                               sizeof(t_tcpclient), 0, A_DEFFLOAT, 0);
-  class_addmethod(tcpclient_class, (t_method)tcpclient_connect, gensym("connect")
+  class_addmethod(tcpclient_class, (t_method)tcpclient_connect,
+                  gensym("connect")
                   , A_SYMBOL, A_FLOAT, 0);
-  class_addmethod(tcpclient_class, (t_method)tcpclient_disconnect, gensym("disconnect"), 0);
+  class_addmethod(tcpclient_class, (t_method)tcpclient_disconnect,
+                  gensym("disconnect"), 0);
 
-  class_addmethod(tcpclient_class, (t_method)tcpclient_serialize, gensym("serialize"), A_FLOAT, 0);
+  class_addmethod(tcpclient_class, (t_method)tcpclient_serialize,
+                  gensym("serialize"), A_FLOAT, 0);
 
-  class_addmethod(tcpclient_class, (t_method)tcpclient_send, gensym("send"), A_GIMME, 0);
+  class_addmethod(tcpclient_class, (t_method)tcpclient_send, gensym("send"),
+                  A_GIMME, 0);
   class_addlist(tcpclient_class, (t_method)tcpclient_send);
 
   class_addbang(tcpclient_class, (t_method)tcpclient_info);
@@ -298,7 +339,4 @@ IEMNET_EXTERN void tcpclient_setup(void)
 
 IEMNET_INITIALIZER(tcpclient_setup);
 
-
-
-
 /* end of tcpclient.c */
diff --git a/tcpreceive.c b/tcpreceive.c
index d008108..b79c0d6 100644
--- a/tcpreceive.c
+++ b/tcpreceive.c
@@ -1,5 +1,5 @@
 /* tcpreceive.c
- * copyright (c) 2010 IOhannes m zmölnig, IEM
+ * copyright © 2010-2015 IOhannes m zmölnig, IEM
  * copyright (c) 2006-2010 Martin Peach
  * copyright (c) Miller Puckette
  */
@@ -18,8 +18,8 @@
 /* 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, write to the Free Software                  */
-/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.  */
+/* along with this program; if not, see                                         */
+/*     http://www.gnu.org/licenses/                                             */
 /*                                                                              */
 
 #define DEBUGLEVEL 1
@@ -32,14 +32,15 @@ static const char*objName="tcpreceive";
 # include <netinet/tcp.h>
 #endif
 
+#include <string.h>
+
 /* ----------------------------- tcpreceive ------------------------- */
 
 static t_class *tcpreceive_class;
 
 #define MAX_CONNECTIONS 128 // this is going to cause trouble down the line...:(
 
-typedef struct _tcpconnection
-{
+typedef struct _tcpconnection {
   long            addr;
   unsigned short  port;
   int             socket;
@@ -47,8 +48,7 @@ typedef struct _tcpconnection
   t_iemnet_receiver*receiver;
 } t_tcpconnection;
 
-typedef struct _tcpreceive
-{
+typedef struct _tcpreceive {
   t_object        x_obj;
   t_outlet        *x_msgout;
   t_outlet        *x_addrout;
@@ -62,33 +62,40 @@ typedef struct _tcpreceive
   int             x_nconnections;
   t_tcpconnection x_connection[MAX_CONNECTIONS];
 
-	t_iemnet_floatlist         *x_floatlist;
+  t_iemnet_floatlist         *x_floatlist;
 } t_tcpreceive;
 
+/* forward declarations */
+static int tcpreceive_disconnect(t_tcpreceive *x, int id);
 
-static int tcpreceive_find_socket(t_tcpreceive *x, int fd) {
+static int tcpreceive_find_socket(t_tcpreceive *x, int fd)
+{
   int i;
   for (i = 0; i < MAX_CONNECTIONS; ++i)
-    if (x->x_connection[i].socket == fd)return i;
+    if (x->x_connection[i].socket == fd) {
+      return i;
+    }
 
   return -1;
 }
 
-static int tcpreceive_disconnect(t_tcpreceive *x, int id);
-
 static void tcpreceive_read_callback(void *w, t_iemnet_chunk*c)
 {
   t_tcpconnection*y=(t_tcpconnection*)w;
   t_tcpreceive*x=NULL;
   int index=-1;
-  if(NULL==y || NULL==(x=y->owner))return;
+  if(NULL==y || NULL==(x=y->owner)) {
+    return;
+  }
 
   index=tcpreceive_find_socket(x, y->socket);
   if(index>=0) {
     if(c) {
       // TODO?: outlet info about connection
-      x->x_floatlist=iemnet__chunk2list(c, x->x_floatlist); // gets destroyed in the dtor
-      iemnet__streamout(x->x_msgout, x->x_floatlist->argc, x->x_floatlist->argv, x->x_serialize);
+      x->x_floatlist=iemnet__chunk2list(c,
+                                        x->x_floatlist); // gets destroyed in the dtor
+      iemnet__streamout(x->x_msgout, x->x_floatlist->argc, x->x_floatlist->argv,
+                        x->x_serialize);
     } else {
       // disconnected
       tcpreceive_disconnect(x, index);
@@ -98,25 +105,24 @@ static void tcpreceive_read_callback(void *w, t_iemnet_chunk*c)
 
 /* tcpreceive_addconnection tries to add the socket fd to the list */
 /* returns 1 on success, else 0 */
-static int tcpreceive_addconnection(t_tcpreceive *x, int fd, long addr, unsigned short port)
+static int tcpreceive_addconnection(t_tcpreceive *x, int fd, long addr,
+                                    unsigned short port)
 {
   int i;
-  for (i = 0; i < MAX_CONNECTIONS; ++i)
-    {
-      if (x->x_connection[i].socket == -1)
-        {
-	  x->x_connection[i].socket = fd;
-	  x->x_connection[i].addr = addr;
-	  x->x_connection[i].port = port;
-	  x->x_connection[i].owner = x;
-	  x->x_connection[i].receiver=
-	    iemnet__receiver_create(fd, 
-				    x->x_connection+i, 
-				    tcpreceive_read_callback);
-	  
-	  return 1;
-        }
+  for (i = 0; i < MAX_CONNECTIONS; ++i) {
+    if (x->x_connection[i].socket == -1) {
+      x->x_connection[i].socket = fd;
+      x->x_connection[i].addr = addr;
+      x->x_connection[i].port = port;
+      x->x_connection[i].owner = x;
+      x->x_connection[i].receiver=
+        iemnet__receiver_create(fd,
+                                x->x_connection+i,
+                                tcpreceive_read_callback,
+                                0);
+      return 1;
     }
+  }
   return 0;
 }
 
@@ -132,38 +138,31 @@ static void tcpreceive_connectpoll(t_tcpreceive *x)
   int                 fd;
 
   fd = accept(x->x_connectsocket, (struct sockaddr *)&from, &fromlen);
-  if (fd < 0) error("[%s]  accept failed", objName);
-  else
-    {
-      //       t_socketreceiver *y = socketreceiver_new((void *)x,
-      //         (t_socketnotifier)tcpreceive_notify,
-      //           0, 0);
-      
-      /* get the sender's ip */
-      addr = ntohl(from.sin_addr.s_addr);
-      port = ntohs(from.sin_port);
-      if (tcpreceive_addconnection(x, fd, addr, port))
-	{
-	  x->x_nconnections++;
-	  outlet_float(x->x_connectout, x->x_nconnections);
-	  iemnet__addrout(x->x_statout, x->x_addrout, addr, port);
-        }
-      else
-        {
-	  error ("[%s] Too many connections", objName);
-	  sys_closesocket(fd);
-        }
+  if (fd < 0) {
+    iemnet_log(x, IEMNET_ERROR, "could not accept new connection");
+    sys_sockerror("accept");
+  } else {
+    /* get the sender's ip */
+    addr = ntohl(from.sin_addr.s_addr);
+    port = ntohs(from.sin_port);
+    if (tcpreceive_addconnection(x, fd, addr, port)) {
+      x->x_nconnections++;
+      outlet_float(x->x_connectout, x->x_nconnections);
+      iemnet__addrout(x->x_statout, x->x_addrout, addr, port);
+    } else {
+      iemnet_log(x, IEMNET_ERROR, "too many connections");
+      iemnet__closesocket(fd, 1);
     }
+  }
 }
 
-
 static int tcpreceive_disconnect(t_tcpreceive *x, int id)
 {
   if(id>=0 && id < MAX_CONNECTIONS && x->x_connection[id].port>0) {
-    iemnet__receiver_destroy(x->x_connection[id].receiver);
+    iemnet__receiver_destroy(x->x_connection[id].receiver, 0);
     x->x_connection[id].receiver=NULL;
 
-    sys_closesocket(x->x_connection[id].socket);
+    iemnet__closesocket(x->x_connection[id].socket, 1);
     x->x_connection[id].socket = -1;
 
     x->x_connection[id].addr = 0L;
@@ -176,32 +175,27 @@ static int tcpreceive_disconnect(t_tcpreceive *x, int id)
   return 0;
 }
 
+
 /* tcpreceive_closeall closes all open sockets and deletes them from the list */
 static void tcpreceive_disconnect_all(t_tcpreceive *x)
 {
   int i;
 
-  for (i = 0; i < MAX_CONNECTIONS; i++)
-    {
-      tcpreceive_disconnect(x, i);
-    }
+  for (i = 0; i < MAX_CONNECTIONS; i++) {
+    tcpreceive_disconnect(x, i);
+  }
 }
 
-
-
-
 /* tcpreceive_removeconnection tries to delete the socket fd from the list */
 /* returns 1 on success, else 0 */
 static int tcpreceive_disconnect_socket(t_tcpreceive *x, int fd)
 {
   int i;
-  for (i = 0; i < MAX_CONNECTIONS; ++i)
-    {
-      if (x->x_connection[i].socket == fd)
-        {
-	  return tcpreceive_disconnect(x, i);
-        }
+  for (i = 0; i < MAX_CONNECTIONS; ++i) {
+    if (x->x_connection[i].socket == fd) {
+      return tcpreceive_disconnect(x, i);
     }
+  }
   return 0;
 }
 
@@ -213,6 +207,7 @@ static void tcpreceive_port(t_tcpreceive*x, t_floatarg fportno)
   socklen_t           serversize=sizeof(server);
   int sockfd = x->x_connectsocket;
   int intarg;
+  memset(&server, 0, sizeof(server));
 
   SETFLOAT(ap, -1);
   if(x->x_port == portno) {
@@ -222,15 +217,15 @@ static void tcpreceive_port(t_tcpreceive*x, t_floatarg fportno)
   /* cleanup any open ports */
   if(sockfd>=0) {
     sys_rmpollfn(sockfd);
-    sys_closesocket(sockfd);
+    iemnet__closesocket(sockfd, 1);
     x->x_connectsocket=-1;
     x->x_port=-1;
   }
 
-
   sockfd = socket(AF_INET, SOCK_STREAM, 0);
   if(sockfd<0) {
-    error("[%s]: unable to create socket", objName);
+    iemnet_log(x, IEMNET_ERROR, "unable to create socket");
+    sys_sockerror("socket");
     return;
   }
 
@@ -238,56 +233,57 @@ static void tcpreceive_port(t_tcpreceive*x, t_floatarg fportno)
 #ifdef SO_REUSEADDR
   intarg = 1;
   if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
-		 (char *)&intarg, sizeof(intarg)) 
+                 (char *)&intarg, sizeof(intarg))
       < 0) {
-    error("[%s]: setsockopt (SO_REUSEADDR) failed", objName);
+    iemnet_log(x, IEMNET_ERROR, "unable to enable address re-using");
+    sys_sockerror("setsockopt:SO_REUSEADDR");
   }
 #endif /* SO_REUSEADDR */
 #ifdef SO_REUSEPORT
   intarg = 1;
   if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT,
-		 (char *)&intarg, sizeof(intarg)) 
+                 (char *)&intarg, sizeof(intarg))
       < 0) {
-    error("[%s]: setsockopt (SO_REUSEPORT) failed", objName);
+    iemnet_log(x, IEMNET_ERROR, "unable to enable port re-using");
+    sys_sockerror("setsockopt:SO_REUSEPORT");
   }
 #endif /* SO_REUSEPORT */
 
   /* Stream (TCP) sockets are set NODELAY */
   intarg = 1;
   if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY,
-		 (char *)&intarg, sizeof(intarg)) < 0)
-    post("[%s]: setsockopt (TCP_NODELAY) failed", objName);
-
+                 (char *)&intarg, sizeof(intarg)) < 0) {
+    iemnet_log(x, IEMNET_ERROR, "unable to enable immediate sending");
+    sys_sockerror("setsockopt:TCP_NODELAY");
+  }
 
   server.sin_family = AF_INET;
   server.sin_addr.s_addr = INADDR_ANY;
   server.sin_port = htons((u_short)portno);
 
   /* name the socket */
-  if (bind(sockfd, (struct sockaddr *)&server, serversize) < 0)
-    {
-      sys_sockerror("[tcpreceive] bind failed");
-      sys_closesocket(sockfd);
-      sockfd = -1;
-      outlet_anything(x->x_statout, gensym("port"), 1, ap);
-      return;
-    }
+  if (bind(sockfd, (struct sockaddr *)&server, serversize) < 0) {
+    iemnet_log(x, IEMNET_ERROR, "couldn't bind socket");
+    sys_sockerror("bind");
+    iemnet__closesocket(sockfd, 1);
+    sockfd = -1;
+    outlet_anything(x->x_statout, gensym("port"), 1, ap);
+    return;
+  }
 
   /* streaming protocol */
-  if (listen(sockfd, 5) < 0)
-    {
-      sys_sockerror("[tcpreceive] listen");
-      sys_closesocket(sockfd);
-      sockfd = -1;
-      outlet_anything(x->x_statout, gensym("port"), 1, ap);
-      return;
-    }
-  else
-    {
-      sys_addpollfn(sockfd, 
-		    (t_fdpollfn)tcpreceive_connectpoll, 
-		    x); // wait for new connections 
-    }
+  if (listen(sockfd, 5) < 0) {
+    iemnet_log(x, IEMNET_ERROR, "unable to listen on socket");
+    sys_sockerror("listen");
+    iemnet__closesocket(sockfd, 1);
+    sockfd = -1;
+    outlet_anything(x->x_statout, gensym("port"), 1, ap);
+    return;
+  } else {
+    sys_addpollfn(sockfd,
+                  (t_fdpollfn)tcpreceive_connectpoll,
+                  x); // wait for new connections
+  }
 
   x->x_connectsocket = sockfd;
   x->x_port = portno;
@@ -297,25 +293,27 @@ static void tcpreceive_port(t_tcpreceive*x, t_floatarg fportno)
     x->x_port=ntohs(server.sin_port);
   }
 
-
   SETFLOAT(ap, x->x_port);
   outlet_anything(x->x_statout, gensym("port"), 1, ap);
 }
 
-static void tcpreceive_serialize(t_tcpreceive *x, t_floatarg doit) {
+static void tcpreceive_serialize(t_tcpreceive *x, t_floatarg doit)
+{
   x->x_serialize=doit;
 }
 
-
 static void tcpreceive_free(t_tcpreceive *x)
-{ /* is this ever called? */
-  if (x->x_connectsocket >= 0)
-    {
-      sys_rmpollfn(x->x_connectsocket);
-      sys_closesocket(x->x_connectsocket);
-    }
+{
+  /* is this ever called? */
+  if (x->x_connectsocket >= 0) {
+    sys_rmpollfn(x->x_connectsocket);
+    iemnet__closesocket(x->x_connectsocket, 1);
+  }
   tcpreceive_disconnect_all(x);
-	if(x->x_floatlist)iemnet__floatlist_destroy(x->x_floatlist);x->x_floatlist=NULL;
+  if(x->x_floatlist) {
+    iemnet__floatlist_destroy(x->x_floatlist);
+  }
+  x->x_floatlist=NULL;
 }
 
 static void *tcpreceive_new(t_floatarg fportno)
@@ -328,7 +326,7 @@ static void *tcpreceive_new(t_floatarg fportno)
   x->x_msgout = outlet_new(&x->x_obj, 0);
   x->x_addrout = outlet_new(&x->x_obj, gensym("list")); /* legacy */
   x->x_connectout = outlet_new(&x->x_obj, gensym("float")); /* legacy */
-  x->x_statout = outlet_new(&x->x_obj, 0);/* outlet for everything else */
+  x->x_statout = outlet_new(&x->x_obj, 0); /* outlet for everything else */
 
   x->x_serialize=1;
 
@@ -337,12 +335,11 @@ static void *tcpreceive_new(t_floatarg fportno)
   x->x_nconnections=0;
 
   /* clear the connection list */
-  for (i = 0; i < MAX_CONNECTIONS; ++i)
-    {
-      x->x_connection[i].socket = -1;
-      x->x_connection[i].addr = 0L;
-      x->x_connection[i].port = 0;
-    }
+  for (i = 0; i < MAX_CONNECTIONS; ++i) {
+    x->x_connection[i].socket = -1;
+    x->x_connection[i].addr = 0L;
+    x->x_connection[i].port = 0;
+  }
 
   x->x_floatlist=iemnet__floatlist_create(1024);
 
@@ -354,22 +351,23 @@ static void *tcpreceive_new(t_floatarg fportno)
 
 IEMNET_EXTERN void tcpreceive_setup(void)
 {
-  if(!iemnet__register(objName))return;
+  if(!iemnet__register(objName)) {
+    return;
+  }
   tcpreceive_class = class_new(gensym(objName),
-			       (t_newmethod)tcpreceive_new, (t_method)tcpreceive_free,
-			       sizeof(t_tcpreceive), 
-			       0, 
-			       A_DEFFLOAT, 0);
-  
-  class_addmethod(tcpreceive_class, (t_method)tcpreceive_port, gensym("port"), A_DEFFLOAT, 0);
-
-  class_addmethod(tcpreceive_class, (t_method)tcpreceive_serialize, gensym("serialize"), A_FLOAT, 0);
+                               (t_newmethod)tcpreceive_new, (t_method)tcpreceive_free,
+                               sizeof(t_tcpreceive),
+                               0,
+                               A_DEFFLOAT, 0);
+
+  class_addmethod(tcpreceive_class, (t_method)tcpreceive_port,
+                  gensym("port"), A_DEFFLOAT, 0);
+
+  class_addmethod(tcpreceive_class, (t_method)tcpreceive_serialize,
+                  gensym("serialize"), A_FLOAT, 0);
   DEBUGMETHOD(tcpreceive_class);
 }
 
 IEMNET_INITIALIZER(tcpreceive_setup);
 
-
 /* end x_net_tcpreceive.c */
-
-
diff --git a/tcpsend.c b/tcpsend.c
index 9c94c19..4597a32 100644
--- a/tcpsend.c
+++ b/tcpsend.c
@@ -1,5 +1,5 @@
 /* tcpsend.c
- * copyright (c) 2010 IOhannes m zmölnig, IEM
+ * copyright © 2010-2015 IOhannes m zmölnig, IEM
  * copyright (c) 2006-2010 Martin Peach
  * copyright (c) Miller Puckette
  */
@@ -18,8 +18,8 @@
 /* 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, write to the Free Software                  */
-/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.  */
+/* along with this program; if not, see                                         */
+/*     http://www.gnu.org/licenses/                                             */
 /*                                                                              */
 
 #define DEBUGLEVEL 1
@@ -33,11 +33,9 @@ static const char objName[] = "tcpsend";
 # include <netinet/tcp.h>
 #endif
 
-
 static t_class *tcpsend_class;
 
-typedef struct _tcpsend
-{
+typedef struct _tcpsend {
   t_object x_obj;
   int      x_fd;
   t_iemnet_sender*x_sender;
@@ -45,71 +43,71 @@ typedef struct _tcpsend
 
 static void tcpsend_disconnect(t_tcpsend *x)
 {
-  if (x->x_fd >= 0)
-    {
-      if(x->x_sender)iemnet__sender_destroy(x->x_sender); x->x_sender=NULL;
-      sys_closesocket(x->x_fd);
-      x->x_fd = -1;
-      outlet_float(x->x_obj.ob_outlet, 0);
-      post("tcpsend: disconnected");
-    }
+  if(x->x_sender) {
+    iemnet__sender_destroy(x->x_sender, 0);
+  }
+  x->x_sender=NULL;
+  if (x->x_fd >= 0) {
+    iemnet__closesocket(x->x_fd, 1);
+    x->x_fd = -1;
+    outlet_float(x->x_obj.ob_outlet, 0);
+  }
 }
 
-
-
 static void tcpsend_connect(t_tcpsend *x, t_symbol *hostname,
-			    t_floatarg fportno)
+                            t_floatarg fportno)
 {
   struct sockaddr_in  server;
   struct hostent      *hp;
   int                 sockfd;
   int                 portno = fportno;
   int                 intarg;
+  memset(&server, 0, sizeof(server));
 
-  if (x->x_fd >= 0)
-    {
-      error("tcpsend: already connected");
-      return;
-    }
+  if (x->x_fd >= 0) {
+    iemnet_log(x, IEMNET_ERROR, "already connected");
+    return;
+  }
 
   /* create a socket */
   sockfd = socket(AF_INET, SOCK_STREAM, 0);
   DEBUG("send socket %d\n", sockfd);
-  if (sockfd < 0)
-    {
-      sys_sockerror("tcpsend: socket");
-      return;
-    }
+  if (sockfd < 0) {
+    iemnet_log(x, IEMNET_ERROR, "unable to open socket");
+    sys_sockerror("socket");
+    return;
+  }
   /* connect socket using hostname provided in command line */
   server.sin_family = AF_INET;
   hp = gethostbyname(hostname->s_name);
-  if (hp == 0)
-    {
-      post("tcpsend: bad host?\n");
-      return;
-    }
+  if (hp == 0) {
+    iemnet_log(x, IEMNET_ERROR, "bad host '%s'?", hostname->s_name);
+    return;
+  }
   /* for stream (TCP) sockets, specify "nodelay" */
   intarg = 1;
   if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY,
-		 (char *)&intarg, sizeof(intarg)) < 0)
-    post("tcpsend: setsockopt (TCP_NODELAY) failed\n");
+                 (char *)&intarg, sizeof(intarg)) < 0) {
+    iemnet_log(x, IEMNET_ERROR, "unable to enable immediate sending");
+    sys_sockerror("setsockopt");
+  }
 
   memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
 
   /* assign client port number */
   server.sin_port = htons((u_short)portno);
 
-  post("tcpsend: connecting to port %d", portno);
+  iemnet_log(x, IEMNET_VERBOSE, "connecting to port %d", portno);
   /* try to connect. */
-  if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0)
-    {
-      sys_sockerror("tcpsend: connecting stream socket");
-      sys_closesocket(sockfd);
-      return;
-    }
+  if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) {
+    iemnet_log(x, IEMNET_ERROR, "unable to initiate connection on socket %d", sockfd);
+    sys_sockerror("connect");
+    iemnet__closesocket(sockfd, 1);
+    return;
+  }
   x->x_fd = sockfd;
 
-  x->x_sender=iemnet__sender_create(sockfd);
+  x->x_sender=iemnet__sender_create(sockfd, NULL, NULL, 0);
 
   outlet_float(x->x_obj.ob_outlet, 1);
 }
@@ -140,18 +138,20 @@ static void *tcpsend_new(void)
 
 IEMNET_EXTERN void tcpsend_setup(void)
 {
-  if(!iemnet__register(objName))return;
-  tcpsend_class = class_new(gensym(objName), 
-			    (t_newmethod)tcpsend_new, (t_method)tcpsend_free,
-			    sizeof(t_tcpsend), 
-			    0, 0);
+  if(!iemnet__register(objName)) {
+    return;
+  }
+  tcpsend_class = class_new(gensym(objName),
+                            (t_newmethod)tcpsend_new, (t_method)tcpsend_free,
+                            sizeof(t_tcpsend),
+                            0, 0);
 
   class_addmethod(tcpsend_class, (t_method)tcpsend_connect,
-		  gensym("connect"), A_SYMBOL, A_FLOAT, 0);
+                  gensym("connect"), A_SYMBOL, A_FLOAT, 0);
   class_addmethod(tcpsend_class, (t_method)tcpsend_disconnect,
-		  gensym("disconnect"), 0);
+                  gensym("disconnect"), 0);
   class_addmethod(tcpsend_class, (t_method)tcpsend_send, gensym("send"),
-		  A_GIMME, 0);
+                  A_GIMME, 0);
   class_addlist(tcpsend_class, (t_method)tcpsend_send);
 
   DEBUGMETHOD(tcpsend_class);
@@ -159,5 +159,4 @@ IEMNET_EXTERN void tcpsend_setup(void)
 
 IEMNET_INITIALIZER(tcpsend_setup);
 
-
 /* end tcpsend.c */
diff --git a/tcpserver.c b/tcpserver.c
index ad4387d..ded8abe 100644
--- a/tcpserver.c
+++ b/tcpserver.c
@@ -1,5 +1,5 @@
 /* tcpserver.c
- * copyright (c) 2010 IOhannes m zmölnig, IEM
+ * copyright © 2010-2015 IOhannes m zmölnig, IEM
  * copyright (c) 2006-2010 Martin Peach
  * copyright (c) 2004 Olaf Matthes
  */
@@ -19,8 +19,8 @@
 /* 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, write to the Free Software                  */
-/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.  */
+/* along with this program; if not, see                                         */
+/*     http://www.gnu.org/licenses/                                             */
 /*                                                                              */
 
 /* ---------------------------------------------------------------------------- */
@@ -29,6 +29,8 @@
 #include "iemnet.h"
 #include "iemnet_data.h"
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
 #define MAX_CONNECT 32 /* maximum number of connections */
 
@@ -37,97 +39,99 @@
 static t_class *tcpserver_class;
 static const char objName[] = "tcpserver";
 
-typedef struct _tcpserver_socketreceiver
-{
+typedef struct _tcpserver_socketreceiver {
   struct _tcpserver *sr_owner;
 
   long           sr_host;
   unsigned short sr_port;
-  t_int          sr_fd;
+  int          sr_fd;
   t_iemnet_sender*sr_sender;
   t_iemnet_receiver*sr_receiver;
 } t_tcpserver_socketreceiver;
 
-typedef struct _tcpserver
-{
+typedef struct _tcpserver {
   t_object                    x_obj;
   t_outlet                    *x_msgout;
   t_outlet                    *x_connectout;
   t_outlet                    *x_sockout; // legacy
   t_outlet                    *x_addrout; // legacy
-  t_outlet                    *x_statout; 
+  t_outlet                    *x_statout;
 
   int                          x_serialize;
 
   t_tcpserver_socketreceiver  *x_sr[MAX_CONNECT]; /* socket per connection */
-  t_int                       x_nconnections;
+  unsigned int              x_nconnections;
 
-  t_int                       x_connectsocket;    /* socket waiting for new connections */
-  t_int                       x_port;
+  int
+  x_connectsocket;    /* socket waiting for new connections */
+  int                       x_port;
 
-  int                         x_defaulttarget; /* the default connection to send to; 0=broadcast; >0 use this client; <0 exclude this client */
-	t_iemnet_floatlist         *x_floatlist;
+  int
+  x_defaulttarget; /* the default connection to send to; 0=broadcast; >0 use this client; <0 exclude this client */
+  t_iemnet_floatlist         *x_floatlist;
 } t_tcpserver;
 
+/* forward declarations */
 static void tcpserver_receive_callback(void*x, t_iemnet_chunk*);
 
-static t_tcpserver_socketreceiver *tcpserver_socketreceiver_new(t_tcpserver *owner, int sockfd, struct sockaddr_in*addr)
+static t_tcpserver_socketreceiver *tcpserver_socketreceiver_new(
+  t_tcpserver *owner, int sockfd, struct sockaddr_in*addr)
 {
-  t_tcpserver_socketreceiver *x = (t_tcpserver_socketreceiver *)getbytes(sizeof(*x));
+  t_tcpserver_socketreceiver *x = (t_tcpserver_socketreceiver *)getbytes(
+                                    sizeof(*x));
   if(NULL==x) {
-    error("%s_socketreceiver: unable to allocate %d bytes", objName, sizeof(*x));
+    iemnet_log(x, IEMNET_FATAL, "unable to allocate %d bytes", (int)sizeof(*x));
     return NULL;
-  } else {
-    x->sr_owner=owner;
+  }
+  x->sr_owner=owner;
 
-    x->sr_fd=sockfd;
+  x->sr_fd=sockfd;
 
-    x->sr_host=ntohl(addr->sin_addr.s_addr);
-    x->sr_port=ntohs(addr->sin_port);
+  x->sr_host=ntohl(addr->sin_addr.s_addr);
+  x->sr_port=ntohs(addr->sin_port);
 
-    x->sr_sender=iemnet__sender_create(sockfd);
-    x->sr_receiver=iemnet__receiver_create(sockfd, x, tcpserver_receive_callback);
-  }
+  x->sr_sender=iemnet__sender_create(sockfd, NULL, NULL, 0);
+  x->sr_receiver=iemnet__receiver_create(sockfd, x,
+                                         tcpserver_receive_callback, 0);
   return (x);
 }
 
 static void tcpserver_socketreceiver_free(t_tcpserver_socketreceiver *x)
 {
   DEBUG("freeing %x", x);
-  if (x != NULL)
-    {
-      int sockfd=x->sr_fd;
-      t_iemnet_sender*sender=x->sr_sender;
-      t_iemnet_receiver*receiver=x->sr_receiver;
-
-      x->sr_owner=NULL;
-      x->sr_sender=NULL;
-      x->sr_receiver=NULL;
-
-      x->sr_fd=-1;
-		
-		
-	  if(sender)  iemnet__sender_destroy(sender);
-	  if(receiver)iemnet__receiver_destroy(receiver);
-		
-	   sys_closesocket(sockfd);
-		
-
-      freebytes(x, sizeof(*x));
+  if (x != NULL) {
+    int sockfd=x->sr_fd;
+    t_iemnet_sender*sender=x->sr_sender;
+    t_iemnet_receiver*receiver=x->sr_receiver;
+
+    x->sr_owner=NULL;
+    x->sr_sender=NULL;
+    x->sr_receiver=NULL;
+
+    x->sr_fd=-1;
+
+    if(sender) {
+      iemnet__sender_destroy(sender, 0);
     }
-  DEBUG("freeed %x", x);
+    if(receiver) {
+      iemnet__receiver_destroy(receiver, 0);
+    }
+
+    iemnet__closesocket(sockfd, 1);
+
+    freebytes(x, sizeof(*x));
+  }
+  DEBUG("freed %x", x);
 }
 
 static int tcpserver_socket2index(t_tcpserver*x, int sockfd)
 {
-  int i=0;
-  for(i = 0; i < x->x_nconnections; i++) /* check if connection exists */
-    {
-      if(x->x_sr[i]->sr_fd == sockfd)
-        {
-          return i;
-        }
-    }  
+  unsigned int i=0;
+  for(i = 0; i < x->x_nconnections; i++) { /* check if connection exists */
+    if(x->x_sr[i]->sr_fd == sockfd) {
+      return i;
+    }
+  }
   return -1;
 }
 
@@ -137,28 +141,27 @@ static int tcpserver_socket2index(t_tcpserver*x, int sockfd)
  */
 static int tcpserver_fixindex(t_tcpserver*x, int client)
 {
-  if(x->x_nconnections <= 0)
-    {
-      pd_error(x, "[%s]: no clients connected", objName);
-      return -1;
-    }
-  
-  if (!((client > 0) && (client <= x->x_nconnections)))
-    {
-      pd_error(x, "[%s] client %d out of range [1..%d]", objName, client, x->x_nconnections);
-      return -1;
-    }
+  if(x->x_nconnections <= 0) {
+    iemnet_log(x, IEMNET_ERROR, "no clients connected");
+    return -1;
+  }
+
+  if (!((client > 0) && ((unsigned int)client <= x->x_nconnections))) {
+    iemnet_log(x, IEMNET_ERROR,
+               "client:%d out of range [1..%d]",
+               client, (int)(x->x_nconnections));
+    return -1;
+  }
   return (client-1);
 }
 
-
 /* ---------------- tcpserver info ---------------------------- */
-static void tcpserver_info_client(t_tcpserver *x, int client)
+static void tcpserver_info_client(t_tcpserver *x, unsigned int client)
 {
   // "client <id> <socket> <IP> <port>"
   // "bufsize <id> <insize> <outsize>"
   static t_atom output_atom[4];
-  if(x&&x->x_sr&&x->x_sr[client]) {
+  if(x&&client<MAX_CONNECT&&x->x_sr[client]) {
     int sockfd = x->x_sr[client]->sr_fd;
     unsigned short port   = x->x_sr[client]->sr_port;
     long address = x->x_sr[client]->sr_host;
@@ -167,7 +170,7 @@ static void tcpserver_info_client(t_tcpserver *x, int client)
     int insize =iemnet__receiver_getsize(x->x_sr[client]->sr_receiver);
     int outsize=iemnet__sender_getsize  (x->x_sr[client]->sr_sender  );
 
-    snprintf(hostname, MAXPDSTRING-1, "%d.%d.%d.%d", 
+    snprintf(hostname, MAXPDSTRING-1, "%d.%d.%d.%d",
              (unsigned char)((address & 0xFF000000)>>24),
              (unsigned char)((address & 0x0FF0000)>>16),
              (unsigned char)((address & 0x0FF00)>>8),
@@ -188,17 +191,16 @@ static void tcpserver_info_client(t_tcpserver *x, int client)
   }
 }
 
-
-static void tcpserver_info(t_tcpserver *x) {
+static void tcpserver_info(t_tcpserver *x)
+{
   static t_atom output_atom[4];
   int sockfd=x->x_connectsocket;
 
-
   int port=x->x_port;
 
   if(sockfd<0) {
-    // no open port
-    post("no valid sock");
+    iemnet_log(x, IEMNET_ERROR, "no open socket");
+    return;
   }
 
   if(x->x_port<=0) {
@@ -208,7 +210,9 @@ static void tcpserver_info(t_tcpserver *x) {
       x->x_port=ntohs(server.sin_port);
       port=x->x_port;
     } else {
-      post("gesockname failed for %d", sockfd);
+      iemnet_log(x, IEMNET_ERROR, "unable to get socket name for %d", sockfd);
+      sys_sockerror("getsockname");
+      return;
     }
   }
 
@@ -216,26 +220,26 @@ static void tcpserver_info(t_tcpserver *x) {
   outlet_anything( x->x_statout, gensym("port"), 1, output_atom);
 }
 
-
-static void tcpserver_info_connection(t_tcpserver *x, t_tcpserver_socketreceiver*y)
+static void tcpserver_info_connection(t_tcpserver *x,
+                                      t_tcpserver_socketreceiver*y)
 {
   iemnet__addrout(x->x_statout, x->x_addrout, y->sr_host, y->sr_port);
   outlet_float(x->x_sockout, y->sr_fd);
 }
 
 /* ---------------- main tcpserver (send) stuff --------------------- */
-static void tcpserver_disconnect_socket(t_tcpserver *x, t_floatarg fsocket);
-static void tcpserver_send_bytes(t_tcpserver*x, int client, t_iemnet_chunk*chunk)
+static void tcpserver_disconnect_socket(t_tcpserver *x,
+                                        t_floatarg fsocket);
+
+static void tcpserver_send_bytes_client(t_tcpserver*x,
+                                        t_tcpserver_socketreceiver*sr, int client, t_iemnet_chunk*chunk)
 {
-  DEBUG("send_bytes to %x -> %x[%d]", x, x->x_sr, client);
-  if(x->x_sr)DEBUG("client %X", x->x_sr[client]);
-  if(x && x->x_sr && x->x_sr[client]) {
+  if(sr) {
     t_atom                  output_atom[3];
     int size=-1;
 
-    t_iemnet_sender*sender=sender=x->x_sr[client]->sr_sender;
-    int sockfd = x->x_sr[client]->sr_fd;
-
+    t_iemnet_sender*sender=sr->sr_sender;
+    int sockfd = sr->sr_fd;
     if(sender) {
       size=iemnet__sender_send(sender, chunk);
     }
@@ -243,7 +247,7 @@ static void tcpserver_send_bytes(t_tcpserver*x, int client, t_iemnet_chunk*chunk
     SETFLOAT(&output_atom[0], client+1);
     SETFLOAT(&output_atom[1], size);
     SETFLOAT(&output_atom[2], sockfd);
-    outlet_anything( x->x_statout, gensym("sent"), 3, output_atom);
+    outlet_anything( x->x_statout, gensym("sendbuffersize"), 3, output_atom);
 
     if(size<0) {
       // disconnected!
@@ -252,109 +256,165 @@ static void tcpserver_send_bytes(t_tcpserver*x, int client, t_iemnet_chunk*chunk
   }
 }
 
+static void tcpserver_send_bytes(t_tcpserver*x, int client,
+                                 t_iemnet_chunk*chunk)
+{
+  t_tcpserver_socketreceiver*sr=NULL;
+  if(x&&client<MAX_CONNECT) {
+    sr=x->x_sr[client];
+  }
+  DEBUG("send_bytes to %p[%d] -> %p", x, client, sr);
+  tcpserver_send_bytes_client(x, sr, client, chunk);
+}
 
+/* send the chunk to all non-null clients */
+static void tcpserver_send_bytes_clients(t_tcpserver*x,
+    t_tcpserver_socketreceiver**sr, unsigned int nsr, t_iemnet_chunk*chunk)
+{
+  unsigned int i=0;
+  for(i=0; i<nsr; i++) {
+    tcpserver_send_bytes_client(x, sr[i], i, chunk);
+  }
+}
 
 /* broadcasts a message to all connected clients but the given one */
-static void tcpserver_send_butclient(t_tcpserver *x, int but, int argc, t_atom *argv)
+static void tcpserver_send_butclient(t_tcpserver *x, unsigned int but,
+                                     int argc, t_atom *argv)
 {
-  int client=0;
-  t_iemnet_chunk*chunk=iemnet__chunk_create_list(argc, argv);
+  unsigned int client=0;
+  t_iemnet_chunk*chunk=NULL;
+  t_tcpserver_socketreceiver**sr=NULL;
+  if(!x || !x->x_nconnections) {
+    return;
+  }
 
-  /* enumerate through the clients and send each the message */
-  for(client = 0; client < x->x_nconnections; client++)	/* check if connection exists */
-    {
-      /* socket exists for this client */
-      if(client!=but)tcpserver_send_bytes(x, client, chunk);
-    }
+  chunk=iemnet__chunk_create_list(argc, argv);
+  sr=(t_tcpserver_socketreceiver**)calloc(x->x_nconnections,
+                                          sizeof(t_tcpserver_socketreceiver*));
+
+  for(client=0; client<x->x_nconnections; client++) {
+    sr[client]=x->x_sr[client];
+  }
+
+  if(but<x->x_nconnections) {
+    sr[but]=NULL;
+  }
+
+  tcpserver_send_bytes_clients(x, sr, x->x_nconnections, chunk);
+
+  free(sr);
   iemnet__chunk_destroy(chunk);
 }
 /* sends a message to a given client */
-static void tcpserver_send_toclient(t_tcpserver *x, int client, int argc, t_atom *argv)
+static void tcpserver_send_toclient(t_tcpserver *x, unsigned int client,
+                                    int argc, t_atom *argv)
 {
   t_iemnet_chunk*chunk=iemnet__chunk_create_list(argc, argv);
   tcpserver_send_bytes(x, client, chunk);
   iemnet__chunk_destroy(chunk);
 }
 
-
-
 /* send message to client using client number
    note that the client numbers might change in case a client disconnects! */
 /* clients start at 1 but our index starts at 0 */
-static void tcpserver_send_client(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv)
+static void tcpserver_send_client(t_tcpserver *x, t_symbol *s, int argc,
+                                  t_atom *argv)
 {
   int client=0;
-      
-  if (argc > 0)
-    {
-      client=tcpserver_fixindex(x, atom_getint(argv));
-      if(client<0)return;
-      if(argc==1) {
-        tcpserver_info_client(x, client);
-      } else {
-        tcpserver_send_toclient(x, client, argc-1, argv+1);
-      }
+
+  if (argc > 0) {
+    client=tcpserver_fixindex(x, atom_getint(argv));
+    if(client<0) {
       return;
     }
-  else 
-    {
-      for(client=0; client<x->x_nconnections; client++)
-        tcpserver_info_client(x, client);
+    if(argc==1) {
+      tcpserver_info_client(x, client);
+    } else {
+      tcpserver_send_toclient(x, client, argc-1, argv+1);
     }
+    return;
+  } else {
+    unsigned int client;
+    for(client=0; client<x->x_nconnections; client++) {
+      tcpserver_info_client(x, client);
+    }
+  }
 }
 
 /* broadcasts a message to all connected clients */
-static void tcpserver_broadcast(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv)
+static void tcpserver_broadcast(t_tcpserver *x, t_symbol *s, int argc,
+                                t_atom *argv)
 {
-  int     client;
-  t_iemnet_chunk*chunk=iemnet__chunk_create_list(argc, argv);
+  unsigned int client=0;
+  t_iemnet_chunk*chunk=NULL;
+  t_tcpserver_socketreceiver**sr=NULL;
+  if(!x || !x->x_nconnections) {
+    return;
+  }
 
-  /* enumerate through the clients and send each the message */
-  for(client = 0; client < x->x_nconnections; client++)	/* check if connection exists */
-    {
-      /* socket exists for this client */
-      tcpserver_send_bytes(x, client, chunk);
-    }
+  chunk=iemnet__chunk_create_list(argc, argv);
+  sr=(t_tcpserver_socketreceiver**)calloc(x->x_nconnections,
+                                          sizeof(t_tcpserver_socketreceiver*));
+
+  for(client=0; client<x->x_nconnections; client++) {
+    sr[client]=x->x_sr[client];
+  }
+
+  tcpserver_send_bytes_clients(x, sr, x->x_nconnections, chunk);
+
+  free(sr);
   iemnet__chunk_destroy(chunk);
 }
 
 /* broadcasts a message to all connected clients */
-static void tcpserver_broadcastbut(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv)
+static void tcpserver_broadcastbut(t_tcpserver *x, t_symbol *s, int argc,
+                                   t_atom *argv)
 {
-  int client=0;
   int but=-1;
-
-  t_iemnet_chunk*chunk=NULL;
-
   if(argc<2) {
     return;
   }
-  if((but=tcpserver_fixindex(x, atom_getint(argv)))<0)return;
+  if((but=tcpserver_fixindex(x, atom_getint(argv)))<0) {
+    return;
+  }
   tcpserver_send_butclient(x, but, argc-1, argv+1);
 }
 
-static void tcpserver_defaultsend(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv)
+static void tcpserver_defaultsend(t_tcpserver *x, t_symbol *s, int argc,
+                                  t_atom *argv)
 {
   int client=-1;
   int sockfd=x->x_defaulttarget;
-  if(0==sockfd) 
-    tcpserver_broadcast(x, s, argc, argv);
-  else if(sockfd>0) {
+  if(sockfd>0) {
     client=tcpserver_socket2index(x, sockfd);
-    tcpserver_send_toclient(x, client, argc, argv);
+    if(client>=0) {
+      tcpserver_send_toclient(x, client, argc, argv);
+      return;
+    }
+    iemnet_log(x, IEMNET_ERROR, "illegal socket:%d, switching to broadcast mode", sockfd);
+    x->x_defaulttarget=0;
   } else if(sockfd<0) {
     client=tcpserver_socket2index(x, -sockfd);
-    tcpserver_send_butclient(x, client, argc, argv);     
+    if(client>=0) {
+      tcpserver_send_butclient(x, client, argc, argv);
+      return;
+    }
+    iemnet_log(x, IEMNET_ERROR, "illegal socket:%d excluded, switching to broadcast mode", sockfd);
+    x->x_defaulttarget=0;
   }
+
+  tcpserver_broadcast(x, s, argc, argv);
 }
 static void tcpserver_defaulttarget(t_tcpserver *x, t_floatarg f)
 {
   int sockfd=0;
   int rawclient=f;
-  int client=(rawclient<0)?(-rawclient):rawclient;
+  unsigned int client=(rawclient<0)?(-rawclient):rawclient;
 
   if(client > x->x_nconnections) {
-    error("[%s] target %d out of range [0..%d]", objName, client,  x->x_nconnections);
+    iemnet_log(x, IEMNET_ERROR,
+               "target %d out of range [0..%d]",
+               client, (int)(x->x_nconnections));
     return;
   }
 
@@ -363,7 +423,9 @@ static void tcpserver_defaulttarget(t_tcpserver *x, t_floatarg f)
     sockfd=x->x_sr[client-1]->sr_fd;
   }
 
-  if(rawclient<0)sockfd=-sockfd;  
+  if(rawclient<0) {
+    sockfd=-sockfd;
+  }
 
   x->x_defaulttarget=sockfd;
 }
@@ -373,46 +435,43 @@ static void tcpserver_targetsocket(t_tcpserver *x, t_floatarg f)
   x->x_defaulttarget=sockfd;
 }
 
-
-
 /* send message to client using socket number */
-static void tcpserver_send_socket(t_tcpserver *x, t_symbol *s, int argc, t_atom *argv)
+static void tcpserver_send_socket(t_tcpserver *x, t_symbol *s, int argc,
+                                  t_atom *argv)
 {
   int     client = -1;
   t_iemnet_chunk*chunk=NULL;
   if(argc) {
     client = tcpserver_socket2index(x, atom_getint(argv));
-    if(client<0)return;
+    if(client<0) {
+      return;
+    }
   } else {
-    pd_error(x, "%s_send: no socket specified", objName);
+    iemnet_log(x, IEMNET_ERROR, "no socket specified");
     return;
   }
 
   /* get socket number of connection (first element in list) */
-  if(argc && argv->a_type == A_FLOAT)
-    {
-      int sockfd=atom_getint(argv);
-      client = tcpserver_socket2index(x, sockfd);
-      if(client < 0)
-        {
-          post("%s_send: no connection on socket %d", objName, sockfd);
-          return;
-        }
-    }
-  else
-    {
-      post("%s_send: no socket specified", objName);
+  if(argc && argv->a_type == A_FLOAT) {
+    int sockfd=atom_getint(argv);
+    client = tcpserver_socket2index(x, sockfd);
+    if(client < 0) {
+      iemnet_log(x, IEMNET_ERROR, "no connection on socket %d", sockfd);
       return;
     }
-  
+  } else {
+    iemnet_log(x, IEMNET_ERROR, "only numeric sockets allowed");
+    return;
+  }
+
   chunk=iemnet__chunk_create_list(argc-1, argv+1);
   tcpserver_send_bytes(x, client, chunk);
   iemnet__chunk_destroy(chunk);
 }
 
-static void tcpserver_disconnect(t_tcpserver *x, int client)
+static void tcpserver_disconnect(t_tcpserver *x, unsigned int client)
 {
-  int k;
+  unsigned int k;
   DEBUG("disconnect %x %d", x, client);
   tcpserver_info_connection(x, x->x_sr[client]);
 
@@ -420,89 +479,98 @@ static void tcpserver_disconnect(t_tcpserver *x, int client)
   x->x_sr[client]=NULL;
 
   /* rearrange list now: move entries to close the gap */
-  for(k = client; k < x->x_nconnections; k++)
-    {
-      x->x_sr[k] = x->x_sr[k + 1];
-    }
+  for(k = client; k < x->x_nconnections; k++) {
+    x->x_sr[k] = x->x_sr[k + 1];
+  }
   x->x_sr[k + 1]=NULL;
   x->x_nconnections--;
 
-
   outlet_float(x->x_connectout, x->x_nconnections);
 }
 
-
 /* disconnect a client by number */
 static void tcpserver_disconnect_client(t_tcpserver *x, t_floatarg fclient)
 {
   int client = tcpserver_fixindex(x, fclient);
 
-  if(client<0)return;
+  if(client<0) {
+    return;
+  }
   tcpserver_disconnect(x, client);
 }
 
-
 /* disconnect a client by socket */
 static void tcpserver_disconnect_socket(t_tcpserver *x, t_floatarg fsocket)
 {
   int id=tcpserver_socket2index(x, (int)fsocket);
-  if(id>=0)
+  if(id>=0) {
     tcpserver_disconnect_client(x, id+1);
+  }
 }
 
-
-
 /* disconnect a client by socket */
 static void tcpserver_disconnect_all(t_tcpserver *x)
 {
-  int id=x->x_nconnections;
-  while(--id>=0) {
+  unsigned int id;
+  for(id=0; id<x->x_nconnections; id++) {
     tcpserver_disconnect(x, id);
   }
 }
 
 /* ---------------- main tcpserver (receive) stuff --------------------- */
-static void tcpserver_receive_callback(void *y0, 
-				       t_iemnet_chunk*c) {
+static void tcpserver_receive_callback(void *y0,
+                                       t_iemnet_chunk*c)
+{
   t_tcpserver_socketreceiver *y=(t_tcpserver_socketreceiver*)y0;
   t_tcpserver*x=NULL;
-  if(NULL==y || NULL==(x=y->sr_owner))return;
-  
+  if(NULL==y || NULL==(x=y->sr_owner)) {
+    return;
+  }
+
   if(c) {
     tcpserver_info_connection(x, y);
-	  x->x_floatlist=iemnet__chunk2list(c, x->x_floatlist); // get's destroyed in the dtor
-    iemnet__streamout(x->x_msgout, x->x_floatlist->argc, x->x_floatlist->argv, x->x_serialize);
+    x->x_floatlist=iemnet__chunk2list(c,
+                                      x->x_floatlist); // get's destroyed in the dtor
+    iemnet__streamout(x->x_msgout, x->x_floatlist->argc, x->x_floatlist->argv,
+                      x->x_serialize);
   } else {
     // disconnected
     int sockfd=y->sr_fd;
+    iemnet_log(x, IEMNET_VERBOSE, "got disconnection for socket:%d", sockfd);
     tcpserver_disconnect_socket(x, sockfd);
   }
-
-  //  post("tcpserver: %d bytes in %d packets", bytecount, packetcount);
 }
 
 static void tcpserver_connectpoll(t_tcpserver *x)
 {
   struct sockaddr_in  incomer_address;
-  unsigned int        sockaddrl = sizeof( struct sockaddr );
-  int                 fd = accept(x->x_connectsocket, (struct sockaddr*)&incomer_address, &sockaddrl);
+  socklen_t           sockaddrl = sizeof( struct sockaddr );
+  int                 fd = accept(x->x_connectsocket,
+                                  (struct sockaddr*)&incomer_address, &sockaddrl);
   int                 i;
 
-  if (fd < 0) post("%s: accept failed", objName);
-  else
-    {
-      t_tcpserver_socketreceiver *y = tcpserver_socketreceiver_new((void *)x, fd, &incomer_address);
-      if (!y)
-        {
-          sys_closesocket(fd);
-          return;
-        }
-      x->x_nconnections++;
-      i = x->x_nconnections - 1;
-      x->x_sr[i] = y;
-
-      tcpserver_info_connection(x, y);
+  if (fd < 0) {
+    post("%s: accept failed", objName);
+  } else {
+    t_tcpserver_socketreceiver *y = NULL;
+    if(x->x_nconnections>=MAX_CONNECT) {
+      iemnet_log(x, IEMNET_ERROR,
+                 "cannot handle more than %d connections, dropping!",
+                 x->x_nconnections);
+      iemnet__closesocket(fd, 1);
+    }
+
+    y = tcpserver_socketreceiver_new((void *)x, fd, &incomer_address);
+    if (!y) {
+      iemnet__closesocket(fd, 1);
+      return;
     }
+    x->x_nconnections++;
+    i = x->x_nconnections - 1;
+    x->x_sr[i] = y;
+
+    tcpserver_info_connection(x, y);
+  }
 
   outlet_float(x->x_connectout, x->x_nconnections);
 }
@@ -514,6 +582,8 @@ static void tcpserver_port(t_tcpserver*x, t_floatarg fportno)
   struct sockaddr_in  server;
   socklen_t           serversize=sizeof(server);
   int sockfd = x->x_connectsocket;
+  memset(&server, 0, sizeof(server));
+
   SETFLOAT(ap, -1);
   if(x->x_port == portno) {
     return;
@@ -522,14 +592,17 @@ static void tcpserver_port(t_tcpserver*x, t_floatarg fportno)
   /* cleanup any open ports */
   if(sockfd>=0) {
     sys_rmpollfn(sockfd);
-    sys_closesocket(sockfd);
+    iemnet__closesocket(sockfd, 1);
     x->x_connectsocket=-1;
     x->x_port=-1;
   }
 
-
   sockfd = socket(AF_INET, SOCK_STREAM, 0);
-
+  if(sockfd<0) {
+    iemnet_log(x, IEMNET_ERROR, "unable to create TCP/IP socket");
+    sys_sockerror("socket");
+    return;
+  }
 
   server.sin_family = AF_INET;
 
@@ -539,43 +612,41 @@ static void tcpserver_port(t_tcpserver*x, t_floatarg fportno)
   /* assign server port number */
   server.sin_port = htons((u_short)portno);
   /* name the socket */
-  if (bind(sockfd, (struct sockaddr *)&server, serversize) < 0)
-    {
-      sys_sockerror("tcpserver: bind");
-      sys_closesocket(sockfd);
-      outlet_anything(x->x_statout, gensym("port"), 1, ap);
-      return;
-    }
+  if (bind(sockfd, (struct sockaddr *)&server, serversize) < 0) {
+    iemnet_log(x, IEMNET_ERROR, "unable to bind to TCP/IP socket");
+    sys_sockerror("bind");
+    iemnet__closesocket(sockfd, 1);
+    outlet_anything(x->x_statout, gensym("port"), 1, ap);
+    return;
+  }
 
   /* streaming protocol */
-  if (listen(sockfd, 5) < 0)
-    {
-      sys_sockerror("tcpserver: listen");
-      sys_closesocket(sockfd);
-      sockfd = -1;
-      outlet_anything(x->x_statout, gensym("port"), 1, ap);
-      return;
-    }
-  else
-    {
-      sys_addpollfn(sockfd, (t_fdpollfn)tcpserver_connectpoll, x); // wait for new connections 
-    }
+  if (listen(sockfd, 5) < 0) {
+    iemnet_log(x, IEMNET_ERROR, "unable to listen on TCP/IP socket");
+    sys_sockerror("listen");
+    iemnet__closesocket(sockfd, 1);
+    sockfd = -1;
+    outlet_anything(x->x_statout, gensym("port"), 1, ap);
+    return;
+  } else {
+      /* wait for new connections */
+      sys_addpollfn(sockfd, (t_fdpollfn)tcpserver_connectpoll, x);
+  }
 
   x->x_connectsocket = sockfd;
   x->x_port = portno;
 
-
   // find out which port is actually used (useful when assigning "0")
   if(!getsockname(sockfd, (struct sockaddr *)&server, &serversize)) {
     x->x_port=ntohs(server.sin_port);
   }
 
-
   SETFLOAT(ap, x->x_port);
   outlet_anything(x->x_statout, gensym("port"), 1, ap);
 }
 
-static void tcpserver_serialize(t_tcpserver *x, t_floatarg doit) {
+static void tcpserver_serialize(t_tcpserver *x, t_floatarg doit)
+{
   x->x_serialize=doit;
 }
 
@@ -588,10 +659,12 @@ static void *tcpserver_new(t_floatarg fportno)
   x = (t_tcpserver *)pd_new(tcpserver_class);
 
   x->x_msgout = outlet_new(&x->x_obj, 0); /* 1st outlet for received data */
-  x->x_connectout = outlet_new(&x->x_obj, gensym("float")); /* 2nd outlet for number of connected clients */
+  x->x_connectout = outlet_new(&x->x_obj,
+                               gensym("float")); /* 2nd outlet for number of connected clients */
   x->x_sockout = outlet_new(&x->x_obj, gensym("float"));
   x->x_addrout = outlet_new(&x->x_obj, gensym("list" ));
-  x->x_statout = outlet_new(&x->x_obj, 0);/* 5th outlet for everything else */
+  x->x_statout = outlet_new(&x->x_obj,
+                            0);/* 5th outlet for everything else */
 
   x->x_serialize=1;
 
@@ -599,14 +672,11 @@ static void *tcpserver_new(t_floatarg fportno)
   x->x_port = -1;
   x->x_nconnections = 0;
 
-  for(i = 0; i < MAX_CONNECT; i++)
-    {
-      x->x_sr[i] = NULL;
-    }
+  for(i = 0; i < MAX_CONNECT; i++) {
+    x->x_sr[i] = NULL;
+  }
 
   x->x_defaulttarget=0;
-	
-	
   x->x_floatlist=iemnet__floatlist_create(1024);
 
   tcpserver_port(x, fportno);
@@ -618,46 +688,59 @@ static void tcpserver_free(t_tcpserver *x)
 {
   int     i;
 
-  for(i = 0; i < MAX_CONNECT; i++)
-    {
-      if (NULL!=x->x_sr[i]) {
-        DEBUG("[%s] free %x", objName, x);
-        tcpserver_socketreceiver_free(x->x_sr[i]);
-        x->x_sr[i]=NULL;
-      }
-    }
-  if (x->x_connectsocket >= 0)
-    {
-      sys_rmpollfn(x->x_connectsocket);
-      sys_closesocket(x->x_connectsocket);
+  for(i = 0; i < MAX_CONNECT; i++) {
+    if (NULL!=x->x_sr[i]) {
+      DEBUG("[%s] free %x", objName, x);
+      tcpserver_socketreceiver_free(x->x_sr[i]);
+      x->x_sr[i]=NULL;
     }
-	if(x->x_floatlist)iemnet__floatlist_destroy(x->x_floatlist);x->x_floatlist=NULL;
+  }
+  if (x->x_connectsocket >= 0) {
+    sys_rmpollfn(x->x_connectsocket);
+    iemnet__closesocket(x->x_connectsocket, 1);
+  }
+  if(x->x_floatlist) {
+    iemnet__floatlist_destroy(x->x_floatlist);
+  }
+  x->x_floatlist=NULL;
 }
 
 IEMNET_EXTERN void tcpserver_setup(void)
 {
-  if(!iemnet__register(objName))return;
+  if(!iemnet__register(objName)) {
+    return;
+  }
 
-  tcpserver_class = class_new(gensym(objName),(t_newmethod)tcpserver_new, (t_method)tcpserver_free,
+  tcpserver_class = class_new(gensym(objName),(t_newmethod)tcpserver_new,
+                              (t_method)tcpserver_free,
                               sizeof(t_tcpserver), 0, A_DEFFLOAT, 0);
-  class_addmethod(tcpserver_class, (t_method)tcpserver_disconnect_client, gensym("disconnectclient"), A_DEFFLOAT, 0);
-  class_addmethod(tcpserver_class, (t_method)tcpserver_disconnect_socket, gensym("disconnectsocket"), A_DEFFLOAT, 0);
-  class_addmethod(tcpserver_class, (t_method)tcpserver_disconnect_all, gensym("disconnect"), 0);
-
-  class_addmethod(tcpserver_class, (t_method)tcpserver_send_socket, gensym("send"), A_GIMME, 0);
-  class_addmethod(tcpserver_class, (t_method)tcpserver_send_client, gensym("client"), A_GIMME, 0);
-
-  class_addmethod(tcpserver_class, (t_method)tcpserver_broadcast, gensym("broadcast"), A_GIMME, 0);
-
-  class_addmethod(tcpserver_class, (t_method)tcpserver_defaulttarget, gensym("target"), A_DEFFLOAT, 0);
-  class_addmethod(tcpserver_class, (t_method)tcpserver_targetsocket, gensym("targetsocket"), A_DEFFLOAT, 0);
+  class_addmethod(tcpserver_class, (t_method)tcpserver_disconnect_client,
+                  gensym("disconnectclient"), A_DEFFLOAT, 0);
+  class_addmethod(tcpserver_class, (t_method)tcpserver_disconnect_socket,
+                  gensym("disconnectsocket"), A_DEFFLOAT, 0);
+  class_addmethod(tcpserver_class, (t_method)tcpserver_disconnect_all,
+                  gensym("disconnect"), 0);
+
+  class_addmethod(tcpserver_class, (t_method)tcpserver_send_socket,
+                  gensym("send"), A_GIMME, 0);
+  class_addmethod(tcpserver_class, (t_method)tcpserver_send_client,
+                  gensym("client"), A_GIMME, 0);
+
+  class_addmethod(tcpserver_class, (t_method)tcpserver_broadcast,
+                  gensym("broadcast"), A_GIMME, 0);
+
+  class_addmethod(tcpserver_class, (t_method)tcpserver_defaulttarget,
+                  gensym("target"), A_DEFFLOAT, 0);
+  class_addmethod(tcpserver_class, (t_method)tcpserver_targetsocket,
+                  gensym("targetsocket"), A_DEFFLOAT, 0);
   class_addlist  (tcpserver_class, (t_method)tcpserver_defaultsend);
 
+  class_addmethod(tcpserver_class, (t_method)tcpserver_serialize,
+                  gensym("serialize"), A_FLOAT, 0);
 
-  class_addmethod(tcpserver_class, (t_method)tcpserver_serialize, gensym("serialize"), A_FLOAT, 0);
 
-
-  class_addmethod(tcpserver_class, (t_method)tcpserver_port, gensym("port"), A_DEFFLOAT, 0);
+  class_addmethod(tcpserver_class, (t_method)tcpserver_port, gensym("port"),
+                  A_DEFFLOAT, 0);
   class_addbang  (tcpserver_class, (t_method)tcpserver_info);
 
   DEBUGMETHOD(tcpserver_class);
@@ -665,5 +748,4 @@ IEMNET_EXTERN void tcpserver_setup(void)
 
 IEMNET_INITIALIZER(tcpserver_setup);
 
-
 /* end of tcpserver.c */
diff --git a/test.txt b/test.txt
deleted file mode 100644
index e36d4ff..0000000
--- a/test.txt
+++ /dev/null
@@ -1 +0,0 @@
-testing one two three
diff --git a/tests/sequence/01_client.pd b/tests/sequence/01_client.pd
deleted file mode 100644
index c9ffd18..0000000
--- a/tests/sequence/01_client.pd
+++ /dev/null
@@ -1,119 +0,0 @@
-#N canvas 501 150 636 624 10;
-#X obj 139 179 tcpclient;
-#X msg 308 152 connect \$1 9999;
-#X msg 308 108 bang;
-#X obj 308 130 symbol localhost;
-#X symbolatom 351 112 10 0 0 0 - - -;
-#X obj 159 201 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 127
-127;
-#X obj 139 284 list split 1;
-#X obj 139 242 until;
-#X obj 139 263 list append;
-#X obj 139 219 t b l;
-#X obj 183 243 bang;
-#X obj 139 306 select 255;
-#X obj 139 328 i;
-#X obj 139 350 + 1;
-#X obj 139 372 t f f;
-#X obj 121 398 f;
-#X obj 114 108 metro 100;
-#X obj 114 85 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
-1;
-#X msg 114 130 1;
-#X obj 79 323 t b b;
-#X msg 108 345 0;
-#X floatatom 121 555 5 0 0 3 dummyload - -;
-#X obj 253 378 -;
-#X obj 252 354 t f f;
-#X obj 253 400 select 1;
-#X obj 306 489 print error;
-#X obj 306 443 pack 0 0 0;
-#X obj 185 426 t f f;
-#X obj 373 416 + 1;
-#X obj 185 448 select 254;
-#X msg 185 470 -1;
-#X obj 206 328 t b f f f;
-#X msg 306 465 \$2 should be \$3;
-#X obj 306 421 t b b;
-#X obj 459 485 i;
-#X obj 459 507 + 1;
-#X obj 459 529 t f f;
-#X floatatom 459 551 5 0 0 3 errors - -;
-#X text 49 27 testing the server;
-#X floatatom 188 78 5 0 0 0 - - -;
-#X obj 55 394 i;
-#X obj 55 416 + 1;
-#X obj 55 438 t f f;
-#X floatatom 22 481 5 0 0 3 iterations - -;
-#X msg 56 372 0;
-#X obj 52 125 t b b;
-#X obj 52 147 timer;
-#X floatatom 52 169 5 0 0 0 - - -;
-#X obj 22 458 i;
-#X obj 14 344 metro 100;
-#X msg 14 366 bang;
-#X obj 16 325 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
-1;
-#X connect 0 0 9 0;
-#X connect 0 1 5 0;
-#X connect 1 0 0 0;
-#X connect 2 0 3 0;
-#X connect 3 0 1 0;
-#X connect 4 0 3 0;
-#X connect 6 0 11 0;
-#X connect 6 1 8 1;
-#X connect 6 2 10 0;
-#X connect 7 0 8 0;
-#X connect 8 0 6 0;
-#X connect 9 0 7 0;
-#X connect 9 1 8 1;
-#X connect 10 0 7 1;
-#X connect 11 0 12 0;
-#X connect 11 1 31 0;
-#X connect 12 0 13 0;
-#X connect 13 0 14 0;
-#X connect 14 0 15 1;
-#X connect 14 1 12 1;
-#X connect 15 0 21 0;
-#X connect 16 0 18 0;
-#X connect 16 0 45 0;
-#X connect 17 0 16 0;
-#X connect 18 0 0 0;
-#X connect 19 0 15 0;
-#X connect 19 1 20 0;
-#X connect 19 1 40 0;
-#X connect 20 0 12 1;
-#X connect 22 0 24 0;
-#X connect 23 0 22 1;
-#X connect 23 1 22 0;
-#X connect 24 1 33 0;
-#X connect 26 0 32 0;
-#X connect 27 0 29 0;
-#X connect 27 1 28 0;
-#X connect 28 0 26 2;
-#X connect 29 0 30 0;
-#X connect 30 0 22 1;
-#X connect 31 0 19 0;
-#X connect 31 1 27 0;
-#X connect 31 2 23 0;
-#X connect 31 3 26 1;
-#X connect 32 0 25 0;
-#X connect 33 0 26 0;
-#X connect 33 1 34 0;
-#X connect 34 0 35 0;
-#X connect 35 0 36 0;
-#X connect 36 0 37 0;
-#X connect 36 1 34 1;
-#X connect 39 0 16 1;
-#X connect 40 0 41 0;
-#X connect 41 0 42 0;
-#X connect 42 0 48 1;
-#X connect 42 1 40 1;
-#X connect 44 0 40 0;
-#X connect 45 0 46 0;
-#X connect 45 1 46 1;
-#X connect 46 0 47 0;
-#X connect 48 0 43 0;
-#X connect 49 0 50 0;
-#X connect 50 0 48 0;
-#X connect 51 0 49 0;
diff --git a/tests/sequence/01_server.pd b/tests/sequence/01_server.pd
deleted file mode 100644
index 8e84863..0000000
--- a/tests/sequence/01_server.pd
+++ /dev/null
@@ -1,59 +0,0 @@
-#N canvas 219 165 438 532 10;
-#X obj 71 256 tcpserver 9999;
-#X obj 71 278 t b;
-#X obj 71 300 i;
-#X obj 115 326 + 1;
-#X obj 115 348 % 255;
-#X obj 250 252 loadbang;
-#X msg 71 388 broadcast \$1;
-#X obj 71 429 list append;
-#X obj 250 274 f 1024;
-#X obj 250 296 t b f b;
-#X obj 250 438 list prepend;
-#X obj 273 319 until;
-#X obj 273 341 f 255;
-#X obj 273 363 list prepend;
-#X obj 273 385 t l l;
-#X msg 106 276 bang;
-#X msg 321 250 bang;
-#X obj 71 451 list trim;
-#X obj 23 229 t a;
-#X text 27 43 responds to any data from the client by sending pack
-a stream consisting of a header and a dummy payload.;
-#X text 31 84 the dummy payload is a number of 0xFF bytes;
-#X obj 71 322 t f f;
-#X text 32 99 the header is a single byte counting up from 0..254 (and
-wrapping around);
-#X floatatom 166 305 5 0 0 0 - - -;
-#X obj 152 169 route sent;
-#X obj 152 191 unpack 0 0 0;
-#X floatatom 186 225 0 0 0 0 - - -;
-#X floatatom 221 211 5 0 0 0 - - -;
-#X connect 0 0 1 0;
-#X connect 0 4 24 0;
-#X connect 1 0 2 0;
-#X connect 2 0 21 0;
-#X connect 3 0 4 0;
-#X connect 4 0 2 1;
-#X connect 5 0 8 0;
-#X connect 6 0 7 0;
-#X connect 7 0 17 0;
-#X connect 8 0 9 0;
-#X connect 9 0 10 0;
-#X connect 9 1 11 0;
-#X connect 10 0 7 1;
-#X connect 11 0 12 0;
-#X connect 12 0 13 0;
-#X connect 13 0 14 0;
-#X connect 14 0 10 1;
-#X connect 14 1 13 1;
-#X connect 15 0 1 0;
-#X connect 16 0 8 0;
-#X connect 17 0 18 0;
-#X connect 18 0 0 0;
-#X connect 21 0 6 0;
-#X connect 21 1 3 0;
-#X connect 23 0 3 1;
-#X connect 24 0 25 0;
-#X connect 25 1 26 0;
-#X connect 25 2 27 0;
diff --git a/udpclient-help.pd b/udpclient-help.pd
index 18e6d3c..6cf60a6 100644
--- a/udpclient-help.pd
+++ b/udpclient-help.pd
@@ -1,35 +1,35 @@
-#N canvas 0 34 988 533 12;
-#X msg 96 97 disconnect;
-#X floatatom 255 351 3 0 0 0 - - -;
-#X floatatom 284 351 3 0 0 0 - - -;
-#X floatatom 311 351 3 0 0 0 - - -;
-#X floatatom 336 351 3 0 0 0 - - -;
+#N canvas 4 49 1100 592 12;
+#X msg 116 117 disconnect;
+#X floatatom 255 351 3 0 0 0 - - -, f 3;
+#X floatatom 284 351 3 0 0 0 - - -, f 3;
+#X floatatom 311 351 3 0 0 0 - - -, f 3;
+#X floatatom 336 351 3 0 0 0 - - -, f 3;
 #X text 219 351 from;
 #X obj 275 307 tgl 15 0 empty empty connected 18 7 0 8 -24198 -241291
--1 1 1;
-#X text 187 21 connect with an IP address and port number;
+-1 0 1;
+#X text 197 21 connect with an IP address and port number;
 #X text 44 257 See also:;
 #X msg 21 22 connect 127.0.0.1 9997;
-#X text 364 156 semicolon-terminated string for netserver or netreceive
+#X text 414 176 semicolon-terminated string for netserver or netreceive
 ;
-#X text 302 182 'send' prefix is optional;
+#X text 322 202 'send' prefix is optional;
 #X obj 235 412 spigot;
 #X obj 274 389 tgl 15 0 empty empty enable_print 18 7 0 8 -24198 -241291
--1 1 1;
-#X floatatom 772 190 9 0 0 0 - - -;
+-1 0 1;
+#X floatatom 872 280 9 0 0 0 - - -, f 9;
 #X text 40 399 2010/03/01 Martin Peach;
-#X text 418 440 Attempting to print long messages can hang Pd!;
-#X obj 772 166 route sent;
-#X text 844 190 sent bytes;
-#X floatatom 772 347 3 0 0 0 - - -;
-#X floatatom 826 347 3 0 0 0 - - -;
-#X floatatom 799 347 3 0 0 0 - - -;
-#X obj 772 268 route address;
-#X obj 772 296 unpack f f f f f;
-#X floatatom 853 347 3 0 0 0 - - -;
-#X floatatom 881 321 6 0 0 0 - - -;
-#X text 879 347 ip;
-#X text 927 320 port;
+#X text 438 440 Attempting to print long messages can hang Pd!;
+#X obj 872 256 route sent;
+#X text 944 280 sent bytes;
+#X floatatom 872 437 3 0 0 0 - - -, f 3;
+#X floatatom 926 437 3 0 0 0 - - -, f 3;
+#X floatatom 899 437 3 0 0 0 - - -, f 3;
+#X obj 872 358 route address;
+#X obj 872 386 unpack f f f f f;
+#X floatatom 953 437 3 0 0 0 - - -, f 3;
+#X floatatom 981 411 6 0 0 0 - - -, f 6;
+#X text 979 437 ip;
+#X text 1027 430 port;
 #X obj 520 344 spigot;
 #X obj 559 321 tgl 15 0 empty empty enable_print 18 7 0 8 -24198 -241291
 -1 0 1;
@@ -43,21 +43,25 @@ net objects. all information is available via outlet#4 as well!;
 #X obj 235 441 print udpclient:received;
 #X obj 520 373 print udpclient:status;
 #X obj 255 328 unpack f f f f f;
-#X floatatom 364 351 6 0 0 0 - - -;
-#X msg 128 129 send 47 116 101 115 116 32 104 101 108 108 111 10;
-#X msg 156 157 send 51 49 32 97 98 99 59 10;
-#X text 482 128 /test hello (OSC message);
-#X text 308 255 udpclient can be used for a bi-directional connection
+#X floatatom 364 351 6 0 0 0 - - -, f 6;
+#X msg 148 149 send 47 116 101 115 116 32 104 101 108 108 111 10;
+#X msg 176 177 send 51 49 32 97 98 99 59 10;
+#X text 552 148 /test hello (OSC message);
+#X text 312 255 udpclient can be used for a bi-directional connection
 ;
-#X msg 183 184 97 98 99 100 10;
+#X msg 203 204 97 98 99 100 10;
 #X msg 47 48 connect swisstime.ethz.ch 13;
-#X text 527 14 udpclient can connect to a server and send and receive
+#X text 547 14 udpclient can connect to a server and send and receive
 messages as lists of bytes. Any integer value between 0 and 255 can
 be transmitted or received.;
 #X obj 295 281 s \$0.udpclient.o4;
 #X obj 520 298 r \$0.udpclient.o4;
-#X obj 772 142 r \$0.udpclient.o4;
-#X obj 772 242 r \$0.udpclient.o4;
+#X obj 872 232 r \$0.udpclient.o4;
+#X obj 872 332 r \$0.udpclient.o4;
+#X msg 74 75 connect 127.0.0.1 7999 7999;
+#X text 303 67 optional second argument to set the local port (where
+we receive the returning messages) \; default is to choose any available
+port.;
 #X connect 0 0 35 0;
 #X connect 9 0 35 0;
 #X connect 12 0 36 0;
@@ -87,3 +91,4 @@ be transmitted or received.;
 #X connect 48 0 28 0;
 #X connect 49 0 17 0;
 #X connect 50 0 22 0;
+#X connect 51 0 35 0;
diff --git a/udpclient.c b/udpclient.c
index 153fbe0..ca6d0c5 100644
--- a/udpclient.c
+++ b/udpclient.c
@@ -1,5 +1,5 @@
 /* udpclient.c
- * copyright (c) 2010 IOhannes m zmölnig, IEM
+ * copyright © 2010-2015 IOhannes m zmölnig, IEM
  */
 
 /*                                                                              */
@@ -16,8 +16,8 @@
 /* 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, write to the Free Software                  */
-/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.  */
+/* along with this program; if not, see                                         */
+/*     http://www.gnu.org/licenses/                                             */
 /*                                                                              */
 
 /* ---------------------------------------------------------------------------- */
@@ -32,11 +32,8 @@
 static t_class *udpclient_class;
 static const char objName[] = "udpclient";
 
-
-typedef struct _udpclient
-{
+typedef struct _udpclient {
   t_object        x_obj;
-  t_clock         *x_clock;
   t_outlet        *x_msgout;
   t_outlet        *x_addrout;
   t_outlet        *x_connectout;
@@ -45,133 +42,143 @@ typedef struct _udpclient
   t_iemnet_sender*x_sender;
   t_iemnet_receiver*x_receiver;
 
-
   int             x_fd; // the socket
   char           *x_hostname; // address we want to connect to as text
   int             x_connectstate; // 0 = not connected, 1 = connected
-  int             x_port; // port we're connected to
-  long            x_addr; // address we're connected to as 32bit int
+  u_short         x_port; // port we're sending to
+  u_short         x_sendport; // port we're sending from
 
+  long            x_addr; // address we're connected to as 32bit int
 
-  /* multithread stuff */
-  pthread_t       x_threadid; /* id of child thread */
-  pthread_attr_t  x_threadattr; /* attributes of child thread */
-
-	t_iemnet_floatlist         *x_floatlist;
+  t_iemnet_floatlist         *x_floatlist;
 } t_udpclient;
 
 
+/* forward declarations */
 static void udpclient_receive_callback(void *x, t_iemnet_chunk*);
 
-
-
 /* connection handling */
 
-static void *udpclient_child_connect(void *w)
+static void *udpclient_doconnect(t_udpclient*x, int subthread)
 {
-  t_udpclient         *x = (t_udpclient*) w;
-
   struct sockaddr_in  server;
   struct hostent      *hp;
   int                 sockfd;
   int                 broadcast = 1;/* nonzero is true */
+  memset(&server, 0, sizeof(server));
 
-  if (x->x_sender)
-    {
-      error("[%s] already connected", objName);
-      return (x);
-    }
+  if (x->x_sender) {
+    iemnet_log(x, IEMNET_ERROR, "already connected");
+    return (x);
+  }
+
+  /* connect socket using hostname provided in command line */
+  hp = gethostbyname(x->x_hostname);
+  if (hp == 0) {
+    iemnet_log(x, IEMNET_ERROR, "bad host '%s'?", x->x_hostname);
+    return (x);
+  }
+  server.sin_family = AF_INET;
 
   /* create a socket */
   sockfd = socket(AF_INET, SOCK_DGRAM, 0);
   DEBUG("send socket %d\n", sockfd);
-  if (sockfd < 0)
-    {
-      sys_sockerror("udpclient: socket");
-      return (x);
-    }
+  if (sockfd < 0) {
+    iemnet_log(x, IEMNET_ERROR, "unable to create socket");
+    sys_sockerror("socket");
+    return (x);
+  }
 
-  /* Based on zmoelnig's patch 2221504:
-     Enable sending of broadcast messages (if hostname is a broadcast address)*/
+  /* Enable sending of broadcast messages (if hostname is a broadcast address) */
 #ifdef SO_BROADCAST
-  if( 0 != setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (const void *)&broadcast, sizeof(broadcast)))
-    {
-      error("[%s] couldn't switch to broadcast mode", objName);
-    }
+  if( 0 != setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST,
+                      (const void *)&broadcast, sizeof(broadcast))) {
+    iemnet_log(x, IEMNET_ERROR, "unable to switch to broadcast mode");
+    sys_sockerror("setsockopt");
+  }
 #endif /* SO_BROADCAST */
-    
-  /* connect socket using hostname provided in command line */
-  server.sin_family = AF_INET;
-  hp = gethostbyname(x->x_hostname);
-  if (hp == 0)
-    {
-      error("[%s] bad host '%s'?", objName, x->x_hostname);
-      return (x);
-    }
-  memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
 
-  /* assign client port number */
-  server.sin_port = htons((u_short)x->x_port);
+  if(x->x_sendport>0) {
+    server.sin_family = AF_INET;
+    server.sin_port = htons(x->x_sendport);
+    server.sin_addr.s_addr = INADDR_ANY;
+    if (bind(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) {
+      iemnet_log(x, IEMNET_ERROR, "unable to bind with sending port %d (continuing with random port)", x->x_sendport);
+      sys_sockerror("bind");
+    }
+  }
 
-  DEBUG("connecting to port %d", x->x_port);
   /* try to connect. */
-  if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0)
-    {
-      sys_sockerror("udpclient: connecting stream socket");
-      sys_closesocket(sockfd);
-      return (x);
-    }
+  /* assign client port number */
+  memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
+  server.sin_port = htons(x->x_port);
+  DEBUG("connecting to %s:%d", x->x_hostname, x->x_port);
+
+  if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) {
+    iemnet_log(x, IEMNET_ERROR, "unable to connect to stream socket");
+    sys_sockerror("connect");
+    iemnet__closesocket(sockfd, 1);
+    return (x);
+  }
   x->x_fd = sockfd;
   x->x_addr = ntohl(*(long *)hp->h_addr);
 
-  x->x_sender=iemnet__sender_create(sockfd);
-  x->x_receiver=iemnet__receiver_create(sockfd, x,  udpclient_receive_callback);
+  x->x_sender=iemnet__sender_create(sockfd, NULL, NULL, subthread);
+  x->x_receiver=iemnet__receiver_create(sockfd, x,
+                                        udpclient_receive_callback, subthread);
 
   x->x_connectstate = 1;
-
-  clock_delay(x->x_clock, 0);
-  return (x);
-}
-static void udpclient_tick(t_udpclient *x)
-{
   outlet_float(x->x_connectout, 1);
+  return (x);
 }
 
-
-static void udpclient_disconnect(t_udpclient *x)
+static int udpclient_do_disconnect(t_udpclient *x)
 {
-  if (x->x_fd >= 0)
-    {
-
-      DEBUG("disconnect %x %x", x->x_sender, x->x_receiver);
-      if(x->x_receiver)iemnet__receiver_destroy(x->x_receiver); x->x_receiver=NULL;
-      if(x->x_sender)iemnet__sender_destroy(x->x_sender); x->x_sender=NULL;
+  DEBUG("disconnect %x %x", x->x_sender, x->x_receiver);
+  if(x->x_receiver) {
+    iemnet__receiver_destroy(x->x_receiver, 0);
+  }
+  x->x_receiver=NULL;
+  if(x->x_sender) {
+    iemnet__sender_destroy(x->x_sender, 0);
+  }
+  x->x_sender=NULL;
 
-      sys_closesocket(x->x_fd);
-      x->x_fd = -1;
-      x->x_connectstate = 0;
-      outlet_float(x->x_connectout, 0);
-    }
-  else pd_error(x, "[%s] not connected", objName);
+  x->x_connectstate = 0;
+  if (x->x_fd < 0) {
+    return 0;
+  }
+  iemnet__closesocket(x->x_fd, 1);
+  x->x_fd = -1;
+  return 1;
+}
+static void udpclient_disconnect(t_udpclient *x) {
+  if(!udpclient_do_disconnect(x)) {
+    iemnet_log(x, IEMNET_ERROR, "not connected");
+  } else {
+    outlet_float(x->x_connectout, 0);
+  }
 }
 
-
-static void udpclient_connect(t_udpclient *x, t_symbol *hostname, t_floatarg fportno)
+static void udpclient_connect(t_udpclient *x, t_symbol *hostname,
+                              t_floatarg fportno,
+			      t_floatarg fsndportno)
 {
-  if(x->x_fd>=0)udpclient_disconnect(x);
+  if(x->x_fd>=0) {
+    udpclient_disconnect(x);
+  }
   /* we get hostname and port and pass them on
      to the child thread that establishes the connection */
   x->x_hostname = hostname->s_name;
   x->x_port = fportno;
+  x->x_sendport = (fsndportno>0)?fsndportno:0;
   x->x_connectstate = 0;
-  /* start child thread */
-  if(pthread_create(&x->x_threadid, &x->x_threadattr, udpclient_child_connect, x) < 0)
-    error("%s: could not create new thread", objName);
+  udpclient_doconnect(x, 0);
 }
 
 /* sending/receiving */
-
-static void udpclient_send(t_udpclient *x, t_symbol *s, int argc, t_atom *argv)
+static void udpclient_send(t_udpclient *x, t_symbol *s, int argc,
+                           t_atom *argv)
 {
   int size=0;
   t_atom output_atom;
@@ -184,16 +191,20 @@ static void udpclient_send(t_udpclient *x, t_symbol *s, int argc, t_atom *argv)
   iemnet__chunk_destroy(chunk);
 
   SETFLOAT(&output_atom, size);
-  outlet_anything( x->x_statusout, gensym("sent"), 1, &output_atom);
+  outlet_anything( x->x_statusout, gensym("sendbuffersize"), 1,
+                   &output_atom);
 }
 
-static void udpclient_receive_callback(void*y, t_iemnet_chunk*c) {
+static void udpclient_receive_callback(void*y, t_iemnet_chunk*c)
+{
   t_udpclient *x=(t_udpclient*)y;
 
   if(c) {
     iemnet__addrout(x->x_statusout, x->x_addrout, x->x_addr, x->x_port);
-    x->x_floatlist=iemnet__chunk2list(c, x->x_floatlist); // gets destroyed in the dtor
-    outlet_list(x->x_msgout, gensym("list"),x->x_floatlist->argc, x->x_floatlist->argv);
+    x->x_floatlist=iemnet__chunk2list(c,
+                                      x->x_floatlist); /* gets destroyed in the dtor */
+    outlet_list(x->x_msgout, gensym("list"),x->x_floatlist->argc,
+                x->x_floatlist->argv);
   } else {
     // disconnected
     DEBUG("disconnected");
@@ -207,13 +218,13 @@ static void udpclient_receive_callback(void*y, t_iemnet_chunk*c) {
 
 static void *udpclient_new(void)
 {
-  int i;
-
   t_udpclient *x = (t_udpclient *)pd_new(udpclient_class);
-  x->x_msgout = outlet_new(&x->x_obj, 0);	/* received data */
+  x->x_msgout = outlet_new(&x->x_obj, 0); /* received data */
   x->x_addrout = outlet_new(&x->x_obj, gensym("list"));
-  x->x_connectout = outlet_new(&x->x_obj, gensym("float"));	/* connection state */
-  x->x_statusout = outlet_new(&x->x_obj, 0);/* last outlet for everything else */
+  x->x_connectout = outlet_new(&x->x_obj,
+                               gensym("float")); /* connection state */
+  x->x_statusout = outlet_new(&x->x_obj,
+                              0); /* last outlet for everything else */
 
   x->x_fd = -1;
   x->x_addr = 0L;
@@ -222,37 +233,35 @@ static void *udpclient_new(void)
   x->x_sender=NULL;
   x->x_receiver=NULL;
 
-  x->x_clock = clock_new(x, (t_method)udpclient_tick);
-
   x->x_floatlist=iemnet__floatlist_create(1024);
 
-  /* prepare child thread */
-  if(pthread_attr_init(&x->x_threadattr) < 0)
-    verbose(1, "[%s] warning: could not prepare child thread", objName);
-  if(pthread_attr_setdetachstate(&x->x_threadattr, PTHREAD_CREATE_DETACHED) < 0)
-    verbose(1, "[%s] warning: could not prepare child thread", objName);
-    
-
   return (x);
 }
 
 static void udpclient_free(t_udpclient *x)
 {
-  udpclient_disconnect(x);
-  if(x->x_clock)clock_free(x->x_clock);x->x_clock=NULL;
-	if(x->x_floatlist)iemnet__floatlist_destroy(x->x_floatlist);x->x_floatlist=NULL;
+  udpclient_do_disconnect(x);
+  if(x->x_floatlist) {
+    iemnet__floatlist_destroy(x->x_floatlist);
+  }
+  x->x_floatlist=NULL;
 }
 
 IEMNET_EXTERN void udpclient_setup(void)
 {
-  if(!iemnet__register(objName))return;
+  if(!iemnet__register(objName)) {
+    return;
+  }
   udpclient_class = class_new(gensym(objName), (t_newmethod)udpclient_new,
                               (t_method)udpclient_free,
                               sizeof(t_udpclient), 0, A_DEFFLOAT, 0);
-  class_addmethod(udpclient_class, (t_method)udpclient_connect, gensym("connect")
-                  , A_SYMBOL, A_FLOAT, 0);
-  class_addmethod(udpclient_class, (t_method)udpclient_disconnect, gensym("disconnect"), 0);
-  class_addmethod(udpclient_class, (t_method)udpclient_send, gensym("send"), A_GIMME, 0);
+  class_addmethod(udpclient_class, (t_method)udpclient_connect,
+                  gensym("connect")
+                  , A_SYMBOL, A_FLOAT, A_DEFFLOAT, 0);
+  class_addmethod(udpclient_class, (t_method)udpclient_disconnect,
+                  gensym("disconnect"), 0);
+  class_addmethod(udpclient_class, (t_method)udpclient_send, gensym("send"),
+                  A_GIMME, 0);
   class_addlist(udpclient_class, (t_method)udpclient_send);
 
   DEBUGMETHOD(udpclient_class);
diff --git a/udpreceive.c b/udpreceive.c
index 768d42e..7956860 100644
--- a/udpreceive.c
+++ b/udpreceive.c
@@ -1,5 +1,5 @@
 /* udpreceive.c
- * copyright (c) 2010 IOhannes m zmölnig, IEM
+ * copyright © 2010-2015 IOhannes m zmölnig, IEM
  * copyright (c) 2006-2010 Martin Peach
  * copyright (c) Miller Puckette
  */
@@ -18,105 +18,118 @@
 /* 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, write to the Free Software                  */
-/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.  */
+/* along with this program; if not, see                                         */
+/*     http://www.gnu.org/licenses/                                             */
 
 #define DEBUGLEVEL 1
 
 static const char objName[] = "udpreceive";
 
 #include "iemnet.h"
+#include <string.h>
 
 /* ----------------------------- udpreceive ------------------------- */
 
 static t_class *udpreceive_class;
 
-typedef struct _udpreceive
-{
+typedef struct _udpreceive {
   t_object  x_obj;
   t_outlet  *x_msgout;
   t_outlet  *x_addrout;
   t_outlet  *x_statout;
 
-  int       x_connectsocket;
+  int       x_fd;
   int       x_port;
-  t_iemnet_receiver*x_receiver;
-	t_iemnet_floatlist         *x_floatlist;
+  t_iemnet_receiver *x_receiver;
+  t_iemnet_floatlist*x_floatlist;
+
+  int x_reuseport, x_reuseaddr;
 } t_udpreceive;
 
 
-static void udpreceive_read_callback(void*y, t_iemnet_chunk*c) {
+static void udpreceive_read_callback(void*y, t_iemnet_chunk*c)
+{
   t_udpreceive*x=(t_udpreceive*)y;
   if(c) {
     iemnet__addrout(x->x_statout, x->x_addrout, c->addr, c->port);
-    x->x_floatlist=iemnet__chunk2list(c, x->x_floatlist); // gets destroyed in the dtor
-    outlet_list(x->x_msgout, gensym("list"), x->x_floatlist->argc, x->x_floatlist->argv);
+    x->x_floatlist=iemnet__chunk2list(c,
+                                      x->x_floatlist); // gets destroyed in the dtor
+    outlet_list(x->x_msgout, gensym("list"), x->x_floatlist->argc,
+                x->x_floatlist->argv);
   } else {
-    post("[%s] nothing received", objName);
+    iemnet_log(x, IEMNET_VERBOSE, "nothing received");
   }
 }
 
-static void udpreceive_port(t_udpreceive*x, t_floatarg fportno)
+static int udpreceive_setport(t_udpreceive*x, unsigned short portno)
 {
-  static t_atom ap[1];
-  int                 portno = fportno;
   struct sockaddr_in  server;
   socklen_t           serversize=sizeof(server);
-  int sockfd = x->x_connectsocket;
+  int sockfd = x->x_fd;
   int intarg;
+  memset(&server, 0, sizeof(server));
 
-  SETFLOAT(ap, -1);
   if(x->x_port == portno) {
-    return;
+    iemnet_log(x, IEMNET_VERBOSE, "skipping re-binding to port:%d", portno);
+    return 1;
   }
 
   /* cleanup any open ports */
+  if(x->x_receiver) {
+    iemnet__receiver_destroy(x->x_receiver, 0);
+    x->x_receiver=NULL;
+  }
   if(sockfd>=0) {
-    iemnet__receiver_destroy(x->x_receiver);
-    x->x_connectsocket=-1;
+    iemnet__closesocket(sockfd, 1);
+    x->x_fd=-1;
     x->x_port=-1;
   }
 
   sockfd = socket(AF_INET, SOCK_DGRAM, 0);
   if(sockfd<0) {
-    error("[%s]: unable to create socket", objName);
-    return;
+    iemnet_log(x, IEMNET_ERROR, "unable to create socket");
+    sys_sockerror("socket");
+    return 0;
   }
 
   /* ask OS to allow another Pd to reopen this port after we close it. */
 #ifdef SO_REUSEADDR
-  intarg = 1;
-  if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
-                 (char *)&intarg, sizeof(intarg)) 
-      < 0) {
-    error("[%s]: setsockopt (SO_REUSEADDR) failed", objName);
+  if(x->x_reuseaddr) {
+    intarg = 1;
+    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
+                   (void *)&intarg, sizeof(intarg))
+        < 0) {
+      iemnet_log(x, IEMNET_ERROR, "unable to enable address re-using");
+      sys_sockerror("setsockopt:SO_REUSEADDR");
+    }
   }
 #endif /* SO_REUSEADDR */
 #ifdef SO_REUSEPORT
-  intarg = 1;
-  if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT,
-                 (char *)&intarg, sizeof(intarg)) 
-      < 0) {
-    error("[%s]: setsockopt (SO_REUSEPORT) failed", objName);
+  if(x->x_reuseport) {
+    intarg = 1;
+    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT,
+                   (void *)&intarg, sizeof(intarg))
+        < 0) {
+      iemnet_log(x, IEMNET_ERROR, "unable to enable port re-using");
+      sys_sockerror("setsockopt:SO_REUSEPORT");
+    }
   }
 #endif /* SO_REUSEPORT */
 
-
   server.sin_family = AF_INET;
   server.sin_addr.s_addr = INADDR_ANY;
   server.sin_port = htons((u_short)portno);
 
   /* name the socket */
-  if (bind(sockfd, (struct sockaddr *)&server, serversize) < 0)
-    {
-      sys_sockerror("[udpreceive] bind failed");
-      sys_closesocket(sockfd);
-      sockfd = -1;
-      outlet_anything(x->x_statout, gensym("port"), 1, ap);
-      return;
-    }
+  if (bind(sockfd, (struct sockaddr *)&server, serversize) < 0) {
+    iemnet_log(x, IEMNET_ERROR, "unable to bind to socket");
+    sys_sockerror("bind");
+    iemnet__closesocket(sockfd, 1);
+    sockfd = -1;
+    return 0;
+  }
 
-  x->x_connectsocket = sockfd;
+  x->x_fd = sockfd;
   x->x_port = portno;
 
   // find out which port is actually used (useful when assigning "0")
@@ -125,54 +138,121 @@ static void udpreceive_port(t_udpreceive*x, t_floatarg fportno)
   }
 
   x->x_receiver=iemnet__receiver_create(sockfd,
-					x, 
-					udpreceive_read_callback);
+                                        x,
+                                        udpreceive_read_callback,
+                                        0);
+  return 1;
+}
+
+static void udpreceive_port(t_udpreceive*x, t_symbol*s, int argc,
+                            t_atom*argv)
+{
+  t_atom ap[1];
+  if(argc) {
+    if(argc>1 || A_FLOAT != argv->a_type) {
+      iemnet_log(x, IEMNET_ERROR, "usage: %s [<portnum>]", s->s_name);
+      return;
+    }
+    SETFLOAT(ap, -1);
+    if(!udpreceive_setport(x, atom_getint(argv))) {
+      outlet_anything(x->x_statout, gensym("port"), 1, ap);
+    }
+  }
 
   SETFLOAT(ap, x->x_port);
   outlet_anything(x->x_statout, gensym("port"), 1, ap);
 }
 
+static void udpreceive_optionI(t_udpreceive*x, t_symbol*s, int argc,
+                               t_atom*argv)
+{
+  int*reuse=NULL;
+  if(gensym("reuseport")==s) {
+    reuse=&x->x_reuseport;
+  }
+  if(gensym("reuseaddr")==s) {
+    reuse=&x->x_reuseaddr;
+  }
+
+  if(!reuse) {
+    iemnet_log(x, IEMNET_ERROR, "unknown option '%s'", s->s_name);
+    return;
+  }
+  if(argc) {
+    if(1==argc && A_FLOAT == argv->a_type) {
+      *reuse=atom_getint(argv);
+      return;
+    } else {
+      iemnet_log(x, IEMNET_ERROR, "usage: %s [<val>]", s->s_name);
+      return;
+    }
+  } else {
+    t_atom ap[1];
+    SETFLOAT(ap, *reuse);
+    outlet_anything(x->x_statout, s, 1, ap);
+  }
+}
 
 static void *udpreceive_new(t_floatarg fportno)
 {
-    t_udpreceive*x = (t_udpreceive *)pd_new(udpreceive_class);
+  t_udpreceive*x = (t_udpreceive *)pd_new(udpreceive_class);
 
-    x->x_msgout = outlet_new(&x->x_obj, 0);
-    x->x_addrout = outlet_new(&x->x_obj, gensym("list"));
-    x->x_statout = outlet_new(&x->x_obj, 0);
+  x->x_msgout = outlet_new(&x->x_obj, 0);
+  x->x_addrout = outlet_new(&x->x_obj, gensym("list"));
+  x->x_statout = outlet_new(&x->x_obj, 0);
 
-    x->x_connectsocket = -1;
-    x->x_port = -1;
-    x->x_receiver = NULL;
+  x->x_fd = -1;
+  x->x_port = -1;
+  x->x_receiver = NULL;
 
-    x->x_floatlist=iemnet__floatlist_create(1024);
+  x->x_floatlist=iemnet__floatlist_create(1024);
 
-    udpreceive_port(x, fportno);
+  x->x_reuseaddr = 1;
+  x->x_reuseport = 0;
 
-    return (x);
+  udpreceive_setport(x, fportno);
+
+  return (x);
 }
 
 static void udpreceive_free(t_udpreceive *x)
 {
-  iemnet__receiver_destroy(x->x_receiver);
-  x->x_connectsocket=0;
+  if(x->x_receiver) {
+    iemnet__receiver_destroy(x->x_receiver, 0);
+  }
+  x->x_receiver=NULL;
+  if(x->x_fd >= 0) {
+    iemnet__closesocket(x->x_fd, 0);
+  }
+  x->x_fd=-1;
 
   outlet_free(x->x_msgout);
   outlet_free(x->x_addrout);
   outlet_free(x->x_statout);
 
-	if(x->x_floatlist)iemnet__floatlist_destroy(x->x_floatlist);x->x_floatlist=NULL;
+  if(x->x_floatlist) {
+    iemnet__floatlist_destroy(x->x_floatlist);
+  }
+  x->x_floatlist=NULL;
 }
 
 IEMNET_EXTERN void udpreceive_setup(void)
 {
-  if(!iemnet__register(objName))return;
-    udpreceive_class = class_new(gensym(objName),
-        (t_newmethod)udpreceive_new, (t_method)udpreceive_free,
-        sizeof(t_udpreceive), 0, A_DEFFLOAT, 0);
-
-    class_addmethod(udpreceive_class, (t_method)udpreceive_port, 
-		    gensym("port"), A_DEFFLOAT, 0);
+  if(!iemnet__register(objName)) {
+    return;
+  }
+  udpreceive_class = class_new(gensym(objName),
+                               (t_newmethod)udpreceive_new, (t_method)udpreceive_free,
+                               sizeof(t_udpreceive), 0, A_DEFFLOAT, 0);
+
+  class_addmethod(udpreceive_class, (t_method)udpreceive_port,
+                  gensym("port"), A_GIMME, 0);
+
+  /* options for opening new sockets */
+  class_addmethod(udpreceive_class, (t_method)udpreceive_optionI,
+                  gensym("reuseaddr"), A_GIMME, 0);
+  class_addmethod(udpreceive_class, (t_method)udpreceive_optionI,
+                  gensym("reuseport"), A_GIMME, 0);
 
   DEBUGMETHOD(udpreceive_class);
 }
diff --git a/udpsend.c b/udpsend.c
index b5b26b1..dccd9c5 100644
--- a/udpsend.c
+++ b/udpsend.c
@@ -1,5 +1,5 @@
 /* udpsend.c
- * copyright (c) 2010 IOhannes m zmölnig, IEM
+ * copyright © 2010-2015 IOhannes m zmölnig, IEM
  * copyright (c) 2006-2010 Martin Peach
  * copyright (c) Miller Puckette
  */
@@ -18,8 +18,8 @@
 /* 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, write to the Free Software                  */
-/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.  */
+/* along with this program; if not, see                                         */
+/*     http://www.gnu.org/licenses/                                             */
 /*                                                                              */
 
 #define DEBUGLEVEL 1
@@ -31,94 +31,82 @@ static const char objName[] = "udpsend";
 
 static t_class *udpsend_class;
 
-typedef struct _udpsend
-{
+typedef struct _udpsend {
   t_object x_obj;
   t_iemnet_sender*x_sender;
+  int x_fd;
 } t_udpsend;
 
 static void udpsend_connect(t_udpsend *x, t_symbol *hostname,
-			    t_floatarg fportno)
+                            t_floatarg fportno)
 {
   struct sockaddr_in  server;
+  struct hostent      *hp = NULL;
   int                 sockfd;
   int                 portno = fportno;
   int                 broadcast = 1;/* nonzero is true */
+  memset(&server, 0, sizeof(server));
 
-  if (x->x_sender)
-    {
-      error("[%s] already connected", objName);
-      return;
-    }
+  if (x->x_sender) {
+    iemnet_log(x, IEMNET_ERROR, "already connected");
+    return;
+  }
 
-  /* create a socket */
-  sockfd = socket(AF_INET, SOCK_DGRAM, 0);
-  DEBUG("send socket %d\n", sockfd);
-  if (sockfd < 0)
-    {
-      sys_sockerror("[udpsend] socket");
-      return;
-    }
-
-  /* Based on zmoelnig's patch 2221504:
-     Enable sending of broadcast messages (if hostname is a broadcast address)*/
-#ifdef SO_BROADCAST
-  if( 0 != setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (const void *)&broadcast, sizeof(broadcast)))
-    {
-      error("[%s] couldn't switch to broadcast mode", objName);
-    }
-#endif /* SO_BROADCAST */
-    
   /* connect socket using hostname provided in command line */
   server.sin_family = AF_INET;
 
-  do {
-#if 0
-    struct addrinfo * addr=NULL;
-    if(getaddrinfo(hostname->s_name, NULL, NULL, &addr)) {
-      error("[%s] bad host '%s'?", objName, hostname->s_name);
-      return;
-    } else {
-      struct addrinfo * res;
-      for (res = addr; res != NULL; res = res->ai_next) {
-	struct sockaddr_in *sa = (struct sockaddr_in *) res->ai_addr;
-	int len = res->ai_addrlen;
-	//      memcpy((char *)&server.sin_addr, (char *)res->ai_addr, hp->h_length);
-	// LATER check how to do that...
-      }
-    }
-    freeaddrinfo(addr);
-#else
-    struct hostent      *hp = gethostbyname(hostname->s_name);
-    if (hp == 0)
-      {
-	error("[%s] bad host '%s'?", objName, hostname->s_name);
-	return;
-      }
-    memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
-#endif
-  } while(0);
+  hp = gethostbyname(hostname->s_name);
+  if (hp == 0) {
+    iemnet_log(x, IEMNET_ERROR, "bad host '%s'?", hostname->s_name);
+    return;
+  }
+  memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
 
   /* assign client port number */
   server.sin_port = htons((u_short)portno);
 
   DEBUG("connecting to port %d", portno);
+
+
+  /* create a socket */
+  sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+  DEBUG("send socket %d\n", sockfd);
+  if (sockfd < 0) {
+    iemnet_log(x, IEMNET_ERROR, "unable to create datagram socket");
+    sys_sockerror("socket");
+    return;
+  }
+
+  /* Enable sending of broadcast messages (if hostname is a broadcast address)*/
+#ifdef SO_BROADCAST
+  if( 0 != setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST,
+                      (const void *)&broadcast, sizeof(broadcast))) {
+    iemnet_log(x, IEMNET_ERROR, "unable to switch to broadcast mode");
+    sys_sockerror("setsockopt:SO_BROADCAST");
+  }
+#endif /* SO_BROADCAST */
+
   /* try to connect. */
-  if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0)
-    {
-      sys_sockerror("[udpsend] connecting stream socket");
-      sys_closesocket(sockfd);
-      return;
-    }
-  x->x_sender=iemnet__sender_create(sockfd);
+  if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) {
+    iemnet_log(x, IEMNET_ERROR, "unable to connect to socket:%d", sockfd);
+    sys_sockerror("connect");
+    iemnet__closesocket(sockfd, 1);
+    return;
+  }
+  x->x_sender=iemnet__sender_create(sockfd, NULL, NULL, 0);
+  x->x_fd = sockfd;
   outlet_float(x->x_obj.ob_outlet, 1);
 }
 
 static void udpsend_disconnect(t_udpsend *x)
 {
   if(x->x_sender) {
-    iemnet__sender_destroy(x->x_sender);
-    x->x_sender=NULL;
+    iemnet__sender_destroy(x->x_sender, 0);
+  }
+  x->x_sender=NULL;
+  if(x->x_fd >= 0) {
+    iemnet__closesocket(x->x_fd, 1);
+    x->x_fd=-1;
     outlet_float(x->x_obj.ob_outlet, 0);
   }
 }
@@ -130,7 +118,7 @@ static void udpsend_send(t_udpsend *x, t_symbol *s, int argc, t_atom *argv)
     iemnet__sender_send(x->x_sender, chunk);
     iemnet__chunk_destroy(chunk);
   } else {
-    error("[%s]: not connected", objName);
+    iemnet_log(x, IEMNET_ERROR, "not connected");
   }
 }
 
@@ -144,23 +132,26 @@ static void *udpsend_new(void)
   t_udpsend *x = (t_udpsend *)pd_new(udpsend_class);
   outlet_new(&x->x_obj, gensym("float"));
   x->x_sender=NULL;
-  return (x);
+  x->x_fd=-1;
+ return (x);
 }
 
 IEMNET_EXTERN void udpsend_setup(void)
 {
-  if(!iemnet__register(objName))return;
+  if(!iemnet__register(objName)) {
+    return;
+  }
   udpsend_class = class_new(gensym(objName), (t_newmethod)udpsend_new,
-			    (t_method)udpsend_free,
-			    sizeof(t_udpsend), 0, 0);
+                            (t_method)udpsend_free,
+                            sizeof(t_udpsend), 0, 0);
 
   class_addmethod(udpsend_class, (t_method)udpsend_connect,
-		  gensym("connect"), A_SYMBOL, A_FLOAT, 0);
+                  gensym("connect"), A_SYMBOL, A_FLOAT, 0);
   class_addmethod(udpsend_class, (t_method)udpsend_disconnect,
-		  gensym("disconnect"), 0);
+                  gensym("disconnect"), 0);
 
   class_addmethod(udpsend_class, (t_method)udpsend_send, gensym("send"),
-		  A_GIMME, 0);
+                  A_GIMME, 0);
   class_addlist(udpsend_class, (t_method)udpsend_send);
   DEBUGMETHOD(udpsend_class);
 }
@@ -168,4 +159,3 @@ IEMNET_EXTERN void udpsend_setup(void)
 IEMNET_INITIALIZER(udpsend_setup);
 
 /* end udpsend.c*/
-
diff --git a/udpserver.c b/udpserver.c
index 50550b3..900e0d7 100644
--- a/udpserver.c
+++ b/udpserver.c
@@ -1,5 +1,8 @@
 /* udpserver.c
- * copyright (c) 2010 IOhannes m zmölnig, IEM
+ *
+ * listens on a UDP-socket for bi-directional communication
+ *
+ * copyright © 2010-2015 IOhannes m zmölnig, IEM
  * copyright (c) 2006-2010 Martin Peach
  * copyright (c) 2004 Olaf Matthes
  */
@@ -19,8 +22,8 @@
 /* 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, write to the Free Software                  */
-/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.  */
+/* along with this program; if not, see                                         */
+/*     http://www.gnu.org/licenses/                                             */
 /*                                                                              */
 
 /* ---------------------------------------------------------------------------- */
@@ -28,6 +31,7 @@
 #include "iemnet.h"
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 #define MAX_CONNECT 32 /* maximum number of connections */
 
@@ -36,43 +40,46 @@
 static t_class *udpserver_class;
 static const char objName[] = "udpserver";
 
-typedef struct _udpserver_sender
-{
+typedef struct _udpserver_sender {
   struct _udpserver *sr_owner;
 
   long           sr_host;
   unsigned short sr_port;
-  t_int          sr_fd;
+  int          sr_fd;
   t_iemnet_sender*sr_sender;
 } t_udpserver_sender;
 
-typedef struct _udpserver
-{
-  t_object                    x_obj;
-  t_outlet                   *x_msgout;
-  t_outlet                   *x_connectout;
-  t_outlet                   *x_sockout; // legacy
-  t_outlet                   *x_addrout; // legacy
-  t_outlet                   *x_statout; 
+typedef struct _udpserver {
+  t_object x_obj;
+  t_outlet*x_msgout;
+  t_outlet*x_connectout;
+  t_outlet*x_sockout; // legacy
+  t_outlet*x_addrout; // legacy
+  t_outlet*x_statout;
 
-  t_udpserver_sender         *x_sr[MAX_CONNECT]; /* socket per connection */
-  t_int                       x_nconnections;
+  t_udpserver_sender*x_sr[MAX_CONNECT]; /* socket per connection */
+  unsigned int       x_nconnections;
 
-  t_int                       x_connectsocket;    /* socket waiting for new connections */
-  t_int                       x_port;
-  unsigned char               x_accept; /* whether we accept new connections or not */
+  int x_connectsocket;    /* socket waiting for new connections */
+  unsigned short x_port;
+  unsigned char  x_accept; /* whether we accept new connections or not */
 
-  int                         x_defaulttarget; /* the default connection to send to; 0=broadcast; >0 use this client; <0 exclude this client */
+  /* the default connection to send to;
+     0=broadcast; >0 use this client; <0 exclude this client
+  */
+  int x_defaulttarget;
 
-  t_iemnet_receiver          *x_receiver;
-  t_iemnet_floatlist         *x_floatlist;
+  t_iemnet_receiver*x_receiver;
+  t_iemnet_floatlist*x_floatlist;
 } t_udpserver;
 
-static t_udpserver_sender *udpserver_sender_new(t_udpserver *owner,  unsigned long host, unsigned short port)
+static t_udpserver_sender *udpserver_sender_new(t_udpserver *owner,
+    unsigned long host, unsigned short port)
 {
-  t_udpserver_sender *x = (t_udpserver_sender *)malloc(sizeof(t_udpserver_sender));
+  t_udpserver_sender *x = (t_udpserver_sender *)malloc(sizeof(
+                            t_udpserver_sender));
   if(NULL==x) {
-    error("%s_sender: unable to allocate %d bytes", objName, sizeof(*x));
+    iemnet_log(owner, IEMNET_FATAL, "unable to allocate %d bytes to create sender", (int)sizeof(*x));
     return NULL;
   } else {
     int sockfd = owner->x_connectsocket;
@@ -83,7 +90,7 @@ static t_udpserver_sender *udpserver_sender_new(t_udpserver *owner,  unsigned lo
     x->sr_host=host; //ntohl(addr->sin_addr.s_addr);
     x->sr_port=port; //ntohs(addr->sin_port);
 
-    x->sr_sender=iemnet__sender_create(sockfd);
+    x->sr_sender=iemnet__sender_create(sockfd, NULL, NULL, 0);
   }
   return (x);
 }
@@ -91,39 +98,40 @@ static t_udpserver_sender *udpserver_sender_new(t_udpserver *owner,  unsigned lo
 static void udpserver_sender_free(t_udpserver_sender *x)
 {
   DEBUG("freeing %x", x);
-  if (x != NULL)
-    {
-      int sockfd=x->sr_fd;
-      t_iemnet_sender*sender=x->sr_sender;
-
-      x->sr_owner=NULL;
-      x->sr_sender=NULL;
-
-      x->sr_fd=-1;
+  if (x != NULL) {
+    int sockfd=x->sr_fd;
+    t_iemnet_sender*sender=x->sr_sender;
 
-      free(x);
+    x->sr_owner=NULL;
+    x->sr_sender=NULL;
+    x->sr_fd=-1;
 
-      if(sender)  iemnet__sender_destroy(sender);
+    free(x);
 
-      sys_closesocket(sockfd);
+    if(sender) {
+      iemnet__sender_destroy(sender, 0);
+    }
+    if(sockfd>=0) {
+      iemnet__closesocket(sockfd, 1);
     }
-  DEBUG("freeed %x", x);
+  }
+  /* coverity[pass_freed_arg]: this is merely for debugging printout */
+  DEBUG("freed %x", x);
 }
 
-static t_udpserver_sender* udpserver_sender_copy(t_udpserver_sender*x) {
+static t_udpserver_sender* udpserver_sender_copy(t_udpserver_sender*x)
+{
   return udpserver_sender_new(x->sr_owner,x->sr_host, x->sr_port);
 }
 
 static int udpserver_socket2index(t_udpserver*x, int sockfd)
 {
-  int i=0;
-  for(i = 0; i < x->x_nconnections; i++) /* check if connection exists */
-    {
-      if(x->x_sr[i]->sr_fd == sockfd)
-        {
-          return i;
-        }
-    }  
+  unsigned int i=0;
+  for(i = 0; i < x->x_nconnections; i++) { /* check if connection exists */
+    if(x->x_sr[i]->sr_fd == sockfd) {
+      return i;
+    }
+  }
   return -1;
 }
 
@@ -131,37 +139,53 @@ static int udpserver_socket2index(t_udpserver*x, int sockfd)
  *  if the id is invalid, returns -1
  *  if the id is valid, return the 0-based index (client-1)
  */
-static int udpserver_fixindex(t_udpserver*x, int client)
+static int udpserver_fixindex(t_udpserver*x, int client_)
 {
-  if(x->x_nconnections <= 0)
-    {
-      pd_error(x, "[%s]: no clients connected", objName);
-      return -1;
-    }
-  
-  if (!((client > 0) && (client <= x->x_nconnections)))
-    {
-      pd_error(x, "[%s] client %d out of range [1..%d]", objName, client, x->x_nconnections);
-      return -1;
-    }
+  unsigned int client;
+  if(client_<1) {
+    iemnet_log(x, IEMNET_ERROR,
+               "client:%d out of range [1..%d]",
+               client_, (int)(x->x_nconnections));
+    return -1;
+  }
+  client = (unsigned int)client_;
+  if(x->x_nconnections <= 0) {
+    iemnet_log(x, IEMNET_ERROR, "no clients connected");
+    return -1;
+  }
+
+  if (client > x->x_nconnections) {
+    iemnet_log(x, IEMNET_ERROR,
+               "client:%d out of range [1..%d]",
+               client, (int)(x->x_nconnections));
+    return -1;
+  }
   return (client-1);
 }
 
 
 /* returns 1 if addr1==addr2, 0 otherwise */
-static int equal_addr(unsigned long host1, unsigned short port1,  unsigned long host2, unsigned short port2) {
+static int equal_addr(unsigned long host1, unsigned short port1,
+                      unsigned long host2, unsigned short port2)
+{
   return (
-          ((port1 == port2) && 
-           (host1 == host2))
-          );
+           ((port1 == port2) &&
+            (host1 == host2))
+         );
 }
 
 
-static int udpserver__find_sender(t_udpserver*x,  unsigned long host, unsigned short port) {
-  int i=0;
+static int udpserver__find_sender(t_udpserver*x,  unsigned long host,
+                                  unsigned short port)
+{
+  unsigned int i=0;
   for(i=0; i<x->x_nconnections; i++) {
-    if(NULL==x->x_sr[i])return -1;
-    if(equal_addr(host, port, x->x_sr[i]->sr_host, x->x_sr[i]->sr_port))return i;
+    if(NULL==x->x_sr[i]) {
+      return -1;
+    }
+    if(equal_addr(host, port, x->x_sr[i]->sr_host, x->x_sr[i]->sr_port)) {
+      return i;
+    }
   }
   return -1;
 }
@@ -170,19 +194,21 @@ static int udpserver__find_sender(t_udpserver*x,  unsigned long host, unsigned s
  * check whether the sender is already registered
  * if not, add it to the list of registered senders
  */
-static t_udpserver_sender* udpserver_sender_add(t_udpserver*x, 
-						unsigned long host, unsigned short port )
+static t_udpserver_sender* udpserver_sender_add(t_udpserver*x,
+    unsigned long host, unsigned short port )
 {
   int id=-1;
 
-  if(!x->x_accept)return NULL;
+  if(!x->x_accept) {
+    return NULL;
+  }
 
   id=udpserver__find_sender(x, host, port);
   DEBUG("%X:%d -> %d", host, port, id);
   if(id<0) {
 #if 1
     /* since udp is a connection-less protocol we have no way of knowing the currently connected clients
-     * the following 3 lines assume, that there is only one client connected (the last we got data from 
+     * the following 3 lines assume, that there is only one client connected (the last we got data from
      */
     id=0;
     udpserver_sender_free(x->x_sr[id]);
@@ -213,9 +239,10 @@ static t_udpserver_sender* udpserver_sender_add(t_udpserver*x,
   return NULL;
 }
 
-static void udpserver_sender_remove(t_udpserver*x, int id) {
-  if(id>=0 && id<x->x_nconnections && x->x_sr[id]) {
-    int i;
+static void udpserver_sender_remove(t_udpserver*x, unsigned int id)
+{
+  if(id<x->x_nconnections && x->x_sr[id]) {
+    unsigned int i;
 
     t_udpserver_sender* sdr=x->x_sr[id];
     udpserver_sender_free(sdr);
@@ -230,16 +257,13 @@ static void udpserver_sender_remove(t_udpserver*x, int id) {
   }
 }
 
-
-
-
 /* ---------------- udpserver info ---------------------------- */
 static void udpserver_info_client(t_udpserver *x, int client)
 {
   // "client <id> <socket> <IP> <port>"
   // "bufsize <id> <insize> <outsize>"
   static t_atom output_atom[4];
-  if(x&&x->x_sr&&x->x_sr[client]) {
+  if(x&&client<MAX_CONNECT&&x->x_sr[client]) {
     int sockfd = x->x_sr[client]->sr_fd;
     unsigned short port   = x->x_sr[client]->sr_port;
     long address = x->x_sr[client]->sr_host;
@@ -248,12 +272,12 @@ static void udpserver_info_client(t_udpserver *x, int client)
     int insize =iemnet__receiver_getsize(x->x_receiver);
     int outsize=iemnet__sender_getsize  (x->x_sr[client]->sr_sender  );
 
-    snprintf(hostname, MAXPDSTRING-1, "%d.%d.%d.%d", 
+    snprintf(hostname, MAXPDSTRING-1, "%d.%d.%d.%d",
              (unsigned char)((address & 0xFF000000)>>24),
              (unsigned char)((address & 0x0FF0000)>>16),
              (unsigned char)((address & 0x0FF00)>>8),
-	     (unsigned char)((address & 0x0FF))
-	     );
+             (unsigned char)((address & 0x0FF))
+            );
     hostname[MAXPDSTRING-1]=0;
 
     SETFLOAT (output_atom+0, client+1);
@@ -271,27 +295,29 @@ static void udpserver_info_client(t_udpserver *x, int client)
 }
 
 
-static void udpserver_info(t_udpserver *x) {
+static void udpserver_info(t_udpserver *x)
+{
   static t_atom output_atom[4];
   int sockfd=x->x_connectsocket;
 
-
   int port=x->x_port;
 
   if(sockfd<0) {
     // no open port
-    error("[%s] no valid sock", objName);
+    iemnet_log(x, IEMNET_ERROR, "no open socket");
   }
 
-
   if(x->x_port<=0) {
     struct sockaddr_in  server;
     socklen_t           serversize=sizeof(server);
+    memset(&server, 0, sizeof(server));
+
     if(!getsockname(sockfd, (struct sockaddr *)&server, &serversize)) {
       x->x_port=ntohs(server.sin_port);
       port=x->x_port;
     } else {
-      error("[%s] gesockname failed for %d", objName, sockfd);
+      iemnet_log(x, IEMNET_ERROR, "getsockname failed for socket:%d", sockfd);
+      sys_sockerror("getsockname");
     }
   }
 
@@ -307,16 +333,20 @@ static void udpserver_info_connection(t_udpserver *x, t_udpserver_sender*y)
 }
 
 /* ---------------- main udpserver (send) stuff --------------------- */
-static void udpserver_disconnect_socket(t_udpserver *x, t_floatarg fsocket);
-static void udpserver_send_bytes(t_udpserver*x, int client, t_iemnet_chunk*chunk)
+static void udpserver_disconnect_socket(t_udpserver *x,
+                                        t_floatarg fsocket);
+static void udpserver_send_bytes(t_udpserver*x, unsigned int client,
+                                 t_iemnet_chunk*chunk)
 {
   DEBUG("send_bytes to %x -> %x[%d]", x, x->x_sr, client);
-  if(x->x_sr)DEBUG("client %X", x->x_sr[client]);
-  if(x && x->x_sr && x->x_sr[client]) {
+  if(client<MAX_CONNECT) {
+    DEBUG("client %X", x->x_sr[client]);
+  }
+  if(x && client<MAX_CONNECT && x->x_sr[client]) {
     t_atom                  output_atom[3];
     int size=0;
 
-    t_iemnet_sender*sender=sender=x->x_sr[client]->sr_sender;
+    t_iemnet_sender*sender=x->x_sr[client]->sr_sender;
     int sockfd = x->x_sr[client]->sr_fd;
 
     chunk->addr=x->x_sr[client]->sr_host;
@@ -329,7 +359,7 @@ static void udpserver_send_bytes(t_udpserver*x, int client, t_iemnet_chunk*chunk
     SETFLOAT(&output_atom[0], client+1);
     SETFLOAT(&output_atom[1], size);
     SETFLOAT(&output_atom[2], sockfd);
-    outlet_anything( x->x_statout, gensym("sent"), 3, output_atom);
+    outlet_anything( x->x_statout, gensym("sendbuffersize"), 3, output_atom);
 
     if(size<0) {
       // disconnected!
@@ -339,111 +369,134 @@ static void udpserver_send_bytes(t_udpserver*x, int client, t_iemnet_chunk*chunk
 }
 
 
-
 /* broadcasts a message to all connected clients but the given one */
-static void udpserver_send_butclient(t_udpserver *x, int but, int argc, t_atom *argv)
+static void udpserver_send_butclient(t_udpserver *x, unsigned int but,
+                                     int argc, t_atom *argv)
 {
-  int client=0;
+  unsigned int client=0;
   t_iemnet_chunk*chunk=iemnet__chunk_create_list(argc, argv);
 
   /* enumerate through the clients and send each the message */
-  for(client = 0; client < x->x_nconnections; client++)	/* check if connection exists */
-    {
-      /* socket exists for this client */
-      if(client!=but)udpserver_send_bytes(x, client, chunk);
+  for(client = 0; client < x->x_nconnections;
+      client++) {	/* check if connection exists */
+    /* socket exists for this client */
+    if(client!=but) {
+      udpserver_send_bytes(x, client, chunk);
     }
+  }
   iemnet__chunk_destroy(chunk);
 }
 /* sends a message to a given client */
-static void udpserver_send_toclient(t_udpserver *x, int client, int argc, t_atom *argv)
+static void udpserver_send_toclient(t_udpserver *x, unsigned int client,
+                                    int argc, t_atom *argv)
 {
   t_iemnet_chunk*chunk=iemnet__chunk_create_list(argc, argv);
   udpserver_send_bytes(x, client, chunk);
   iemnet__chunk_destroy(chunk);
 }
 
-
-
 /* send message to client using client number
    note that the client numbers might change in case a client disconnects! */
 /* clients start at 1 but our index starts at 0 */
-static void udpserver_send_client(t_udpserver *x, t_symbol *s, int argc, t_atom *argv)
-{
-  int client=0;
-      
-  if (argc > 0)
-    {
-      client=udpserver_fixindex(x, atom_getint(argv));
-      if(client<0)return;
-      if(argc==1) {
-        udpserver_info_client(x, client);
-      } else {
-        udpserver_send_toclient(x, client, argc-1, argv+1);
-      }
+static void udpserver_send_client(t_udpserver *x, t_symbol *s, int argc,
+                                  t_atom *argv)
+{
+  unsigned int client=0;
+
+  if (argc > 0) {
+    int c=udpserver_fixindex(x, atom_getint(argv));
+    if(c<0) {
       return;
     }
-  else 
-    {
-      for(client=0; client<x->x_nconnections; client++)
-        udpserver_info_client(x, client);
+    client=(unsigned int)c;
+    if(argc==1) {
+      udpserver_info_client(x, client);
+    } else {
+      udpserver_send_toclient(x, client, argc-1, argv+1);
+    }
+    return;
+  } else {
+    for(client=0; client<x->x_nconnections; client++) {
+      udpserver_info_client(x, client);
     }
+  }
 }
 
 /* broadcasts a message to all connected clients */
-static void udpserver_broadcast(t_udpserver *x, t_symbol *s, int argc, t_atom *argv)
+static void udpserver_broadcast(t_udpserver *x, t_symbol *s, int argc,
+                                t_atom *argv)
 {
-  int     client;
+  unsigned int   client;
   t_iemnet_chunk*chunk=iemnet__chunk_create_list(argc, argv);
 
   DEBUG("broadcasting to %d clients", x->x_nconnections);
 
   /* enumerate through the clients and send each the message */
-  for(client = 0; client < x->x_nconnections; client++)	/* check if connection exists */
-    {
-      /* socket exists for this client */
-      udpserver_send_bytes(x, client, chunk);
-    }
+  for(client = 0; client < x->x_nconnections;
+      client++) {	/* check if connection exists */
+    /* socket exists for this client */
+    udpserver_send_bytes(x, client, chunk);
+  }
   iemnet__chunk_destroy(chunk);
 }
 
 /* broadcasts a message to all connected clients */
-static void udpserver_broadcastbut(t_udpserver *x, t_symbol *s, int argc, t_atom *argv)
+static void udpserver_broadcastbut(t_udpserver *x, t_symbol *s, int argc,
+                                   t_atom *argv)
 {
-  int client=0;
-  int but=-1;
-
-  t_iemnet_chunk*chunk=NULL;
+  int but;
 
   if(argc<2) {
     return;
   }
-  if((but=udpserver_fixindex(x, atom_getint(argv)))<0)return;
+  if((but=udpserver_fixindex(x, atom_getint(argv)))<0) {
+    return;
+  }
   udpserver_send_butclient(x, but, argc-1, argv+1);
 }
 
-static void udpserver_defaultsend(t_udpserver *x, t_symbol *s, int argc, t_atom *argv)
+static void udpserver_defaultsend(t_udpserver *x, t_symbol *s, int argc,
+                                  t_atom *argv)
 {
   int client=-1;
   int sockfd=x->x_defaulttarget;
   DEBUG("sending to sockfd: %d", sockfd);
-  if(0==sockfd) 
-    udpserver_broadcast(x, s, argc, argv);
-  else if(sockfd>0) {
+  if(sockfd>0) {
     client=udpserver_socket2index(x, sockfd);
-    udpserver_send_toclient(x, client, argc, argv);
+    if(client<0) {
+      iemnet_log(x, IEMNET_ERROR,
+                 "invalid socket %d, switching to broadcast mode",
+                 sockfd);
+      x->x_defaulttarget=0;
+    } else {
+      udpserver_send_toclient(x, client, argc, argv);
+      return;
+    }
   } else if(sockfd<0) {
     client=udpserver_socket2index(x, -sockfd);
-    udpserver_send_butclient(x, client, argc, argv);     
+    if(client<0) {
+      iemnet_log(x, IEMNET_ERROR,
+                 "invalid excluded socket %d, switching to broadcast mode",
+                 -sockfd);
+      x->x_defaulttarget=0;
+    } else {
+      udpserver_send_butclient(x, client, argc, argv);
+      return;
+    }
   }
+
+  udpserver_broadcast(x, s, argc, argv);
 }
 static void udpserver_defaulttarget(t_udpserver *x, t_floatarg f)
 {
   int sockfd=0;
   int rawclient=f;
-  int client=(rawclient<0)?(-rawclient):rawclient;
+  unsigned int client=(rawclient<0)?(-rawclient):rawclient;
 
   if(client > x->x_nconnections) {
-    error("[%s] target %d out of range [0..%d]", objName, client,  x->x_nconnections);
+    iemnet_log(x, IEMNET_ERROR,
+               "target:%d out of range [0..%d]",
+               client, (int)(x->x_nconnections));
     return;
   }
 
@@ -452,7 +505,9 @@ static void udpserver_defaulttarget(t_udpserver *x, t_floatarg f)
     sockfd=x->x_sr[client-1]->sr_fd;
   }
 
-  if(rawclient<0)sockfd=-sockfd;  
+  if(rawclient<0) {
+    sockfd=-sockfd;
+  }
 
   x->x_defaulttarget=sockfd;
 }
@@ -463,120 +518,130 @@ static void udpserver_targetsocket(t_udpserver *x, t_floatarg f)
 }
 
 
-
 /* send message to client using socket number */
-static void udpserver_send_socket(t_udpserver *x, t_symbol *s, int argc, t_atom *argv)
+static void udpserver_send_socket(t_udpserver *x, t_symbol *s, int argc,
+                                  t_atom *argv)
 {
   int     client = -1;
   t_iemnet_chunk*chunk=NULL;
   if(argc) {
     client = udpserver_socket2index(x, atom_getint(argv));
-    if(client<0)return;
+    if(client<0) {
+      return;
+    }
   } else {
-    pd_error(x, "%s_send: no socket specified", objName);
+    iemnet_log(x, IEMNET_ERROR, "no socket specified");
     return;
   }
 
   /* get socket number of connection (first element in list) */
-  if(argc && argv->a_type == A_FLOAT)
-    {
-      int sockfd=atom_getint(argv);
-      client = udpserver_socket2index(x, sockfd);
-      if(client < 0)
-        {
-          error("[%s]: no connection on socket %d", objName, sockfd);
-          return;
-        }
-    }
-  else
-    {
-      error("[%s]: no socket specified", objName);
+  if(argc && argv->a_type == A_FLOAT) {
+    int sockfd=atom_getint(argv);
+    client = udpserver_socket2index(x, sockfd);
+    if(client < 0) {
+      iemnet_log(x, IEMNET_ERROR, "no connection on socket:%d", sockfd);
       return;
     }
-  
+  } else {
+    iemnet_log(x, IEMNET_ERROR, "no socket specified");
+    return;
+  }
+
   chunk=iemnet__chunk_create_list(argc-1, argv+1);
   udpserver_send_bytes(x, client, chunk);
   iemnet__chunk_destroy(chunk);
 }
 
-static void udpserver_disconnect(t_udpserver *x, int client)
+static void udpserver_disconnect(t_udpserver *x, unsigned int client)
 {
-  int k;
-  DEBUG("disconnect %x %d", x, client);
-  t_udpserver_sender*sdr;
+  t_udpserver_sender*sdr=NULL;
   int conns;
+  DEBUG("disconnect %x %d", x, client);
 
-  if(client<0 || client >= x->x_nconnections)return;
+  if(client >= x->x_nconnections) {
+    return;
+  }
 
-  sdr=udpserver_sender_copy(x->x_sr[client]);
+  sdr = (t_udpserver_sender *)calloc(1, sizeof(t_udpserver_sender));
+  if(sdr) {
+    sdr->sr_host=x->x_sr[client]->sr_host;
+    sdr->sr_port=x->x_sr[client]->sr_port;
+  }
 
   udpserver_sender_remove(x, client);
   conns=x->x_nconnections;
 
-
-  udpserver_info_connection(x, sdr);
+  if(sdr) {
+    udpserver_info_connection(x, sdr);
+    free(sdr);
+  }
   outlet_float(x->x_connectout, conns);
 }
 
-
 /* disconnect a client by number */
 static void udpserver_disconnect_client(t_udpserver *x, t_floatarg fclient)
 {
   int client = udpserver_fixindex(x, fclient);
 
-  if(client<0)return;
+  if(client<0) {
+    return;
+  }
   udpserver_disconnect(x, client);
 }
 
-
 /* disconnect a client by socket */
 static void udpserver_disconnect_socket(t_udpserver *x, t_floatarg fsocket)
 {
   int id=udpserver_socket2index(x, (int)fsocket);
-  if(id>=0)
+  if(id>=0) {
     udpserver_disconnect_client(x, id+1);
+  }
 }
 
-
-
 /* disconnect a client by socket */
 static void udpserver_disconnect_all(t_udpserver *x)
 {
-  int id=x->x_nconnections;
-  while(--id>=0) {
+  unsigned int id;
+  for(id=0; id<x->x_nconnections; id++) {
     udpserver_disconnect(x, id);
   }
 }
 
 /* whether we should accept new connections */
-static void udpserver_accept(t_udpserver *x, t_float f) {
+static void udpserver_accept(t_udpserver *x, t_float f)
+{
   x->x_accept=(unsigned char)f;
 }
 
-
 /* ---------------- main udpserver (receive) stuff --------------------- */
-static void udpserver_receive_callback(void *y, t_iemnet_chunk*c) {
+static void udpserver_receive_callback(void *y, t_iemnet_chunk*c)
+{
   t_udpserver*x=(t_udpserver*)y;
-  if(NULL==y)return;
+  if(NULL==y) {
+    return;
+  }
 
   if(c) {
-    int conns = x->x_nconnections;
+    unsigned int conns = x->x_nconnections;
+    t_udpserver_sender*sdr=NULL;
     DEBUG("add new sender from %d", c->port);
-    t_udpserver_sender*sdr=udpserver_sender_add(x, c->addr, c->port);
+    sdr=udpserver_sender_add(x, c->addr, c->port);
     DEBUG("added new sender from %d", c->port);
     if(sdr) {
       udpserver_info_connection(x, sdr);
-      x->x_floatlist=iemnet__chunk2list(c, x->x_floatlist); // gets destroyed in the dtor
+      x->x_floatlist=iemnet__chunk2list(c,
+                                        x->x_floatlist); // gets destroyed in the dtor
 
       /* here we might have a reentrancy problem */
       if(conns!=x->x_nconnections) {
         outlet_float(x->x_connectout, x->x_nconnections);
       }
-      outlet_list(x->x_msgout, gensym("list"), x->x_floatlist->argc, x->x_floatlist->argv);
+      outlet_list(x->x_msgout, gensym("list"), x->x_floatlist->argc,
+                  x->x_floatlist->argv);
     }
   } else {
     // disconnection never happens with a connectionless protocol like UDP
-    pd_error(x, "[%s] received disconnection event", objName);
+    iemnet_log(x, IEMNET_ERROR, "received disconnection event");
   }
 }
 
@@ -585,34 +650,34 @@ static void udpserver_receive_callback(void *y, t_iemnet_chunk*c) {
 static void udpserver_connectpoll(t_udpserver *x)
 {
   struct sockaddr_in  incomer_address;
-  unsigned int        sockaddrl = sizeof( struct sockaddr );
+  socklen_t           sockaddrl = sizeof( struct sockaddr );
   int                 fd = -1;
   int                 i;
 
   // TODO: provide a way to not accept connection
   // idea: add a message "accept $1" to turn off/on acceptance of new connections
-  fd = accept(x->x_connectsocket, (struct sockaddr*)&incomer_address, &sockaddrl);
+  fd = accept(x->x_connectsocket, (struct sockaddr*)&incomer_address,
+              &sockaddrl);
 
   bug("connectpoll");
 
-  if (fd < 0) error("[%s] accept failed", objName);
-  else
-    {
-      unsigned long host  = ntohl(incomer_address.sin_addr.s_addr);
-      unsigned short port = ntohs(incomer_address.sin_port);
-
-      t_udpserver_sender *y = udpserver_sender_new(x, host, port);
-      if (!y)
-        {
-          sys_closesocket(fd);
-          return;
-        }
-      x->x_nconnections++;
-      i = x->x_nconnections - 1;
-      x->x_sr[i] = y;
+  if (fd < 0) {
+    error("[%s] accept failed", objName);
+  } else {
+    unsigned long host  = ntohl(incomer_address.sin_addr.s_addr);
+    unsigned short port = ntohs(incomer_address.sin_port);
 
-      udpserver_info_connection(x, y);
+    t_udpserver_sender *y = udpserver_sender_new(x, host, port);
+    if (!y) {
+      iemnet__closesocket(fd, 1);
+      return;
     }
+    x->x_nconnections++;
+    i = x->x_nconnections - 1;
+    x->x_sr[i] = y;
+
+    udpserver_info_connection(x, y);
+  }
 
   outlet_float(x->x_connectout, x->x_nconnections);
 }
@@ -624,6 +689,8 @@ static void udpserver_port(t_udpserver*x, t_floatarg fportno)
   struct sockaddr_in  server;
   socklen_t           serversize=sizeof(server);
   int sockfd = x->x_connectsocket;
+  memset(&server, 0, sizeof(server));
+
   SETFLOAT(ap, -1);
   if(x->x_port == portno) {
     return;
@@ -632,14 +699,18 @@ static void udpserver_port(t_udpserver*x, t_floatarg fportno)
   /* cleanup any open ports */
   if(sockfd>=0) {
     //sys_rmpollfn(sockfd);
-    sys_closesocket(sockfd);
+    iemnet__closesocket(sockfd, 0);
     x->x_connectsocket=-1;
     x->x_port=-1;
   }
 
 
   sockfd = socket(AF_INET, SOCK_DGRAM, 0);
-
+  if(sockfd<0) {
+    iemnet_log(x, IEMNET_ERROR, "unable to create socket");
+    sys_sockerror("socket");
+    return;
+  }
 
   server.sin_family = AF_INET;
 
@@ -649,28 +720,26 @@ static void udpserver_port(t_udpserver*x, t_floatarg fportno)
   /* assign server port number */
   server.sin_port = htons((u_short)portno);
   /* name the socket */
-  if (bind(sockfd, (struct sockaddr *)&server, serversize) < 0)
-    {
-      sys_sockerror("udpserver: bind");
-      sys_closesocket(sockfd);
-      outlet_anything(x->x_statout, gensym("port"), 1, ap);
-      return;
-    }
+  if (bind(sockfd, (struct sockaddr *)&server, serversize) < 0) {
+    iemnet_log(x, IEMNET_ERROR, "unable to bind to socket");
+    sys_sockerror("bind");
+    iemnet__closesocket(sockfd, 1);
+    outlet_anything(x->x_statout, gensym("port"), 1, ap);
+    return;
+  }
 
   x->x_receiver=iemnet__receiver_create(sockfd,
-					x, 
-					udpserver_receive_callback);
-
+                                        x,
+                                        udpserver_receive_callback,
+                                        0);
   x->x_connectsocket = sockfd;
   x->x_port = portno;
 
-
   // find out which port is actually used (useful when assigning "0")
   if(!getsockname(sockfd, (struct sockaddr *)&server, &serversize)) {
     x->x_port=ntohs(server.sin_port);
   }
 
-
   SETFLOAT(ap, x->x_port);
   outlet_anything(x->x_statout, gensym("port"), 1, ap);
 }
@@ -683,19 +752,20 @@ static void *udpserver_new(t_floatarg fportno)
   x = (t_udpserver *)pd_new(udpserver_class);
 
   x->x_msgout = outlet_new(&x->x_obj, 0); /* 1st outlet for received data */
-  x->x_connectout = outlet_new(&x->x_obj, gensym("float")); /* 2nd outlet for number of connected clients */
+  x->x_connectout = outlet_new(&x->x_obj,
+                               gensym("float")); /* 2nd outlet for number of connected clients */
   x->x_sockout = outlet_new(&x->x_obj, gensym("float"));
   x->x_addrout = outlet_new(&x->x_obj, gensym("list" ));
-  x->x_statout = outlet_new(&x->x_obj, 0);/* 5th outlet for everything else */
+  /* 5th outlet for everything else */
+  x->x_statout = outlet_new(&x->x_obj, 0);
 
   x->x_connectsocket = -1;
   x->x_port = -1;
   x->x_nconnections = 0;
 
-  for(i = 0; i < MAX_CONNECT; i++)
-    {
-      x->x_sr[i] = NULL;
-    }
+  for(i = 0; i < MAX_CONNECT; i++) {
+    x->x_sr[i] = NULL;
+  }
 
   x->x_defaulttarget=0;
   x->x_floatlist=iemnet__floatlist_create(1024);
@@ -710,46 +780,63 @@ static void *udpserver_new(t_floatarg fportno)
 static void udpserver_free(t_udpserver *x)
 {
   int     i;
-
-  for(i = 0; i < MAX_CONNECT; i++)
-    {
-      if (NULL!=x->x_sr[i]) {
-        DEBUG("[%s] free %x", objName, x);
-        udpserver_sender_free(x->x_sr[i]);
-        x->x_sr[i]=NULL;
-      }
+  for(i = 0; i < MAX_CONNECT; i++) {
+    if (NULL!=x->x_sr[i]) {
+      DEBUG("[%s] free %x", objName, x);
+      udpserver_sender_free(x->x_sr[i]);
+      x->x_sr[i]=NULL;
     }
-  if (x->x_connectsocket >= 0)
-    {
-      //sys_rmpollfn(x->x_connectsocket);
-      sys_closesocket(x->x_connectsocket);
-    }
-	if(x->x_floatlist)iemnet__floatlist_destroy(x->x_floatlist);x->x_floatlist=NULL;
+  }
+  if(x->x_receiver) {
+      iemnet__receiver_destroy(x->x_receiver, 0);
+      x->x_receiver=NULL;
+  }
+  if (x->x_connectsocket >= 0) {
+    iemnet__closesocket(x->x_connectsocket, 0);
+    x->x_connectsocket = -1;
+  }
+  if(x->x_floatlist) {
+    iemnet__floatlist_destroy(x->x_floatlist);
+    x->x_floatlist=NULL;
+  }
 }
 
 IEMNET_EXTERN void udpserver_setup(void)
 {
-  if(!iemnet__register(objName))return;
+  if(!iemnet__register(objName)) {
+    return;
+  }
   error("[%s] does not work yet", objName);
 
-  udpserver_class = class_new(gensym(objName),(t_newmethod)udpserver_new, (t_method)udpserver_free,
+  udpserver_class = class_new(gensym(objName),(t_newmethod)udpserver_new,
+                              (t_method)udpserver_free,
                               sizeof(t_udpserver), 0, A_DEFFLOAT, 0);
-  class_addmethod(udpserver_class, (t_method)udpserver_disconnect_client, gensym("disconnectclient"), A_DEFFLOAT, 0);
-  class_addmethod(udpserver_class, (t_method)udpserver_disconnect_socket, gensym("disconnectsocket"), A_DEFFLOAT, 0);
-  class_addmethod(udpserver_class, (t_method)udpserver_disconnect_all, gensym("disconnect"), 0);
-
-  class_addmethod(udpserver_class, (t_method)udpserver_accept, gensym("accept"), A_FLOAT, 0);
-
-  class_addmethod(udpserver_class, (t_method)udpserver_send_socket, gensym("send"), A_GIMME, 0);
-  class_addmethod(udpserver_class, (t_method)udpserver_send_client, gensym("client"), A_GIMME, 0);
-
-  class_addmethod(udpserver_class, (t_method)udpserver_broadcast, gensym("broadcast"), A_GIMME, 0);
-
-  class_addmethod(udpserver_class, (t_method)udpserver_defaulttarget, gensym("target"), A_DEFFLOAT, 0);
-  class_addmethod(udpserver_class, (t_method)udpserver_targetsocket, gensym("targetsocket"), A_DEFFLOAT, 0);
+  class_addmethod(udpserver_class, (t_method)udpserver_disconnect_client,
+                  gensym("disconnectclient"), A_DEFFLOAT, 0);
+  class_addmethod(udpserver_class, (t_method)udpserver_disconnect_socket,
+                  gensym("disconnectsocket"), A_DEFFLOAT, 0);
+  class_addmethod(udpserver_class, (t_method)udpserver_disconnect_all,
+                  gensym("disconnect"), 0);
+
+  class_addmethod(udpserver_class, (t_method)udpserver_accept,
+                  gensym("accept"), A_FLOAT, 0);
+
+  class_addmethod(udpserver_class, (t_method)udpserver_send_socket,
+                  gensym("send"), A_GIMME, 0);
+  class_addmethod(udpserver_class, (t_method)udpserver_send_client,
+                  gensym("client"), A_GIMME, 0);
+
+  class_addmethod(udpserver_class, (t_method)udpserver_broadcast,
+                  gensym("broadcast"), A_GIMME, 0);
+
+  class_addmethod(udpserver_class, (t_method)udpserver_defaulttarget,
+                  gensym("target"), A_DEFFLOAT, 0);
+  class_addmethod(udpserver_class, (t_method)udpserver_targetsocket,
+                  gensym("targetsocket"), A_DEFFLOAT, 0);
   class_addlist  (udpserver_class, (t_method)udpserver_defaultsend);
 
-  class_addmethod(udpserver_class, (t_method)udpserver_port, gensym("port"), A_DEFFLOAT, 0);
+  class_addmethod(udpserver_class, (t_method)udpserver_port, gensym("port"),
+                  A_DEFFLOAT, 0);
   class_addbang  (udpserver_class, (t_method)udpserver_info);
 
   DEBUGMETHOD(udpserver_class);
diff --git a/udpsndrcv-help.pd b/udpsndrcv-help.pd
new file mode 100644
index 0000000..e65f129
--- /dev/null
+++ b/udpsndrcv-help.pd
@@ -0,0 +1,59 @@
+#N canvas 247 75 632 526 10;
+#X obj 72 255 udpsndrcv;
+#X msg 72 148 connect localhost 12345 54321;
+#X obj 382 255 udpsndrcv;
+#X obj 72 360 print A:connected?;
+#X obj 102 329 print A:data;
+#X obj 132 300 print A:status;
+#X obj 442 300 print B:status;
+#X obj 412 329 print B:data;
+#X obj 382 357 print B:connected?;
+#X msg 86 171 send 10 20 30 40;
+#X msg 91 196 disconnect;
+#X msg 114 224 status;
+#X msg 401 196 disconnect;
+#X msg 424 224 status;
+#X msg 382 148 connect localhost 54321 12345;
+#X msg 396 171 send 50 40 30 20 10;
+#X text 80 26 [udpsndrcv] bi-directional communication;
+#X text 74 59 this is an abstraction around [udpclient] for compatibility
+with mrpeach/net's object of the same name.;
+#N canvas 4 78 530 417 sending/receiving 0;
+#X obj 142 275 udpsndrcv;
+#X msg 161 216 disconnect;
+#X msg 184 244 status;
+#X msg 142 168 connect localhost 55555 55555;
+#X msg 156 191 send 5 5 5;
+#X obj 202 320 print C:status;
+#X obj 172 349 print C:data;
+#X obj 142 377 print C:connected?;
+#X text 52 58 when using the same port for sending and receiving \,
+you must talk with real remote host (NOT localhost).;
+#X text 55 88 else you will simply be talking to yourself...;
+#X text 156 146 talk to yourself.;
+#X connect 0 0 7 0;
+#X connect 0 1 6 0;
+#X connect 0 2 5 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
+#X restore 172 492 pd sending/receiving on the same port;
+#X text 86 394 send to port:12345;
+#X text 72 409 listen on port:54321;
+#X text 396 394 send to port:54321;
+#X text 382 409 listen on port:12345;
+#X connect 0 0 3 0;
+#X connect 0 1 4 0;
+#X connect 0 2 5 0;
+#X connect 1 0 0 0;
+#X connect 2 0 8 0;
+#X connect 2 1 7 0;
+#X connect 2 2 6 0;
+#X connect 9 0 0 0;
+#X connect 10 0 0 0;
+#X connect 11 0 0 0;
+#X connect 12 0 2 0;
+#X connect 13 0 2 0;
+#X connect 14 0 2 0;
+#X connect 15 0 2 0;
diff --git a/udpsndrcv.pd b/udpsndrcv.pd
new file mode 100644
index 0000000..119ed0d
--- /dev/null
+++ b/udpsndrcv.pd
@@ -0,0 +1,71 @@
+#N canvas 512 227 613 300 10;
+#X obj 60 73 inlet;
+#X obj 116 174 udpclient;
+#X obj 43 249 outlet conn?;
+#X obj 145 258 outlet data;
+#X obj 260 270 outlet status;
+#X obj 60 105 t a a;
+#X obj 60 127 route status;
+#X obj 216 65 route connect disconnect;
+#X obj 116 196 t l l;
+#N canvas 5 49 450 300 received 0;
+#X obj 101 65 inlet;
+#X obj 101 87 list length;
+#X obj 101 131 delay 0;
+#X obj 190 172 +;
+#X obj 190 194 t f f;
+#X obj 130 223 f;
+#X obj 130 195 t b f;
+#X msg 101 153 0;
+#X obj 101 109 t b f f;
+#X obj 130 275 outlet received;
+#X msg 130 245 received \$1;
+#X obj 350 172 +;
+#X obj 350 194 t f f;
+#X obj 290 223 f;
+#X obj 236 54 inlet;
+#X msg 290 245 total \$1;
+#X obj 236 76 route bang reset;
+#X msg 290 112 0;
+#X connect 0 0 1 0;
+#X connect 1 0 8 0;
+#X connect 2 0 7 0;
+#X connect 3 0 4 0;
+#X connect 4 0 5 1;
+#X connect 4 1 3 1;
+#X connect 5 0 10 0;
+#X connect 6 0 5 0;
+#X connect 6 1 3 1;
+#X connect 7 0 6 0;
+#X connect 8 0 2 0;
+#X connect 8 1 3 0;
+#X connect 8 2 11 0;
+#X connect 10 0 9 0;
+#X connect 11 0 12 0;
+#X connect 12 0 13 1;
+#X connect 12 1 11 1;
+#X connect 13 0 15 0;
+#X connect 14 0 16 0;
+#X connect 15 0 9 0;
+#X connect 16 0 13 0;
+#X connect 16 1 17 0;
+#X connect 17 0 12 0;
+#X restore 260 241 pd received;
+#X obj 60 149 t b;
+#X obj 216 90 t b;
+#X msg 216 112 reset;
+#X connect 0 0 5 0;
+#X connect 1 0 8 0;
+#X connect 1 2 2 0;
+#X connect 5 0 6 0;
+#X connect 5 1 7 0;
+#X connect 6 0 10 0;
+#X connect 6 1 1 0;
+#X connect 7 0 11 0;
+#X connect 7 1 11 0;
+#X connect 8 0 3 0;
+#X connect 8 1 9 0;
+#X connect 9 0 4 0;
+#X connect 10 0 9 1;
+#X connect 11 0 12 0;
+#X connect 12 0 9 1;

-- 
pd-iemnet packaging



More information about the pkg-multimedia-commits mailing list