[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