summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am244
-rw-r--r--src/Makefile.in1510
-rw-r--r--src/app_thread.cpp195
-rw-r--r--src/app_thread.hpp88
-rw-r--r--src/atomic_counter.hpp163
-rw-r--r--src/atomic_ptr.hpp158
-rw-r--r--src/blob.hpp33
-rw-r--r--src/command.cpp38
-rw-r--r--src/command.hpp127
-rw-r--r--src/config.hpp86
-rw-r--r--src/ctx.cpp316
-rw-r--r--src/ctx.hpp156
-rw-r--r--src/decoder.hpp156
-rw-r--r--src/devpoll.cpp222
-rw-r--r--src/devpoll.hpp110
-rw-r--r--src/downstream.cpp101
-rw-r--r--src/downstream.hpp61
-rw-r--r--src/encoder.hpp160
-rw-r--r--src/epoll.cpp213
-rw-r--r--src/epoll.hpp106
-rw-r--r--src/err.cpp190
-rw-r--r--src/err.hpp123
-rw-r--r--src/fd.hpp44
-rw-r--r--src/forwarder.cpp38
-rw-r--r--src/forwarder.hpp31
-rw-r--r--src/fq.cpp130
-rw-r--r--src/fq.hpp68
-rw-r--r--src/i_endpoint.hpp43
-rw-r--r--src/i_engine.hpp49
-rw-r--r--src/i_inout.hpp60
-rw-r--r--src/i_poll_events.hpp45
-rw-r--r--src/io_object.cpp92
-rw-r--r--src/io_object.hpp77
-rw-r--r--src/io_thread.cpp105
-rw-r--r--src/io_thread.hpp85
-rw-r--r--src/ip.cpp335
-rw-r--r--src/ip.hpp69
-rw-r--r--src/kqueue.cpp226
-rw-r--r--src/kqueue.hpp113
-rw-r--r--src/lb.cpp123
-rw-r--r--src/lb.hpp65
-rw-r--r--src/libzmq.pc.in10
-rw-r--r--src/likely.hpp32
-rw-r--r--src/msg_content.hpp51
-rw-r--r--src/mutex.hpp120
-rw-r--r--src/object.cpp374
-rw-r--r--src/object.hpp118
-rw-r--r--src/options.cpp225
-rw-r--r--src/options.hpp68
-rw-r--r--src/owned.cpp71
-rw-r--r--src/owned.hpp89
-rw-r--r--src/pair.cpp139
-rw-r--r--src/pair.hpp63
-rw-r--r--src/pgm_receiver.cpp217
-rw-r--r--src/pgm_receiver.hpp122
-rw-r--r--src/pgm_sender.cpp160
-rw-r--r--src/pgm_sender.hpp95
-rw-r--r--src/pgm_socket.cpp538
-rw-r--r--src/pgm_socket.hpp105
-rw-r--r--src/pipe.cpp281
-rw-r--r--src/pipe.hpp169
-rw-r--r--src/platform.hpp.in228
-rw-r--r--src/poll.cpp207
-rw-r--r--src/poll.hpp113
-rw-r--r--src/poller.hpp72
-rw-r--r--src/prefix_tree.cpp180
-rw-r--r--src/prefix_tree.hpp55
-rw-r--r--src/pub.cpp177
-rw-r--r--src/pub.hpp70
-rw-r--r--src/queue.cpp101
-rw-r--r--src/queue.hpp31
-rw-r--r--src/rep.cpp280
-rw-r--r--src/rep.hpp85
-rw-r--r--src/req.cpp286
-rw-r--r--src/req.hpp93
-rw-r--r--src/select.cpp234
-rw-r--r--src/select.hpp123
-rw-r--r--src/session.cpp291
-rw-r--r--src/session.hpp104
-rw-r--r--src/signaler.cpp339
-rw-r--r--src/signaler.hpp71
-rw-r--r--src/socket_base.cpp681
-rw-r--r--src/socket_base.hpp177
-rw-r--r--src/stdint.hpp70
-rw-r--r--src/streamer.cpp38
-rw-r--r--src/streamer.hpp31
-rw-r--r--src/sub.cpp191
-rw-r--r--src/sub.hpp81
-rw-r--r--src/tcp_connecter.cpp307
-rw-r--r--src/tcp_connecter.hpp80
-rw-r--r--src/tcp_listener.cpp352
-rw-r--r--src/tcp_listener.hpp68
-rw-r--r--src/tcp_socket.cpp226
-rw-r--r--src/tcp_socket.hpp71
-rw-r--r--src/thread.cpp108
-rw-r--r--src/thread.hpp86
-rw-r--r--src/upstream.cpp98
-rw-r--r--src/upstream.hpp62
-rw-r--r--src/uuid.cpp235
-rw-r--r--src/uuid.hpp110
-rw-r--r--src/windows.hpp78
-rw-r--r--src/wire.hpp98
-rw-r--r--src/xrep.cpp271
-rw-r--r--src/xrep.hpp95
-rw-r--r--src/xreq.cpp118
-rw-r--r--src/xreq.hpp67
-rw-r--r--src/yarray.hpp110
-rw-r--r--src/yarray_item.hpp62
-rw-r--r--src/ypipe.hpp191
-rw-r--r--src/yqueue.hpp197
-rw-r--r--src/zmq.cpp663
-rw-r--r--src/zmq_connecter.cpp136
-rw-r--r--src/zmq_connecter.hpp88
-rw-r--r--src/zmq_decoder.cpp107
-rw-r--r--src/zmq_decoder.hpp59
-rw-r--r--src/zmq_encoder.cpp89
-rw-r--r--src/zmq_encoder.hpp55
-rw-r--r--src/zmq_engine.cpp195
-rw-r--r--src/zmq_engine.hpp86
-rw-r--r--src/zmq_init.cpp195
-rw-r--r--src/zmq_init.hpp89
-rw-r--r--src/zmq_listener.cpp75
-rw-r--r--src/zmq_listener.hpp67
123 files changed, 18804 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..fa97ca3
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,244 @@
+lib_LTLIBRARIES = libzmq.la
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libzmq.pc
+
+include_HEADERS = ../include/zmq.h ../include/zmq.hpp
+
+if BUILD_PGM
+pgm_sources = ../foreign/openpgm/@pgm_basename@/openpgm/pgm/packet.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/time.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/if.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/getifaddrs.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/getnodeaddr.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/indextoaddr.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/indextoname.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/nametoindex.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/inet_network.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/md5.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/gsi.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/tsi.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/signal.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/txwi.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/rxwi.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/transport.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/source.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/receiver.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/recv.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/pgm.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/timer.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/net.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/rate_control.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/async.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/checksum.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/reed_solomon.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/galois_tables.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/wsastrerror.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/glib-compat.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/backtrace.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/log.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/sockaddr.c \
+ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/version.c
+
+../foreign/openpgm/@pgm_basename@/openpgm/pgm/version.c: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/version_generator.py
+ python ../foreign/openpgm/@pgm_basename@/openpgm/pgm/version_generator.py > $@
+
+../foreign/openpgm/@pgm_basename@/openpgm/pgm/galois_tables.c: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/galois_generator.pl
+ perl ../foreign/openpgm/@pgm_basename@/openpgm/pgm/galois_generator.pl > $@
+endif
+
+nodist_libzmq_la_SOURCES = $(pgm_sources)
+
+libzmq_la_SOURCES = app_thread.hpp \
+ atomic_counter.hpp \
+ atomic_ptr.hpp \
+ blob.hpp \
+ command.hpp \
+ config.hpp \
+ ctx.hpp \
+ decoder.hpp \
+ devpoll.hpp \
+ downstream.hpp \
+ encoder.hpp \
+ epoll.hpp \
+ err.hpp \
+ fd.hpp \
+ forwarder.hpp \
+ fq.hpp \
+ i_inout.hpp \
+ io_object.hpp \
+ io_thread.hpp \
+ ip.hpp \
+ i_endpoint.hpp \
+ i_engine.hpp \
+ i_poll_events.hpp \
+ kqueue.hpp \
+ lb.hpp \
+ likely.hpp \
+ msg_content.hpp \
+ mutex.hpp \
+ object.hpp \
+ options.hpp \
+ owned.hpp \
+ pgm_receiver.hpp \
+ pgm_sender.hpp \
+ pgm_socket.hpp \
+ pipe.hpp \
+ platform.hpp \
+ poll.hpp \
+ poller.hpp \
+ pair.hpp \
+ prefix_tree.hpp \
+ pub.hpp \
+ queue.hpp \
+ rep.hpp \
+ req.hpp \
+ select.hpp \
+ session.hpp \
+ signaler.hpp \
+ socket_base.hpp \
+ stdint.hpp \
+ streamer.hpp \
+ sub.hpp \
+ tcp_connecter.hpp \
+ tcp_listener.hpp \
+ tcp_socket.hpp \
+ thread.hpp \
+ upstream.hpp \
+ uuid.hpp \
+ windows.hpp \
+ wire.hpp \
+ xrep.hpp \
+ xreq.hpp \
+ yarray.hpp \
+ yarray_item.hpp \
+ ypipe.hpp \
+ yqueue.hpp \
+ zmq_connecter.hpp \
+ zmq_decoder.hpp \
+ zmq_encoder.hpp \
+ zmq_engine.hpp \
+ zmq_init.hpp \
+ zmq_listener.hpp \
+ app_thread.cpp \
+ command.cpp \
+ ctx.cpp \
+ devpoll.cpp \
+ downstream.cpp \
+ epoll.cpp \
+ err.cpp \
+ forwarder.cpp \
+ fq.cpp \
+ io_object.cpp \
+ io_thread.cpp \
+ ip.cpp \
+ kqueue.cpp \
+ lb.cpp \
+ object.cpp \
+ options.cpp \
+ owned.cpp \
+ pgm_receiver.cpp \
+ pgm_sender.cpp \
+ pgm_socket.cpp \
+ pair.cpp \
+ prefix_tree.cpp \
+ pipe.cpp \
+ poll.cpp \
+ pub.cpp \
+ queue.cpp \
+ rep.cpp \
+ req.cpp \
+ select.cpp \
+ session.cpp \
+ signaler.cpp \
+ socket_base.cpp \
+ streamer.cpp \
+ sub.cpp \
+ tcp_connecter.cpp \
+ tcp_listener.cpp \
+ tcp_socket.cpp \
+ thread.cpp \
+ upstream.cpp \
+ uuid.cpp \
+ xrep.cpp \
+ xreq.cpp \
+ zmq.cpp \
+ zmq_connecter.cpp \
+ zmq_decoder.cpp \
+ zmq_encoder.cpp \
+ zmq_engine.cpp \
+ zmq_init.cpp \
+ zmq_listener.cpp
+
+if ON_MINGW
+libzmq_la_LDFLAGS = -no-undefined -avoid-version -version-info @LTVER@ @LIBZMQ_EXTRA_LDFLAGS@
+else
+libzmq_la_LDFLAGS = -version-info @LTVER@ @LIBZMQ_EXTRA_LDFLAGS@
+endif
+
+if BUILD_PGM
+
+if ON_MINGW
+libpgm_diff_flags = \
+ -D_WIN32_WINNT=0x0501 \
+ -DCONFIG_16BIT_CHECKSUM \
+ -DCONFIG_HAVE_IFR_NETMASK \
+ -DCONFIG_BIND_INADDR_ANY \
+ -DCONFIG_GALOIS_MUL_LUT \
+ -DIF_NAMESIZE=256 \
+ -DPGM_GNUC_INTERNAL=G_GNUC_INTERNAL \
+ -DCONFIG_HAVE_WSACMSGHDR \
+ -DGETTEXT_PACKAGE='"pgm"' \
+ -DG_LOG_DOMAIN='"Pgm"'
+
+else
+libpgm_diff_flags = \
+ -D__need_IOV_MAX \
+ -DCONFIG_16BIT_CHECKSUM \
+ -DCONFIG_HAVE_PSELECT \
+ -DCONFIG_HAVE_POLL \
+ -DCONFIG_HAVE_PPOLL \
+ -DCONFIG_HAVE_EPOLL \
+ -DCONFIG_HAVE_CLOCK_GETTIME \
+ -DCONFIG_HAVE_CLOCK_NANOSLEEP \
+ -DCONFIG_HAVE_NANOSLEEP \
+ -DCONFIG_HAVE_USLEEP \
+ -DCONFIG_HAVE_RTC \
+ -DCONFIG_HAVE_TSC \
+ -DCONFIG_HAVE_IFR_NETMASK \
+ -DCONFIG_HAVE_GETIFADDRS \
+ -DCONFIG_HAVE_GETHOSTBYNAME2 \
+ -DCONFIG_HAVE_GETPROTOBYNAME_R \
+ -DCONFIG_BIND_INADDR_ANY \
+ -DCONFIG_GALOIS_MUL_LUT \
+ -DCONFIG_HAVE_MCAST_JOIN \
+ -DCONFIG_HAVE_IP_MREQN \
+ -DCONFIG_HAVE_SPRINTF_GROUPING \
+ -DCONFIG_HAVE_HPET \
+ -DPGM_GNUC_INTERNAL=G_GNUC_INTERNAL \
+ -DGETTEXT_PACKAGE='"pgm"' \
+ -DG_LOG_DOMAIN='"Pgm"'
+endif
+
+libzmq_la_CFLAGS = -I$(top_srcdir)/foreign/openpgm/@pgm_basename@/openpgm/pgm/include/ @LIBZMQ_EXTRA_CXXFLAGS@ \
+ -Wall \
+ -pedantic \
+ -std=gnu99 \
+ -fno-strict-aliasing \
+ --param max-inline-insns-single=600 \
+ -D_REENTRANT \
+ -D_GNU_SOURCE \
+ ${libpgm_diff_flags}
+
+libzmq_la_CXXFLAGS = -I$(top_srcdir)/foreign/openpgm/@pgm_basename@/openpgm/pgm/include/ \
+ @LIBZMQ_EXTRA_CXXFLAGS@
+endif
+
+if BUILD_NO_PGM
+libzmq_la_CXXFLAGS = @LIBZMQ_EXTRA_CXXFLAGS@
+endif
+
+dist-hook:
+ -rm $(distdir)/platform.hpp
+
+
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..bc3f00f
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,1510 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src
+DIST_COMMON = $(include_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in $(srcdir)/libzmq.pc.in \
+ $(srcdir)/platform.hpp.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/config/libtool.m4 \
+ $(top_srcdir)/config/ltoptions.m4 \
+ $(top_srcdir)/config/ltsugar.m4 \
+ $(top_srcdir)/config/ltversion.m4 \
+ $(top_srcdir)/config/lt~obsolete.m4 $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = platform.hpp
+CONFIG_CLEAN_FILES = libzmq.pc
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgconfigdir)" \
+ "$(DESTDIR)$(includedir)"
+libLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libzmq_la_LIBADD =
+am_libzmq_la_OBJECTS = libzmq_la-app_thread.lo libzmq_la-command.lo \
+ libzmq_la-ctx.lo libzmq_la-devpoll.lo libzmq_la-downstream.lo \
+ libzmq_la-epoll.lo libzmq_la-err.lo libzmq_la-forwarder.lo \
+ libzmq_la-fq.lo libzmq_la-io_object.lo libzmq_la-io_thread.lo \
+ libzmq_la-ip.lo libzmq_la-kqueue.lo libzmq_la-lb.lo \
+ libzmq_la-object.lo libzmq_la-options.lo libzmq_la-owned.lo \
+ libzmq_la-pgm_receiver.lo libzmq_la-pgm_sender.lo \
+ libzmq_la-pgm_socket.lo libzmq_la-pair.lo \
+ libzmq_la-prefix_tree.lo libzmq_la-pipe.lo libzmq_la-poll.lo \
+ libzmq_la-pub.lo libzmq_la-queue.lo libzmq_la-rep.lo \
+ libzmq_la-req.lo libzmq_la-select.lo libzmq_la-session.lo \
+ libzmq_la-signaler.lo libzmq_la-socket_base.lo \
+ libzmq_la-streamer.lo libzmq_la-sub.lo \
+ libzmq_la-tcp_connecter.lo libzmq_la-tcp_listener.lo \
+ libzmq_la-tcp_socket.lo libzmq_la-thread.lo \
+ libzmq_la-upstream.lo libzmq_la-uuid.lo libzmq_la-xrep.lo \
+ libzmq_la-xreq.lo libzmq_la-zmq.lo libzmq_la-zmq_connecter.lo \
+ libzmq_la-zmq_decoder.lo libzmq_la-zmq_encoder.lo \
+ libzmq_la-zmq_engine.lo libzmq_la-zmq_init.lo \
+ libzmq_la-zmq_listener.lo
+@BUILD_PGM_TRUE@am__objects_1 = libzmq_la-packet.lo libzmq_la-time.lo \
+@BUILD_PGM_TRUE@ libzmq_la-if.lo libzmq_la-getifaddrs.lo \
+@BUILD_PGM_TRUE@ libzmq_la-getnodeaddr.lo \
+@BUILD_PGM_TRUE@ libzmq_la-indextoaddr.lo \
+@BUILD_PGM_TRUE@ libzmq_la-indextoname.lo \
+@BUILD_PGM_TRUE@ libzmq_la-nametoindex.lo \
+@BUILD_PGM_TRUE@ libzmq_la-inet_network.lo libzmq_la-md5.lo \
+@BUILD_PGM_TRUE@ libzmq_la-gsi.lo libzmq_la-tsi.lo \
+@BUILD_PGM_TRUE@ libzmq_la-signal.lo libzmq_la-txwi.lo \
+@BUILD_PGM_TRUE@ libzmq_la-rxwi.lo libzmq_la-transport.lo \
+@BUILD_PGM_TRUE@ libzmq_la-source.lo libzmq_la-receiver.lo \
+@BUILD_PGM_TRUE@ libzmq_la-recv.lo libzmq_la-pgm.lo \
+@BUILD_PGM_TRUE@ libzmq_la-timer.lo libzmq_la-net.lo \
+@BUILD_PGM_TRUE@ libzmq_la-rate_control.lo libzmq_la-async.lo \
+@BUILD_PGM_TRUE@ libzmq_la-checksum.lo \
+@BUILD_PGM_TRUE@ libzmq_la-reed_solomon.lo \
+@BUILD_PGM_TRUE@ libzmq_la-galois_tables.lo \
+@BUILD_PGM_TRUE@ libzmq_la-wsastrerror.lo \
+@BUILD_PGM_TRUE@ libzmq_la-glib-compat.lo \
+@BUILD_PGM_TRUE@ libzmq_la-backtrace.lo libzmq_la-log.lo \
+@BUILD_PGM_TRUE@ libzmq_la-sockaddr.lo libzmq_la-version.lo
+nodist_libzmq_la_OBJECTS = $(am__objects_1)
+libzmq_la_OBJECTS = $(am_libzmq_la_OBJECTS) \
+ $(nodist_libzmq_la_OBJECTS)
+libzmq_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(libzmq_la_CXXFLAGS) \
+ $(CXXFLAGS) $(libzmq_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/config/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(libzmq_la_SOURCES) $(nodist_libzmq_la_SOURCES)
+DIST_SOURCES = $(libzmq_la_SOURCES)
+pkgconfigDATA_INSTALL = $(INSTALL_DATA)
+DATA = $(pkgconfig_DATA)
+includeHEADERS_INSTALL = $(INSTALL_HEADER)
+HEADERS = $(include_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBZMQ_EXTRA_CXXFLAGS = @LIBZMQ_EXTRA_CXXFLAGS@
+LIBZMQ_EXTRA_LDFLAGS = @LIBZMQ_EXTRA_LDFLAGS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LTVER = @LTVER@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+have_asciidoc = @have_asciidoc@
+have_gzip = @have_gzip@
+have_perl = @have_perl@
+have_pkg_config = @have_pkg_config@
+have_python = @have_python@
+have_xmlto = @have_xmlto@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+inttypes = @inttypes@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pgm_basename = @pgm_basename@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+stdint = @stdint@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+lib_LTLIBRARIES = libzmq.la
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libzmq.pc
+include_HEADERS = ../include/zmq.h ../include/zmq.hpp
+@BUILD_PGM_TRUE@pgm_sources = ../foreign/openpgm/@pgm_basename@/openpgm/pgm/packet.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/time.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/if.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/getifaddrs.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/getnodeaddr.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/indextoaddr.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/indextoname.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/nametoindex.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/inet_network.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/md5.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/gsi.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/tsi.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/signal.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/txwi.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/rxwi.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/transport.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/source.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/receiver.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/recv.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/pgm.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/timer.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/net.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/rate_control.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/async.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/checksum.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/reed_solomon.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/galois_tables.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/wsastrerror.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/glib-compat.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/backtrace.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/log.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/sockaddr.c \
+@BUILD_PGM_TRUE@ ../foreign/openpgm/@pgm_basename@/openpgm/pgm/version.c
+
+nodist_libzmq_la_SOURCES = $(pgm_sources)
+libzmq_la_SOURCES = app_thread.hpp \
+ atomic_counter.hpp \
+ atomic_ptr.hpp \
+ blob.hpp \
+ command.hpp \
+ config.hpp \
+ ctx.hpp \
+ decoder.hpp \
+ devpoll.hpp \
+ downstream.hpp \
+ encoder.hpp \
+ epoll.hpp \
+ err.hpp \
+ fd.hpp \
+ forwarder.hpp \
+ fq.hpp \
+ i_inout.hpp \
+ io_object.hpp \
+ io_thread.hpp \
+ ip.hpp \
+ i_endpoint.hpp \
+ i_engine.hpp \
+ i_poll_events.hpp \
+ kqueue.hpp \
+ lb.hpp \
+ likely.hpp \
+ msg_content.hpp \
+ mutex.hpp \
+ object.hpp \
+ options.hpp \
+ owned.hpp \
+ pgm_receiver.hpp \
+ pgm_sender.hpp \
+ pgm_socket.hpp \
+ pipe.hpp \
+ platform.hpp \
+ poll.hpp \
+ poller.hpp \
+ pair.hpp \
+ prefix_tree.hpp \
+ pub.hpp \
+ queue.hpp \
+ rep.hpp \
+ req.hpp \
+ select.hpp \
+ session.hpp \
+ signaler.hpp \
+ socket_base.hpp \
+ stdint.hpp \
+ streamer.hpp \
+ sub.hpp \
+ tcp_connecter.hpp \
+ tcp_listener.hpp \
+ tcp_socket.hpp \
+ thread.hpp \
+ upstream.hpp \
+ uuid.hpp \
+ windows.hpp \
+ wire.hpp \
+ xrep.hpp \
+ xreq.hpp \
+ yarray.hpp \
+ yarray_item.hpp \
+ ypipe.hpp \
+ yqueue.hpp \
+ zmq_connecter.hpp \
+ zmq_decoder.hpp \
+ zmq_encoder.hpp \
+ zmq_engine.hpp \
+ zmq_init.hpp \
+ zmq_listener.hpp \
+ app_thread.cpp \
+ command.cpp \
+ ctx.cpp \
+ devpoll.cpp \
+ downstream.cpp \
+ epoll.cpp \
+ err.cpp \
+ forwarder.cpp \
+ fq.cpp \
+ io_object.cpp \
+ io_thread.cpp \
+ ip.cpp \
+ kqueue.cpp \
+ lb.cpp \
+ object.cpp \
+ options.cpp \
+ owned.cpp \
+ pgm_receiver.cpp \
+ pgm_sender.cpp \
+ pgm_socket.cpp \
+ pair.cpp \
+ prefix_tree.cpp \
+ pipe.cpp \
+ poll.cpp \
+ pub.cpp \
+ queue.cpp \
+ rep.cpp \
+ req.cpp \
+ select.cpp \
+ session.cpp \
+ signaler.cpp \
+ socket_base.cpp \
+ streamer.cpp \
+ sub.cpp \
+ tcp_connecter.cpp \
+ tcp_listener.cpp \
+ tcp_socket.cpp \
+ thread.cpp \
+ upstream.cpp \
+ uuid.cpp \
+ xrep.cpp \
+ xreq.cpp \
+ zmq.cpp \
+ zmq_connecter.cpp \
+ zmq_decoder.cpp \
+ zmq_encoder.cpp \
+ zmq_engine.cpp \
+ zmq_init.cpp \
+ zmq_listener.cpp
+
+@ON_MINGW_FALSE@libzmq_la_LDFLAGS = -version-info @LTVER@ @LIBZMQ_EXTRA_LDFLAGS@
+@ON_MINGW_TRUE@libzmq_la_LDFLAGS = -no-undefined -avoid-version -version-info @LTVER@ @LIBZMQ_EXTRA_LDFLAGS@
+@BUILD_PGM_TRUE@@ON_MINGW_FALSE@libpgm_diff_flags = \
+@BUILD_PGM_TRUE@@ON_MINGW_FALSE@ -D__need_IOV_MAX \
+@BUILD_PGM_TRUE@@ON_MINGW_FALSE@ -DCONFIG_16BIT_CHECKSUM \
+@BUILD_PGM_TRUE@@ON_MINGW_FALSE@ -DCONFIG_HAVE_PSELECT \
+@BUILD_PGM_TRUE@@ON_MINGW_FALSE@ -DCONFIG_HAVE_POLL \
+@BUILD_PGM_TRUE@@ON_MINGW_FALSE@ -DCONFIG_HAVE_PPOLL \
+@BUILD_PGM_TRUE@@ON_MINGW_FALSE@ -DCONFIG_HAVE_EPOLL \
+@BUILD_PGM_TRUE@@ON_MINGW_FALSE@ -DCONFIG_HAVE_CLOCK_GETTIME \
+@BUILD_PGM_TRUE@@ON_MINGW_FALSE@ -DCONFIG_HAVE_CLOCK_NANOSLEEP \
+@BUILD_PGM_TRUE@@ON_MINGW_FALSE@ -DCONFIG_HAVE_NANOSLEEP \
+@BUILD_PGM_TRUE@@ON_MINGW_FALSE@ -DCONFIG_HAVE_USLEEP \
+@BUILD_PGM_TRUE@@ON_MINGW_FALSE@ -DCONFIG_HAVE_RTC \
+@BUILD_PGM_TRUE@@ON_MINGW_FALSE@ -DCONFIG_HAVE_TSC \
+@BUILD_PGM_TRUE@@ON_MINGW_FALSE@ -DCONFIG_HAVE_IFR_NETMASK \
+@BUILD_PGM_TRUE@@ON_MINGW_FALSE@ -DCONFIG_HAVE_GETIFADDRS \
+@BUILD_PGM_TRUE@@ON_MINGW_FALSE@ -DCONFIG_HAVE_GETHOSTBYNAME2 \
+@BUILD_PGM_TRUE@@ON_MINGW_FALSE@ -DCONFIG_HAVE_GETPROTOBYNAME_R \
+@BUILD_PGM_TRUE@@ON_MINGW_FALSE@ -DCONFIG_BIND_INADDR_ANY \
+@BUILD_PGM_TRUE@@ON_MINGW_FALSE@ -DCONFIG_GALOIS_MUL_LUT \
+@BUILD_PGM_TRUE@@ON_MINGW_FALSE@ -DCONFIG_HAVE_MCAST_JOIN \
+@BUILD_PGM_TRUE@@ON_MINGW_FALSE@ -DCONFIG_HAVE_IP_MREQN \
+@BUILD_PGM_TRUE@@ON_MINGW_FALSE@ -DCONFIG_HAVE_SPRINTF_GROUPING \
+@BUILD_PGM_TRUE@@ON_MINGW_FALSE@ -DCONFIG_HAVE_HPET \
+@BUILD_PGM_TRUE@@ON_MINGW_FALSE@ -DPGM_GNUC_INTERNAL=G_GNUC_INTERNAL \
+@BUILD_PGM_TRUE@@ON_MINGW_FALSE@ -DGETTEXT_PACKAGE='"pgm"' \
+@BUILD_PGM_TRUE@@ON_MINGW_FALSE@ -DG_LOG_DOMAIN='"Pgm"'
+
+@BUILD_PGM_TRUE@@ON_MINGW_TRUE@libpgm_diff_flags = \
+@BUILD_PGM_TRUE@@ON_MINGW_TRUE@ -D_WIN32_WINNT=0x0501 \
+@BUILD_PGM_TRUE@@ON_MINGW_TRUE@ -DCONFIG_16BIT_CHECKSUM \
+@BUILD_PGM_TRUE@@ON_MINGW_TRUE@ -DCONFIG_HAVE_IFR_NETMASK \
+@BUILD_PGM_TRUE@@ON_MINGW_TRUE@ -DCONFIG_BIND_INADDR_ANY \
+@BUILD_PGM_TRUE@@ON_MINGW_TRUE@ -DCONFIG_GALOIS_MUL_LUT \
+@BUILD_PGM_TRUE@@ON_MINGW_TRUE@ -DIF_NAMESIZE=256 \
+@BUILD_PGM_TRUE@@ON_MINGW_TRUE@ -DPGM_GNUC_INTERNAL=G_GNUC_INTERNAL \
+@BUILD_PGM_TRUE@@ON_MINGW_TRUE@ -DCONFIG_HAVE_WSACMSGHDR \
+@BUILD_PGM_TRUE@@ON_MINGW_TRUE@ -DGETTEXT_PACKAGE='"pgm"' \
+@BUILD_PGM_TRUE@@ON_MINGW_TRUE@ -DG_LOG_DOMAIN='"Pgm"'
+
+@BUILD_PGM_TRUE@libzmq_la_CFLAGS = -I$(top_srcdir)/foreign/openpgm/@pgm_basename@/openpgm/pgm/include/ @LIBZMQ_EXTRA_CXXFLAGS@ \
+@BUILD_PGM_TRUE@ -Wall \
+@BUILD_PGM_TRUE@ -pedantic \
+@BUILD_PGM_TRUE@ -std=gnu99 \
+@BUILD_PGM_TRUE@ -fno-strict-aliasing \
+@BUILD_PGM_TRUE@ --param max-inline-insns-single=600 \
+@BUILD_PGM_TRUE@ -D_REENTRANT \
+@BUILD_PGM_TRUE@ -D_GNU_SOURCE \
+@BUILD_PGM_TRUE@ ${libpgm_diff_flags}
+
+@BUILD_NO_PGM_TRUE@libzmq_la_CXXFLAGS = @LIBZMQ_EXTRA_CXXFLAGS@
+@BUILD_PGM_TRUE@libzmq_la_CXXFLAGS = -I$(top_srcdir)/foreign/openpgm/@pgm_basename@/openpgm/pgm/include/ \
+@BUILD_PGM_TRUE@ @LIBZMQ_EXTRA_CXXFLAGS@
+
+all: platform.hpp
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .cpp .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+platform.hpp: stamp-h1
+ @if test ! -f $@; then \
+ rm -f stamp-h1; \
+ $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \
+ else :; fi
+
+stamp-h1: $(srcdir)/platform.hpp.in $(top_builddir)/config.status
+ @rm -f stamp-h1
+ cd $(top_builddir) && $(SHELL) ./config.status src/platform.hpp
+$(srcdir)/platform.hpp.in: $(am__configure_deps)
+ cd $(top_srcdir) && $(AUTOHEADER)
+ rm -f stamp-h1
+ touch $@
+
+distclean-hdr:
+ -rm -f platform.hpp stamp-h1
+libzmq.pc: $(top_builddir)/config.status $(srcdir)/libzmq.pc.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ f=$(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ p=$(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libzmq.la: $(libzmq_la_OBJECTS) $(libzmq_la_DEPENDENCIES)
+ $(libzmq_la_LINK) -rpath $(libdir) $(libzmq_la_OBJECTS) $(libzmq_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-app_thread.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-async.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-backtrace.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-checksum.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-command.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-ctx.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-devpoll.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-downstream.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-epoll.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-err.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-forwarder.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-fq.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-galois_tables.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-getifaddrs.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-getnodeaddr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-glib-compat.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-gsi.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-if.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-indextoaddr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-indextoname.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-inet_network.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-io_object.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-io_thread.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-ip.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-kqueue.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-lb.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-log.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-md5.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-nametoindex.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-net.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-object.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-options.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-owned.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-packet.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-pair.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-pgm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-pgm_receiver.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-pgm_sender.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-pgm_socket.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-pipe.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-poll.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-prefix_tree.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-pub.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-queue.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-rate_control.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-receiver.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-recv.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-reed_solomon.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-rep.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-req.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-rxwi.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-select.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-session.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-signal.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-signaler.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-sockaddr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-socket_base.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-source.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-streamer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-sub.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-tcp_connecter.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-tcp_listener.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-tcp_socket.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-thread.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-time.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-timer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-transport.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-tsi.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-txwi.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-upstream.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-uuid.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-version.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-wsastrerror.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-xrep.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-xreq.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-zmq.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-zmq_connecter.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-zmq_decoder.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-zmq_encoder.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-zmq_engine.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-zmq_init.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libzmq_la-zmq_listener.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+libzmq_la-packet.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/packet.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-packet.lo -MD -MP -MF $(DEPDIR)/libzmq_la-packet.Tpo -c -o libzmq_la-packet.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/packet.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/packet.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-packet.Tpo $(DEPDIR)/libzmq_la-packet.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/packet.c' object='libzmq_la-packet.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-packet.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/packet.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/packet.c
+
+libzmq_la-time.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/time.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-time.lo -MD -MP -MF $(DEPDIR)/libzmq_la-time.Tpo -c -o libzmq_la-time.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/time.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/time.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-time.Tpo $(DEPDIR)/libzmq_la-time.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/time.c' object='libzmq_la-time.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-time.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/time.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/time.c
+
+libzmq_la-if.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/if.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-if.lo -MD -MP -MF $(DEPDIR)/libzmq_la-if.Tpo -c -o libzmq_la-if.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/if.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/if.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-if.Tpo $(DEPDIR)/libzmq_la-if.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/if.c' object='libzmq_la-if.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-if.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/if.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/if.c
+
+libzmq_la-getifaddrs.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/getifaddrs.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-getifaddrs.lo -MD -MP -MF $(DEPDIR)/libzmq_la-getifaddrs.Tpo -c -o libzmq_la-getifaddrs.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/getifaddrs.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/getifaddrs.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-getifaddrs.Tpo $(DEPDIR)/libzmq_la-getifaddrs.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/getifaddrs.c' object='libzmq_la-getifaddrs.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-getifaddrs.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/getifaddrs.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/getifaddrs.c
+
+libzmq_la-getnodeaddr.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/getnodeaddr.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-getnodeaddr.lo -MD -MP -MF $(DEPDIR)/libzmq_la-getnodeaddr.Tpo -c -o libzmq_la-getnodeaddr.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/getnodeaddr.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/getnodeaddr.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-getnodeaddr.Tpo $(DEPDIR)/libzmq_la-getnodeaddr.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/getnodeaddr.c' object='libzmq_la-getnodeaddr.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-getnodeaddr.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/getnodeaddr.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/getnodeaddr.c
+
+libzmq_la-indextoaddr.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/indextoaddr.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-indextoaddr.lo -MD -MP -MF $(DEPDIR)/libzmq_la-indextoaddr.Tpo -c -o libzmq_la-indextoaddr.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/indextoaddr.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/indextoaddr.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-indextoaddr.Tpo $(DEPDIR)/libzmq_la-indextoaddr.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/indextoaddr.c' object='libzmq_la-indextoaddr.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-indextoaddr.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/indextoaddr.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/indextoaddr.c
+
+libzmq_la-indextoname.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/indextoname.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-indextoname.lo -MD -MP -MF $(DEPDIR)/libzmq_la-indextoname.Tpo -c -o libzmq_la-indextoname.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/indextoname.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/indextoname.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-indextoname.Tpo $(DEPDIR)/libzmq_la-indextoname.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/indextoname.c' object='libzmq_la-indextoname.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-indextoname.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/indextoname.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/indextoname.c
+
+libzmq_la-nametoindex.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/nametoindex.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-nametoindex.lo -MD -MP -MF $(DEPDIR)/libzmq_la-nametoindex.Tpo -c -o libzmq_la-nametoindex.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/nametoindex.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/nametoindex.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-nametoindex.Tpo $(DEPDIR)/libzmq_la-nametoindex.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/nametoindex.c' object='libzmq_la-nametoindex.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-nametoindex.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/nametoindex.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/nametoindex.c
+
+libzmq_la-inet_network.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/inet_network.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-inet_network.lo -MD -MP -MF $(DEPDIR)/libzmq_la-inet_network.Tpo -c -o libzmq_la-inet_network.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/inet_network.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/inet_network.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-inet_network.Tpo $(DEPDIR)/libzmq_la-inet_network.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/inet_network.c' object='libzmq_la-inet_network.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-inet_network.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/inet_network.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/inet_network.c
+
+libzmq_la-md5.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/md5.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-md5.lo -MD -MP -MF $(DEPDIR)/libzmq_la-md5.Tpo -c -o libzmq_la-md5.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/md5.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/md5.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-md5.Tpo $(DEPDIR)/libzmq_la-md5.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/md5.c' object='libzmq_la-md5.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-md5.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/md5.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/md5.c
+
+libzmq_la-gsi.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/gsi.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-gsi.lo -MD -MP -MF $(DEPDIR)/libzmq_la-gsi.Tpo -c -o libzmq_la-gsi.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/gsi.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/gsi.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-gsi.Tpo $(DEPDIR)/libzmq_la-gsi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/gsi.c' object='libzmq_la-gsi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-gsi.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/gsi.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/gsi.c
+
+libzmq_la-tsi.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/tsi.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-tsi.lo -MD -MP -MF $(DEPDIR)/libzmq_la-tsi.Tpo -c -o libzmq_la-tsi.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/tsi.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/tsi.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-tsi.Tpo $(DEPDIR)/libzmq_la-tsi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/tsi.c' object='libzmq_la-tsi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-tsi.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/tsi.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/tsi.c
+
+libzmq_la-signal.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/signal.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-signal.lo -MD -MP -MF $(DEPDIR)/libzmq_la-signal.Tpo -c -o libzmq_la-signal.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/signal.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/signal.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-signal.Tpo $(DEPDIR)/libzmq_la-signal.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/signal.c' object='libzmq_la-signal.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-signal.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/signal.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/signal.c
+
+libzmq_la-txwi.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/txwi.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-txwi.lo -MD -MP -MF $(DEPDIR)/libzmq_la-txwi.Tpo -c -o libzmq_la-txwi.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/txwi.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/txwi.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-txwi.Tpo $(DEPDIR)/libzmq_la-txwi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/txwi.c' object='libzmq_la-txwi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-txwi.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/txwi.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/txwi.c
+
+libzmq_la-rxwi.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/rxwi.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-rxwi.lo -MD -MP -MF $(DEPDIR)/libzmq_la-rxwi.Tpo -c -o libzmq_la-rxwi.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/rxwi.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/rxwi.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-rxwi.Tpo $(DEPDIR)/libzmq_la-rxwi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/rxwi.c' object='libzmq_la-rxwi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-rxwi.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/rxwi.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/rxwi.c
+
+libzmq_la-transport.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/transport.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-transport.lo -MD -MP -MF $(DEPDIR)/libzmq_la-transport.Tpo -c -o libzmq_la-transport.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/transport.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/transport.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-transport.Tpo $(DEPDIR)/libzmq_la-transport.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/transport.c' object='libzmq_la-transport.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-transport.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/transport.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/transport.c
+
+libzmq_la-source.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/source.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-source.lo -MD -MP -MF $(DEPDIR)/libzmq_la-source.Tpo -c -o libzmq_la-source.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/source.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/source.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-source.Tpo $(DEPDIR)/libzmq_la-source.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/source.c' object='libzmq_la-source.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-source.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/source.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/source.c
+
+libzmq_la-receiver.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/receiver.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-receiver.lo -MD -MP -MF $(DEPDIR)/libzmq_la-receiver.Tpo -c -o libzmq_la-receiver.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/receiver.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/receiver.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-receiver.Tpo $(DEPDIR)/libzmq_la-receiver.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/receiver.c' object='libzmq_la-receiver.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-receiver.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/receiver.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/receiver.c
+
+libzmq_la-recv.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/recv.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-recv.lo -MD -MP -MF $(DEPDIR)/libzmq_la-recv.Tpo -c -o libzmq_la-recv.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/recv.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/recv.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-recv.Tpo $(DEPDIR)/libzmq_la-recv.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/recv.c' object='libzmq_la-recv.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-recv.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/recv.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/recv.c
+
+libzmq_la-pgm.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/pgm.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-pgm.lo -MD -MP -MF $(DEPDIR)/libzmq_la-pgm.Tpo -c -o libzmq_la-pgm.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/pgm.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/pgm.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-pgm.Tpo $(DEPDIR)/libzmq_la-pgm.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/pgm.c' object='libzmq_la-pgm.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-pgm.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/pgm.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/pgm.c
+
+libzmq_la-timer.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/timer.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-timer.lo -MD -MP -MF $(DEPDIR)/libzmq_la-timer.Tpo -c -o libzmq_la-timer.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/timer.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/timer.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-timer.Tpo $(DEPDIR)/libzmq_la-timer.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/timer.c' object='libzmq_la-timer.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-timer.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/timer.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/timer.c
+
+libzmq_la-net.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/net.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-net.lo -MD -MP -MF $(DEPDIR)/libzmq_la-net.Tpo -c -o libzmq_la-net.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/net.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/net.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-net.Tpo $(DEPDIR)/libzmq_la-net.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/net.c' object='libzmq_la-net.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-net.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/net.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/net.c
+
+libzmq_la-rate_control.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/rate_control.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-rate_control.lo -MD -MP -MF $(DEPDIR)/libzmq_la-rate_control.Tpo -c -o libzmq_la-rate_control.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/rate_control.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/rate_control.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-rate_control.Tpo $(DEPDIR)/libzmq_la-rate_control.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/rate_control.c' object='libzmq_la-rate_control.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-rate_control.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/rate_control.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/rate_control.c
+
+libzmq_la-async.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/async.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-async.lo -MD -MP -MF $(DEPDIR)/libzmq_la-async.Tpo -c -o libzmq_la-async.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/async.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/async.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-async.Tpo $(DEPDIR)/libzmq_la-async.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/async.c' object='libzmq_la-async.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-async.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/async.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/async.c
+
+libzmq_la-checksum.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/checksum.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-checksum.lo -MD -MP -MF $(DEPDIR)/libzmq_la-checksum.Tpo -c -o libzmq_la-checksum.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/checksum.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/checksum.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-checksum.Tpo $(DEPDIR)/libzmq_la-checksum.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/checksum.c' object='libzmq_la-checksum.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-checksum.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/checksum.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/checksum.c
+
+libzmq_la-reed_solomon.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/reed_solomon.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-reed_solomon.lo -MD -MP -MF $(DEPDIR)/libzmq_la-reed_solomon.Tpo -c -o libzmq_la-reed_solomon.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/reed_solomon.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/reed_solomon.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-reed_solomon.Tpo $(DEPDIR)/libzmq_la-reed_solomon.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/reed_solomon.c' object='libzmq_la-reed_solomon.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-reed_solomon.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/reed_solomon.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/reed_solomon.c
+
+libzmq_la-galois_tables.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/galois_tables.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-galois_tables.lo -MD -MP -MF $(DEPDIR)/libzmq_la-galois_tables.Tpo -c -o libzmq_la-galois_tables.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/galois_tables.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/galois_tables.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-galois_tables.Tpo $(DEPDIR)/libzmq_la-galois_tables.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/galois_tables.c' object='libzmq_la-galois_tables.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-galois_tables.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/galois_tables.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/galois_tables.c
+
+libzmq_la-wsastrerror.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/wsastrerror.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-wsastrerror.lo -MD -MP -MF $(DEPDIR)/libzmq_la-wsastrerror.Tpo -c -o libzmq_la-wsastrerror.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/wsastrerror.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/wsastrerror.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-wsastrerror.Tpo $(DEPDIR)/libzmq_la-wsastrerror.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/wsastrerror.c' object='libzmq_la-wsastrerror.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-wsastrerror.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/wsastrerror.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/wsastrerror.c
+
+libzmq_la-glib-compat.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/glib-compat.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-glib-compat.lo -MD -MP -MF $(DEPDIR)/libzmq_la-glib-compat.Tpo -c -o libzmq_la-glib-compat.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/glib-compat.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/glib-compat.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-glib-compat.Tpo $(DEPDIR)/libzmq_la-glib-compat.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/glib-compat.c' object='libzmq_la-glib-compat.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-glib-compat.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/glib-compat.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/glib-compat.c
+
+libzmq_la-backtrace.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/backtrace.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-backtrace.lo -MD -MP -MF $(DEPDIR)/libzmq_la-backtrace.Tpo -c -o libzmq_la-backtrace.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/backtrace.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/backtrace.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-backtrace.Tpo $(DEPDIR)/libzmq_la-backtrace.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/backtrace.c' object='libzmq_la-backtrace.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-backtrace.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/backtrace.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/backtrace.c
+
+libzmq_la-log.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/log.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-log.lo -MD -MP -MF $(DEPDIR)/libzmq_la-log.Tpo -c -o libzmq_la-log.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/log.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/log.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-log.Tpo $(DEPDIR)/libzmq_la-log.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/log.c' object='libzmq_la-log.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-log.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/log.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/log.c
+
+libzmq_la-sockaddr.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/sockaddr.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-sockaddr.lo -MD -MP -MF $(DEPDIR)/libzmq_la-sockaddr.Tpo -c -o libzmq_la-sockaddr.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/sockaddr.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/sockaddr.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-sockaddr.Tpo $(DEPDIR)/libzmq_la-sockaddr.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/sockaddr.c' object='libzmq_la-sockaddr.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-sockaddr.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/sockaddr.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/sockaddr.c
+
+libzmq_la-version.lo: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/version.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -MT libzmq_la-version.lo -MD -MP -MF $(DEPDIR)/libzmq_la-version.Tpo -c -o libzmq_la-version.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/version.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/version.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libzmq_la-version.Tpo $(DEPDIR)/libzmq_la-version.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../foreign/openpgm/@pgm_basename@/openpgm/pgm/version.c' object='libzmq_la-version.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CFLAGS) $(CFLAGS) -c -o libzmq_la-version.lo `test -f '../foreign/openpgm/@pgm_basename@/openpgm/pgm/version.c' || echo '$(srcdir)/'`../foreign/openpgm/@pgm_basename@/openpgm/pgm/version.c
+
+.cpp.o:
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $<
+
+libzmq_la-app_thread.lo: app_thread.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-app_thread.lo -MD -MP -MF $(DEPDIR)/libzmq_la-app_thread.Tpo -c -o libzmq_la-app_thread.lo `test -f 'app_thread.cpp' || echo '$(srcdir)/'`app_thread.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-app_thread.Tpo $(DEPDIR)/libzmq_la-app_thread.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='app_thread.cpp' object='libzmq_la-app_thread.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-app_thread.lo `test -f 'app_thread.cpp' || echo '$(srcdir)/'`app_thread.cpp
+
+libzmq_la-command.lo: command.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-command.lo -MD -MP -MF $(DEPDIR)/libzmq_la-command.Tpo -c -o libzmq_la-command.lo `test -f 'command.cpp' || echo '$(srcdir)/'`command.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-command.Tpo $(DEPDIR)/libzmq_la-command.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='command.cpp' object='libzmq_la-command.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-command.lo `test -f 'command.cpp' || echo '$(srcdir)/'`command.cpp
+
+libzmq_la-ctx.lo: ctx.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-ctx.lo -MD -MP -MF $(DEPDIR)/libzmq_la-ctx.Tpo -c -o libzmq_la-ctx.lo `test -f 'ctx.cpp' || echo '$(srcdir)/'`ctx.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-ctx.Tpo $(DEPDIR)/libzmq_la-ctx.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='ctx.cpp' object='libzmq_la-ctx.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-ctx.lo `test -f 'ctx.cpp' || echo '$(srcdir)/'`ctx.cpp
+
+libzmq_la-devpoll.lo: devpoll.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-devpoll.lo -MD -MP -MF $(DEPDIR)/libzmq_la-devpoll.Tpo -c -o libzmq_la-devpoll.lo `test -f 'devpoll.cpp' || echo '$(srcdir)/'`devpoll.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-devpoll.Tpo $(DEPDIR)/libzmq_la-devpoll.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='devpoll.cpp' object='libzmq_la-devpoll.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-devpoll.lo `test -f 'devpoll.cpp' || echo '$(srcdir)/'`devpoll.cpp
+
+libzmq_la-downstream.lo: downstream.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-downstream.lo -MD -MP -MF $(DEPDIR)/libzmq_la-downstream.Tpo -c -o libzmq_la-downstream.lo `test -f 'downstream.cpp' || echo '$(srcdir)/'`downstream.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-downstream.Tpo $(DEPDIR)/libzmq_la-downstream.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='downstream.cpp' object='libzmq_la-downstream.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-downstream.lo `test -f 'downstream.cpp' || echo '$(srcdir)/'`downstream.cpp
+
+libzmq_la-epoll.lo: epoll.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-epoll.lo -MD -MP -MF $(DEPDIR)/libzmq_la-epoll.Tpo -c -o libzmq_la-epoll.lo `test -f 'epoll.cpp' || echo '$(srcdir)/'`epoll.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-epoll.Tpo $(DEPDIR)/libzmq_la-epoll.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='epoll.cpp' object='libzmq_la-epoll.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-epoll.lo `test -f 'epoll.cpp' || echo '$(srcdir)/'`epoll.cpp
+
+libzmq_la-err.lo: err.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-err.lo -MD -MP -MF $(DEPDIR)/libzmq_la-err.Tpo -c -o libzmq_la-err.lo `test -f 'err.cpp' || echo '$(srcdir)/'`err.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-err.Tpo $(DEPDIR)/libzmq_la-err.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='err.cpp' object='libzmq_la-err.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-err.lo `test -f 'err.cpp' || echo '$(srcdir)/'`err.cpp
+
+libzmq_la-forwarder.lo: forwarder.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-forwarder.lo -MD -MP -MF $(DEPDIR)/libzmq_la-forwarder.Tpo -c -o libzmq_la-forwarder.lo `test -f 'forwarder.cpp' || echo '$(srcdir)/'`forwarder.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-forwarder.Tpo $(DEPDIR)/libzmq_la-forwarder.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='forwarder.cpp' object='libzmq_la-forwarder.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-forwarder.lo `test -f 'forwarder.cpp' || echo '$(srcdir)/'`forwarder.cpp
+
+libzmq_la-fq.lo: fq.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-fq.lo -MD -MP -MF $(DEPDIR)/libzmq_la-fq.Tpo -c -o libzmq_la-fq.lo `test -f 'fq.cpp' || echo '$(srcdir)/'`fq.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-fq.Tpo $(DEPDIR)/libzmq_la-fq.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='fq.cpp' object='libzmq_la-fq.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-fq.lo `test -f 'fq.cpp' || echo '$(srcdir)/'`fq.cpp
+
+libzmq_la-io_object.lo: io_object.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-io_object.lo -MD -MP -MF $(DEPDIR)/libzmq_la-io_object.Tpo -c -o libzmq_la-io_object.lo `test -f 'io_object.cpp' || echo '$(srcdir)/'`io_object.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-io_object.Tpo $(DEPDIR)/libzmq_la-io_object.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='io_object.cpp' object='libzmq_la-io_object.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-io_object.lo `test -f 'io_object.cpp' || echo '$(srcdir)/'`io_object.cpp
+
+libzmq_la-io_thread.lo: io_thread.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-io_thread.lo -MD -MP -MF $(DEPDIR)/libzmq_la-io_thread.Tpo -c -o libzmq_la-io_thread.lo `test -f 'io_thread.cpp' || echo '$(srcdir)/'`io_thread.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-io_thread.Tpo $(DEPDIR)/libzmq_la-io_thread.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='io_thread.cpp' object='libzmq_la-io_thread.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-io_thread.lo `test -f 'io_thread.cpp' || echo '$(srcdir)/'`io_thread.cpp
+
+libzmq_la-ip.lo: ip.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-ip.lo -MD -MP -MF $(DEPDIR)/libzmq_la-ip.Tpo -c -o libzmq_la-ip.lo `test -f 'ip.cpp' || echo '$(srcdir)/'`ip.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-ip.Tpo $(DEPDIR)/libzmq_la-ip.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='ip.cpp' object='libzmq_la-ip.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-ip.lo `test -f 'ip.cpp' || echo '$(srcdir)/'`ip.cpp
+
+libzmq_la-kqueue.lo: kqueue.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-kqueue.lo -MD -MP -MF $(DEPDIR)/libzmq_la-kqueue.Tpo -c -o libzmq_la-kqueue.lo `test -f 'kqueue.cpp' || echo '$(srcdir)/'`kqueue.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-kqueue.Tpo $(DEPDIR)/libzmq_la-kqueue.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='kqueue.cpp' object='libzmq_la-kqueue.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-kqueue.lo `test -f 'kqueue.cpp' || echo '$(srcdir)/'`kqueue.cpp
+
+libzmq_la-lb.lo: lb.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-lb.lo -MD -MP -MF $(DEPDIR)/libzmq_la-lb.Tpo -c -o libzmq_la-lb.lo `test -f 'lb.cpp' || echo '$(srcdir)/'`lb.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-lb.Tpo $(DEPDIR)/libzmq_la-lb.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lb.cpp' object='libzmq_la-lb.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-lb.lo `test -f 'lb.cpp' || echo '$(srcdir)/'`lb.cpp
+
+libzmq_la-object.lo: object.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-object.lo -MD -MP -MF $(DEPDIR)/libzmq_la-object.Tpo -c -o libzmq_la-object.lo `test -f 'object.cpp' || echo '$(srcdir)/'`object.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-object.Tpo $(DEPDIR)/libzmq_la-object.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='object.cpp' object='libzmq_la-object.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-object.lo `test -f 'object.cpp' || echo '$(srcdir)/'`object.cpp
+
+libzmq_la-options.lo: options.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-options.lo -MD -MP -MF $(DEPDIR)/libzmq_la-options.Tpo -c -o libzmq_la-options.lo `test -f 'options.cpp' || echo '$(srcdir)/'`options.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-options.Tpo $(DEPDIR)/libzmq_la-options.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='options.cpp' object='libzmq_la-options.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-options.lo `test -f 'options.cpp' || echo '$(srcdir)/'`options.cpp
+
+libzmq_la-owned.lo: owned.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-owned.lo -MD -MP -MF $(DEPDIR)/libzmq_la-owned.Tpo -c -o libzmq_la-owned.lo `test -f 'owned.cpp' || echo '$(srcdir)/'`owned.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-owned.Tpo $(DEPDIR)/libzmq_la-owned.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='owned.cpp' object='libzmq_la-owned.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-owned.lo `test -f 'owned.cpp' || echo '$(srcdir)/'`owned.cpp
+
+libzmq_la-pgm_receiver.lo: pgm_receiver.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-pgm_receiver.lo -MD -MP -MF $(DEPDIR)/libzmq_la-pgm_receiver.Tpo -c -o libzmq_la-pgm_receiver.lo `test -f 'pgm_receiver.cpp' || echo '$(srcdir)/'`pgm_receiver.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-pgm_receiver.Tpo $(DEPDIR)/libzmq_la-pgm_receiver.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='pgm_receiver.cpp' object='libzmq_la-pgm_receiver.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-pgm_receiver.lo `test -f 'pgm_receiver.cpp' || echo '$(srcdir)/'`pgm_receiver.cpp
+
+libzmq_la-pgm_sender.lo: pgm_sender.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-pgm_sender.lo -MD -MP -MF $(DEPDIR)/libzmq_la-pgm_sender.Tpo -c -o libzmq_la-pgm_sender.lo `test -f 'pgm_sender.cpp' || echo '$(srcdir)/'`pgm_sender.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-pgm_sender.Tpo $(DEPDIR)/libzmq_la-pgm_sender.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='pgm_sender.cpp' object='libzmq_la-pgm_sender.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-pgm_sender.lo `test -f 'pgm_sender.cpp' || echo '$(srcdir)/'`pgm_sender.cpp
+
+libzmq_la-pgm_socket.lo: pgm_socket.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-pgm_socket.lo -MD -MP -MF $(DEPDIR)/libzmq_la-pgm_socket.Tpo -c -o libzmq_la-pgm_socket.lo `test -f 'pgm_socket.cpp' || echo '$(srcdir)/'`pgm_socket.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-pgm_socket.Tpo $(DEPDIR)/libzmq_la-pgm_socket.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='pgm_socket.cpp' object='libzmq_la-pgm_socket.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-pgm_socket.lo `test -f 'pgm_socket.cpp' || echo '$(srcdir)/'`pgm_socket.cpp
+
+libzmq_la-pair.lo: pair.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-pair.lo -MD -MP -MF $(DEPDIR)/libzmq_la-pair.Tpo -c -o libzmq_la-pair.lo `test -f 'pair.cpp' || echo '$(srcdir)/'`pair.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-pair.Tpo $(DEPDIR)/libzmq_la-pair.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='pair.cpp' object='libzmq_la-pair.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-pair.lo `test -f 'pair.cpp' || echo '$(srcdir)/'`pair.cpp
+
+libzmq_la-prefix_tree.lo: prefix_tree.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-prefix_tree.lo -MD -MP -MF $(DEPDIR)/libzmq_la-prefix_tree.Tpo -c -o libzmq_la-prefix_tree.lo `test -f 'prefix_tree.cpp' || echo '$(srcdir)/'`prefix_tree.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-prefix_tree.Tpo $(DEPDIR)/libzmq_la-prefix_tree.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='prefix_tree.cpp' object='libzmq_la-prefix_tree.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-prefix_tree.lo `test -f 'prefix_tree.cpp' || echo '$(srcdir)/'`prefix_tree.cpp
+
+libzmq_la-pipe.lo: pipe.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-pipe.lo -MD -MP -MF $(DEPDIR)/libzmq_la-pipe.Tpo -c -o libzmq_la-pipe.lo `test -f 'pipe.cpp' || echo '$(srcdir)/'`pipe.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-pipe.Tpo $(DEPDIR)/libzmq_la-pipe.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='pipe.cpp' object='libzmq_la-pipe.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-pipe.lo `test -f 'pipe.cpp' || echo '$(srcdir)/'`pipe.cpp
+
+libzmq_la-poll.lo: poll.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-poll.lo -MD -MP -MF $(DEPDIR)/libzmq_la-poll.Tpo -c -o libzmq_la-poll.lo `test -f 'poll.cpp' || echo '$(srcdir)/'`poll.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-poll.Tpo $(DEPDIR)/libzmq_la-poll.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='poll.cpp' object='libzmq_la-poll.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-poll.lo `test -f 'poll.cpp' || echo '$(srcdir)/'`poll.cpp
+
+libzmq_la-pub.lo: pub.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-pub.lo -MD -MP -MF $(DEPDIR)/libzmq_la-pub.Tpo -c -o libzmq_la-pub.lo `test -f 'pub.cpp' || echo '$(srcdir)/'`pub.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-pub.Tpo $(DEPDIR)/libzmq_la-pub.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='pub.cpp' object='libzmq_la-pub.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-pub.lo `test -f 'pub.cpp' || echo '$(srcdir)/'`pub.cpp
+
+libzmq_la-queue.lo: queue.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-queue.lo -MD -MP -MF $(DEPDIR)/libzmq_la-queue.Tpo -c -o libzmq_la-queue.lo `test -f 'queue.cpp' || echo '$(srcdir)/'`queue.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-queue.Tpo $(DEPDIR)/libzmq_la-queue.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='queue.cpp' object='libzmq_la-queue.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-queue.lo `test -f 'queue.cpp' || echo '$(srcdir)/'`queue.cpp
+
+libzmq_la-rep.lo: rep.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-rep.lo -MD -MP -MF $(DEPDIR)/libzmq_la-rep.Tpo -c -o libzmq_la-rep.lo `test -f 'rep.cpp' || echo '$(srcdir)/'`rep.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-rep.Tpo $(DEPDIR)/libzmq_la-rep.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='rep.cpp' object='libzmq_la-rep.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-rep.lo `test -f 'rep.cpp' || echo '$(srcdir)/'`rep.cpp
+
+libzmq_la-req.lo: req.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-req.lo -MD -MP -MF $(DEPDIR)/libzmq_la-req.Tpo -c -o libzmq_la-req.lo `test -f 'req.cpp' || echo '$(srcdir)/'`req.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-req.Tpo $(DEPDIR)/libzmq_la-req.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='req.cpp' object='libzmq_la-req.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-req.lo `test -f 'req.cpp' || echo '$(srcdir)/'`req.cpp
+
+libzmq_la-select.lo: select.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-select.lo -MD -MP -MF $(DEPDIR)/libzmq_la-select.Tpo -c -o libzmq_la-select.lo `test -f 'select.cpp' || echo '$(srcdir)/'`select.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-select.Tpo $(DEPDIR)/libzmq_la-select.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='select.cpp' object='libzmq_la-select.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-select.lo `test -f 'select.cpp' || echo '$(srcdir)/'`select.cpp
+
+libzmq_la-session.lo: session.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-session.lo -MD -MP -MF $(DEPDIR)/libzmq_la-session.Tpo -c -o libzmq_la-session.lo `test -f 'session.cpp' || echo '$(srcdir)/'`session.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-session.Tpo $(DEPDIR)/libzmq_la-session.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='session.cpp' object='libzmq_la-session.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-session.lo `test -f 'session.cpp' || echo '$(srcdir)/'`session.cpp
+
+libzmq_la-signaler.lo: signaler.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-signaler.lo -MD -MP -MF $(DEPDIR)/libzmq_la-signaler.Tpo -c -o libzmq_la-signaler.lo `test -f 'signaler.cpp' || echo '$(srcdir)/'`signaler.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-signaler.Tpo $(DEPDIR)/libzmq_la-signaler.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='signaler.cpp' object='libzmq_la-signaler.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-signaler.lo `test -f 'signaler.cpp' || echo '$(srcdir)/'`signaler.cpp
+
+libzmq_la-socket_base.lo: socket_base.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-socket_base.lo -MD -MP -MF $(DEPDIR)/libzmq_la-socket_base.Tpo -c -o libzmq_la-socket_base.lo `test -f 'socket_base.cpp' || echo '$(srcdir)/'`socket_base.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-socket_base.Tpo $(DEPDIR)/libzmq_la-socket_base.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='socket_base.cpp' object='libzmq_la-socket_base.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-socket_base.lo `test -f 'socket_base.cpp' || echo '$(srcdir)/'`socket_base.cpp
+
+libzmq_la-streamer.lo: streamer.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-streamer.lo -MD -MP -MF $(DEPDIR)/libzmq_la-streamer.Tpo -c -o libzmq_la-streamer.lo `test -f 'streamer.cpp' || echo '$(srcdir)/'`streamer.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-streamer.Tpo $(DEPDIR)/libzmq_la-streamer.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='streamer.cpp' object='libzmq_la-streamer.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-streamer.lo `test -f 'streamer.cpp' || echo '$(srcdir)/'`streamer.cpp
+
+libzmq_la-sub.lo: sub.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-sub.lo -MD -MP -MF $(DEPDIR)/libzmq_la-sub.Tpo -c -o libzmq_la-sub.lo `test -f 'sub.cpp' || echo '$(srcdir)/'`sub.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-sub.Tpo $(DEPDIR)/libzmq_la-sub.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='sub.cpp' object='libzmq_la-sub.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-sub.lo `test -f 'sub.cpp' || echo '$(srcdir)/'`sub.cpp
+
+libzmq_la-tcp_connecter.lo: tcp_connecter.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-tcp_connecter.lo -MD -MP -MF $(DEPDIR)/libzmq_la-tcp_connecter.Tpo -c -o libzmq_la-tcp_connecter.lo `test -f 'tcp_connecter.cpp' || echo '$(srcdir)/'`tcp_connecter.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-tcp_connecter.Tpo $(DEPDIR)/libzmq_la-tcp_connecter.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tcp_connecter.cpp' object='libzmq_la-tcp_connecter.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-tcp_connecter.lo `test -f 'tcp_connecter.cpp' || echo '$(srcdir)/'`tcp_connecter.cpp
+
+libzmq_la-tcp_listener.lo: tcp_listener.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-tcp_listener.lo -MD -MP -MF $(DEPDIR)/libzmq_la-tcp_listener.Tpo -c -o libzmq_la-tcp_listener.lo `test -f 'tcp_listener.cpp' || echo '$(srcdir)/'`tcp_listener.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-tcp_listener.Tpo $(DEPDIR)/libzmq_la-tcp_listener.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tcp_listener.cpp' object='libzmq_la-tcp_listener.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-tcp_listener.lo `test -f 'tcp_listener.cpp' || echo '$(srcdir)/'`tcp_listener.cpp
+
+libzmq_la-tcp_socket.lo: tcp_socket.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-tcp_socket.lo -MD -MP -MF $(DEPDIR)/libzmq_la-tcp_socket.Tpo -c -o libzmq_la-tcp_socket.lo `test -f 'tcp_socket.cpp' || echo '$(srcdir)/'`tcp_socket.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-tcp_socket.Tpo $(DEPDIR)/libzmq_la-tcp_socket.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tcp_socket.cpp' object='libzmq_la-tcp_socket.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-tcp_socket.lo `test -f 'tcp_socket.cpp' || echo '$(srcdir)/'`tcp_socket.cpp
+
+libzmq_la-thread.lo: thread.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-thread.lo -MD -MP -MF $(DEPDIR)/libzmq_la-thread.Tpo -c -o libzmq_la-thread.lo `test -f 'thread.cpp' || echo '$(srcdir)/'`thread.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-thread.Tpo $(DEPDIR)/libzmq_la-thread.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='thread.cpp' object='libzmq_la-thread.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-thread.lo `test -f 'thread.cpp' || echo '$(srcdir)/'`thread.cpp
+
+libzmq_la-upstream.lo: upstream.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-upstream.lo -MD -MP -MF $(DEPDIR)/libzmq_la-upstream.Tpo -c -o libzmq_la-upstream.lo `test -f 'upstream.cpp' || echo '$(srcdir)/'`upstream.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-upstream.Tpo $(DEPDIR)/libzmq_la-upstream.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='upstream.cpp' object='libzmq_la-upstream.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-upstream.lo `test -f 'upstream.cpp' || echo '$(srcdir)/'`upstream.cpp
+
+libzmq_la-uuid.lo: uuid.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-uuid.lo -MD -MP -MF $(DEPDIR)/libzmq_la-uuid.Tpo -c -o libzmq_la-uuid.lo `test -f 'uuid.cpp' || echo '$(srcdir)/'`uuid.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-uuid.Tpo $(DEPDIR)/libzmq_la-uuid.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='uuid.cpp' object='libzmq_la-uuid.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-uuid.lo `test -f 'uuid.cpp' || echo '$(srcdir)/'`uuid.cpp
+
+libzmq_la-xrep.lo: xrep.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-xrep.lo -MD -MP -MF $(DEPDIR)/libzmq_la-xrep.Tpo -c -o libzmq_la-xrep.lo `test -f 'xrep.cpp' || echo '$(srcdir)/'`xrep.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-xrep.Tpo $(DEPDIR)/libzmq_la-xrep.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='xrep.cpp' object='libzmq_la-xrep.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-xrep.lo `test -f 'xrep.cpp' || echo '$(srcdir)/'`xrep.cpp
+
+libzmq_la-xreq.lo: xreq.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-xreq.lo -MD -MP -MF $(DEPDIR)/libzmq_la-xreq.Tpo -c -o libzmq_la-xreq.lo `test -f 'xreq.cpp' || echo '$(srcdir)/'`xreq.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-xreq.Tpo $(DEPDIR)/libzmq_la-xreq.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='xreq.cpp' object='libzmq_la-xreq.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-xreq.lo `test -f 'xreq.cpp' || echo '$(srcdir)/'`xreq.cpp
+
+libzmq_la-zmq.lo: zmq.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-zmq.lo -MD -MP -MF $(DEPDIR)/libzmq_la-zmq.Tpo -c -o libzmq_la-zmq.lo `test -f 'zmq.cpp' || echo '$(srcdir)/'`zmq.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-zmq.Tpo $(DEPDIR)/libzmq_la-zmq.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='zmq.cpp' object='libzmq_la-zmq.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-zmq.lo `test -f 'zmq.cpp' || echo '$(srcdir)/'`zmq.cpp
+
+libzmq_la-zmq_connecter.lo: zmq_connecter.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-zmq_connecter.lo -MD -MP -MF $(DEPDIR)/libzmq_la-zmq_connecter.Tpo -c -o libzmq_la-zmq_connecter.lo `test -f 'zmq_connecter.cpp' || echo '$(srcdir)/'`zmq_connecter.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-zmq_connecter.Tpo $(DEPDIR)/libzmq_la-zmq_connecter.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='zmq_connecter.cpp' object='libzmq_la-zmq_connecter.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-zmq_connecter.lo `test -f 'zmq_connecter.cpp' || echo '$(srcdir)/'`zmq_connecter.cpp
+
+libzmq_la-zmq_decoder.lo: zmq_decoder.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-zmq_decoder.lo -MD -MP -MF $(DEPDIR)/libzmq_la-zmq_decoder.Tpo -c -o libzmq_la-zmq_decoder.lo `test -f 'zmq_decoder.cpp' || echo '$(srcdir)/'`zmq_decoder.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-zmq_decoder.Tpo $(DEPDIR)/libzmq_la-zmq_decoder.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='zmq_decoder.cpp' object='libzmq_la-zmq_decoder.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-zmq_decoder.lo `test -f 'zmq_decoder.cpp' || echo '$(srcdir)/'`zmq_decoder.cpp
+
+libzmq_la-zmq_encoder.lo: zmq_encoder.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-zmq_encoder.lo -MD -MP -MF $(DEPDIR)/libzmq_la-zmq_encoder.Tpo -c -o libzmq_la-zmq_encoder.lo `test -f 'zmq_encoder.cpp' || echo '$(srcdir)/'`zmq_encoder.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-zmq_encoder.Tpo $(DEPDIR)/libzmq_la-zmq_encoder.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='zmq_encoder.cpp' object='libzmq_la-zmq_encoder.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-zmq_encoder.lo `test -f 'zmq_encoder.cpp' || echo '$(srcdir)/'`zmq_encoder.cpp
+
+libzmq_la-zmq_engine.lo: zmq_engine.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-zmq_engine.lo -MD -MP -MF $(DEPDIR)/libzmq_la-zmq_engine.Tpo -c -o libzmq_la-zmq_engine.lo `test -f 'zmq_engine.cpp' || echo '$(srcdir)/'`zmq_engine.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-zmq_engine.Tpo $(DEPDIR)/libzmq_la-zmq_engine.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='zmq_engine.cpp' object='libzmq_la-zmq_engine.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-zmq_engine.lo `test -f 'zmq_engine.cpp' || echo '$(srcdir)/'`zmq_engine.cpp
+
+libzmq_la-zmq_init.lo: zmq_init.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-zmq_init.lo -MD -MP -MF $(DEPDIR)/libzmq_la-zmq_init.Tpo -c -o libzmq_la-zmq_init.lo `test -f 'zmq_init.cpp' || echo '$(srcdir)/'`zmq_init.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-zmq_init.Tpo $(DEPDIR)/libzmq_la-zmq_init.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='zmq_init.cpp' object='libzmq_la-zmq_init.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-zmq_init.lo `test -f 'zmq_init.cpp' || echo '$(srcdir)/'`zmq_init.cpp
+
+libzmq_la-zmq_listener.lo: zmq_listener.cpp
+@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -MT libzmq_la-zmq_listener.lo -MD -MP -MF $(DEPDIR)/libzmq_la-zmq_listener.Tpo -c -o libzmq_la-zmq_listener.lo `test -f 'zmq_listener.cpp' || echo '$(srcdir)/'`zmq_listener.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libzmq_la-zmq_listener.Tpo $(DEPDIR)/libzmq_la-zmq_listener.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='zmq_listener.cpp' object='libzmq_la-zmq_listener.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libzmq_la_CXXFLAGS) $(CXXFLAGS) -c -o libzmq_la-zmq_listener.lo `test -f 'zmq_listener.cpp' || echo '$(srcdir)/'`zmq_listener.cpp
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-pkgconfigDATA: $(pkgconfig_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(pkgconfigdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)"
+ @list='$(pkgconfig_DATA)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(pkgconfigDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgconfigdir)/$$f'"; \
+ $(pkgconfigDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgconfigdir)/$$f"; \
+ done
+
+uninstall-pkgconfigDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkgconfig_DATA)'; for p in $$list; do \
+ f=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(pkgconfigdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(pkgconfigdir)/$$f"; \
+ done
+install-includeHEADERS: $(include_HEADERS)
+ @$(NORMAL_INSTALL)
+ test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)"
+ @list='$(include_HEADERS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(includeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(includedir)/$$f'"; \
+ $(includeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(includedir)/$$f"; \
+ done
+
+uninstall-includeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(include_HEADERS)'; for p in $$list; do \
+ f=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(includedir)/$$f'"; \
+ rm -f "$(DESTDIR)$(includedir)/$$f"; \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) platform.hpp.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) platform.hpp.in $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) platform.hpp.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) platform.hpp.in $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$(top_distdir)" distdir="$(distdir)" \
+ dist-hook
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(DATA) $(HEADERS) platform.hpp
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(includedir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-hdr distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-includeHEADERS install-pkgconfigDATA
+
+install-dvi: install-dvi-am
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES \
+ uninstall-pkgconfigDATA
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libLTLIBRARIES clean-libtool ctags dist-hook distclean \
+ distclean-compile distclean-generic distclean-hdr \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am \
+ install-includeHEADERS install-info install-info-am \
+ install-libLTLIBRARIES install-man install-pdf install-pdf-am \
+ install-pkgconfigDATA install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-includeHEADERS \
+ uninstall-libLTLIBRARIES uninstall-pkgconfigDATA
+
+
+@BUILD_PGM_TRUE@../foreign/openpgm/@pgm_basename@/openpgm/pgm/version.c: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/version_generator.py
+@BUILD_PGM_TRUE@ python ../foreign/openpgm/@pgm_basename@/openpgm/pgm/version_generator.py > $@
+
+@BUILD_PGM_TRUE@../foreign/openpgm/@pgm_basename@/openpgm/pgm/galois_tables.c: ../foreign/openpgm/@pgm_basename@/openpgm/pgm/galois_generator.pl
+@BUILD_PGM_TRUE@ perl ../foreign/openpgm/@pgm_basename@/openpgm/pgm/galois_generator.pl > $@
+
+dist-hook:
+ -rm $(distdir)/platform.hpp
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/app_thread.cpp b/src/app_thread.cpp
new file mode 100644
index 0000000..fbf034c
--- /dev/null
+++ b/src/app_thread.cpp
@@ -0,0 +1,195 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <new>
+#include <algorithm>
+
+#include "../include/zmq.h"
+
+#include "platform.hpp"
+
+#if defined ZMQ_HAVE_WINDOWS
+#include "windows.hpp"
+#if defined _MSC_VER
+#include <intrin.h>
+#endif
+#else
+#include <unistd.h>
+#endif
+
+#include "app_thread.hpp"
+#include "ctx.hpp"
+#include "err.hpp"
+#include "pipe.hpp"
+#include "config.hpp"
+#include "socket_base.hpp"
+#include "pair.hpp"
+#include "pub.hpp"
+#include "sub.hpp"
+#include "req.hpp"
+#include "rep.hpp"
+#include "xreq.hpp"
+#include "xrep.hpp"
+#include "upstream.hpp"
+#include "downstream.hpp"
+
+// If the RDTSC is available we use it to prevent excessive
+// polling for commands. The nice thing here is that it will work on any
+// system with x86 architecture and gcc or MSVC compiler.
+#if (defined __GNUC__ && (defined __i386__ || defined __x86_64__)) ||\
+ (defined _MSC_VER && (defined _M_IX86 || defined _M_X64))
+#define ZMQ_DELAY_COMMANDS
+#endif
+
+zmq::app_thread_t::app_thread_t (ctx_t *ctx_,
+ uint32_t thread_slot_) :
+ object_t (ctx_, thread_slot_),
+ last_processing_time (0),
+ terminated (false)
+{
+}
+
+zmq::app_thread_t::~app_thread_t ()
+{
+ zmq_assert (sockets.empty ());
+}
+
+void zmq::app_thread_t::stop ()
+{
+ send_stop ();
+}
+
+zmq::signaler_t *zmq::app_thread_t::get_signaler ()
+{
+ return &signaler;
+}
+
+bool zmq::app_thread_t::process_commands (bool block_, bool throttle_)
+{
+ bool received;
+ command_t cmd;
+ if (block_) {
+ received = signaler.recv (&cmd, true);
+ zmq_assert (received);
+ }
+ else {
+
+#if defined ZMQ_DELAY_COMMANDS
+ // Optimised version of command processing - it doesn't have to check
+ // for incoming commands each time. It does so only if certain time
+ // elapsed since last command processing. Command delay varies
+ // depending on CPU speed: It's ~1ms on 3GHz CPU, ~2ms on 1.5GHz CPU
+ // etc. The optimisation makes sense only on platforms where getting
+ // a timestamp is a very cheap operation (tens of nanoseconds).
+ if (throttle_) {
+
+ // Get timestamp counter.
+#if defined __GNUC__
+ uint32_t low;
+ uint32_t high;
+ __asm__ volatile ("rdtsc" : "=a" (low), "=d" (high));
+ uint64_t current_time = (uint64_t) high << 32 | low;
+#elif defined _MSC_VER
+ uint64_t current_time = __rdtsc ();
+#else
+#error
+#endif
+
+ // Check whether certain time have elapsed since last command
+ // processing.
+ if (current_time - last_processing_time <= max_command_delay)
+ return !terminated;
+ last_processing_time = current_time;
+ }
+#endif
+
+ // Check whether there are any commands pending for this thread.
+ received = signaler.recv (&cmd, false);
+ }
+
+ // Process all the commands available at the moment.
+ while (received) {
+ cmd.destination->process_command (cmd);
+ received = signaler.recv (&cmd, false);
+ }
+
+ return !terminated;
+}
+
+zmq::socket_base_t *zmq::app_thread_t::create_socket (int type_)
+{
+ socket_base_t *s = NULL;
+ switch (type_) {
+ case ZMQ_PAIR:
+ s = new (std::nothrow) pair_t (this);
+ break;
+ case ZMQ_PUB:
+ s = new (std::nothrow) pub_t (this);
+ break;
+ case ZMQ_SUB:
+ s = new (std::nothrow) sub_t (this);
+ break;
+ case ZMQ_REQ:
+ s = new (std::nothrow) req_t (this);
+ break;
+ case ZMQ_REP:
+ s = new (std::nothrow) rep_t (this);
+ break;
+ case ZMQ_XREQ:
+ s = new (std::nothrow) xreq_t (this);
+ break;
+ case ZMQ_XREP:
+ s = new (std::nothrow) xrep_t (this);
+ break;
+ case ZMQ_UPSTREAM:
+ s = new (std::nothrow) upstream_t (this);
+ break;
+ case ZMQ_DOWNSTREAM:
+ s = new (std::nothrow) downstream_t (this);
+ break;
+ default:
+ if (sockets.empty ())
+ get_ctx ()->no_sockets (this);
+ errno = EINVAL;
+ return NULL;
+ }
+ zmq_assert (s);
+
+ sockets.push_back (s);
+
+ return s;
+}
+
+void zmq::app_thread_t::remove_socket (socket_base_t *socket_)
+{
+ sockets.erase (socket_);
+ if (sockets.empty ())
+ get_ctx ()->no_sockets (this);
+}
+
+void zmq::app_thread_t::process_stop ()
+{
+ terminated = true;
+}
+
+bool zmq::app_thread_t::is_terminated ()
+{
+ return terminated;
+}
+
diff --git a/src/app_thread.hpp b/src/app_thread.hpp
new file mode 100644
index 0000000..f0deaab
--- /dev/null
+++ b/src/app_thread.hpp
@@ -0,0 +1,88 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_APP_THREAD_HPP_INCLUDED__
+#define __ZMQ_APP_THREAD_HPP_INCLUDED__
+
+#include <vector>
+
+#include "stdint.hpp"
+#include "object.hpp"
+#include "yarray.hpp"
+#include "signaler.hpp"
+
+namespace zmq
+{
+
+ class app_thread_t : public object_t
+ {
+ public:
+
+ app_thread_t (class ctx_t *ctx_, uint32_t thread_slot_);
+
+ ~app_thread_t ();
+
+ // Interrupt blocking call if the app thread is stuck in one.
+ // This function is is called from a different thread!
+ void stop ();
+
+ // Returns signaler associated with this application thread.
+ signaler_t *get_signaler ();
+
+ // Processes commands sent to this thread (if any). If 'block' is
+ // set to true, returns only after at least one command was processed.
+ // If throttle argument is true, commands are processed at most once
+ // in a predefined time period. The function returns false is the
+ // associated context was terminated, true otherwise.
+ bool process_commands (bool block_, bool throttle_);
+
+ // Create a socket of a specified type.
+ class socket_base_t *create_socket (int type_);
+
+ // Unregister the socket from the app_thread (called by socket itself).
+ void remove_socket (class socket_base_t *socket_);
+
+ // Returns true is the associated context was already terminated.
+ bool is_terminated ();
+
+ private:
+
+ // Command handlers.
+ void process_stop ();
+
+ // All the sockets created from this application thread.
+ typedef yarray_t <socket_base_t> sockets_t;
+ sockets_t sockets;
+
+ // App thread's signaler object.
+ signaler_t signaler;
+
+ // Timestamp of when commands were processed the last time.
+ uint64_t last_processing_time;
+
+ // If true, 'stop' command was already received.
+ bool terminated;
+
+ app_thread_t (const app_thread_t&);
+ void operator = (const app_thread_t&);
+ };
+
+}
+
+#endif
diff --git a/src/atomic_counter.hpp b/src/atomic_counter.hpp
new file mode 100644
index 0000000..b446627
--- /dev/null
+++ b/src/atomic_counter.hpp
@@ -0,0 +1,163 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_ATOMIC_COUNTER_HPP_INCLUDED__
+#define __ZMQ_ATOMIC_COUNTER_HPP_INCLUDED__
+
+#include "stdint.hpp"
+#include "platform.hpp"
+
+#if defined ZMQ_FORCE_MUTEXES
+#define ZMQ_ATOMIC_COUNTER_MUTEX
+#elif (defined __i386__ || defined __x86_64__) && defined __GNUC__
+#define ZMQ_ATOMIC_COUNTER_X86
+#elif defined ZMQ_HAVE_WINDOWS
+#define ZMQ_ATOMIC_COUNTER_WINDOWS
+#elif (defined ZMQ_HAVE_SOLARIS || defined ZMQ_HAVE_NETBSD)
+#define ZMQ_ATOMIC_COUNTER_ATOMIC_H
+#else
+#define ZMQ_ATOMIC_COUNTER_MUTEX
+#endif
+
+#if defined ZMQ_ATOMIC_COUNTER_MUTEX
+#include "mutex.hpp"
+#elif defined ZMQ_ATOMIC_COUNTER_WINDOWS
+#include "windows.hpp"
+#elif defined ZMQ_ATOMIC_COUNTER_ATOMIC_H
+#include <atomic.h>
+#endif
+
+namespace zmq
+{
+
+ // This class represents an integer that can be incremented/decremented
+ // in atomic fashion.
+
+ class atomic_counter_t
+ {
+ public:
+
+ typedef uint32_t integer_t;
+
+ inline atomic_counter_t (integer_t value_ = 0) :
+ value (value_)
+ {
+ }
+
+ inline ~atomic_counter_t ()
+ {
+ }
+
+ // Set counter value (not thread-safe).
+ inline void set (integer_t value_)
+ {
+ value = value_;
+ }
+
+ // Atomic addition. Returns the old value.
+ inline integer_t add (integer_t increment_)
+ {
+ integer_t old_value;
+
+#if defined ZMQ_ATOMIC_COUNTER_WINDOWS
+ old_value = InterlockedExchangeAdd ((LONG*) &value, increment_);
+#elif defined ZMQ_ATOMIC_COUNTER_ATOMIC_H
+ integer_t new_value = atomic_add_32_nv (&value, increment_);
+ old_value = new_value - increment_;
+#elif defined ZMQ_ATOMIC_COUNTER_X86
+ __asm__ volatile (
+ "lock; xadd %0, %1 \n\t"
+ : "=r" (old_value), "=m" (value)
+ : "0" (increment_), "m" (value)
+ : "cc", "memory");
+#elif defined ZMQ_ATOMIC_COUNTER_MUTEX
+ sync.lock ();
+ old_value = value;
+ value += increment_;
+ sync.unlock ();
+#else
+#error atomic_counter is not implemented for this platform
+#endif
+ return old_value;
+ }
+
+ // Atomic subtraction. Returns false if the counter drops to zero.
+ inline bool sub (integer_t decrement)
+ {
+#if defined ZMQ_ATOMIC_COUNTER_WINDOWS
+ LONG delta = - ((LONG) decrement);
+ integer_t old = InterlockedExchangeAdd ((LONG*) &value, delta);
+ return old - decrement != 0;
+#elif defined ZMQ_ATOMIC_COUNTER_ATOMIC_H
+ int32_t delta = - ((int32_t) decrement);
+ integer_t nv = atomic_add_32_nv (&value, delta);
+ return nv != 0;
+#elif defined ZMQ_ATOMIC_COUNTER_X86
+ integer_t oldval = -decrement;
+ volatile integer_t *val = &value;
+ __asm__ volatile ("lock; xaddl %0,%1"
+ : "=r" (oldval), "=m" (*val)
+ : "0" (oldval), "m" (*val)
+ : "cc", "memory");
+ return oldval != decrement;
+#elif defined ZMQ_ATOMIC_COUNTER_MUTEX
+ sync.lock ();
+ value -= decrement;
+ bool result = value ? true : false;
+ sync.unlock ();
+ return result;
+#else
+#error atomic_counter is not implemented for this platform
+#endif
+ }
+
+ inline integer_t get ()
+ {
+ return value;
+ }
+
+ private:
+
+ volatile integer_t value;
+#if defined ZMQ_ATOMIC_COUNTER_MUTEX
+ mutex_t sync;
+#endif
+
+ atomic_counter_t (const atomic_counter_t&);
+ void operator = (const atomic_counter_t&);
+ };
+
+}
+
+// Remove macros local to this file.
+#if defined ZMQ_ATOMIC_COUNTER_WINDOWS
+#undef ZMQ_ATOMIC_COUNTER_WINDOWS
+#endif
+#if defined ZMQ_ATOMIC_COUNTER_ATOMIC_H
+#undef ZMQ_ATOMIC_COUNTER_ATOMIC_H
+#endif
+#if defined ZMQ_ATOMIC_COUNTER_X86
+#undef ZMQ_ATOMIC_COUNTER_X86
+#endif
+#if defined ZMQ_ATOMIC_COUNTER_MUTEX
+#undef ZMQ_ATOMIC_COUNTER_MUTEX
+#endif
+
+#endif
+
diff --git a/src/atomic_ptr.hpp b/src/atomic_ptr.hpp
new file mode 100644
index 0000000..54db64f
--- /dev/null
+++ b/src/atomic_ptr.hpp
@@ -0,0 +1,158 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_ATOMIC_PTR_HPP_INCLUDED__
+#define __ZMQ_ATOMIC_PTR_HPP_INCLUDED__
+
+#include "platform.hpp"
+
+#if defined ZMQ_FORCE_MUTEXES
+#define ZMQ_ATOMIC_PTR_MUTEX
+#elif (defined __i386__ || defined __x86_64__) && defined __GNUC__
+#define ZMQ_ATOMIC_PTR_X86
+#elif defined ZMQ_HAVE_WINDOWS
+#define ZMQ_ATOMIC_PTR_WINDOWS
+#elif (defined ZMQ_HAVE_SOLARIS || defined ZMQ_HAVE_NETBSD)
+#define ZMQ_ATOMIC_PTR_ATOMIC_H
+#else
+#define ZMQ_ATOMIC_PTR_MUTEX
+#endif
+
+#if defined ZMQ_ATOMIC_PTR_MUTEX
+#include "mutex.hpp"
+#elif defined ZMQ_ATOMIC_PTR_WINDOWS
+#include "windows.hpp"
+#elif defined ZMQ_ATOMIC_PTR_ATOMIC_H
+#include <atomic.h>
+#endif
+
+namespace zmq
+{
+
+ // This class encapsulates several atomic operations on pointers.
+
+ template <typename T> class atomic_ptr_t
+ {
+ public:
+
+ // Initialise atomic pointer
+ inline atomic_ptr_t ()
+ {
+ ptr = NULL;
+ }
+
+ // Destroy atomic pointer
+ inline ~atomic_ptr_t ()
+ {
+ }
+
+ // Set value of atomic pointer in a non-threadsafe way
+ // Use this function only when you are sure that at most one
+ // thread is accessing the pointer at the moment.
+ inline void set (T *ptr_)
+ {
+ this->ptr = ptr_;
+ }
+
+ // Perform atomic 'exchange pointers' operation. Pointer is set
+ // to the 'val' value. Old value is returned.
+ inline T *xchg (T *val_)
+ {
+#if defined ZMQ_ATOMIC_PTR_WINDOWS
+ return (T*) InterlockedExchangePointer ((PVOID*) &ptr, val_);
+#elif defined ZMQ_ATOMIC_PTR_ATOMIC_H
+ return (T*) atomic_swap_ptr (&ptr, val_);
+#elif defined ZMQ_ATOMIC_PTR_X86
+ T *old;
+ __asm__ volatile (
+ "lock; xchg %0, %2"
+ : "=r" (old), "=m" (ptr)
+ : "m" (ptr), "0" (val_));
+ return old;
+#elif defined ZMQ_ATOMIC_PTR_MUTEX
+ sync.lock ();
+ T *old = (T*) ptr;
+ ptr = val_;
+ sync.unlock ();
+ return old;
+#else
+#error atomic_ptr is not implemented for this platform
+#endif
+ }
+
+ // Perform atomic 'compare and swap' operation on the pointer.
+ // The pointer is compared to 'cmp' argument and if they are
+ // equal, its value is set to 'val'. Old value of the pointer
+ // is returned.
+ inline T *cas (T *cmp_, T *val_)
+ {
+#if defined ZMQ_ATOMIC_PTR_WINDOWS
+ return (T*) InterlockedCompareExchangePointer (
+ (volatile PVOID*) &ptr, val_, cmp_);
+#elif defined ZMQ_ATOMIC_PTR_ATOMIC_H
+ return (T*) atomic_cas_ptr (&ptr, cmp_, val_);
+#elif defined ZMQ_ATOMIC_PTR_X86
+ T *old;
+ __asm__ volatile (
+ "lock; cmpxchg %2, %3"
+ : "=a" (old), "=m" (ptr)
+ : "r" (val_), "m" (ptr), "0" (cmp_)
+ : "cc");
+ return old;
+#elif defined ZMQ_ATOMIC_PTR_MUTEX
+ sync.lock ();
+ T *old = (T*) ptr;
+ if (ptr == cmp_)
+ ptr = val_;
+ sync.unlock ();
+ return old;
+#else
+#error atomic_ptr is not implemented for this platform
+#endif
+ }
+
+ private:
+
+ volatile T *ptr;
+#if defined ZMQ_ATOMIC_PTR_MUTEX
+ mutex_t sync;
+#endif
+
+ atomic_ptr_t (const atomic_ptr_t&);
+ void operator = (const atomic_ptr_t&);
+ };
+
+}
+
+// Remove macros local to this file.
+#if defined ZMQ_ATOMIC_PTR_WINDOWS
+#undef ZMQ_ATOMIC_PTR_WINDOWS
+#endif
+#if defined ZMQ_ATOMIC_PTR_ATOMIC_H
+#undef ZMQ_ATOMIC_PTR_ATOMIC_H
+#endif
+#if defined ZMQ_ATOMIC_PTR_X86
+#undef ZMQ_ATOMIC_PTR_X86
+#endif
+#if defined ZMQ_ATOMIC_PTR_MUTEX
+#undef ZMQ_ATOMIC_PTR_MUTEX
+#endif
+
+#endif
+
diff --git a/src/blob.hpp b/src/blob.hpp
new file mode 100644
index 0000000..a4fa8cd
--- /dev/null
+++ b/src/blob.hpp
@@ -0,0 +1,33 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_BLOB_HPP_INCLUDED__
+#define __ZMQ_BLOB_HPP_INCLUDED__
+
+#include <string>
+
+namespace zmq
+{
+
+ // Object to hold dynamically allocated opaque binary data.
+ typedef std::basic_string <unsigned char> blob_t;
+
+}
+
+#endif
diff --git a/src/command.cpp b/src/command.cpp
new file mode 100644
index 0000000..8bf7ea2
--- /dev/null
+++ b/src/command.cpp
@@ -0,0 +1,38 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdlib.h>
+
+#include "command.hpp"
+
+void zmq::deallocate_command (command_t *cmd_)
+{
+ switch (cmd_->type) {
+ case command_t::attach:
+ if (cmd_->args.attach.peer_identity)
+ free (cmd_->args.attach.peer_identity);
+ break;
+ case command_t::bind:
+ if (cmd_->args.bind.peer_identity)
+ free (cmd_->args.bind.peer_identity);
+ break;
+ default:
+ /* noop */;
+ }
+}
diff --git a/src/command.hpp b/src/command.hpp
new file mode 100644
index 0000000..3d00cd7
--- /dev/null
+++ b/src/command.hpp
@@ -0,0 +1,127 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_COMMAND_HPP_INCLUDED__
+#define __ZMQ_COMMAND_HPP_INCLUDED__
+
+#include "stdint.hpp"
+
+namespace zmq
+{
+
+ // This structure defines the commands that can be sent between threads.
+
+ struct command_t
+ {
+ // Object to process the command.
+ class object_t *destination;
+
+ enum type_t
+ {
+ stop,
+ plug,
+ own,
+ attach,
+ bind,
+ revive,
+ reader_info,
+ pipe_term,
+ pipe_term_ack,
+ term_req,
+ term,
+ term_ack
+ } type;
+
+ union {
+
+ // Sent to I/O thread to let it know that it should
+ // terminate itself.
+ struct {
+ } stop;
+
+ // Sent to I/O object to make it register with its I/O thread.
+ struct {
+ } plug;
+
+ // Sent to socket to let it know about the newly created object.
+ struct {
+ class owned_t *object;
+ } own;
+
+ // Attach the engine to the session.
+ struct {
+ struct i_engine *engine;
+ unsigned char peer_identity_size;
+ unsigned char *peer_identity;
+ } attach;
+
+ // Sent from session to socket to establish pipe(s) between them.
+ // Caller have used inc_seqnum beforehand sending the command.
+ struct {
+ class reader_t *in_pipe;
+ class writer_t *out_pipe;
+ unsigned char peer_identity_size;
+ unsigned char *peer_identity;
+ } bind;
+
+ // Sent by pipe writer to inform dormant pipe reader that there
+ // are messages in the pipe.
+ struct {
+ } revive;
+
+ // Sent by pipe reader to inform pipe writer
+ // about how many messages it has read so far.
+ // Used to implement the flow control.
+ struct {
+ uint64_t msgs_read;
+ } reader_info;
+
+ // Sent by pipe reader to pipe writer to ask it to terminate
+ // its end of the pipe.
+ struct {
+ } pipe_term;
+
+ // Pipe writer acknowledges pipe_term command.
+ struct {
+ } pipe_term_ack;
+
+ // Sent by I/O object ot the socket to request the shutdown of
+ // the I/O object.
+ struct {
+ class owned_t *object;
+ } term_req;
+
+ // Sent by socket to I/O object to start its shutdown.
+ struct {
+ } term;
+
+ // Sent by I/O object to the socket to acknowledge it has
+ // shut down.
+ struct {
+ } term_ack;
+
+ } args;
+ };
+
+ // Function to deallocate dynamically allocated components of the command.
+ void deallocate_command (command_t *cmd_);
+
+}
+
+#endif
diff --git a/src/config.hpp b/src/config.hpp
new file mode 100644
index 0000000..2c0ac2d
--- /dev/null
+++ b/src/config.hpp
@@ -0,0 +1,86 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_CONFIG_HPP_INCLUDED__
+#define __ZMQ_CONFIG_HPP_INCLUDED__
+
+namespace zmq
+{
+
+ // Compile-time settings.
+
+ enum
+ {
+ // Maximal number of OS threads that can own 0MQ sockets
+ // at the same time.
+ max_app_threads = 512,
+
+ // Number of new messages in message pipe needed to trigger new memory
+ // allocation. Setting this parameter to 256 decreases the impact of
+ // memory allocation by approximately 99.6%
+ message_pipe_granularity = 256,
+
+ // Number of signals that can be read by the signaler
+ // using a single system call.
+ signal_buffer_size = 8,
+
+ // Determines how often does socket poll for new commands when it
+ // still has unprocessed messages to handle. Thus, if it is set to 100,
+ // socket will process 100 inbound messages before doing the poll.
+ // If there are no unprocessed messages available, poll is done
+ // immediately. Decreasing the value trades overall latency for more
+ // real-time behaviour (less latency peaks).
+ inbound_poll_rate = 100,
+
+ // Maximal batching size for engines with receiving functionality.
+ // So, if there are 10 messages that fit into the batch size, all of
+ // them may be read by a single 'recv' system call, thus avoiding
+ // unnecessary network stack traversals.
+ in_batch_size = 8192,
+
+ // Maximal batching size for engines with sending functionality.
+ // So, if there are 10 messages that fit into the batch size, all of
+ // them may be written by a single 'send' system call, thus avoiding
+ // unnecessary network stack traversals.
+ out_batch_size = 8192,
+
+ // Maximal delta between high and low watermark.
+ max_wm_delta = 1024,
+
+ // Maximum number of events the I/O thread can process in one go.
+ max_io_events = 256,
+
+ // Maximal wait time for a timer (milliseconds).
+ max_timer_period = 100,
+
+ // Maximal delay to process command in API thread (in CPU ticks).
+ // 3,000,000 ticks equals to 1 - 2 milliseconds on current CPUs.
+ max_command_delay = 3000000,
+
+ // Maximal number of non-accepted connections that can be held by
+ // TCP listener object.
+ tcp_connection_backlog = 10,
+
+ // Maximum transport data unit size for PGM (TPDU).
+ pgm_max_tpdu = 1500
+ };
+
+}
+
+#endif
diff --git a/src/ctx.cpp b/src/ctx.cpp
new file mode 100644
index 0000000..f0e177d
--- /dev/null
+++ b/src/ctx.cpp
@@ -0,0 +1,316 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <new>
+#include <string.h>
+
+#include "../include/zmq.h"
+
+#include "ctx.hpp"
+#include "socket_base.hpp"
+#include "app_thread.hpp"
+#include "io_thread.hpp"
+#include "platform.hpp"
+#include "err.hpp"
+#include "pipe.hpp"
+
+#if defined ZMQ_HAVE_WINDOWS
+#include "windows.h"
+#endif
+
+zmq::ctx_t::ctx_t (uint32_t io_threads_) :
+ sockets (0),
+ terminated (false)
+{
+#ifdef ZMQ_HAVE_WINDOWS
+ // Intialise Windows sockets. Note that WSAStartup can be called multiple
+ // times given that WSACleanup will be called for each WSAStartup.
+ WORD version_requested = MAKEWORD (2, 2);
+ WSADATA wsa_data;
+ int rc = WSAStartup (version_requested, &wsa_data);
+ zmq_assert (rc == 0);
+ zmq_assert (LOBYTE (wsa_data.wVersion) == 2 &&
+ HIBYTE (wsa_data.wVersion) == 2);
+#endif
+
+ // Initialise the array of signalers.
+ signalers_count = max_app_threads + io_threads_;
+ signalers = (signaler_t**) malloc (sizeof (signaler_t*) * signalers_count);
+ zmq_assert (signalers);
+ memset (signalers, 0, sizeof (signaler_t*) * signalers_count);
+
+ // Create I/O thread objects and launch them.
+ for (uint32_t i = 0; i != io_threads_; i++) {
+ io_thread_t *io_thread = new (std::nothrow) io_thread_t (this, i);
+ zmq_assert (io_thread);
+ io_threads.push_back (io_thread);
+ signalers [i] = io_thread->get_signaler ();
+ io_thread->start ();
+ }
+}
+
+int zmq::ctx_t::term ()
+{
+ // First send stop command to application threads so that any
+ // blocking calls are interrupted.
+ for (app_threads_t::size_type i = 0; i != app_threads.size (); i++)
+ app_threads [i].app_thread->stop ();
+
+ // Then mark context as terminated.
+ term_sync.lock ();
+ zmq_assert (!terminated);
+ terminated = true;
+ bool destroy = (sockets == 0);
+ term_sync.unlock ();
+
+ // If there are no sockets open, destroy the context immediately.
+ if (destroy)
+ delete this;
+
+ return 0;
+}
+
+zmq::ctx_t::~ctx_t ()
+{
+ // Ask I/O threads to terminate. If stop signal wasn't sent to I/O
+ // thread subsequent invocation of destructor would hang-up.
+ for (io_threads_t::size_type i = 0; i != io_threads.size (); i++)
+ io_threads [i]->stop ();
+
+ // Wait till I/O threads actually terminate.
+ for (io_threads_t::size_type i = 0; i != io_threads.size (); i++)
+ delete io_threads [i];
+
+ // Close all application theads, sockets, io_objects etc.
+ for (app_threads_t::size_type i = 0; i != app_threads.size (); i++)
+ delete app_threads [i].app_thread;
+
+ // Deallocate all the orphaned pipes.
+ while (!pipes.empty ())
+ delete *pipes.begin ();
+
+ // Deallocate the array of pointers to signalers. No special work is
+ // needed as signalers themselves were deallocated with their
+ // corresponding (app_/io_) thread objects.
+ free (signalers);
+
+#ifdef ZMQ_HAVE_WINDOWS
+ // On Windows, uninitialise socket layer.
+ int rc = WSACleanup ();
+ wsa_assert (rc != SOCKET_ERROR);
+#endif
+}
+
+zmq::socket_base_t *zmq::ctx_t::create_socket (int type_)
+{
+ app_threads_sync.lock ();
+
+ // Find whether the calling thread has app_thread_t object associated
+ // already. At the same time find an unused app_thread_t so that it can
+ // be used if there's no associated object for the calling thread.
+ // Check whether thread ID is already assigned. If so, return it.
+ app_threads_t::size_type unused = app_threads.size ();
+ app_threads_t::size_type current;
+ for (current = 0; current != app_threads.size (); current++) {
+ if (app_threads [current].associated &&
+ thread_t::equal (thread_t::id (), app_threads [current].tid))
+ break;
+ if (!app_threads [current].associated)
+ unused = current;
+ }
+
+ // If no app_thread_t is associated with the calling thread,
+ // associate it with one of the unused app_thread_t objects.
+ if (current == app_threads.size ()) {
+
+ // If all the existing app_threads are already used, create one more.
+ if (unused == app_threads.size ()) {
+
+ // If max_app_threads limit was reached, return error.
+ if (app_threads.size () == max_app_threads) {
+ app_threads_sync.unlock ();
+ errno = EMTHREAD;
+ return NULL;
+ }
+
+ // Create the new application thread proxy object.
+ app_thread_info_t info;
+ info.associated = false;
+ info.app_thread = new (std::nothrow) app_thread_t (this,
+ io_threads.size () + app_threads.size ());
+ zmq_assert (info.app_thread);
+ signalers [io_threads.size () + app_threads.size ()] =
+ info.app_thread->get_signaler ();
+ app_threads.push_back (info);
+ }
+
+ // Incidentally, this works both when there is an unused app_thread
+ // and when a new one is created.
+ current = unused;
+
+ // Associate the selected app_thread with the OS thread.
+ app_threads [current].associated = true;
+ app_threads [current].tid = thread_t::id ();
+ }
+
+ app_thread_t *thread = app_threads [current].app_thread;
+ app_threads_sync.unlock ();
+
+ socket_base_t *s = thread->create_socket (type_);
+ if (!s)
+ return NULL;
+
+ term_sync.lock ();
+ sockets++;
+ term_sync.unlock ();
+
+ return s;
+}
+
+void zmq::ctx_t::destroy_socket ()
+{
+ // If zmq_term was already called and there are no more sockets,
+ // terminate the whole 0MQ infrastructure.
+ term_sync.lock ();
+ zmq_assert (sockets > 0);
+ sockets--;
+ bool destroy = (sockets == 0 && terminated);
+ term_sync.unlock ();
+
+ if (destroy)
+ delete this;
+}
+
+void zmq::ctx_t::no_sockets (app_thread_t *thread_)
+{
+ app_threads_sync.lock ();
+ app_threads_t::size_type i;
+ for (i = 0; i != app_threads.size (); i++)
+ if (app_threads [i].app_thread == thread_) {
+ app_threads [i].associated = false;
+ break;
+ }
+ zmq_assert (i != app_threads.size ());
+ app_threads_sync.unlock ();
+}
+
+void zmq::ctx_t::send_command (uint32_t destination_,
+ const command_t &command_)
+{
+ signalers [destination_]->send (command_);
+}
+
+bool zmq::ctx_t::recv_command (uint32_t thread_slot_,
+ command_t *command_, bool block_)
+{
+ return signalers [thread_slot_]->recv (command_, block_);
+}
+
+zmq::io_thread_t *zmq::ctx_t::choose_io_thread (uint64_t affinity_)
+{
+ // Find the I/O thread with minimum load.
+ zmq_assert (io_threads.size () > 0);
+ int min_load = -1;
+ io_threads_t::size_type result = 0;
+ for (io_threads_t::size_type i = 0; i != io_threads.size (); i++) {
+ if (!affinity_ || (affinity_ & (uint64_t (1) << i))) {
+ int load = io_threads [i]->get_load ();
+ if (min_load == -1 || load < min_load) {
+ min_load = load;
+ result = i;
+ }
+ }
+ }
+ zmq_assert (min_load != -1);
+ return io_threads [result];
+}
+
+void zmq::ctx_t::register_pipe (class pipe_t *pipe_)
+{
+ pipes_sync.lock ();
+ bool inserted = pipes.insert (pipe_).second;
+ zmq_assert (inserted);
+ pipes_sync.unlock ();
+}
+
+void zmq::ctx_t::unregister_pipe (class pipe_t *pipe_)
+{
+ pipes_sync.lock ();
+ pipes_t::size_type erased = pipes.erase (pipe_);
+ zmq_assert (erased == 1);
+ pipes_sync.unlock ();
+}
+
+int zmq::ctx_t::register_endpoint (const char *addr_,
+ socket_base_t *socket_)
+{
+ endpoints_sync.lock ();
+
+ bool inserted = endpoints.insert (std::make_pair (std::string (addr_),
+ socket_)).second;
+ if (!inserted) {
+ errno = EADDRINUSE;
+ endpoints_sync.unlock ();
+ return -1;
+ }
+
+ endpoints_sync.unlock ();
+ return 0;
+}
+
+void zmq::ctx_t::unregister_endpoints (socket_base_t *socket_)
+{
+ endpoints_sync.lock ();
+
+ endpoints_t::iterator it = endpoints.begin ();
+ while (it != endpoints.end ()) {
+ if (it->second == socket_) {
+ endpoints_t::iterator to_erase = it;
+ it++;
+ endpoints.erase (to_erase);
+ continue;
+ }
+ it++;
+ }
+
+ endpoints_sync.unlock ();
+}
+
+zmq::socket_base_t *zmq::ctx_t::find_endpoint (const char *addr_)
+{
+ endpoints_sync.lock ();
+
+ endpoints_t::iterator it = endpoints.find (addr_);
+ if (it == endpoints.end ()) {
+ endpoints_sync.unlock ();
+ errno = ECONNREFUSED;
+ return NULL;
+ }
+ socket_base_t *endpoint = it->second;
+
+ // Increment the command sequence number of the peer so that it won't
+ // get deallocated until "bind" command is issued by the caller.
+ // The subsequent 'bind' has to be called with inc_seqnum parameter
+ // set to false, so that the seqnum isn't incremented twice.
+ endpoint->inc_seqnum ();
+
+ endpoints_sync.unlock ();
+ return endpoint;
+}
+
diff --git a/src/ctx.hpp b/src/ctx.hpp
new file mode 100644
index 0000000..c96a923
--- /dev/null
+++ b/src/ctx.hpp
@@ -0,0 +1,156 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_CTX_HPP_INCLUDED__
+#define __ZMQ_CTX_HPP_INCLUDED__
+
+#include <vector>
+#include <set>
+#include <map>
+#include <string>
+
+#include "signaler.hpp"
+#include "ypipe.hpp"
+#include "config.hpp"
+#include "mutex.hpp"
+#include "stdint.hpp"
+#include "thread.hpp"
+
+namespace zmq
+{
+
+ // Context object encapsulates all the global state associated with
+ // the library.
+
+ class ctx_t
+ {
+ public:
+
+ // Create the context object. The argument specifies the size
+ // of I/O thread pool to create.
+ ctx_t (uint32_t io_threads_);
+
+ // This function is called when user invokes zmq_term. If there are
+ // no more sockets open it'll cause all the infrastructure to be shut
+ // down. If there are open sockets still, the deallocation happens
+ // after the last one is closed.
+ int term ();
+
+ // Create a socket.
+ class socket_base_t *create_socket (int type_);
+
+ // Destroy a socket.
+ void destroy_socket ();
+
+ // Called by app_thread_t when it has no more sockets. The function
+ // should disassociate the object from the current OS thread.
+ void no_sockets (class app_thread_t *thread_);
+
+ // Send command to the destination thread.
+ void send_command (uint32_t destination_, const command_t &command_);
+
+ // Receive command from another thread.
+ bool recv_command (uint32_t thread_slot_, command_t *command_,
+ bool block_);
+
+ // Returns the I/O thread that is the least busy at the moment.
+ // Taskset specifies which I/O threads are eligible (0 = all).
+ class io_thread_t *choose_io_thread (uint64_t taskset_);
+
+ // All pipes are registered with the context so that even the
+ // orphaned pipes can be deallocated on the terminal shutdown.
+ void register_pipe (class pipe_t *pipe_);
+ void unregister_pipe (class pipe_t *pipe_);
+
+ // Management of inproc endpoints.
+ int register_endpoint (const char *addr_, class socket_base_t *socket_);
+ void unregister_endpoints (class socket_base_t *socket_);
+ class socket_base_t *find_endpoint (const char *addr_);
+
+ private:
+
+ ~ctx_t ();
+
+ struct app_thread_info_t
+ {
+ // If false, 0MQ application thread is free, there's no associated
+ // OS thread.
+ bool associated;
+
+ // ID of the associated OS thread. If 'associated' is false,
+ // this field contains bogus data.
+ thread_t::id_t tid;
+
+ // Pointer to the 0MQ application thread object.
+ class app_thread_t *app_thread;
+ };
+
+ // Application threads.
+ typedef std::vector <app_thread_info_t> app_threads_t;
+ app_threads_t app_threads;
+
+ // Synchronisation of accesses to shared application thread data.
+ mutex_t app_threads_sync;
+
+ // I/O threads.
+ typedef std::vector <class io_thread_t*> io_threads_t;
+ io_threads_t io_threads;
+
+ // Array of pointers to signalers for both application and I/O threads.
+ int signalers_count;
+ signaler_t **signalers;
+
+ // As pipes may reside in orphaned state in particular moments
+ // of the pipe shutdown process, i.e. neither pipe reader nor
+ // pipe writer hold reference to the pipe, we have to hold references
+ // to all pipes in context so that we can deallocate them
+ // during terminal shutdown even though it conincides with the
+ // pipe being in the orphaned state.
+ typedef std::set <class pipe_t*> pipes_t;
+ pipes_t pipes;
+
+ // Synchronisation of access to the pipes repository.
+ mutex_t pipes_sync;
+
+ // Number of sockets alive.
+ int sockets;
+
+ // If true, zmq_term was already called. When last socket is closed
+ // the whole 0MQ infrastructure should be deallocated.
+ bool terminated;
+
+ // Synchronisation of access to the termination data (socket count
+ // and 'terminated' flag).
+ mutex_t term_sync;
+
+ // List of inproc endpoints within this context.
+ typedef std::map <std::string, class socket_base_t*> endpoints_t;
+ endpoints_t endpoints;
+
+ // Synchronisation of access to the list of inproc endpoints.
+ mutex_t endpoints_sync;
+
+ ctx_t (const ctx_t&);
+ void operator = (const ctx_t&);
+ };
+
+}
+
+#endif
+
diff --git a/src/decoder.hpp b/src/decoder.hpp
new file mode 100644
index 0000000..1662bda
--- /dev/null
+++ b/src/decoder.hpp
@@ -0,0 +1,156 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_DECODER_HPP_INCLUDED__
+#define __ZMQ_DECODER_HPP_INCLUDED__
+
+#include <stddef.h>
+#include <string.h>
+#include <stdlib.h>
+#include <algorithm>
+
+#include "err.hpp"
+
+namespace zmq
+{
+
+ // Helper base class for decoders that know the amount of data to read
+ // in advance at any moment. Knowing the amount in advance is a property
+ // of the protocol used. Both AMQP and backend protocol are based on
+ // size-prefixed paradigm, therefore they are using decoder_t to parse
+ // the messages. On the other hand, XML-based transports (like XMPP or
+ // SOAP) don't allow for knowing the size of data to read in advance and
+ // should use different decoding algorithms.
+ //
+ // Decoder implements the state machine that parses the incoming buffer.
+ // Derived class should implement individual state machine actions.
+
+ template <typename T> class decoder_t
+ {
+ public:
+
+ inline decoder_t (size_t bufsize_) :
+ read_pos (NULL),
+ to_read (0),
+ next (NULL),
+ bufsize (bufsize_)
+ {
+ buf = (unsigned char*) malloc (bufsize_);
+ zmq_assert (buf);
+ }
+
+ inline ~decoder_t ()
+ {
+ free (buf);
+ }
+
+ // Returns a buffer to be filled with binary data.
+ inline void get_buffer (unsigned char **data_, size_t *size_)
+ {
+ // If we are expected to read large message, we'll opt for zero-
+ // copy, i.e. we'll ask caller to fill the data directly to the
+ // message. Note that subsequent read(s) are non-blocking, thus
+ // each single read reads at most SO_RCVBUF bytes at once not
+ // depending on how large is the chunk returned from here.
+ // As a consequence, large messages being received won't block
+ // other engines running in the same I/O thread for excessive
+ // amounts of time.
+ if (to_read >= bufsize) {
+ *data_ = read_pos;
+ *size_ = to_read;
+ return;
+ }
+
+ *data_ = buf;
+ *size_ = bufsize;
+ }
+
+ // Processes the data in the buffer previously allocated using
+ // get_buffer function. size_ argument specifies nemuber of bytes
+ // actually filled into the buffer. Function returns number of
+ // bytes actually processed.
+ inline size_t process_buffer (unsigned char *data_, size_t size_)
+ {
+ // In case of zero-copy simply adjust the pointers, no copying
+ // is required. Also, run the state machine in case all the data
+ // were processed.
+ if (data_ == read_pos) {
+ read_pos += size_;
+ to_read -= size_;
+
+ while (!to_read)
+ if (!(static_cast <T*> (this)->*next) ())
+ return size_;
+ return size_;
+ }
+
+ size_t pos = 0;
+ while (true) {
+
+ // Try to get more space in the message to fill in.
+ // If none is available, return.
+ while (!to_read)
+ if (!(static_cast <T*> (this)->*next) ())
+ return pos;
+
+ // If there are no more data in the buffer, return.
+ if (pos == size_)
+ return pos;
+
+ // Copy the data from buffer to the message.
+ size_t to_copy = std::min (to_read, size_ - pos);
+ memcpy (read_pos, data_ + pos, to_copy);
+ read_pos += to_copy;
+ pos += to_copy;
+ to_read -= to_copy;
+ }
+ }
+
+ protected:
+
+ // Prototype of state machine action. Action should return false if
+ // it is unable to push the data to the system.
+ typedef bool (T::*step_t) ();
+
+ // This function should be called from derived class to read data
+ // from the buffer and schedule next state machine action.
+ inline void next_step (void *read_pos_, size_t to_read_,
+ step_t next_)
+ {
+ read_pos = (unsigned char*) read_pos_;
+ to_read = to_read_;
+ next = next_;
+ }
+
+ private:
+
+ unsigned char *read_pos;
+ size_t to_read;
+ step_t next;
+
+ size_t bufsize;
+ unsigned char *buf;
+
+ decoder_t (const decoder_t&);
+ void operator = (const decoder_t&);
+ };
+
+}
+
+#endif
diff --git a/src/devpoll.cpp b/src/devpoll.cpp
new file mode 100644
index 0000000..003f465
--- /dev/null
+++ b/src/devpoll.cpp
@@ -0,0 +1,222 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "platform.hpp"
+
+#if defined ZMQ_HAVE_SOLARIS || defined ZMQ_HAVE_HPUX
+
+#include <sys/devpoll.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <limits.h>
+#include <algorithm>
+
+#include "devpoll.hpp"
+#include "err.hpp"
+#include "config.hpp"
+#include "i_poll_events.hpp"
+
+zmq::devpoll_t::devpoll_t () :
+ stopping (false)
+{
+ // Get limit on open files
+ struct rlimit rl;
+ int rc = getrlimit (RLIMIT_NOFILE, &rl);
+ errno_assert (rc != -1);
+ fd_table.resize (rl.rlim_cur);
+
+ for (rlim_t i = 0; i < rl.rlim_cur; i ++)
+ fd_table [i].valid = false;
+
+ devpoll_fd = open ("/dev/poll", O_RDWR);
+ errno_assert (devpoll_fd != -1);
+}
+
+zmq::devpoll_t::~devpoll_t ()
+{
+ worker.stop ();
+
+ // Make sure there are no fds registered on shutdown.
+ zmq_assert (load.get () == 0);
+
+ close (devpoll_fd);
+}
+
+void zmq::devpoll_t::devpoll_ctl (fd_t fd_, short events_)
+{
+ struct pollfd pfd = {fd_, events_, 0};
+ ssize_t rc = write (devpoll_fd, &pfd, sizeof pfd);
+ zmq_assert (rc == sizeof pfd);
+}
+
+zmq::devpoll_t::handle_t zmq::devpoll_t::add_fd (fd_t fd_,
+ i_poll_events *reactor_)
+{
+ assert (!fd_table [fd_].valid);
+
+ fd_table [fd_].events = 0;
+ fd_table [fd_].reactor = reactor_;
+ fd_table [fd_].valid = true;
+ fd_table [fd_].accepted = false;
+
+ devpoll_ctl (fd_, 0);
+ pending_list.push_back (fd_);
+
+ // Increase the load metric of the thread.
+ load.add (1);
+
+ return fd_;
+}
+
+void zmq::devpoll_t::rm_fd (handle_t handle_)
+{
+ assert (fd_table [handle_].valid);
+
+ devpoll_ctl (handle_, POLLREMOVE);
+ fd_table [handle_].valid = false;
+
+ // Decrease the load metric of the thread.
+ load.sub (1);
+}
+
+void zmq::devpoll_t::set_pollin (handle_t handle_)
+{
+ devpoll_ctl (handle_, POLLREMOVE);
+ fd_table [handle_].events |= POLLIN;
+ devpoll_ctl (handle_, fd_table [handle_].events);
+}
+
+void zmq::devpoll_t::reset_pollin (handle_t handle_)
+{
+ devpoll_ctl (handle_, POLLREMOVE);
+ fd_table [handle_].events &= ~((short) POLLIN);
+ devpoll_ctl (handle_, fd_table [handle_].events);
+}
+
+void zmq::devpoll_t::set_pollout (handle_t handle_)
+{
+ devpoll_ctl (handle_, POLLREMOVE);
+ fd_table [handle_].events |= POLLOUT;
+ devpoll_ctl (handle_, fd_table [handle_].events);
+}
+
+void zmq::devpoll_t::reset_pollout (handle_t handle_)
+{
+ devpoll_ctl (handle_, POLLREMOVE);
+ fd_table [handle_].events &= ~((short) POLLOUT);
+ devpoll_ctl (handle_, fd_table [handle_].events);
+}
+
+void zmq::devpoll_t::add_timer (i_poll_events *events_)
+{
+ timers.push_back (events_);
+}
+
+void zmq::devpoll_t::cancel_timer (i_poll_events *events_)
+{
+ timers_t::iterator it = std::find (timers.begin (), timers.end (), events_);
+ if (it != timers.end ())
+ timers.erase (it);
+}
+
+int zmq::devpoll_t::get_load ()
+{
+ return load.get ();
+}
+
+void zmq::devpoll_t::start ()
+{
+ worker.start (worker_routine, this);
+}
+
+void zmq::devpoll_t::stop ()
+{
+ stopping = true;
+}
+
+void zmq::devpoll_t::loop ()
+{
+ // According to the poll(7d) man page, we can retrieve
+ // no more then (OPEN_MAX - 1) events.
+ int nfds = std::min ((int) max_io_events, OPEN_MAX - 1);
+
+ while (!stopping) {
+
+ struct pollfd ev_buf [max_io_events];
+ struct dvpoll poll_req;
+
+ for (pending_list_t::size_type i = 0; i < pending_list.size (); i ++)
+ fd_table [pending_list [i]].accepted = true;
+ pending_list.clear ();
+
+ poll_req.dp_fds = &ev_buf [0];
+ poll_req.dp_nfds = nfds;
+ poll_req.dp_timeout = timers.empty () ? -1 : max_timer_period;
+
+ // Wait for events.
+ int n = ioctl (devpoll_fd, DP_POLL, &poll_req);
+ if (n == -1 && errno == EINTR)
+ continue;
+ errno_assert (n != -1);
+
+ // Handle timer.
+ if (!n) {
+
+ // Use local list of timers as timer handlers may fill new timers
+ // into the original array.
+ timers_t t;
+ std::swap (timers, t);
+
+ // Trigger all the timers.
+ for (timers_t::iterator it = t.begin (); it != t.end (); it ++)
+ (*it)->timer_event ();
+
+ continue;
+ }
+
+ for (int i = 0; i < n; i ++) {
+
+ fd_entry_t *fd_ptr = &fd_table [ev_buf [i].fd];
+ if (!fd_ptr->valid || !fd_ptr->accepted)
+ continue;
+ if (ev_buf [i].revents & (POLLERR | POLLHUP))
+ fd_ptr->reactor->in_event ();
+ if (!fd_ptr->valid || !fd_ptr->accepted)
+ continue;
+ if (ev_buf [i].revents & POLLOUT)
+ fd_ptr->reactor->out_event ();
+ if (!fd_ptr->valid || !fd_ptr->accepted)
+ continue;
+ if (ev_buf [i].revents & POLLIN)
+ fd_ptr->reactor->in_event ();
+ }
+ }
+}
+
+void zmq::devpoll_t::worker_routine (void *arg_)
+{
+ ((devpoll_t*) arg_)->loop ();
+}
+
+#endif
diff --git a/src/devpoll.hpp b/src/devpoll.hpp
new file mode 100644
index 0000000..019d268
--- /dev/null
+++ b/src/devpoll.hpp
@@ -0,0 +1,110 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_DEVPOLL_HPP_INCLUDED__
+#define __ZMQ_DEVPOLL_HPP_INCLUDED__
+
+#include "platform.hpp"
+
+#if defined ZMQ_HAVE_SOLARIS || ZMQ_HAVE_HPUX
+
+#include <vector>
+
+#include "fd.hpp"
+#include "thread.hpp"
+#include "atomic_counter.hpp"
+
+namespace zmq
+{
+
+ // Implements socket polling mechanism using the Solaris-specific
+ // "/dev/poll" interface.
+
+ class devpoll_t
+ {
+ public:
+
+ typedef fd_t handle_t;
+
+ devpoll_t ();
+ ~devpoll_t ();
+
+ // "poller" concept.
+ handle_t add_fd (fd_t fd_, struct i_poll_events *events_);
+ void rm_fd (handle_t handle_);
+ void set_pollin (handle_t handle_);
+ void reset_pollin (handle_t handle_);
+ void set_pollout (handle_t handle_);
+ void reset_pollout (handle_t handle_);
+ void add_timer (struct i_poll_events *events_);
+ void cancel_timer (struct i_poll_events *events_);
+ int get_load ();
+ void start ();
+ void stop ();
+
+ private:
+
+ // Main worker thread routine.
+ static void worker_routine (void *arg_);
+
+ // Main event loop.
+ void loop ();
+
+ // File descriptor referring to "/dev/poll" pseudo-device.
+ fd_t devpoll_fd;
+
+ struct fd_entry_t
+ {
+ short events;
+ struct i_poll_events *reactor;
+ bool valid;
+ bool accepted;
+ };
+
+ std::vector <fd_entry_t> fd_table;
+
+ typedef std::vector <fd_t> pending_list_t;
+ pending_list_t pending_list;
+
+ // Pollset manipulation function.
+ void devpoll_ctl (fd_t fd_, short events_);
+
+ // List of all the engines waiting for the timer event.
+ typedef std::vector <struct i_poll_events*> timers_t;
+ timers_t timers;
+
+ // If true, thread is in the process of shutting down.
+ bool stopping;
+
+ // Handle of the physical thread doing the I/O work.
+ thread_t worker;
+
+ // Load of the poller. Currently number of file descriptors
+ // registered with the poller.
+ atomic_counter_t load;
+
+ devpoll_t (const devpoll_t&);
+ void operator = (const devpoll_t&);
+ };
+
+}
+
+#endif
+
+#endif
diff --git a/src/downstream.cpp b/src/downstream.cpp
new file mode 100644
index 0000000..4074a9e
--- /dev/null
+++ b/src/downstream.cpp
@@ -0,0 +1,101 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "../include/zmq.h"
+
+#include "downstream.hpp"
+#include "err.hpp"
+#include "pipe.hpp"
+
+zmq::downstream_t::downstream_t (class app_thread_t *parent_) :
+ socket_base_t (parent_)
+{
+ options.requires_in = false;
+ options.requires_out = true;
+}
+
+zmq::downstream_t::~downstream_t ()
+{
+}
+
+void zmq::downstream_t::xattach_pipes (class reader_t *inpipe_,
+ class writer_t *outpipe_, const blob_t &peer_identity_)
+{
+ zmq_assert (!inpipe_ && outpipe_);
+ lb.attach (outpipe_);
+}
+
+void zmq::downstream_t::xdetach_inpipe (class reader_t *pipe_)
+{
+ // There are no inpipes, so this function shouldn't be called at all.
+ zmq_assert (false);
+}
+
+void zmq::downstream_t::xdetach_outpipe (class writer_t *pipe_)
+{
+ zmq_assert (pipe_);
+ lb.detach (pipe_);
+}
+
+void zmq::downstream_t::xkill (class reader_t *pipe_)
+{
+ // There are no inpipes, so this function shouldn't be called at all.
+ zmq_assert (false);
+}
+
+void zmq::downstream_t::xrevive (class reader_t *pipe_)
+{
+ // There are no inpipes, so this function shouldn't be called at all.
+ zmq_assert (false);
+}
+
+void zmq::downstream_t::xrevive (class writer_t *pipe_)
+{
+ lb.revive (pipe_);
+}
+
+int zmq::downstream_t::xsetsockopt (int option_, const void *optval_,
+ size_t optvallen_)
+{
+ // No special option for this socket type.
+ errno = EINVAL;
+ return -1;
+}
+
+int zmq::downstream_t::xsend (zmq_msg_t *msg_, int flags_)
+{
+ return lb.send (msg_, flags_);
+}
+
+int zmq::downstream_t::xrecv (zmq_msg_t *msg_, int flags_)
+{
+ errno = ENOTSUP;
+ return -1;
+}
+
+bool zmq::downstream_t::xhas_in ()
+{
+ return false;
+}
+
+bool zmq::downstream_t::xhas_out ()
+{
+ return lb.has_out ();
+}
+
diff --git a/src/downstream.hpp b/src/downstream.hpp
new file mode 100644
index 0000000..1306743
--- /dev/null
+++ b/src/downstream.hpp
@@ -0,0 +1,61 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_DOWNSTREAM_HPP_INCLUDED__
+#define __ZMQ_DOWNSTREAM_HPP_INCLUDED__
+
+#include "socket_base.hpp"
+#include "lb.hpp"
+
+namespace zmq
+{
+
+ class downstream_t : public socket_base_t
+ {
+ public:
+
+ downstream_t (class app_thread_t *parent_);
+ ~downstream_t ();
+
+ // Overloads of functions from socket_base_t.
+ void xattach_pipes (class reader_t *inpipe_, class writer_t *outpipe_,
+ const blob_t &peer_identity_);
+ void xdetach_inpipe (class reader_t *pipe_);
+ void xdetach_outpipe (class writer_t *pipe_);
+ void xkill (class reader_t *pipe_);
+ void xrevive (class reader_t *pipe_);
+ void xrevive (class writer_t *pipe_);
+ int xsetsockopt (int option_, const void *optval_, size_t optvallen_);
+ int xsend (zmq_msg_t *msg_, int flags_);
+ int xrecv (zmq_msg_t *msg_, int flags_);
+ bool xhas_in ();
+ bool xhas_out ();
+
+ private:
+
+ // Load balancer managing the outbound pipes.
+ lb_t lb;
+
+ downstream_t (const downstream_t&);
+ void operator = (const downstream_t&);
+ };
+
+}
+
+#endif
diff --git a/src/encoder.hpp b/src/encoder.hpp
new file mode 100644
index 0000000..10fe912
--- /dev/null
+++ b/src/encoder.hpp
@@ -0,0 +1,160 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_ENCODER_HPP_INCLUDED__
+#define __ZMQ_ENCODER_HPP_INCLUDED__
+
+#include "platform.hpp"
+#if defined ZMQ_HAVE_WINDOWS
+#include "windows.hpp"
+#endif
+
+#include <stddef.h>
+#include <string.h>
+#include <stdlib.h>
+#include <algorithm>
+
+#include "err.hpp"
+
+namespace zmq
+{
+
+ // Helper base class for encoders. It implements the state machine that
+ // fills the outgoing buffer. Derived classes should implement individual
+ // state machine actions.
+
+ template <typename T> class encoder_t
+ {
+ public:
+
+ inline encoder_t (size_t bufsize_) :
+ bufsize (bufsize_)
+ {
+ buf = (unsigned char*) malloc (bufsize_);
+ zmq_assert (buf);
+ }
+
+ inline ~encoder_t ()
+ {
+ free (buf);
+ }
+
+ // The function returns a batch of binary data. The data
+ // are filled to a supplied buffer. If no buffer is supplied (data_
+ // points to NULL) decoder object will provide buffer of its own.
+ // If offset is not NULL, it is filled by offset of the first message
+ // in the batch.If there's no beginning of a message in the batch,
+ // offset is set to -1.
+ inline void get_data (unsigned char **data_, size_t *size_,
+ int *offset_ = NULL)
+ {
+ unsigned char *buffer = !*data_ ? buf : *data_;
+ size_t buffersize = !*data_ ? bufsize : *size_;
+
+ size_t pos = 0;
+ if (offset_)
+ *offset_ = -1;
+
+ while (true) {
+
+ // If there are no more data to return, run the state machine.
+ // If there are still no data, return what we already have
+ // in the buffer.
+ if (!to_write) {
+ if (!(static_cast <T*> (this)->*next) ()) {
+ *data_ = buffer;
+ *size_ = pos;
+ return;
+ }
+
+ // If beginning of the message was processed, adjust the
+ // first-message-offset.
+ if (beginning) {
+ if (offset_ && *offset_ == -1)
+ *offset_ = pos;
+ beginning = false;
+ }
+ }
+
+ // If there are no data in the buffer yet and we are able to
+ // fill whole buffer in a single go, let's use zero-copy.
+ // There's no disadvantage to it as we cannot stuck multiple
+ // messages into the buffer anyway. Note that subsequent
+ // write(s) are non-blocking, thus each single write writes
+ // at most SO_SNDBUF bytes at once not depending on how large
+ // is the chunk returned from here.
+ // As a consequence, large messages being sent won't block
+ // other engines running in the same I/O thread for excessive
+ // amounts of time.
+ if (!pos && !*data_ && to_write >= buffersize) {
+ *data_ = write_pos;
+ *size_ = to_write;
+ write_pos = NULL;
+ to_write = 0;
+ return;
+ }
+
+ // Copy data to the buffer. If the buffer is full, return.
+ size_t to_copy = std::min (to_write, buffersize - pos);
+ memcpy (buffer + pos, write_pos, to_copy);
+ pos += to_copy;
+ write_pos += to_copy;
+ to_write -= to_copy;
+ if (pos == buffersize) {
+ *data_ = buffer;
+ *size_ = pos;
+ return;
+ }
+ }
+ }
+
+ protected:
+
+ // Prototype of state machine action.
+ typedef bool (T::*step_t) ();
+
+ // This function should be called from derived class to write the data
+ // to the buffer and schedule next state machine action. Set beginning
+ // to true when you are writing first byte of a message.
+ inline void next_step (void *write_pos_, size_t to_write_,
+ step_t next_, bool beginning_)
+ {
+ write_pos = (unsigned char*) write_pos_;
+ to_write = to_write_;
+ next = next_;
+ beginning = beginning_;
+ }
+
+ private:
+
+ unsigned char *write_pos;
+ size_t to_write;
+ step_t next;
+ bool beginning;
+
+ size_t bufsize;
+ unsigned char *buf;
+
+ encoder_t (const encoder_t&);
+ void operator = (const encoder_t&);
+ };
+
+}
+
+#endif
diff --git a/src/epoll.cpp b/src/epoll.cpp
new file mode 100644
index 0000000..e22eb8c
--- /dev/null
+++ b/src/epoll.cpp
@@ -0,0 +1,213 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "platform.hpp"
+
+#ifdef ZMQ_HAVE_LINUX
+
+#include <sys/epoll.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <algorithm>
+#include <new>
+
+#include "epoll.hpp"
+#include "err.hpp"
+#include "config.hpp"
+#include "i_poll_events.hpp"
+
+zmq::epoll_t::epoll_t () :
+ stopping (false)
+{
+ epoll_fd = epoll_create (1);
+ errno_assert (epoll_fd != -1);
+}
+
+zmq::epoll_t::~epoll_t ()
+{
+ // Wait till the worker thread exits.
+ worker.stop ();
+
+ // Make sure there are no fds registered on shutdown.
+ zmq_assert (load.get () == 0);
+
+ close (epoll_fd);
+ for (retired_t::iterator it = retired.begin (); it != retired.end (); it ++)
+ delete *it;
+}
+
+zmq::epoll_t::handle_t zmq::epoll_t::add_fd (fd_t fd_, i_poll_events *events_)
+{
+ poll_entry_t *pe = new (std::nothrow) poll_entry_t;
+ zmq_assert (pe != NULL);
+
+ // The memset is not actually needed. It's here to prevent debugging
+ // tools to complain about using uninitialised memory.
+ memset (pe, 0, sizeof (poll_entry_t));
+
+ pe->fd = fd_;
+ pe->ev.events = 0;
+ pe->ev.data.ptr = pe;
+ pe->events = events_;
+
+ int rc = epoll_ctl (epoll_fd, EPOLL_CTL_ADD, fd_, &pe->ev);
+ errno_assert (rc != -1);
+
+ // Increase the load metric of the thread.
+ load.add (1);
+
+ return pe;
+}
+
+void zmq::epoll_t::rm_fd (handle_t handle_)
+{
+ poll_entry_t *pe = (poll_entry_t*) handle_;
+ int rc = epoll_ctl (epoll_fd, EPOLL_CTL_DEL, pe->fd, &pe->ev);
+ errno_assert (rc != -1);
+ pe->fd = retired_fd;
+ retired.push_back (pe);
+
+ // Decrease the load metric of the thread.
+ load.sub (1);
+}
+
+void zmq::epoll_t::set_pollin (handle_t handle_)
+{
+ poll_entry_t *pe = (poll_entry_t*) handle_;
+ pe->ev.events |= EPOLLIN;
+ int rc = epoll_ctl (epoll_fd, EPOLL_CTL_MOD, pe->fd, &pe->ev);
+ errno_assert (rc != -1);
+}
+
+void zmq::epoll_t::reset_pollin (handle_t handle_)
+{
+ poll_entry_t *pe = (poll_entry_t*) handle_;
+ pe->ev.events &= ~((short) EPOLLIN);
+ int rc = epoll_ctl (epoll_fd, EPOLL_CTL_MOD, pe->fd, &pe->ev);
+ errno_assert (rc != -1);
+}
+
+void zmq::epoll_t::set_pollout (handle_t handle_)
+{
+ poll_entry_t *pe = (poll_entry_t*) handle_;
+ pe->ev.events |= EPOLLOUT;
+ int rc = epoll_ctl (epoll_fd, EPOLL_CTL_MOD, pe->fd, &pe->ev);
+ errno_assert (rc != -1);
+}
+
+void zmq::epoll_t::reset_pollout (handle_t handle_)
+{
+ poll_entry_t *pe = (poll_entry_t*) handle_;
+ pe->ev.events &= ~((short) EPOLLOUT);
+ int rc = epoll_ctl (epoll_fd, EPOLL_CTL_MOD, pe->fd, &pe->ev);
+ errno_assert (rc != -1);
+}
+
+void zmq::epoll_t::add_timer (i_poll_events *events_)
+{
+ timers.push_back (events_);
+}
+
+void zmq::epoll_t::cancel_timer (i_poll_events *events_)
+{
+ timers_t::iterator it = std::find (timers.begin (), timers.end (), events_);
+ if (it == timers.end ())
+ return;
+ timers.erase (it);
+}
+
+int zmq::epoll_t::get_load ()
+{
+ return load.get ();
+}
+
+void zmq::epoll_t::start ()
+{
+ worker.start (worker_routine, this);
+}
+
+void zmq::epoll_t::stop ()
+{
+ stopping = true;
+}
+
+void zmq::epoll_t::loop ()
+{
+ epoll_event ev_buf [max_io_events];
+
+ while (!stopping) {
+
+ // Wait for events.
+ int n;
+ while (true) {
+ n = epoll_wait (epoll_fd, &ev_buf [0], max_io_events,
+ timers.empty () ? -1 : max_timer_period);
+ if (!(n == -1 && errno == EINTR)) {
+ errno_assert (n != -1);
+ break;
+ }
+ }
+
+ // Handle timer.
+ if (!n) {
+
+ // Use local list of timers as timer handlers may fill new timers
+ // into the original array.
+ timers_t t;
+ std::swap (timers, t);
+
+ // Trigger all the timers.
+ for (timers_t::iterator it = t.begin (); it != t.end (); it ++)
+ (*it)->timer_event ();
+
+ continue;
+ }
+
+ for (int i = 0; i < n; i ++) {
+ poll_entry_t *pe = ((poll_entry_t*) ev_buf [i].data.ptr);
+
+ if (pe->fd == retired_fd)
+ continue;
+ if (ev_buf [i].events & (EPOLLERR | EPOLLHUP))
+ pe->events->in_event ();
+ if (pe->fd == retired_fd)
+ continue;
+ if (ev_buf [i].events & EPOLLOUT)
+ pe->events->out_event ();
+ if (pe->fd == retired_fd)
+ continue;
+ if (ev_buf [i].events & EPOLLIN)
+ pe->events->in_event ();
+ }
+
+ // Destroy retired event sources.
+ for (retired_t::iterator it = retired.begin (); it != retired.end ();
+ it ++)
+ delete *it;
+ retired.clear ();
+ }
+}
+
+void zmq::epoll_t::worker_routine (void *arg_)
+{
+ ((epoll_t*) arg_)->loop ();
+}
+
+#endif
diff --git a/src/epoll.hpp b/src/epoll.hpp
new file mode 100644
index 0000000..38175cb
--- /dev/null
+++ b/src/epoll.hpp
@@ -0,0 +1,106 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_EPOLL_HPP_INCLUDED__
+#define __ZMQ_EPOLL_HPP_INCLUDED__
+
+#include "platform.hpp"
+
+#ifdef ZMQ_HAVE_LINUX
+
+#include <vector>
+#include <sys/epoll.h>
+
+#include "fd.hpp"
+#include "thread.hpp"
+#include "atomic_counter.hpp"
+
+namespace zmq
+{
+
+ // This class implements socket polling mechanism using the Linux-specific
+ // epoll mechanism.
+
+ class epoll_t
+ {
+ public:
+
+ typedef void* handle_t;
+
+ epoll_t ();
+ ~epoll_t ();
+
+ // "poller" concept.
+ handle_t add_fd (fd_t fd_, struct i_poll_events *events_);
+ void rm_fd (handle_t handle_);
+ void set_pollin (handle_t handle_);
+ void reset_pollin (handle_t handle_);
+ void set_pollout (handle_t handle_);
+ void reset_pollout (handle_t handle_);
+ void add_timer (struct i_poll_events *events_);
+ void cancel_timer (struct i_poll_events *events_);
+ int get_load ();
+ void start ();
+ void stop ();
+
+ private:
+
+ // Main worker thread routine.
+ static void worker_routine (void *arg_);
+
+ // Main event loop.
+ void loop ();
+
+ // Main epoll file descriptor
+ fd_t epoll_fd;
+
+ struct poll_entry_t
+ {
+ fd_t fd;
+ epoll_event ev;
+ struct i_poll_events *events;
+ };
+
+ // List of retired event sources.
+ typedef std::vector <poll_entry_t*> retired_t;
+ retired_t retired;
+
+ // List of all the engines waiting for the timer event.
+ typedef std::vector <struct i_poll_events*> timers_t;
+ timers_t timers;
+
+ // If true, thread is in the process of shutting down.
+ bool stopping;
+
+ // Handle of the physical thread doing the I/O work.
+ thread_t worker;
+
+ // Load of the poller. Currently number of file descriptors
+ // registered with the poller.
+ atomic_counter_t load;
+
+ epoll_t (const epoll_t&);
+ void operator = (const epoll_t&);
+ };
+
+}
+
+#endif
+
+#endif
diff --git a/src/err.cpp b/src/err.cpp
new file mode 100644
index 0000000..17a9689
--- /dev/null
+++ b/src/err.cpp
@@ -0,0 +1,190 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "../include/zmq.h"
+
+#include "err.hpp"
+#include "platform.hpp"
+
+#ifdef ZMQ_HAVE_WINDOWS
+
+const char *zmq::wsa_error()
+{
+ int errcode = WSAGetLastError ();
+ // TODO: This is not a generic way to handle this...
+ if (errcode == WSAEWOULDBLOCK)
+ return NULL;
+
+ // TODO: It seems that list of Windows socket errors is longer than this.
+ // Investigate whether there's a way to convert it into the string
+ // automatically (wsaError->HRESULT->string?).
+ return
+ (errcode == WSABASEERR) ?
+ "No Error" :
+ (errcode == WSAEINTR) ?
+ "Interrupted system call" :
+ (errcode == WSAEBADF) ?
+ "Bad file number" :
+ (errcode == WSAEACCES) ?
+ "Permission denied" :
+ (errcode == WSAEFAULT) ?
+ "Bad address" :
+ (errcode == WSAEINVAL) ?
+ "Invalid argument" :
+ (errcode == WSAEMFILE) ?
+ "Too many open files" :
+ (errcode == WSAEWOULDBLOCK) ?
+ "Operation would block" :
+ (errcode == WSAEINPROGRESS) ?
+ "Operation now in progress" :
+ (errcode == WSAEALREADY) ?
+ "Operation already in progress" :
+ (errcode == WSAENOTSOCK) ?
+ "Socket operation on non-socket" :
+ (errcode == WSAEDESTADDRREQ) ?
+ "Destination address required" :
+ (errcode == WSAEMSGSIZE) ?
+ "Message too long" :
+ (errcode == WSAEPROTOTYPE) ?
+ "Protocol wrong type for socket" :
+ (errcode == WSAENOPROTOOPT) ?
+ "Bad protocol option" :
+ (errcode == WSAEPROTONOSUPPORT) ?
+ "Protocol not supported" :
+ (errcode == WSAESOCKTNOSUPPORT) ?
+ "Socket type not supported" :
+ (errcode == WSAEOPNOTSUPP) ?
+ "Operation not supported on socket" :
+ (errcode == WSAEPFNOSUPPORT) ?
+ "Protocol family not supported" :
+ (errcode == WSAEAFNOSUPPORT) ?
+ "Address family not supported by protocol family" :
+ (errcode == WSAEADDRINUSE) ?
+ "Address already in use" :
+ (errcode == WSAEADDRNOTAVAIL) ?
+ "Can't assign requested address" :
+ (errcode == WSAENETDOWN) ?
+ "Network is down" :
+ (errcode == WSAENETUNREACH) ?
+ "Network is unreachable" :
+ (errcode == WSAENETRESET) ?
+ "Net dropped connection or reset" :
+ (errcode == WSAECONNABORTED) ?
+ "Software caused connection abort" :
+ (errcode == WSAECONNRESET) ?
+ "Connection reset by peer" :
+ (errcode == WSAENOBUFS) ?
+ "No buffer space available" :
+ (errcode == WSAEISCONN) ?
+ "Socket is already connected" :
+ (errcode == WSAENOTCONN) ?
+ "Socket is not connected" :
+ (errcode == WSAESHUTDOWN) ?
+ "Can't send after socket shutdown" :
+ (errcode == WSAETOOMANYREFS) ?
+ "Too many references can't splice" :
+ (errcode == WSAETIMEDOUT) ?
+ "Connection timed out" :
+ (errcode == WSAECONNREFUSED) ?
+ "Connection refused" :
+ (errcode == WSAELOOP) ?
+ "Too many levels of symbolic links" :
+ (errcode == WSAENAMETOOLONG) ?
+ "File name too long" :
+ (errcode == WSAEHOSTDOWN) ?
+ "Host is down" :
+ (errcode == WSAEHOSTUNREACH) ?
+ "No Route to Host" :
+ (errcode == WSAENOTEMPTY) ?
+ "Directory not empty" :
+ (errcode == WSAEPROCLIM) ?
+ "Too many processes" :
+ (errcode == WSAEUSERS) ?
+ "Too many users" :
+ (errcode == WSAEDQUOT) ?
+ "Disc Quota Exceeded" :
+ (errcode == WSAESTALE) ?
+ "Stale NFS file handle" :
+ (errcode == WSAEREMOTE) ?
+ "Too many levels of remote in path" :
+ (errcode == WSASYSNOTREADY) ?
+ "Network SubSystem is unavailable" :
+ (errcode == WSAVERNOTSUPPORTED) ?
+ "WINSOCK DLL Version out of range" :
+ (errcode == WSANOTINITIALISED) ?
+ "Successful WSASTARTUP not yet performed" :
+ (errcode == WSAHOST_NOT_FOUND) ?
+ "Host not found" :
+ (errcode == WSATRY_AGAIN) ?
+ "Non-Authoritative Host not found" :
+ (errcode == WSANO_RECOVERY) ?
+ "Non-Recoverable errors: FORMERR REFUSED NOTIMP" :
+ (errcode == WSANO_DATA) ?
+ "Valid name no data record of requested" :
+ "error not defined";
+}
+void zmq::win_error (char *buffer_, size_t buffer_size_)
+{
+ DWORD errcode = GetLastError ();
+ DWORD rc = FormatMessageA (FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errcode, MAKELANGID(LANG_NEUTRAL,
+ SUBLANG_DEFAULT), buffer_, buffer_size_, NULL );
+ zmq_assert (rc);
+}
+
+void zmq::wsa_error_to_errno ()
+{
+ int errcode = WSAGetLastError ();
+ switch (errcode) {
+ case WSAEINPROGRESS:
+ errno = EAGAIN;
+ return;
+ case WSAEBADF:
+ errno = EBADF;
+ return;
+ case WSAEINVAL:
+ errno = EINVAL;
+ return;
+ case WSAEMFILE:
+ errno = EMFILE;
+ return;
+ case WSAEFAULT:
+ errno = EFAULT;
+ return;
+ case WSAEPROTONOSUPPORT:
+ errno = EPROTONOSUPPORT;
+ return;
+ case WSAENOBUFS:
+ errno = ENOBUFS;
+ return;
+ case WSAENETDOWN:
+ errno = ENETDOWN;
+ return;
+ case WSAEADDRINUSE:
+ errno = EADDRINUSE;
+ return;
+ case WSAEADDRNOTAVAIL:
+ errno = EADDRNOTAVAIL;
+ return;
+ default:
+ wsa_assert (false);
+ }
+}
+
+#endif
diff --git a/src/err.hpp b/src/err.hpp
new file mode 100644
index 0000000..2b76569
--- /dev/null
+++ b/src/err.hpp
@@ -0,0 +1,123 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_ERR_HPP_INCLUDED__
+#define __ZMQ_ERR_HPP_INCLUDED__
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "platform.hpp"
+#include "likely.hpp"
+
+#ifdef ZMQ_HAVE_WINDOWS
+#include "windows.hpp"
+#else
+#include <netdb.h>
+#endif
+
+#ifdef ZMQ_HAVE_WINDOWS
+
+namespace zmq
+{
+
+ const char *wsa_error ();
+ void win_error (char *buffer_, size_t buffer_size_);
+ void wsa_error_to_errno ();
+
+}
+
+// Provides convenient way to check WSA-style errors on Windows.
+#define wsa_assert(x) \
+ do {\
+ if (unlikely (!(x))) {\
+ const char *errstr = zmq::wsa_error ();\
+ if (errstr != NULL) {\
+ fprintf (stderr, "Assertion failed: %s (%s:%d)\n", errstr, \
+ __FILE__, __LINE__);\
+ abort ();\
+ }\
+ }\
+ } while (false)
+
+// Provides convenient way to check GetLastError-style errors on Windows.
+#define win_assert(x) \
+ do {\
+ if (unlikely (!(x))) {\
+ char errstr [256];\
+ zmq::win_error (errstr, 256);\
+ fprintf (stderr, "Assertion failed: %s (%s:%d)\n", errstr, \
+ __FILE__, __LINE__);\
+ abort ();\
+ }\
+ } while (false)
+
+#endif
+
+// This macro works in exactly the same way as the normal assert. It is used
+// in its stead because standard assert on Win32 in broken - it prints nothing
+// when used within the scope of JNI library.
+#define zmq_assert(x) \
+ do {\
+ if (unlikely (!(x))) {\
+ fprintf (stderr, "Assertion failed: %s (%s:%d)\n", #x, \
+ __FILE__, __LINE__);\
+ abort ();\
+ }\
+ } while (false)
+
+// Provides convenient way to check for errno-style errors.
+#define errno_assert(x) \
+ do {\
+ if (unlikely (!(x))) {\
+ perror (NULL);\
+ fprintf (stderr, "%s (%s:%d)\n", #x, __FILE__, __LINE__);\
+ abort ();\
+ }\
+ } while (false)
+
+// Provides convenient way to check for POSIX errors.
+#define posix_assert(x) \
+ do {\
+ if (unlikely (x)) {\
+ fprintf (stderr, "%s (%s:%d)\n", strerror (x), __FILE__, __LINE__);\
+ abort ();\
+ }\
+ } while (false)
+
+// Provides convenient way to check for errors from getaddrinfo.
+#define gai_assert(x) \
+ do {\
+ if (unlikely (x)) {\
+ const char *errstr = gai_strerror (x);\
+ fprintf (stderr, "%s (%s:%d)\n", errstr, __FILE__, __LINE__);\
+ abort ();\
+ }\
+ } while (false)
+
+#endif
+
+#define zmq_not_implemented() \
+ do {\
+ fprintf (stderr, "Hic sunt leones (%s:%d)\n", __FILE__, __LINE__);\
+ abort ();\
+ } while (false)
diff --git a/src/fd.hpp b/src/fd.hpp
new file mode 100644
index 0000000..6ad8252
--- /dev/null
+++ b/src/fd.hpp
@@ -0,0 +1,44 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_FD_HPP_INCLUDED__
+#define __ZMQ_FD_HPP_INCLUDED__
+
+#include "platform.hpp"
+
+#ifdef ZMQ_HAVE_WINDOWS
+#include "windows.hpp"
+#endif
+
+namespace zmq
+{
+#ifdef ZMQ_HAVE_WINDOWS
+#if defined _MSC_VER &&_MSC_VER <= 1400
+ typedef UINT_PTR fd_t;
+ enum {retired_fd = (fd_t)(~0)};
+#else
+ typedef SOCKET fd_t;
+ enum {retired_fd = INVALID_SOCKET};
+#endif
+#else
+ typedef int fd_t;
+ enum {retired_fd = -1};
+#endif
+}
+#endif
diff --git a/src/forwarder.cpp b/src/forwarder.cpp
new file mode 100644
index 0000000..5aab8f2
--- /dev/null
+++ b/src/forwarder.cpp
@@ -0,0 +1,38 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "../include/zmq.h"
+
+#include "forwarder.hpp"
+#include "socket_base.hpp"
+#include "err.hpp"
+
+int zmq::forwarder (socket_base_t *insocket_, socket_base_t *outsocket_)
+{
+ zmq_msg_t msg;
+ int rc = zmq_msg_init (&msg);
+ errno_assert (rc == 0);
+
+ while (true) {
+ insocket_->recv (&msg, 0);
+ outsocket_->send (&msg, 0);
+ }
+
+ return 0;
+}
diff --git a/src/forwarder.hpp b/src/forwarder.hpp
new file mode 100644
index 0000000..68827a4
--- /dev/null
+++ b/src/forwarder.hpp
@@ -0,0 +1,31 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_FORWARDER_HPP_INCLUDED__
+#define __ZMQ_FORWARDER_HPP_INCLUDED__
+
+namespace zmq
+{
+
+ int forwarder (class socket_base_t *insocket_,
+ class socket_base_t *outsocket_);
+
+}
+
+#endif
diff --git a/src/fq.cpp b/src/fq.cpp
new file mode 100644
index 0000000..9028853
--- /dev/null
+++ b/src/fq.cpp
@@ -0,0 +1,130 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "../include/zmq.h"
+
+#include "fq.hpp"
+#include "pipe.hpp"
+#include "err.hpp"
+
+zmq::fq_t::fq_t () :
+ active (0),
+ current (0),
+ more (false)
+{
+}
+
+zmq::fq_t::~fq_t ()
+{
+ for (pipes_t::size_type i = 0; i != pipes.size (); i++)
+ pipes [i]->term ();
+}
+
+void zmq::fq_t::attach (reader_t *pipe_)
+{
+ pipes.push_back (pipe_);
+ pipes.swap (active, pipes.size () - 1);
+ active++;
+}
+
+void zmq::fq_t::detach (reader_t *pipe_)
+{
+ zmq_assert (!more || pipes [current] != pipe_);
+
+ // Remove the pipe from the list; adjust number of active pipes
+ // accordingly.
+ if (pipes.index (pipe_) < active) {
+ active--;
+ if (current == active)
+ current = 0;
+ }
+ pipes.erase (pipe_);
+}
+
+void zmq::fq_t::kill (reader_t *pipe_)
+{
+ // Move the pipe to the list of inactive pipes.
+ active--;
+ if (current == active)
+ current = 0;
+ pipes.swap (pipes.index (pipe_), active);
+}
+
+void zmq::fq_t::revive (reader_t *pipe_)
+{
+ // Move the pipe to the list of active pipes.
+ pipes.swap (pipes.index (pipe_), active);
+ active++;
+}
+
+int zmq::fq_t::recv (zmq_msg_t *msg_, int flags_)
+{
+ // Deallocate old content of the message.
+ zmq_msg_close (msg_);
+
+ // Round-robin over the pipes to get the next message.
+ for (int count = active; count != 0; count--) {
+
+ // Try to fetch new message. If we've already read part of the message
+ // subsequent part should be immediately available.
+ bool fetched = pipes [current]->read (msg_);
+ zmq_assert (!(more && !fetched));
+
+ // Note that when message is not fetched, current pipe is killed and
+ // replaced by another active pipe. Thus we don't have to increase
+ // the 'current' pointer.
+ if (fetched) {
+ more = msg_->flags & ZMQ_MSG_MORE;
+ if (!more) {
+ current++;
+ if (current >= active)
+ current = 0;
+ }
+ return 0;
+ }
+ }
+
+ // No message is available. Initialise the output parameter
+ // to be a 0-byte message.
+ zmq_msg_init (msg_);
+ errno = EAGAIN;
+ return -1;
+}
+
+bool zmq::fq_t::has_in ()
+{
+ // There are subsequent parts of the partly-read message available.
+ if (more)
+ return true;
+
+ // Note that messing with current doesn't break the fairness of fair
+ // queueing algorithm. If there are no messages available current will
+ // get back to its original value. Otherwise it'll point to the first
+ // pipe holding messages, skipping only pipes with no messages available.
+ for (int count = active; count != 0; count--) {
+ if (pipes [current]->check_read ())
+ return true;
+ current++;
+ if (current >= active)
+ current = 0;
+ }
+
+ return false;
+}
+
diff --git a/src/fq.hpp b/src/fq.hpp
new file mode 100644
index 0000000..5c699ee
--- /dev/null
+++ b/src/fq.hpp
@@ -0,0 +1,68 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_FQ_HPP_INCLUDED__
+#define __ZMQ_FQ_HPP_INCLUDED__
+
+#include "yarray.hpp"
+
+namespace zmq
+{
+
+ // Class manages a set of inbound pipes. On receive it performs fair
+ // queueing (RFC970) so that senders gone berserk won't cause denial of
+ // service for decent senders.
+ class fq_t
+ {
+ public:
+
+ fq_t ();
+ ~fq_t ();
+
+ void attach (class reader_t *pipe_);
+ void detach (class reader_t *pipe_);
+ void kill (class reader_t *pipe_);
+ void revive (class reader_t *pipe_);
+ int recv (zmq_msg_t *msg_, int flags_);
+ bool has_in ();
+
+ private:
+
+ // Inbound pipes.
+ typedef yarray_t <class reader_t> pipes_t;
+ pipes_t pipes;
+
+ // Number of active pipes. All the active pipes are located at the
+ // beginning of the pipes array.
+ pipes_t::size_type active;
+
+ // Index of the next bound pipe to read a message from.
+ pipes_t::size_type current;
+
+ // If true, part of a multipart message was already received, but
+ // there are following parts still waiting in the current pipe.
+ bool more;
+
+ fq_t (const fq_t&);
+ void operator = (const fq_t&);
+ };
+
+}
+
+#endif
diff --git a/src/i_endpoint.hpp b/src/i_endpoint.hpp
new file mode 100644
index 0000000..0d14224
--- /dev/null
+++ b/src/i_endpoint.hpp
@@ -0,0 +1,43 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_I_ENDPOINT_HPP_INCLUDED__
+#define __ZMQ_I_ENDPOINT_HPP_INCLUDED__
+
+#include "blob.hpp"
+
+namespace zmq
+{
+
+ struct i_endpoint
+ {
+ virtual ~i_endpoint () {}
+
+ virtual void attach_pipes (class reader_t *inpipe_,
+ class writer_t *outpipe_, const blob_t &peer_identity_) = 0;
+ virtual void detach_inpipe (class reader_t *pipe_) = 0;
+ virtual void detach_outpipe (class writer_t *pipe_) = 0;
+ virtual void kill (class reader_t *pipe_) = 0;
+ virtual void revive (class reader_t *pipe_) = 0;
+ virtual void revive (class writer_t *pipe_) = 0;
+ };
+
+}
+
+#endif
diff --git a/src/i_engine.hpp b/src/i_engine.hpp
new file mode 100644
index 0000000..ea6b850
--- /dev/null
+++ b/src/i_engine.hpp
@@ -0,0 +1,49 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_I_ENGINE_HPP_INCLUDED__
+#define __ZMQ_I_ENGINE_HPP_INCLUDED__
+
+#include <stddef.h>
+
+namespace zmq
+{
+
+ struct i_engine
+ {
+ virtual ~i_engine () {}
+
+ // Plug the engine to the session.
+ virtual void plug (struct i_inout *inout_) = 0;
+
+ // Unplug the engine from the session.
+ virtual void unplug () = 0;
+
+ // This method is called by the session to signalise that there
+ // are messages to send available.
+ virtual void revive () = 0;
+
+ // This method is called by the session to signalise that more
+ // messages can be written to the pipe.
+ virtual void resume_input () = 0;
+ };
+
+}
+
+#endif
diff --git a/src/i_inout.hpp b/src/i_inout.hpp
new file mode 100644
index 0000000..21d1838
--- /dev/null
+++ b/src/i_inout.hpp
@@ -0,0 +1,60 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_I_INOUT_HPP_INCLUDED__
+#define __ZMQ_I_INOUT_HPP_INCLUDED__
+
+#include "../include/zmq.h"
+
+#include "stdint.hpp"
+
+namespace zmq
+{
+
+ struct i_inout
+ {
+ virtual ~i_inout () {}
+
+ // Engine asks to get a message to send to the network.
+ virtual bool read (::zmq_msg_t *msg_) = 0;
+
+ // Engine sends the incoming message further on downstream.
+ virtual bool write (::zmq_msg_t *msg_) = 0;
+
+ // Flush all the previously written messages downstream.
+ virtual void flush () = 0;
+
+ // Drop all the references to the engine. The parameter is the object
+ // to use to reconnect. If reconnection is not required, the argument
+ // is set to NULL.
+ virtual void detach (class owned_t *reconnecter_) = 0;
+
+ // Returns least loaded I/O thread.
+ virtual class io_thread_t *get_io_thread () = 0;
+
+ // Return pointer to the owning socket.
+ virtual class socket_base_t *get_owner () = 0;
+
+ // Return ordinal number of the session.
+ virtual uint64_t get_ordinal () = 0;
+ };
+
+}
+
+#endif
diff --git a/src/i_poll_events.hpp b/src/i_poll_events.hpp
new file mode 100644
index 0000000..8b85f7a
--- /dev/null
+++ b/src/i_poll_events.hpp
@@ -0,0 +1,45 @@
+/*
+Copyright (c) 2007-2010 iMatix Corporation
+
+This file is part of 0MQ.
+
+0MQ is free software; you can redistribute it and/or modify it under
+the terms of the Lesser GNU General Public License as published by
+the Free Software Foundation; either version 3 of the License, or
+(at your option) any later version.
+
+0MQ 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
+Lesser GNU General Public License for more details.
+
+You should have received a copy of the Lesser GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_I_POLL_EVENTS_HPP_INCLUDED__
+#define __ZMQ_I_POLL_EVENTS_HPP_INCLUDED__
+
+namespace zmq
+{
+
+ // Virtual interface to be exposed by object that want to be notified
+ // about events on file descriptors.
+
+ struct i_poll_events
+ {
+ virtual ~i_poll_events () {};
+
+ // Called by I/O thread when file descriptor is ready for reading.
+ virtual void in_event () = 0;
+
+ // Called by I/O thread when file descriptor is ready for writing.
+ virtual void out_event () = 0;
+
+ // Called when timer expires.
+ virtual void timer_event () = 0;
+ };
+
+}
+
+#endif
diff --git a/src/io_object.cpp b/src/io_object.cpp
new file mode 100644
index 0000000..086f173
--- /dev/null
+++ b/src/io_object.cpp
@@ -0,0 +1,92 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "io_object.hpp"
+#include "io_thread.hpp"
+#include "err.hpp"
+
+zmq::io_object_t::io_object_t (io_thread_t *io_thread_)
+{
+ // Retrieve the poller from the thread we are running in.
+ poller = io_thread_->get_poller ();
+}
+
+zmq::io_object_t::~io_object_t ()
+{
+}
+
+void zmq::io_object_t::set_io_thread (io_thread_t *io_thread_)
+{
+ poller = io_thread_->get_poller ();
+}
+
+zmq::io_object_t::handle_t zmq::io_object_t::add_fd (fd_t fd_)
+{
+ return poller->add_fd (fd_, this);
+}
+
+void zmq::io_object_t::rm_fd (handle_t handle_)
+{
+ poller->rm_fd (handle_);
+}
+
+void zmq::io_object_t::set_pollin (handle_t handle_)
+{
+ poller->set_pollin (handle_);
+}
+
+void zmq::io_object_t::reset_pollin (handle_t handle_)
+{
+ poller->reset_pollin (handle_);
+}
+
+void zmq::io_object_t::set_pollout (handle_t handle_)
+{
+ poller->set_pollout (handle_);
+}
+
+void zmq::io_object_t::reset_pollout (handle_t handle_)
+{
+ poller->reset_pollout (handle_);
+}
+
+void zmq::io_object_t::add_timer ()
+{
+ poller->add_timer (this);
+}
+
+void zmq::io_object_t::cancel_timer ()
+{
+ poller->cancel_timer (this);
+}
+
+void zmq::io_object_t::in_event ()
+{
+ zmq_assert (false);
+}
+
+void zmq::io_object_t::out_event ()
+{
+ zmq_assert (false);
+}
+
+void zmq::io_object_t::timer_event ()
+{
+ zmq_assert (false);
+}
diff --git a/src/io_object.hpp b/src/io_object.hpp
new file mode 100644
index 0000000..655e7f5
--- /dev/null
+++ b/src/io_object.hpp
@@ -0,0 +1,77 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_IO_OBJECT_HPP_INCLUDED__
+#define __ZMQ_IO_OBJECT_HPP_INCLUDED__
+
+#include <stddef.h>
+
+#include "stdint.hpp"
+#include "poller.hpp"
+#include "i_poll_events.hpp"
+
+namespace zmq
+{
+
+ // Simple base class for objects that live in I/O threads.
+ // It makes communication with the poller object easier and
+ // makes defining unneeded event handlers unnecessary.
+
+ class io_object_t : public i_poll_events
+ {
+ public:
+
+ io_object_t (class io_thread_t *io_thread_ = NULL);
+ ~io_object_t ();
+
+ protected:
+
+ typedef poller_t::handle_t handle_t;
+
+ // Derived class can init/swap the underlying I/O thread.
+ // Caution: Remove all the file descriptors from the old I/O thread
+ // before swapping to the new one!
+ void set_io_thread (class io_thread_t *io_thread_);
+
+ // Methods to access underlying poller object.
+ handle_t add_fd (fd_t fd_);
+ void rm_fd (handle_t handle_);
+ void set_pollin (handle_t handle_);
+ void reset_pollin (handle_t handle_);
+ void set_pollout (handle_t handle_);
+ void reset_pollout (handle_t handle_);
+ void add_timer ();
+ void cancel_timer ();
+
+ // i_poll_events interface implementation.
+ void in_event ();
+ void out_event ();
+ void timer_event ();
+
+ private:
+
+ poller_t *poller;
+
+ io_object_t (const io_object_t&);
+ void operator = (const io_object_t&);
+ };
+
+}
+
+#endif
diff --git a/src/io_thread.cpp b/src/io_thread.cpp
new file mode 100644
index 0000000..fac6961
--- /dev/null
+++ b/src/io_thread.cpp
@@ -0,0 +1,105 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <new>
+
+#include "../include/zmq.h"
+
+#include "io_thread.hpp"
+#include "platform.hpp"
+#include "err.hpp"
+#include "ctx.hpp"
+
+zmq::io_thread_t::io_thread_t (ctx_t *ctx_,
+ uint32_t thread_slot_) :
+ object_t (ctx_, thread_slot_)
+{
+ poller = new (std::nothrow) poller_t;
+ zmq_assert (poller);
+
+ signaler_handle = poller->add_fd (signaler.get_fd (), this);
+ poller->set_pollin (signaler_handle);
+}
+
+zmq::io_thread_t::~io_thread_t ()
+{
+ delete poller;
+}
+
+void zmq::io_thread_t::start ()
+{
+ // Start the underlying I/O thread.
+ poller->start ();
+}
+
+void zmq::io_thread_t::stop ()
+{
+ send_stop ();
+}
+
+zmq::signaler_t *zmq::io_thread_t::get_signaler ()
+{
+ return &signaler;
+}
+
+int zmq::io_thread_t::get_load ()
+{
+ return poller->get_load ();
+}
+
+void zmq::io_thread_t::in_event ()
+{
+ // TODO: Do we want to limit number of commands I/O thread can
+ // process in a single go?
+
+ while (true) {
+
+ // Get the next command. If there is none, exit.
+ command_t cmd;
+ if (!signaler.recv (&cmd, false))
+ break;
+
+ // Process the command.
+ cmd.destination->process_command (cmd);
+ }
+}
+
+void zmq::io_thread_t::out_event ()
+{
+ // We are never polling for POLLOUT here. This function is never called.
+ zmq_assert (false);
+}
+
+void zmq::io_thread_t::timer_event ()
+{
+ // No timers here. This function is never called.
+ zmq_assert (false);
+}
+
+zmq::poller_t *zmq::io_thread_t::get_poller ()
+{
+ zmq_assert (poller);
+ return poller;
+}
+
+void zmq::io_thread_t::process_stop ()
+{
+ poller->rm_fd (signaler_handle);
+ poller->stop ();
+}
diff --git a/src/io_thread.hpp b/src/io_thread.hpp
new file mode 100644
index 0000000..3d832c0
--- /dev/null
+++ b/src/io_thread.hpp
@@ -0,0 +1,85 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_IO_THREAD_HPP_INCLUDED__
+#define __ZMQ_IO_THREAD_HPP_INCLUDED__
+
+#include <vector>
+
+#include "stdint.hpp"
+#include "object.hpp"
+#include "poller.hpp"
+#include "i_poll_events.hpp"
+#include "signaler.hpp"
+
+namespace zmq
+{
+
+ // Generic part of the I/O thread. Polling-mechanism-specific features
+ // are implemented in separate "polling objects".
+
+ class io_thread_t : public object_t, public i_poll_events
+ {
+ public:
+
+ io_thread_t (class ctx_t *ctx_, uint32_t thread_slot_);
+
+ // Clean-up. If the thread was started, it's neccessary to call 'stop'
+ // before invoking destructor. Otherwise the destructor would hang up.
+ ~io_thread_t ();
+
+ // Launch the physical thread.
+ void start ();
+
+ // Ask underlying thread to stop.
+ void stop ();
+
+ // Returns signaler associated with this I/O thread.
+ signaler_t *get_signaler ();
+
+ // i_poll_events implementation.
+ void in_event ();
+ void out_event ();
+ void timer_event ();
+
+ // Used by io_objects to retrieve the assciated poller object.
+ poller_t *get_poller ();
+
+ // Command handlers.
+ void process_stop ();
+
+ // Returns load experienced by the I/O thread.
+ int get_load ();
+
+ private:
+
+ // Poll thread gets notifications about incoming commands using
+ // this signaler.
+ signaler_t signaler;
+
+ // Handle associated with signaler's file descriptor.
+ poller_t::handle_t signaler_handle;
+
+ // I/O multiplexing is performed using a poller object.
+ poller_t *poller;
+ };
+
+}
+
+#endif
diff --git a/src/ip.cpp b/src/ip.cpp
new file mode 100644
index 0000000..79d90da
--- /dev/null
+++ b/src/ip.cpp
@@ -0,0 +1,335 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdlib.h>
+#include <string>
+
+#include "ip.hpp"
+#include "platform.hpp"
+#include "err.hpp"
+#include "stdint.hpp"
+
+#if defined ZMQ_HAVE_SOLARIS
+
+#include <sys/sockio.h>
+#include <net/if.h>
+#include <unistd.h>
+
+// On Solaris platform, network interface name can be queried by ioctl.
+static int resolve_nic_name (in_addr* addr_, char const *interface_)
+{
+ // Create a socket.
+ int fd = socket (AF_INET, SOCK_DGRAM, 0);
+ zmq_assert (fd != -1);
+
+ // Retrieve number of interfaces.
+ lifnum ifn;
+ ifn.lifn_family = AF_UNSPEC;
+ ifn.lifn_flags = 0;
+ int rc = ioctl (fd, SIOCGLIFNUM, (char*) &ifn);
+ zmq_assert (rc != -1);
+
+ // Allocate memory to get interface names.
+ size_t ifr_size = sizeof (struct lifreq) * ifn.lifn_count;
+ char *ifr = (char*) malloc (ifr_size);
+ errno_assert (ifr);
+
+ // Retrieve interface names.
+ lifconf ifc;
+ ifc.lifc_family = AF_UNSPEC;
+ ifc.lifc_flags = 0;
+ ifc.lifc_len = ifr_size;
+ ifc.lifc_buf = ifr;
+ rc = ioctl (fd, SIOCGLIFCONF, (char*) &ifc);
+ zmq_assert (rc != -1);
+
+ // Find the interface with the specified name and AF_INET family.
+ bool found = false;
+ lifreq *ifrp = ifc.lifc_req;
+ for (int n = 0; n < (int) (ifc.lifc_len / sizeof (lifreq));
+ n ++, ifrp ++) {
+ if (!strcmp (interface_, ifrp->lifr_name)) {
+ rc = ioctl (fd, SIOCGLIFADDR, (char*) ifrp);
+ zmq_assert (rc != -1);
+ if (ifrp->lifr_addr.ss_family == AF_INET) {
+ *addr_ = ((sockaddr_in*) &ifrp->lifr_addr)->sin_addr;
+ found = true;
+ break;
+ }
+ }
+ }
+
+ // Clean-up.
+ free (ifr);
+ close (fd);
+
+ if (!found) {
+ errno = ENODEV;
+ return -1;
+ }
+
+ return 0;
+}
+
+#elif defined ZMQ_HAVE_AIX || ZMQ_HAVE_HPUX
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+
+static int resolve_nic_name (in_addr* addr_, char const *interface_)
+{
+ // Create a socket.
+ int sd = socket (AF_INET, SOCK_DGRAM, 0);
+ zmq_assert (sd != -1);
+
+ struct ifreq ifr;
+
+ // Copy interface name for ioctl get.
+ strncpy (ifr.ifr_name, interface_, sizeof (ifr.ifr_name));
+
+ // Fetch interface address.
+ int rc = ioctl (sd, SIOCGIFADDR, (caddr_t) &ifr, sizeof (struct ifreq));
+
+ // Clean up.
+ close (sd);
+
+ if (rc == -1) {
+ errno = ENODEV;
+ return -1;
+ }
+
+ struct sockaddr *sa = (struct sockaddr *) &ifr.ifr_addr;
+ *addr_ = ((sockaddr_in*)sa)->sin_addr;
+ return 0;
+}
+
+#elif ((defined ZMQ_HAVE_LINUX || defined ZMQ_HAVE_FREEBSD ||\
+ defined ZMQ_HAVE_OSX || defined ZMQ_HAVE_OPENBSD ||\
+ defined ZMQ_HAVE_QNXNTO || defined ZMQ_HAVE_NETBSD)\
+ && defined ZMQ_HAVE_IFADDRS)
+
+#include <ifaddrs.h>
+
+// On these platforms, network interface name can be queried
+// using getifaddrs function.
+static int resolve_nic_name (in_addr* addr_, char const *interface_)
+{
+ // Get the addresses.
+ ifaddrs* ifa = NULL;
+ int rc = getifaddrs (&ifa);
+ zmq_assert (rc == 0);
+ zmq_assert (ifa != NULL);
+
+ // Find the corresponding network interface.
+ bool found = false;
+ for (ifaddrs *ifp = ifa; ifp != NULL ;ifp = ifp->ifa_next)
+ if (ifp->ifa_addr && ifp->ifa_addr->sa_family == AF_INET
+ && !strcmp (interface_, ifp->ifa_name))
+ {
+ *addr_ = ((sockaddr_in*) ifp->ifa_addr)->sin_addr;
+ found = true;
+ break;
+ }
+
+ // Clean-up;
+ freeifaddrs (ifa);
+
+ if (!found) {
+ errno = ENODEV;
+ return -1;
+ }
+
+ return 0;
+}
+
+#else
+
+// On other platforms we assume there are no sane interface names.
+// This is true especially of Windows.
+static int resolve_nic_name (in_addr* addr_, char const *interface_)
+{
+ errno = ENODEV;
+ return -1;
+}
+
+#endif
+
+int zmq::resolve_ip_interface (sockaddr_storage* addr_, socklen_t *addr_len_,
+ char const *interface_)
+{
+ // Find the ':' at end that separates NIC name from service.
+ const char *delimiter = strrchr (interface_, ':');
+ if (!delimiter) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ // Separate the name/port.
+ std::string iface (interface_, delimiter - interface_);
+ std::string service (delimiter + 1);
+
+ // Initialize the output parameter.
+ memset (addr_, 0, sizeof (*addr_));
+
+ // Initialise IPv4-format family/port.
+ sockaddr_in ip4_addr;
+ memset (&ip4_addr, 0, sizeof (ip4_addr));
+ ip4_addr.sin_family = AF_INET;
+ ip4_addr.sin_port = htons ((uint16_t) atoi (service.c_str()));
+
+ // Initialize temporary output pointers with ip4_addr
+ sockaddr *out_addr = (sockaddr *) &ip4_addr;
+ size_t out_addrlen = sizeof (ip4_addr);
+
+ // 0 is not a valid port.
+ if (!ip4_addr.sin_port) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ // * resolves to INADDR_ANY.
+ if (iface.compare("*") == 0) {
+ ip4_addr.sin_addr.s_addr = htonl (INADDR_ANY);
+ zmq_assert (out_addrlen <= sizeof (*addr_));
+ memcpy (addr_, out_addr, out_addrlen);
+ *addr_len_ = out_addrlen;
+ return 0;
+ }
+
+ // Try to resolve the string as a NIC name.
+ int rc = resolve_nic_name (&ip4_addr.sin_addr, iface.c_str());
+ if (rc != 0 && errno != ENODEV)
+ return rc;
+ if (rc == 0) {
+ zmq_assert (out_addrlen <= sizeof (*addr_));
+ memcpy (addr_, out_addr, out_addrlen);
+ *addr_len_ = out_addrlen;
+ return 0;
+ }
+
+ // There's no such interface name. Assume literal address.
+ addrinfo *res = NULL;
+
+ // Set up the query.
+ addrinfo req;
+ memset (&req, 0, sizeof (req));
+
+ // We only support IPv4 addresses for now.
+ req.ai_family = AF_INET;
+
+ // Arbitrary, not used in the output, but avoids duplicate results.
+ req.ai_socktype = SOCK_STREAM;
+
+ // Restrict hostname/service to literals to avoid any DNS lookups or
+ // service-name irregularity due to indeterminate socktype.
+ req.ai_flags = AI_PASSIVE | AI_NUMERICHOST | AI_NUMERICSERV;
+
+ // Resolve the literal address. Some of the error info is lost in case
+ // of error, however, there's no way to report EAI errors via errno.
+ rc = getaddrinfo (iface.c_str(), service.c_str(), &req, &res);
+ if (rc) {
+ errno = ENODEV;
+ return -1;
+ }
+
+ // Use the first result.
+ zmq_assert ((size_t) (res->ai_addrlen) <= sizeof (*addr_));
+ memcpy (addr_, res->ai_addr, res->ai_addrlen);
+ *addr_len_ = res->ai_addrlen;
+
+ // Cleanup getaddrinfo after copying the possibly referenced result.
+ if (res)
+ freeaddrinfo (res);
+
+ return 0;
+}
+
+int zmq::resolve_ip_hostname (sockaddr_storage *addr_, socklen_t *addr_len_,
+ const char *hostname_)
+{
+ // Find the ':' that separates hostname name from service.
+ const char *delimiter = strchr (hostname_, ':');
+ if (!delimiter) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ // Separate the hostname and service.
+ std::string hostname (hostname_, delimiter - hostname_);
+ std::string service (delimiter + 1);
+
+ // Set up the query.
+ addrinfo req;
+ memset (&req, 0, sizeof (req));
+
+ // We only support IPv4 addresses for now.
+ req.ai_family = AF_INET;
+
+ // Need to choose one to avoid duplicate results from getaddrinfo() - this
+ // doesn't really matter, since it's not included in the addr-output.
+ req.ai_socktype = SOCK_STREAM;
+
+ // Avoid named services due to unclear socktype, and don't pick IPv4
+ // addresses if we don't have a local IPv4 address configured.
+ // If this is failing for you on a host with only IPv6 connectivity,
+ // please contribute proper IPv6 support for all functions in this file.
+ req.ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG;
+
+ // Resolve host name. Some of the error info is lost in case of error,
+ // however, there's no way to report EAI errors via errno.
+ addrinfo *res;
+ int rc = getaddrinfo (hostname.c_str (), service.c_str (), &req, &res);
+ if (rc) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ // Copy first result to output addr with hostname and service.
+ zmq_assert ((size_t) (res->ai_addrlen) <= sizeof (*addr_));
+ memcpy (addr_, res->ai_addr, res->ai_addrlen);
+ *addr_len_ = res->ai_addrlen;
+
+ freeaddrinfo (res);
+
+ return 0;
+}
+
+#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS
+
+int zmq::resolve_local_path (sockaddr_storage *addr_, socklen_t *addr_len_,
+ const char *path_)
+{
+ sockaddr_un *un = (sockaddr_un*) addr_;
+ if (strlen (path_) >= sizeof (un->sun_path))
+ {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+ strcpy (un->sun_path, path_);
+ un->sun_family = AF_UNIX;
+ *addr_len_ = sizeof (sockaddr_un);
+ return 0;
+}
+
+#endif
+
diff --git a/src/ip.hpp b/src/ip.hpp
new file mode 100644
index 0000000..d963df2
--- /dev/null
+++ b/src/ip.hpp
@@ -0,0 +1,69 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_IP_HPP_INCLUDED__
+#define __ZMQ_IP_HPP_INCLUDED__
+
+#include "platform.hpp"
+
+#ifdef ZMQ_HAVE_WINDOWS
+#include "windows.hpp"
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#endif
+
+#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS
+#include <sys/un.h>
+#endif
+
+// Some platforms (notably Darwin/OSX and NetBSD) do not define all AI_
+// flags for getaddrinfo(). This can be worked around safely by defining
+// these to 0.
+#ifndef AI_ADDRCONFIG
+#define AI_ADDRCONFIG 0
+#endif
+#ifndef AI_NUMERICSERV
+#define AI_NUMERICSERV 0
+#endif
+
+namespace zmq
+{
+
+ // Resolves network interface name in <nic-name>:<port> format. Symbol "*"
+ // (asterisk) resolves to INADDR_ANY (all network interfaces).
+ int resolve_ip_interface (sockaddr_storage *addr_, socklen_t *addr_len_,
+ char const *interface_);
+
+ // This function resolves a string in <hostname>:<port-number> format.
+ // Hostname can be either the name of the host or its IP address.
+ int resolve_ip_hostname (sockaddr_storage *addr_, socklen_t *addr_len_,
+ const char *hostname_);
+
+#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS
+ // This function sets up address for UNIX domain transport.
+ int resolve_local_path (sockaddr_storage *addr_, socklen_t *addr_len_,
+ const char* pathname_);
+#endif
+}
+
+#endif
diff --git a/src/kqueue.cpp b/src/kqueue.cpp
new file mode 100644
index 0000000..e1fe2fa
--- /dev/null
+++ b/src/kqueue.cpp
@@ -0,0 +1,226 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "platform.hpp"
+
+#if defined ZMQ_HAVE_FREEBSD || defined ZMQ_HAVE_OPENBSD ||\
+ defined ZMQ_HAVE_OSX || defined ZMQ_HAVE_NETBSD
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/event.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <algorithm>
+#include <new>
+
+#include "kqueue.hpp"
+#include "err.hpp"
+#include "config.hpp"
+#include "i_poll_events.hpp"
+
+// NetBSD defines (struct kevent).udata as intptr_t, everyone else
+// as void *.
+#if defined ZMQ_HAVE_NETBSD
+#define kevent_udata_t intptr_t
+#else
+#define kevent_udata_t void *
+#endif
+
+zmq::kqueue_t::kqueue_t () :
+ stopping (false)
+{
+ // Create event queue
+ kqueue_fd = kqueue ();
+ errno_assert (kqueue_fd != -1);
+}
+
+zmq::kqueue_t::~kqueue_t ()
+{
+ worker.stop ();
+
+ // Make sure there are no fds registered on shutdown.
+ zmq_assert (load.get () == 0);
+
+ close (kqueue_fd);
+}
+
+void zmq::kqueue_t::kevent_add (fd_t fd_, short filter_, void *udata_)
+{
+ struct kevent ev;
+
+ EV_SET (&ev, fd_, filter_, EV_ADD, 0, 0, (kevent_udata_t)udata_);
+ int rc = kevent (kqueue_fd, &ev, 1, NULL, 0, NULL);
+ errno_assert (rc != -1);
+}
+
+void zmq::kqueue_t::kevent_delete (fd_t fd_, short filter_)
+{
+ struct kevent ev;
+
+ EV_SET (&ev, fd_, filter_, EV_DELETE, 0, 0, (kevent_udata_t)NULL);
+ int rc = kevent (kqueue_fd, &ev, 1, NULL, 0, NULL);
+ errno_assert (rc != -1);
+}
+
+zmq::kqueue_t::handle_t zmq::kqueue_t::add_fd (fd_t fd_,
+ i_poll_events *reactor_)
+{
+ poll_entry_t *pe = new (std::nothrow) poll_entry_t;
+ zmq_assert (pe != NULL);
+
+ pe->fd = fd_;
+ pe->flag_pollin = 0;
+ pe->flag_pollout = 0;
+ pe->reactor = reactor_;
+
+ return pe;
+}
+
+void zmq::kqueue_t::rm_fd (handle_t handle_)
+{
+ poll_entry_t *pe = (poll_entry_t*) handle_;
+ if (pe->flag_pollin)
+ kevent_delete (pe->fd, EVFILT_READ);
+ if (pe->flag_pollout)
+ kevent_delete (pe->fd, EVFILT_WRITE);
+ pe->fd = retired_fd;
+ retired.push_back (pe);
+}
+
+void zmq::kqueue_t::set_pollin (handle_t handle_)
+{
+ poll_entry_t *pe = (poll_entry_t*) handle_;
+ pe->flag_pollin = true;
+ kevent_add (pe->fd, EVFILT_READ, pe);
+}
+
+void zmq::kqueue_t::reset_pollin (handle_t handle_)
+{
+ poll_entry_t *pe = (poll_entry_t*) handle_;
+ pe->flag_pollin = false;
+ kevent_delete (pe->fd, EVFILT_READ);
+}
+
+void zmq::kqueue_t::set_pollout (handle_t handle_)
+{
+ poll_entry_t *pe = (poll_entry_t*) handle_;
+ pe->flag_pollout = true;
+ kevent_add (pe->fd, EVFILT_WRITE, pe);
+}
+
+void zmq::kqueue_t::reset_pollout (handle_t handle_)
+{
+ poll_entry_t *pe = (poll_entry_t*) handle_;
+ pe->flag_pollout = false;
+ kevent_delete (pe->fd, EVFILT_WRITE);
+}
+
+void zmq::kqueue_t::add_timer (i_poll_events *events_)
+{
+ timers.push_back (events_);
+}
+
+void zmq::kqueue_t::cancel_timer (i_poll_events *events_)
+{
+ timers_t::iterator it = std::find (timers.begin (), timers.end (), events_);
+ if (it != timers.end ())
+ timers.erase (it);
+}
+
+int zmq::kqueue_t::get_load ()
+{
+ return load.get ();
+}
+
+void zmq::kqueue_t::start ()
+{
+ worker.start (worker_routine, this);
+}
+
+void zmq::kqueue_t::stop ()
+{
+ stopping = true;
+}
+
+void zmq::kqueue_t::loop ()
+{
+ while (!stopping) {
+
+ struct kevent ev_buf [max_io_events];
+
+ // Compute time interval to wait.
+ timespec timeout = {max_timer_period / 1000,
+ (max_timer_period % 1000) * 1000000};
+
+ // Wait for events.
+ int n = kevent (kqueue_fd, NULL, 0,
+ &ev_buf [0], max_io_events, timers.empty () ? NULL : &timeout);
+ if (n == -1 && errno == EINTR)
+ continue;
+ errno_assert (n != -1);
+
+ // Handle timer.
+ if (!n) {
+
+ // Use local list of timers as timer handlers may fill new timers
+ // into the original array.
+ timers_t t;
+ std::swap (timers, t);
+
+ // Trigger all the timers.
+ for (timers_t::iterator it = t.begin (); it != t.end (); it ++)
+ (*it)->timer_event ();
+
+ continue;
+ }
+
+ for (int i = 0; i < n; i ++) {
+ poll_entry_t *pe = (poll_entry_t*) ev_buf [i].udata;
+
+ if (pe->fd == retired_fd)
+ continue;
+ if (ev_buf [i].flags & EV_EOF)
+ pe->reactor->in_event ();
+ if (pe->fd == retired_fd)
+ continue;
+ if (ev_buf [i].filter == EVFILT_WRITE)
+ pe->reactor->out_event ();
+ if (pe->fd == retired_fd)
+ continue;
+ if (ev_buf [i].filter == EVFILT_READ)
+ pe->reactor->in_event ();
+ }
+
+ // Destroy retired event sources.
+ for (retired_t::iterator it = retired.begin (); it != retired.end ();
+ it ++)
+ delete *it;
+ retired.clear ();
+ }
+}
+
+void zmq::kqueue_t::worker_routine (void *arg_)
+{
+ ((kqueue_t*) arg_)->loop ();
+}
+
+// Don't pollute namespace with defines local to this file
+#undef kevent_udata_t
+#endif
diff --git a/src/kqueue.hpp b/src/kqueue.hpp
new file mode 100644
index 0000000..ac28a7d
--- /dev/null
+++ b/src/kqueue.hpp
@@ -0,0 +1,113 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_KQUEUE_HPP_INCLUDED__
+#define __ZMQ_KQUEUE_HPP_INCLUDED__
+
+#include "platform.hpp"
+
+#if defined ZMQ_HAVE_FREEBSD || defined ZMQ_HAVE_OPENBSD ||\
+ defined ZMQ_HAVE_OSX || defined ZMQ_HAVE_NETBSD
+
+#include <vector>
+
+#include "fd.hpp"
+#include "thread.hpp"
+#include "atomic_counter.hpp"
+
+namespace zmq
+{
+
+ // Implements socket polling mechanism using the BSD-specific
+ // kqueue interface.
+
+ class kqueue_t
+ {
+ public:
+
+ typedef void* handle_t;
+
+ kqueue_t ();
+ ~kqueue_t ();
+
+ // "poller" concept.
+ handle_t add_fd (fd_t fd_, struct i_poll_events *events_);
+ void rm_fd (handle_t handle_);
+ void set_pollin (handle_t handle_);
+ void reset_pollin (handle_t handle_);
+ void set_pollout (handle_t handle_);
+ void reset_pollout (handle_t handle_);
+ void add_timer (struct i_poll_events *events_);
+ void cancel_timer (struct i_poll_events *events_);
+ int get_load ();
+ void start ();
+ void stop ();
+
+ private:
+
+ // Main worker thread routine.
+ static void worker_routine (void *arg_);
+
+ // Main event loop.
+ void loop ();
+
+ // File descriptor referring to the kernel event queue.
+ fd_t kqueue_fd;
+
+ // Adds the event to the kqueue.
+ void kevent_add (fd_t fd_, short filter_, void *udata_);
+
+ // Deletes the event from the kqueue.
+ void kevent_delete (fd_t fd_, short filter_);
+
+ struct poll_entry_t
+ {
+ fd_t fd;
+ bool flag_pollin;
+ bool flag_pollout;
+ i_poll_events *reactor;
+ };
+
+ // List of retired event sources.
+ typedef std::vector <poll_entry_t*> retired_t;
+ retired_t retired;
+
+ // List of all the engines waiting for the timer event.
+ typedef std::vector <struct i_poll_events*> timers_t;
+ timers_t timers;
+
+ // If true, thread is in the process of shutting down.
+ bool stopping;
+
+ // Handle of the physical thread doing the I/O work.
+ thread_t worker;
+
+ // Load of the poller. Currently number of file descriptors
+ // registered with the poller.
+ atomic_counter_t load;
+
+ kqueue_t (const kqueue_t&);
+ void operator = (const kqueue_t&);
+ };
+
+}
+
+#endif
+
+#endif
diff --git a/src/lb.cpp b/src/lb.cpp
new file mode 100644
index 0000000..ca93ba2
--- /dev/null
+++ b/src/lb.cpp
@@ -0,0 +1,123 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "../include/zmq.h"
+
+#include "lb.hpp"
+#include "pipe.hpp"
+#include "err.hpp"
+
+zmq::lb_t::lb_t () :
+ active (0),
+ current (0),
+ more (false)
+{
+}
+
+zmq::lb_t::~lb_t ()
+{
+ for (pipes_t::size_type i = 0; i != pipes.size (); i++)
+ pipes [i]->term ();
+}
+
+void zmq::lb_t::attach (writer_t *pipe_)
+{
+ pipes.push_back (pipe_);
+ pipes.swap (active, pipes.size () - 1);
+ active++;
+}
+
+void zmq::lb_t::detach (writer_t *pipe_)
+{
+ zmq_assert (!more || pipes [current] != pipe_);
+
+ // Remove the pipe from the list; adjust number of active pipes
+ // accordingly.
+ if (pipes.index (pipe_) < active) {
+ active--;
+ if (current == active)
+ current = 0;
+ }
+ pipes.erase (pipe_);
+}
+
+void zmq::lb_t::revive (writer_t *pipe_)
+{
+ // Move the pipe to the list of active pipes.
+ pipes.swap (pipes.index (pipe_), active);
+ active++;
+}
+
+int zmq::lb_t::send (zmq_msg_t *msg_, int flags_)
+{
+ while (active > 0) {
+ if (pipes [current]->write (msg_)) {
+ more = msg_->flags & ZMQ_MSG_MORE;
+ break;
+ }
+
+ zmq_assert (!more);
+ active--;
+ if (current < active)
+ pipes.swap (current, active);
+ else
+ current = 0;
+ }
+
+ // If there are no pipes we cannot send the message.
+ if (active == 0) {
+ errno = EAGAIN;
+ return -1;
+ }
+
+ // If it's final part of the message we can fluch it downstream and
+ // continue round-robinning (load balance).
+ if (!more) {
+ pipes [current]->flush ();
+ current = (current + 1) % active;
+ }
+
+ // Detach the message from the data buffer.
+ int rc = zmq_msg_init (msg_);
+ zmq_assert (rc == 0);
+
+ return 0;
+}
+
+bool zmq::lb_t::has_out ()
+{
+ // If one part of the message was already written we can definitely
+ // write the rest of the message.
+ if (more)
+ return true;
+
+ while (active > 0) {
+ if (pipes [current]->check_write ())
+ return true;
+
+ active--;
+ if (current < active)
+ pipes.swap (current, active);
+ else
+ current = 0;
+ }
+
+ return false;
+}
+
diff --git a/src/lb.hpp b/src/lb.hpp
new file mode 100644
index 0000000..526a727
--- /dev/null
+++ b/src/lb.hpp
@@ -0,0 +1,65 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_LB_HPP_INCLUDED__
+#define __ZMQ_LB_HPP_INCLUDED__
+
+#include "yarray.hpp"
+
+namespace zmq
+{
+
+ // Class manages a set of outbound pipes. On send it load balances
+ // messages fairly among the pipes.
+ class lb_t
+ {
+ public:
+
+ lb_t ();
+ ~lb_t ();
+
+ void attach (class writer_t *pipe_);
+ void detach (class writer_t *pipe_);
+ void revive (class writer_t *pipe_);
+ int send (zmq_msg_t *msg_, int flags_);
+ bool has_out ();
+
+ private:
+
+ // List of outbound pipes.
+ typedef yarray_t <class writer_t> pipes_t;
+ pipes_t pipes;
+
+ // Number of active pipes. All the active pipes are located at the
+ // beginning of the pipes array.
+ pipes_t::size_type active;
+
+ // Points to the last pipe that the most recent message was sent to.
+ pipes_t::size_type current;
+
+ // True if last we are in the middle of a multipart message.
+ bool more;
+
+ lb_t (const lb_t&);
+ void operator = (const lb_t&);
+ };
+
+}
+
+#endif
diff --git a/src/libzmq.pc.in b/src/libzmq.pc.in
new file mode 100644
index 0000000..ba155a3
--- /dev/null
+++ b/src/libzmq.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libzmq
+Description: 0MQ c++ library
+Version: @VERSION@
+Libs: -L${libdir} -lzmq
+Cflags: -I${includedir}
diff --git a/src/likely.hpp b/src/likely.hpp
new file mode 100644
index 0000000..b7a8171
--- /dev/null
+++ b/src/likely.hpp
@@ -0,0 +1,32 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_LIKELY_HPP_INCLUDED__
+#define __ZMQ_LIKELY_HPP_INCLUDED__
+
+#if defined __GNUC__
+#define likely(x) __builtin_expect ((x), 1)
+#define unlikely(x) __builtin_expect ((x), 0)
+#else
+#define likely(x) (x)
+#define unlikely(x) (x)
+#endif
+
+
+#endif
diff --git a/src/msg_content.hpp b/src/msg_content.hpp
new file mode 100644
index 0000000..d409d45
--- /dev/null
+++ b/src/msg_content.hpp
@@ -0,0 +1,51 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_MSG_HPP_INCLUDE__
+#define __ZMQ_MSG_HPP_INCLUDE__
+
+#include <stddef.h>
+
+#include "../include/zmq.h"
+
+#include "atomic_counter.hpp"
+
+namespace zmq
+{
+
+ // Shared message buffer. Message data are either allocated in one
+ // continuous block along with this structure - thus avoiding one
+ // malloc/free pair or they are stored in used-supplied memory.
+ // In the latter case, ffn member stores pointer to the function to be
+ // used to deallocate the data. If the buffer is actually shared (there
+ // are at least 2 references to it) refcount member contains number of
+ // references.
+
+ struct msg_content_t
+ {
+ void *data;
+ size_t size;
+ zmq_free_fn *ffn;
+ void *hint;
+ zmq::atomic_counter_t refcnt;
+ };
+
+}
+
+#endif
diff --git a/src/mutex.hpp b/src/mutex.hpp
new file mode 100644
index 0000000..3306d2e
--- /dev/null
+++ b/src/mutex.hpp
@@ -0,0 +1,120 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_MUTEX_HPP_INCLUDED__
+#define __ZMQ_MUTEX_HPP_INCLUDED__
+
+#include "platform.hpp"
+#include "err.hpp"
+
+// Mutex class encapsulates OS mutex in a platform-independent way.
+
+#ifdef ZMQ_HAVE_WINDOWS
+
+#include "windows.hpp"
+
+namespace zmq
+{
+
+ class mutex_t
+ {
+ public:
+ inline mutex_t ()
+ {
+ InitializeCriticalSection (&cs);
+ }
+
+ inline ~mutex_t ()
+ {
+ DeleteCriticalSection (&cs);
+ }
+
+ inline void lock ()
+ {
+ EnterCriticalSection (&cs);
+ }
+
+ inline void unlock ()
+ {
+ LeaveCriticalSection (&cs);
+ }
+
+ private:
+
+ CRITICAL_SECTION cs;
+
+ // Disable copy construction and assignment.
+ mutex_t (const mutex_t&);
+ void operator = (const mutex_t&);
+ };
+
+}
+
+#else
+
+#include <pthread.h>
+
+namespace zmq
+{
+
+ class mutex_t
+ {
+ public:
+ inline mutex_t ()
+ {
+ int rc = pthread_mutex_init (&mutex, NULL);
+ if (rc)
+ posix_assert (rc);
+ }
+
+ inline ~mutex_t ()
+ {
+ int rc = pthread_mutex_destroy (&mutex);
+ if (rc)
+ posix_assert (rc);
+ }
+
+ inline void lock ()
+ {
+ int rc = pthread_mutex_lock (&mutex);
+ if (rc)
+ posix_assert (rc);
+ }
+
+ inline void unlock ()
+ {
+ int rc = pthread_mutex_unlock (&mutex);
+ if (rc)
+ posix_assert (rc);
+ }
+
+ private:
+
+ pthread_mutex_t mutex;
+
+ // Disable copy construction and assignment.
+ mutex_t (const mutex_t&);
+ void operator = (const mutex_t&);
+ };
+
+}
+
+#endif
+
+#endif
diff --git a/src/object.cpp b/src/object.cpp
new file mode 100644
index 0000000..324450f
--- /dev/null
+++ b/src/object.cpp
@@ -0,0 +1,374 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <string.h>
+
+#include "object.hpp"
+#include "ctx.hpp"
+#include "err.hpp"
+#include "pipe.hpp"
+#include "io_thread.hpp"
+#include "owned.hpp"
+#include "session.hpp"
+#include "socket_base.hpp"
+
+zmq::object_t::object_t (ctx_t *ctx_, uint32_t thread_slot_) :
+ ctx (ctx_),
+ thread_slot (thread_slot_)
+{
+}
+
+zmq::object_t::object_t (object_t *parent_) :
+ ctx (parent_->ctx),
+ thread_slot (parent_->thread_slot)
+{
+}
+
+zmq::object_t::~object_t ()
+{
+}
+
+uint32_t zmq::object_t::get_thread_slot ()
+{
+ return thread_slot;
+}
+
+zmq::ctx_t *zmq::object_t::get_ctx ()
+{
+ return ctx;
+}
+
+void zmq::object_t::process_command (command_t &cmd_)
+{
+ switch (cmd_.type) {
+
+ case command_t::revive:
+ process_revive ();
+ break;
+
+ case command_t::stop:
+ process_stop ();
+ break;
+
+ case command_t::plug:
+ process_plug ();
+ process_seqnum ();
+ return;
+
+ case command_t::own:
+ process_own (cmd_.args.own.object);
+ process_seqnum ();
+ break;
+
+ case command_t::attach:
+ process_attach (cmd_.args.attach.engine,
+ blob_t (cmd_.args.attach.peer_identity,
+ cmd_.args.attach.peer_identity_size));
+ process_seqnum ();
+ break;
+
+ case command_t::bind:
+ process_bind (cmd_.args.bind.in_pipe, cmd_.args.bind.out_pipe,
+ blob_t (cmd_.args.bind.peer_identity,
+ cmd_.args.bind.peer_identity_size));
+ process_seqnum ();
+ break;
+
+ case command_t::reader_info:
+ process_reader_info (cmd_.args.reader_info.msgs_read);
+ break;
+
+ case command_t::pipe_term:
+ process_pipe_term ();
+ return;
+
+ case command_t::pipe_term_ack:
+ process_pipe_term_ack ();
+ break;
+
+ case command_t::term_req:
+ process_term_req (cmd_.args.term_req.object);
+ break;
+
+ case command_t::term:
+ process_term ();
+ break;
+
+ case command_t::term_ack:
+ process_term_ack ();
+ break;
+
+ default:
+ zmq_assert (false);
+ }
+
+ // The assumption here is that each command is processed once only,
+ // so deallocating it after processing is all right.
+ deallocate_command (&cmd_);
+}
+
+void zmq::object_t::register_pipe (class pipe_t *pipe_)
+{
+ ctx->register_pipe (pipe_);
+}
+
+void zmq::object_t::unregister_pipe (class pipe_t *pipe_)
+{
+ ctx->unregister_pipe (pipe_);
+}
+
+int zmq::object_t::register_endpoint (const char *addr_, socket_base_t *socket_)
+{
+ return ctx->register_endpoint (addr_, socket_);
+}
+
+void zmq::object_t::unregister_endpoints (socket_base_t *socket_)
+{
+ return ctx->unregister_endpoints (socket_);
+}
+
+zmq::socket_base_t *zmq::object_t::find_endpoint (const char *addr_)
+{
+ return ctx->find_endpoint (addr_);
+}
+
+zmq::io_thread_t *zmq::object_t::choose_io_thread (uint64_t taskset_)
+{
+ return ctx->choose_io_thread (taskset_);
+}
+
+void zmq::object_t::send_stop ()
+{
+ // 'stop' command goes always from administrative thread to
+ // the current object.
+ command_t cmd;
+ cmd.destination = this;
+ cmd.type = command_t::stop;
+ ctx->send_command (thread_slot, cmd);
+}
+
+void zmq::object_t::send_plug (owned_t *destination_, bool inc_seqnum_)
+{
+ if (inc_seqnum_)
+ destination_->inc_seqnum ();
+
+ command_t cmd;
+ cmd.destination = destination_;
+ cmd.type = command_t::plug;
+ send_command (cmd);
+}
+
+void zmq::object_t::send_own (socket_base_t *destination_, owned_t *object_)
+{
+ destination_->inc_seqnum ();
+ command_t cmd;
+ cmd.destination = destination_;
+ cmd.type = command_t::own;
+ cmd.args.own.object = object_;
+ send_command (cmd);
+}
+
+void zmq::object_t::send_attach (session_t *destination_, i_engine *engine_,
+ const blob_t &peer_identity_, bool inc_seqnum_)
+{
+ if (inc_seqnum_)
+ destination_->inc_seqnum ();
+
+ command_t cmd;
+ cmd.destination = destination_;
+ cmd.type = command_t::attach;
+ cmd.args.attach.engine = engine_;
+ if (peer_identity_.empty ()) {
+ cmd.args.attach.peer_identity_size = 0;
+ cmd.args.attach.peer_identity = NULL;
+ }
+ else {
+ zmq_assert (peer_identity_.size () <= 0xff);
+ cmd.args.attach.peer_identity_size =
+ (unsigned char) peer_identity_.size ();
+ cmd.args.attach.peer_identity =
+ (unsigned char*) malloc (peer_identity_.size ());
+ zmq_assert (cmd.args.attach.peer_identity_size);
+ memcpy (cmd.args.attach.peer_identity, peer_identity_.data (),
+ peer_identity_.size ());
+ }
+ send_command (cmd);
+}
+
+void zmq::object_t::send_bind (socket_base_t *destination_,
+ reader_t *in_pipe_, writer_t *out_pipe_, const blob_t &peer_identity_,
+ bool inc_seqnum_)
+{
+ if (inc_seqnum_)
+ destination_->inc_seqnum ();
+
+ command_t cmd;
+ cmd.destination = destination_;
+ cmd.type = command_t::bind;
+ cmd.args.bind.in_pipe = in_pipe_;
+ cmd.args.bind.out_pipe = out_pipe_;
+ if (peer_identity_.empty ()) {
+ cmd.args.bind.peer_identity_size = 0;
+ cmd.args.bind.peer_identity = NULL;
+ }
+ else {
+ zmq_assert (peer_identity_.size () <= 0xff);
+ cmd.args.bind.peer_identity_size =
+ (unsigned char) peer_identity_.size ();
+ cmd.args.bind.peer_identity =
+ (unsigned char*) malloc (peer_identity_.size ());
+ zmq_assert (cmd.args.bind.peer_identity_size);
+ memcpy (cmd.args.bind.peer_identity, peer_identity_.data (),
+ peer_identity_.size ());
+ }
+ send_command (cmd);
+}
+
+void zmq::object_t::send_revive (object_t *destination_)
+{
+ command_t cmd;
+ cmd.destination = destination_;
+ cmd.type = command_t::revive;
+ send_command (cmd);
+}
+
+void zmq::object_t::send_reader_info (writer_t *destination_,
+ uint64_t msgs_read_)
+{
+ command_t cmd;
+ cmd.destination = destination_;
+ cmd.type = command_t::reader_info;
+ cmd.args.reader_info.msgs_read = msgs_read_;
+ send_command (cmd);
+}
+
+void zmq::object_t::send_pipe_term (writer_t *destination_)
+{
+ command_t cmd;
+ cmd.destination = destination_;
+ cmd.type = command_t::pipe_term;
+ send_command (cmd);
+}
+
+void zmq::object_t::send_pipe_term_ack (reader_t *destination_)
+{
+ command_t cmd;
+ cmd.destination = destination_;
+ cmd.type = command_t::pipe_term_ack;
+ send_command (cmd);
+}
+
+void zmq::object_t::send_term_req (socket_base_t *destination_,
+ owned_t *object_)
+{
+ command_t cmd;
+ cmd.destination = destination_;
+ cmd.type = command_t::term_req;
+ cmd.args.term_req.object = object_;
+ send_command (cmd);
+}
+
+void zmq::object_t::send_term (owned_t *destination_)
+{
+ command_t cmd;
+ cmd.destination = destination_;
+ cmd.type = command_t::term;
+ send_command (cmd);
+}
+
+void zmq::object_t::send_term_ack (socket_base_t *destination_)
+{
+ command_t cmd;
+ cmd.destination = destination_;
+ cmd.type = command_t::term_ack;
+ send_command (cmd);
+}
+
+void zmq::object_t::process_stop ()
+{
+ zmq_assert (false);
+}
+
+void zmq::object_t::process_plug ()
+{
+ zmq_assert (false);
+}
+
+void zmq::object_t::process_own (owned_t *object_)
+{
+ zmq_assert (false);
+}
+
+void zmq::object_t::process_attach (i_engine *engine_,
+ const blob_t &peer_identity_)
+{
+ zmq_assert (false);
+}
+
+void zmq::object_t::process_bind (reader_t *in_pipe_, writer_t *out_pipe_,
+ const blob_t &peer_identity_)
+{
+ zmq_assert (false);
+}
+
+void zmq::object_t::process_revive ()
+{
+ zmq_assert (false);
+}
+
+void zmq::object_t::process_reader_info (uint64_t msgs_read_)
+{
+ zmq_assert (false);
+}
+
+void zmq::object_t::process_pipe_term ()
+{
+ zmq_assert (false);
+}
+
+void zmq::object_t::process_pipe_term_ack ()
+{
+ zmq_assert (false);
+}
+
+void zmq::object_t::process_term_req (owned_t *object_)
+{
+ zmq_assert (false);
+}
+
+void zmq::object_t::process_term ()
+{
+ zmq_assert (false);
+}
+
+void zmq::object_t::process_term_ack ()
+{
+ zmq_assert (false);
+}
+
+void zmq::object_t::process_seqnum ()
+{
+ zmq_assert (false);
+}
+
+void zmq::object_t::send_command (command_t &cmd_)
+{
+ ctx->send_command (cmd_.destination->get_thread_slot (), cmd_);
+}
+
diff --git a/src/object.hpp b/src/object.hpp
new file mode 100644
index 0000000..a38b0a6
--- /dev/null
+++ b/src/object.hpp
@@ -0,0 +1,118 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_OBJECT_HPP_INCLUDED__
+#define __ZMQ_OBJECT_HPP_INCLUDED__
+
+#include "stdint.hpp"
+#include "blob.hpp"
+
+namespace zmq
+{
+ // Base class for all objects that participate in inter-thread
+ // communication.
+
+ class object_t
+ {
+ public:
+
+ object_t (class ctx_t *ctx_, uint32_t thread_slot_);
+ object_t (object_t *parent_);
+ virtual ~object_t ();
+
+ uint32_t get_thread_slot ();
+ ctx_t *get_ctx ();
+ void process_command (struct command_t &cmd_);
+
+ // Allow pipe to access corresponding context functions.
+ void register_pipe (class pipe_t *pipe_);
+ void unregister_pipe (class pipe_t *pipe_);
+
+ protected:
+
+ // Using following function, socket is able to access global
+ // repository of inproc endpoints.
+ int register_endpoint (const char *addr_, class socket_base_t *socket_);
+ void unregister_endpoints (class socket_base_t *socket_);
+ class socket_base_t *find_endpoint (const char *addr_);
+
+ // Chooses least loaded I/O thread.
+ class io_thread_t *choose_io_thread (uint64_t taskset_);
+
+ // Derived object can use these functions to send commands
+ // to other objects.
+ void send_stop ();
+ void send_plug (class owned_t *destination_, bool inc_seqnum_ = true);
+ void send_own (class socket_base_t *destination_,
+ class owned_t *object_);
+ void send_attach (class session_t *destination_,
+ struct i_engine *engine_, const blob_t &peer_identity_,
+ bool inc_seqnum_ = true);
+ void send_bind (class socket_base_t *destination_,
+ class reader_t *in_pipe_, class writer_t *out_pipe_,
+ const blob_t &peer_identity_, bool inc_seqnum_ = true);
+ void send_revive (class object_t *destination_);
+ void send_reader_info (class writer_t *destination_,
+ uint64_t msgs_read_);
+ void send_pipe_term (class writer_t *destination_);
+ void send_pipe_term_ack (class reader_t *destination_);
+ void send_term_req (class socket_base_t *destination_,
+ class owned_t *object_);
+ void send_term (class owned_t *destination_);
+ void send_term_ack (class socket_base_t *destination_);
+
+ // These handlers can be overloaded by the derived objects. They are
+ // called when command arrives from another thread.
+ virtual void process_stop ();
+ virtual void process_plug ();
+ virtual void process_own (class owned_t *object_);
+ virtual void process_attach (struct i_engine *engine_,
+ const blob_t &peer_identity_);
+ virtual void process_bind (class reader_t *in_pipe_,
+ class writer_t *out_pipe_, const blob_t &peer_identity_);
+ virtual void process_revive ();
+ virtual void process_reader_info (uint64_t msgs_read_);
+ virtual void process_pipe_term ();
+ virtual void process_pipe_term_ack ();
+ virtual void process_term_req (class owned_t *object_);
+ virtual void process_term ();
+ virtual void process_term_ack ();
+
+ // Special handler called after a command that requires a seqnum
+ // was processed. The implementation should catch up with its counter
+ // of processed commands here.
+ virtual void process_seqnum ();
+
+ private:
+
+ // Context provides access to the global state.
+ class ctx_t *ctx;
+
+ // Slot ID of the thread the object belongs to.
+ uint32_t thread_slot;
+
+ void send_command (command_t &cmd_);
+
+ object_t (const object_t&);
+ void operator = (const object_t&);
+ };
+
+}
+
+#endif
diff --git a/src/options.cpp b/src/options.cpp
new file mode 100644
index 0000000..f6b24d6
--- /dev/null
+++ b/src/options.cpp
@@ -0,0 +1,225 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <string.h>
+
+#include "../include/zmq.h"
+
+#include "options.hpp"
+#include "err.hpp"
+
+zmq::options_t::options_t () :
+ hwm (0),
+ swap (0),
+ affinity (0),
+ rate (100),
+ recovery_ivl (10),
+ use_multicast_loop (true),
+ sndbuf (0),
+ rcvbuf (0),
+ requires_in (false),
+ requires_out (false),
+ immediate_connect (true)
+{
+}
+
+int zmq::options_t::setsockopt (int option_, const void *optval_,
+ size_t optvallen_)
+{
+ switch (option_) {
+
+ case ZMQ_HWM:
+ if (optvallen_ != sizeof (uint64_t)) {
+ errno = EINVAL;
+ return -1;
+ }
+ hwm = *((uint64_t*) optval_);
+ return 0;
+
+ case ZMQ_SWAP:
+ if (optvallen_ != sizeof (int64_t)) {
+ errno = EINVAL;
+ return -1;
+ }
+ swap = *((int64_t*) optval_);
+ return 0;
+
+ case ZMQ_AFFINITY:
+ if (optvallen_ != sizeof (uint64_t)) {
+ errno = EINVAL;
+ return -1;
+ }
+ affinity = *((uint64_t*) optval_);
+ return 0;
+
+ case ZMQ_IDENTITY:
+
+ // Empty identity is invalid as well as identity longer than
+ // 255 bytes. Identity starting with binary zero is invalid
+ // as these are used for auto-generated identities.
+ if (optvallen_ < 1 || optvallen_ > 255 ||
+ *((const unsigned char*) optval_) == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ identity.assign ((const unsigned char*) optval_, optvallen_);
+ return 0;
+
+ case ZMQ_RATE:
+ if (optvallen_ != sizeof (int64_t)) {
+ errno = EINVAL;
+ return -1;
+ }
+ rate = (uint32_t) *((int64_t*) optval_);
+ return 0;
+
+ case ZMQ_RECOVERY_IVL:
+ if (optvallen_ != sizeof (int64_t)) {
+ errno = EINVAL;
+ return -1;
+ }
+ recovery_ivl = (uint32_t) *((int64_t*) optval_);
+ return 0;
+
+ case ZMQ_MCAST_LOOP:
+ if (optvallen_ != sizeof (int64_t)) {
+ errno = EINVAL;
+ return -1;
+ }
+ if ((int64_t) *((int64_t*) optval_) == 0)
+ use_multicast_loop = false;
+ else if ((int64_t) *((int64_t*) optval_) == 1)
+ use_multicast_loop = true;
+ else {
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+
+ case ZMQ_SNDBUF:
+ if (optvallen_ != sizeof (uint64_t)) {
+ errno = EINVAL;
+ return -1;
+ }
+ sndbuf = *((uint64_t*) optval_);
+ return 0;
+
+ case ZMQ_RCVBUF:
+ if (optvallen_ != sizeof (uint64_t)) {
+ errno = EINVAL;
+ return -1;
+ }
+ rcvbuf = *((uint64_t*) optval_);
+ return 0;
+ }
+
+ errno = EINVAL;
+ return -1;
+}
+
+int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_)
+{
+ switch (option_) {
+
+ case ZMQ_HWM:
+ if (*optvallen_ < sizeof (uint64_t)) {
+ errno = EINVAL;
+ return -1;
+ }
+ *((uint64_t*) optval_) = hwm;
+ *optvallen_ = sizeof (uint64_t);
+ return 0;
+
+ case ZMQ_SWAP:
+ if (*optvallen_ < sizeof (int64_t)) {
+ errno = EINVAL;
+ return -1;
+ }
+ *((int64_t*) optval_) = swap;
+ *optvallen_ = sizeof (int64_t);
+ return 0;
+
+ case ZMQ_AFFINITY:
+ if (*optvallen_ < sizeof (uint64_t)) {
+ errno = EINVAL;
+ return -1;
+ }
+ *((uint64_t*) optval_) = affinity;
+ *optvallen_ = sizeof (uint64_t);
+ return 0;
+
+ case ZMQ_IDENTITY:
+ if (*optvallen_ < identity.size ()) {
+ errno = EINVAL;
+ return -1;
+ }
+ memcpy (optval_, identity.data (), identity.size ());
+ *optvallen_ = identity.size ();
+ return 0;
+
+
+ case ZMQ_RATE:
+ if (*optvallen_ < sizeof (int64_t)) {
+ errno = EINVAL;
+ return -1;
+ }
+ *((int64_t*) optval_) = rate;
+ *optvallen_ = sizeof (int64_t);
+ return 0;
+
+ case ZMQ_RECOVERY_IVL:
+ if (*optvallen_ < sizeof (int64_t)) {
+ errno = EINVAL;
+ return -1;
+ }
+ *((int64_t*) optval_) = recovery_ivl;
+ *optvallen_ = sizeof (int64_t);
+ return 0;
+
+ case ZMQ_MCAST_LOOP:
+ if (*optvallen_ < sizeof (int64_t)) {
+ errno = EINVAL;
+ return -1;
+ }
+ *((int64_t*) optval_) = use_multicast_loop ? 1 : 0;
+ *optvallen_ = sizeof (int64_t);
+ return 0;
+
+ case ZMQ_SNDBUF:
+ if (*optvallen_ < sizeof (uint64_t)) {
+ errno = EINVAL;
+ return -1;
+ }
+ *((uint64_t*) optval_) = sndbuf;
+ *optvallen_ = sizeof (uint64_t);
+ return 0;
+
+ case ZMQ_RCVBUF:
+ if (*optvallen_ < sizeof (uint64_t)) {
+ errno = EINVAL;
+ return -1;
+ }
+ *((uint64_t*) optval_) = rcvbuf;
+ *optvallen_ = sizeof (uint64_t);
+ return 0;
+ }
+
+ errno = EINVAL;
+ return -1;
+}
diff --git a/src/options.hpp b/src/options.hpp
new file mode 100644
index 0000000..908b166
--- /dev/null
+++ b/src/options.hpp
@@ -0,0 +1,68 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_OPTIONS_HPP_INCLUDED__
+#define __ZMQ_OPTIONS_HPP_INCLUDED__
+
+#include "stddef.h"
+#include "stdint.hpp"
+#include "blob.hpp"
+
+namespace zmq
+{
+
+ struct options_t
+ {
+ options_t ();
+
+ int setsockopt (int option_, const void *optval_, size_t optvallen_);
+ int getsockopt (int option_, void *optval_, size_t *optvallen_);
+
+ uint64_t hwm;
+ int64_t swap;
+ uint64_t affinity;
+ blob_t identity;
+
+ // Maximum tranfer rate [kb/s]. Default 100kb/s.
+ uint32_t rate;
+
+ // Reliability time interval [s]. Default 10s.
+ uint32_t recovery_ivl;
+
+ // Enable multicast loopback. Default disabled (false).
+ bool use_multicast_loop;
+
+ uint64_t sndbuf;
+ uint64_t rcvbuf;
+
+ // These options are never set by the user directly. Instead they are
+ // provided by the specific socket type.
+ bool requires_in;
+ bool requires_out;
+
+ // If true, when connecting, pipes are created immediately without
+ // waiting for the connection to be established. That way the socket
+ // is not aware of the peer's identity, however, it is able to send
+ // messages straight away.
+ bool immediate_connect;
+ };
+
+}
+
+#endif
diff --git a/src/owned.cpp b/src/owned.cpp
new file mode 100644
index 0000000..d6be444
--- /dev/null
+++ b/src/owned.cpp
@@ -0,0 +1,71 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "owned.hpp"
+#include "err.hpp"
+
+zmq::owned_t::owned_t (object_t *parent_, socket_base_t *owner_) :
+ object_t (parent_),
+ owner (owner_),
+ sent_seqnum (0),
+ processed_seqnum (0),
+ shutting_down (false)
+{
+}
+
+zmq::owned_t::~owned_t ()
+{
+}
+
+void zmq::owned_t::inc_seqnum ()
+{
+ // NB: This function may be called from a different thread!
+ sent_seqnum.add (1);
+}
+
+void zmq::owned_t::term ()
+{
+ send_term_req (owner, this);
+}
+
+void zmq::owned_t::process_term ()
+{
+ zmq_assert (!shutting_down);
+ shutting_down = true;
+ finalise ();
+}
+
+void zmq::owned_t::process_seqnum ()
+{
+ // Catch up with counter of processed commands.
+ processed_seqnum++;
+ finalise ();
+}
+
+void zmq::owned_t::finalise ()
+{
+ // If termination request was already received and there are no more
+ // commands to wait for, terminate the object.
+ if (shutting_down && processed_seqnum == sent_seqnum.get ()) {
+ process_unplug ();
+ send_term_ack (owner);
+ delete this;
+ }
+}
+
diff --git a/src/owned.hpp b/src/owned.hpp
new file mode 100644
index 0000000..91189a1
--- /dev/null
+++ b/src/owned.hpp
@@ -0,0 +1,89 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_OWNED_HPP_INCLUDED__
+#define __ZMQ_OWNED_HPP_INCLUDED__
+
+#include "socket_base.hpp"
+#include "atomic_counter.hpp"
+#include "stdint.hpp"
+
+namespace zmq
+{
+
+ // Base class for objects owned by individual sockets. Handles
+ // initialisation and destruction of such objects.
+
+ class owned_t : public object_t
+ {
+ public:
+
+ // The object will live in parent's thread, however, its lifetime
+ // will be managed by its owner socket.
+ owned_t (object_t *parent_, socket_base_t *owner_);
+
+ // When another owned object wants to send command to this object
+ // it calls this function to let it know it should not shut down
+ // before the command is delivered.
+ void inc_seqnum ();
+
+ protected:
+
+ // Ask owner socket to terminate this object.
+ void term ();
+
+ // Derived object destroys owned_t. No point in allowing others to
+ // invoke the destructor. At the same time, it has to be virtual so
+ // that generic owned_t deallocation mechanism destroys specific type
+ // of the owned object correctly.
+ virtual ~owned_t ();
+
+ // io_object_t defines a new handler used to disconnect the object
+ // from the poller object. Implement the handlen in the derived
+ // classes to ensure sane cleanup.
+ virtual void process_unplug () = 0;
+
+ // Socket owning this object. When the socket is being closed it's
+ // responsible for shutting down this object.
+ socket_base_t *owner;
+
+ private:
+
+ // Handlers for incoming commands.
+ void process_term ();
+ void process_seqnum ();
+
+ void finalise ();
+
+ // Sequence number of the last command sent to this object.
+ atomic_counter_t sent_seqnum;
+
+ // Sequence number of the last command processed by this object.
+ uint64_t processed_seqnum;
+
+ // If true, the object is already shutting down.
+ bool shutting_down;
+
+ owned_t (const owned_t&);
+ void operator = (const owned_t&);
+ };
+
+}
+
+#endif
diff --git a/src/pair.cpp b/src/pair.cpp
new file mode 100644
index 0000000..31524de
--- /dev/null
+++ b/src/pair.cpp
@@ -0,0 +1,139 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "../include/zmq.h"
+
+#include "pair.hpp"
+#include "err.hpp"
+#include "pipe.hpp"
+
+zmq::pair_t::pair_t (class app_thread_t *parent_) :
+ socket_base_t (parent_),
+ inpipe (NULL),
+ outpipe (NULL),
+ alive (true)
+{
+ options.requires_in = true;
+ options.requires_out = true;
+}
+
+zmq::pair_t::~pair_t ()
+{
+ if (inpipe)
+ inpipe->term ();
+ if (outpipe)
+ outpipe->term ();
+}
+
+void zmq::pair_t::xattach_pipes (class reader_t *inpipe_,
+ class writer_t *outpipe_, const blob_t &peer_identity_)
+{
+ zmq_assert (!inpipe && !outpipe);
+ inpipe = inpipe_;
+ outpipe = outpipe_;
+ outpipe_alive = true;
+}
+
+void zmq::pair_t::xdetach_inpipe (class reader_t *pipe_)
+{
+ zmq_assert (pipe_ == inpipe);
+ inpipe = NULL;
+}
+
+void zmq::pair_t::xdetach_outpipe (class writer_t *pipe_)
+{
+ zmq_assert (pipe_ == outpipe);
+ outpipe = NULL;
+}
+
+void zmq::pair_t::xkill (class reader_t *pipe_)
+{
+ zmq_assert (alive);
+ alive = false;
+}
+
+void zmq::pair_t::xrevive (class reader_t *pipe_)
+{
+ zmq_assert (!alive);
+ alive = true;
+}
+
+void zmq::pair_t::xrevive (class writer_t *pipe_)
+{
+ zmq_assert (!outpipe_alive);
+ outpipe_alive = true;
+}
+
+int zmq::pair_t::xsetsockopt (int option_, const void *optval_,
+ size_t optvallen_)
+{
+ errno = EINVAL;
+ return -1;
+}
+
+int zmq::pair_t::xsend (zmq_msg_t *msg_, int flags_)
+{
+ if (outpipe == NULL || !outpipe_alive) {
+ errno = EAGAIN;
+ return -1;
+ }
+
+ if (!outpipe->write (msg_)) {
+ outpipe_alive = false;
+ errno = EAGAIN;
+ return -1;
+ }
+
+ outpipe->flush ();
+
+ // Detach the original message from the data buffer.
+ int rc = zmq_msg_init (msg_);
+ zmq_assert (rc == 0);
+
+ return 0;
+}
+
+int zmq::pair_t::xrecv (zmq_msg_t *msg_, int flags_)
+{
+ // Deallocate old content of the message.
+ zmq_msg_close (msg_);
+
+ if (!alive || !inpipe || !inpipe->read (msg_)) {
+ errno = EAGAIN;
+ return -1;
+ }
+ return 0;
+}
+
+bool zmq::pair_t::xhas_in ()
+{
+ if (alive && inpipe && inpipe->check_read ())
+ return true;
+ return false;
+}
+
+bool zmq::pair_t::xhas_out ()
+{
+ if (outpipe == NULL || !outpipe_alive)
+ return false;
+
+ outpipe_alive = outpipe->check_write ();
+ return outpipe_alive;
+}
+
diff --git a/src/pair.hpp b/src/pair.hpp
new file mode 100644
index 0000000..aea249f
--- /dev/null
+++ b/src/pair.hpp
@@ -0,0 +1,63 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_PAIR_HPP_INCLUDED__
+#define __ZMQ_PAIR_HPP_INCLUDED__
+
+#include "socket_base.hpp"
+
+namespace zmq
+{
+
+ class pair_t : public socket_base_t
+ {
+ public:
+
+ pair_t (class app_thread_t *parent_);
+ ~pair_t ();
+
+ // Overloads of functions from socket_base_t.
+ void xattach_pipes (class reader_t *inpipe_, class writer_t *outpipe_,
+ const blob_t &peer_identity_);
+ void xdetach_inpipe (class reader_t *pipe_);
+ void xdetach_outpipe (class writer_t *pipe_);
+ void xkill (class reader_t *pipe_);
+ void xrevive (class reader_t *pipe_);
+ void xrevive (class writer_t *pipe_);
+ int xsetsockopt (int option_, const void *optval_, size_t optvallen_);
+ int xsend (zmq_msg_t *msg_, int flags_);
+ int xrecv (zmq_msg_t *msg_, int flags_);
+ bool xhas_in ();
+ bool xhas_out ();
+
+ private:
+
+ class reader_t *inpipe;
+ class writer_t *outpipe;
+
+ bool alive;
+ bool outpipe_alive;
+
+ pair_t (const pair_t&);
+ void operator = (const pair_t&);
+ };
+
+}
+
+#endif
diff --git a/src/pgm_receiver.cpp b/src/pgm_receiver.cpp
new file mode 100644
index 0000000..048c529
--- /dev/null
+++ b/src/pgm_receiver.cpp
@@ -0,0 +1,217 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "platform.hpp"
+
+#if defined ZMQ_HAVE_OPENPGM
+
+#include <new>
+
+#ifdef ZMQ_HAVE_WINDOWS
+#include "windows.hpp"
+#endif
+
+#include "pgm_receiver.hpp"
+#include "err.hpp"
+#include "stdint.hpp"
+#include "wire.hpp"
+#include "i_inout.hpp"
+
+zmq::pgm_receiver_t::pgm_receiver_t (class io_thread_t *parent_,
+ const options_t &options_) :
+ io_object_t (parent_),
+ pgm_socket (true, options_),
+ options (options_),
+ inout (NULL),
+ mru_decoder (NULL),
+ pending_bytes (0)
+{
+}
+
+zmq::pgm_receiver_t::~pgm_receiver_t ()
+{
+ // Destructor should not be called before unplug.
+ zmq_assert (peers.empty ());
+}
+
+int zmq::pgm_receiver_t::init (bool udp_encapsulation_, const char *network_)
+{
+ return pgm_socket.init (udp_encapsulation_, network_);
+}
+
+void zmq::pgm_receiver_t::plug (i_inout *inout_)
+{
+ // Retrieve PGM fds and start polling.
+ int socket_fd;
+ int waiting_pipe_fd;
+ pgm_socket.get_receiver_fds (&socket_fd, &waiting_pipe_fd);
+ socket_handle = add_fd (socket_fd);
+ pipe_handle = add_fd (waiting_pipe_fd);
+ set_pollin (pipe_handle);
+ set_pollin (socket_handle);
+
+ inout = inout_;
+}
+
+void zmq::pgm_receiver_t::unplug ()
+{
+ // Delete decoders.
+ for (peers_t::iterator it = peers.begin (); it != peers.end (); it++) {
+ if (it->second.decoder != NULL)
+ delete it->second.decoder;
+ }
+ peers.clear ();
+
+ mru_decoder = NULL;
+ pending_bytes = 0;
+
+ // Stop polling.
+ rm_fd (socket_handle);
+ rm_fd (pipe_handle);
+
+ inout = NULL;
+}
+
+void zmq::pgm_receiver_t::revive ()
+{
+ zmq_assert (false);
+}
+
+void zmq::pgm_receiver_t::resume_input ()
+{
+ // It is possible that the most recently used decoder
+ // processed the whole buffer but failed to write
+ // the last message into the pipe.
+ if (pending_bytes == 0) {
+ if (mru_decoder != NULL)
+ mru_decoder->process_buffer (NULL, 0);
+ return;
+ }
+
+ zmq_assert (mru_decoder != NULL);
+ zmq_assert (pending_ptr != NULL);
+
+ // Ask the decoder to process remaining data.
+ size_t n = mru_decoder->process_buffer (pending_ptr, pending_bytes);
+ pending_bytes -= n;
+
+ if (pending_bytes > 0)
+ return;
+
+ // Resume polling.
+ set_pollin (pipe_handle);
+ set_pollin (socket_handle);
+
+ in_event ();
+}
+
+void zmq::pgm_receiver_t::in_event ()
+{
+ // Read data from the underlying pgm_socket.
+ unsigned char *data = NULL;
+ const pgm_tsi_t *tsi = NULL;
+
+ zmq_assert (pending_bytes == 0);
+
+ // TODO: This loop can effectively block other engines in the same I/O
+ // thread in the case of high load.
+ while (true) {
+
+ // Get new batch of data.
+ ssize_t received = pgm_socket.receive ((void**) &data, &tsi);
+
+ // No data to process. This may happen if the packet received is
+ // neither ODATA nor ODATA.
+ if (received == 0)
+ break;
+
+ // Find the peer based on its TSI.
+ peers_t::iterator it = peers.find (*tsi);
+
+ // Data loss. Delete decoder and mark the peer as disjoint.
+ if (received == -1) {
+ if (it != peers.end ()) {
+ it->second.joined = false;
+ if (it->second.decoder == mru_decoder)
+ mru_decoder = NULL;
+ if (it->second.decoder != NULL) {
+ delete it->second.decoder;
+ it->second.decoder = NULL;
+ }
+ }
+ break;
+ }
+
+ // New peer. Add it to the list of know but unjoint peers.
+ if (it == peers.end ()) {
+ peer_info_t peer_info = {false, NULL};
+ it = peers.insert (std::make_pair (*tsi, peer_info)).first;
+ }
+
+ // Read the offset of the fist message in the current packet.
+ zmq_assert ((size_t) received >= sizeof (uint16_t));
+ uint16_t offset = get_uint16 (data);
+ data += sizeof (uint16_t);
+ received -= sizeof (uint16_t);
+
+ // Join the stream if needed.
+ if (!it->second.joined) {
+
+ // There is no beginning of the message in current packet.
+ // Ignore the data.
+ if (offset == 0xffff)
+ continue;
+
+ zmq_assert (offset <= received);
+ zmq_assert (it->second.decoder == NULL);
+
+ // We have to move data to the begining of the first message.
+ data += offset;
+ received -= offset;
+
+ // Mark the stream as joined.
+ it->second.joined = true;
+
+ // Create and connect decoder for the peer.
+ it->second.decoder = new (std::nothrow) zmq_decoder_t (0);
+ it->second.decoder->set_inout (inout);
+ }
+
+ mru_decoder = it->second.decoder;
+
+ // Push all the data to the decoder.
+ ssize_t processed = it->second.decoder->process_buffer (data, received);
+ if (processed < received) {
+ // Save some state so we can resume the decoding process later.
+ pending_bytes = received - processed;
+ pending_ptr = data + processed;
+ // Stop polling.
+ reset_pollin (pipe_handle);
+ reset_pollin (socket_handle);
+
+ break;
+ }
+ }
+
+ // Flush any messages decoder may have produced.
+ inout->flush ();
+}
+
+#endif
+
diff --git a/src/pgm_receiver.hpp b/src/pgm_receiver.hpp
new file mode 100644
index 0000000..1b367bf
--- /dev/null
+++ b/src/pgm_receiver.hpp
@@ -0,0 +1,122 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_PGM_RECEIVER_HPP_INCLUDED__
+#define __ZMQ_PGM_RECEIVER_HPP_INCLUDED__
+
+#include "platform.hpp"
+
+#if defined ZMQ_HAVE_OPENPGM
+
+#ifdef ZMQ_HAVE_WINDOWS
+#include "windows.hpp"
+#endif
+
+#include <map>
+#include <algorithm>
+
+#include "io_object.hpp"
+#include "i_engine.hpp"
+#include "options.hpp"
+#include "zmq_decoder.hpp"
+#include "pgm_socket.hpp"
+
+namespace zmq
+{
+
+ class pgm_receiver_t : public io_object_t, public i_engine
+ {
+
+ public:
+
+ pgm_receiver_t (class io_thread_t *parent_, const options_t &options_);
+ ~pgm_receiver_t ();
+
+ int init (bool udp_encapsulation_, const char *network_);
+
+ // i_engine interface implementation.
+ void plug (struct i_inout *inout_);
+ void unplug ();
+ void revive ();
+ void resume_input ();
+
+ // i_poll_events interface implementation.
+ void in_event ();
+
+ private:
+
+ // If joined is true we are already getting messages from the peer.
+ // It it's false, we are getting data but still we haven't seen
+ // beginning of a message.
+ struct peer_info_t
+ {
+ bool joined;
+ zmq_decoder_t *decoder;
+ };
+
+ struct tsi_comp
+ {
+ inline bool operator () (const pgm_tsi_t &ltsi,
+ const pgm_tsi_t &rtsi) const
+ {
+ if (ltsi.sport < rtsi.sport)
+ return true;
+
+ return (std::lexicographical_compare (ltsi.gsi.identifier,
+ ltsi.gsi.identifier + 6,
+ rtsi.gsi.identifier, rtsi.gsi.identifier + 6));
+ }
+ };
+
+ typedef std::map <pgm_tsi_t, peer_info_t, tsi_comp> peers_t;
+ peers_t peers;
+
+ // PGM socket.
+ pgm_socket_t pgm_socket;
+
+ // Socket options.
+ options_t options;
+
+ // Parent session.
+ i_inout *inout;
+
+ // Most recently used decoder.
+ zmq_decoder_t *mru_decoder;
+
+ // Number of bytes not consumed by the decoder due to pipe overflow.
+ size_t pending_bytes;
+
+ // Pointer to data still waiting to be processed by the decoder.
+ unsigned char *pending_ptr;
+
+ // Poll handle associated with PGM socket.
+ handle_t socket_handle;
+
+ // Poll handle associated with engine PGM waiting pipe.
+ handle_t pipe_handle;
+
+ pgm_receiver_t (const pgm_receiver_t&);
+ void operator = (const pgm_receiver_t&);
+ };
+
+}
+
+#endif
+
+#endif
diff --git a/src/pgm_sender.cpp b/src/pgm_sender.cpp
new file mode 100644
index 0000000..9aeb7a9
--- /dev/null
+++ b/src/pgm_sender.cpp
@@ -0,0 +1,160 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "platform.hpp"
+
+#if defined ZMQ_HAVE_OPENPGM
+
+#ifdef ZMQ_HAVE_WINDOWS
+#include "windows.hpp"
+#endif
+
+#include <stdlib.h>
+
+#include "io_thread.hpp"
+#include "pgm_sender.hpp"
+#include "err.hpp"
+#include "wire.hpp"
+#include "stdint.hpp"
+
+zmq::pgm_sender_t::pgm_sender_t (io_thread_t *parent_,
+ const options_t &options_) :
+ io_object_t (parent_),
+ encoder (0),
+ pgm_socket (false, options_),
+ options (options_),
+ out_buffer (NULL),
+ out_buffer_size (0),
+ write_size (0)
+{
+}
+
+int zmq::pgm_sender_t::init (bool udp_encapsulation_, const char *network_)
+{
+ int rc = pgm_socket.init (udp_encapsulation_, network_);
+ if (rc != 0)
+ return rc;
+
+ out_buffer_size = pgm_socket.get_max_tsdu_size ();
+ out_buffer = (unsigned char*) malloc (out_buffer_size);
+ zmq_assert (out_buffer);
+
+ return rc;
+}
+
+void zmq::pgm_sender_t::plug (i_inout *inout_)
+{
+ // Alocate 2 fds for PGM socket.
+ int downlink_socket_fd = 0;
+ int uplink_socket_fd = 0;
+ int rdata_notify_fd = 0;
+ int pending_notify_fd = 0;
+
+ encoder.set_inout (inout_);
+
+ // Fill fds from PGM transport and add them to the poller.
+ pgm_socket.get_sender_fds (&downlink_socket_fd, &uplink_socket_fd,
+ &rdata_notify_fd, &pending_notify_fd);
+
+ handle = add_fd (downlink_socket_fd);
+ uplink_handle = add_fd (uplink_socket_fd);
+ rdata_notify_handle = add_fd (rdata_notify_fd);
+ pending_notify_handle = add_fd (pending_notify_fd);
+
+ // Set POLLIN. We wont never want to stop polling for uplink = we never
+ // want to stop porocess NAKs.
+ set_pollin (uplink_handle);
+ set_pollin (rdata_notify_handle);
+ set_pollin (pending_notify_handle);
+
+ // Set POLLOUT for downlink_socket_handle.
+ set_pollout (handle);
+}
+
+void zmq::pgm_sender_t::unplug ()
+{
+ rm_fd (handle);
+ rm_fd (uplink_handle);
+ rm_fd (rdata_notify_handle);
+ rm_fd (pending_notify_handle);
+ encoder.set_inout (NULL);
+}
+
+void zmq::pgm_sender_t::revive ()
+{
+ set_pollout (handle);
+ out_event ();
+}
+
+void zmq::pgm_sender_t::resume_input ()
+{
+ zmq_assert (false);
+}
+
+zmq::pgm_sender_t::~pgm_sender_t ()
+{
+ if (out_buffer) {
+ free (out_buffer);
+ out_buffer = NULL;
+ }
+}
+
+void zmq::pgm_sender_t::in_event ()
+{
+ // In event on sender side means NAK or SPMR receiving from some peer.
+ pgm_socket.process_upstream ();
+}
+
+void zmq::pgm_sender_t::out_event ()
+{
+ // POLLOUT event from send socket. If write buffer is empty,
+ // try to read new data from the encoder.
+ if (write_size == 0) {
+
+ // First two bytes (sizeof uint16_t) are used to store message
+ // offset in following steps. Note that by passing our buffer to
+ // the get data function we prevent it from returning its own buffer.
+ unsigned char *bf = out_buffer + sizeof (uint16_t);
+ size_t bfsz = out_buffer_size - sizeof (uint16_t);
+ int offset = -1;
+ encoder.get_data (&bf, &bfsz, &offset);
+
+ // If there are no data to write stop polling for output.
+ if (!bfsz) {
+ reset_pollout (handle);
+ return;
+ }
+
+ // Put offset information in the buffer.
+ write_size = bfsz + sizeof (uint16_t);
+ put_uint16 (out_buffer, offset == -1 ? 0xffff : (uint16_t) offset);
+ }
+
+ // Send the data.
+ size_t nbytes = pgm_socket.send (out_buffer, write_size);
+
+ // We can write either all data or 0 which means rate limit reached.
+ if (nbytes == write_size)
+ write_size = 0;
+ else
+ zmq_assert (nbytes == 0);
+}
+
+#endif
+
diff --git a/src/pgm_sender.hpp b/src/pgm_sender.hpp
new file mode 100644
index 0000000..23a53bc
--- /dev/null
+++ b/src/pgm_sender.hpp
@@ -0,0 +1,95 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_PGM_SENDER_HPP_INCLUDED__
+#define __ZMQ_PGM_SENDER_HPP_INCLUDED__
+
+#include "platform.hpp"
+
+#if defined ZMQ_HAVE_OPENPGM
+
+#ifdef ZMQ_HAVE_WINDOWS
+#include "windows.hpp"
+#endif
+
+#include "stdint.hpp"
+#include "io_object.hpp"
+#include "i_engine.hpp"
+#include "options.hpp"
+#include "pgm_socket.hpp"
+#include "zmq_encoder.hpp"
+
+namespace zmq
+{
+
+ class pgm_sender_t : public io_object_t, public i_engine
+ {
+
+ public:
+
+ pgm_sender_t (class io_thread_t *parent_, const options_t &options_);
+ ~pgm_sender_t ();
+
+ int init (bool udp_encapsulation_, const char *network_);
+
+ // i_engine interface implementation.
+ void plug (struct i_inout *inout_);
+ void unplug ();
+ void revive ();
+ void resume_input ();
+
+ // i_poll_events interface implementation.
+ void in_event ();
+ void out_event ();
+
+ private:
+
+ // Message encoder.
+ zmq_encoder_t encoder;
+
+ // PGM socket.
+ pgm_socket_t pgm_socket;
+
+ // Socket options.
+ options_t options;
+
+ // Poll handle associated with PGM socket.
+ handle_t handle;
+ handle_t uplink_handle;
+ handle_t rdata_notify_handle;
+ handle_t pending_notify_handle;
+
+ // Output buffer from pgm_socket.
+ unsigned char *out_buffer;
+
+ // Output buffer size.
+ size_t out_buffer_size;
+
+ // Number of bytes in the buffer to be written to the socket.
+ // If zero, there are no data to be sent.
+ size_t write_size;
+
+ pgm_sender_t (const pgm_sender_t&);
+ void operator = (const pgm_sender_t&);
+ };
+
+}
+#endif
+
+#endif
diff --git a/src/pgm_socket.cpp b/src/pgm_socket.cpp
new file mode 100644
index 0000000..5a952a7
--- /dev/null
+++ b/src/pgm_socket.cpp
@@ -0,0 +1,538 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "platform.hpp"
+
+#ifdef ZMQ_HAVE_OPENPGM
+
+#ifdef ZMQ_HAVE_WINDOWS
+#include "windows.hpp"
+#endif
+
+#ifdef ZMQ_HAVE_LINUX
+#include <poll.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <string>
+
+#include "options.hpp"
+#include "pgm_socket.hpp"
+#include "config.hpp"
+#include "err.hpp"
+#include "uuid.hpp"
+#include "stdint.hpp"
+
+zmq::pgm_socket_t::pgm_socket_t (bool receiver_, const options_t &options_) :
+ transport (NULL),
+ options (options_),
+ receiver (receiver_),
+ pgm_msgv (NULL),
+ pgm_msgv_len (0),
+ nbytes_rec (0),
+ nbytes_processed (0),
+ pgm_msgv_processed (0)
+{
+}
+
+int zmq::pgm_socket_t::init (bool udp_encapsulation_, const char *network_)
+{
+ // Can not open transport before destroying old one.
+ zmq_assert (transport == NULL);
+
+ // Parse port number.
+ const char *port_delim = strchr (network_, ':');
+ if (!port_delim) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ uint16_t port_number = atoi (port_delim + 1);
+
+ char network [256];
+ if (port_delim - network_ >= (int) sizeof (network) - 1) {
+ errno = EINVAL;
+ return -1;
+ }
+ memset (network, '\0', sizeof (network));
+ memcpy (network, network_, port_delim - network_);
+
+ // Zero counter used in msgrecv.
+ nbytes_rec = 0;
+ nbytes_processed = 0;
+ pgm_msgv_processed = 0;
+
+ int rc;
+ GError *pgm_error = NULL;
+
+ // PGM transport GSI.
+ pgm_gsi_t gsi;
+
+ std::string gsi_base;
+
+ if (options.identity.size () > 0) {
+
+ // Create gsi from identity.
+ // TODO: We assume that identity is standard C string here.
+ // What if it contains binary zeroes?
+ gsi_base.assign ((const char*) options.identity.data (),
+ options.identity.size ());
+ } else {
+
+ // Generate random gsi.
+ gsi_base = uuid_t ().to_string ();
+ }
+
+ rc = pgm_gsi_create_from_string (&gsi, gsi_base.c_str (), -1);
+ if (rc != TRUE) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ struct pgm_transport_info_t *res = NULL;
+ struct pgm_transport_info_t hint;
+ memset (&hint, 0, sizeof (hint));
+ hint.ti_family = AF_INET;
+
+ if (!pgm_if_get_transport_info (network, &hint, &res, &pgm_error)) {
+ if (pgm_error->domain == PGM_IF_ERROR && (
+ pgm_error->code == PGM_IF_ERROR_INVAL ||
+ pgm_error->code == PGM_IF_ERROR_XDEV ||
+ pgm_error->code == PGM_IF_ERROR_NODEV ||
+ pgm_error->code == PGM_IF_ERROR_NOTUNIQ ||
+ pgm_error->code == PGM_IF_ERROR_ADDRFAMILY ||
+ pgm_error->code == PGM_IF_ERROR_FAMILY ||
+ pgm_error->code == PGM_IF_ERROR_NODATA ||
+ pgm_error->code == PGM_IF_ERROR_NONAME ||
+ pgm_error->code == PGM_IF_ERROR_SERVICE)) {
+ g_error_free (pgm_error);
+ errno = EINVAL;
+ return -1;
+ }
+
+ zmq_assert (false);
+ }
+
+ res->ti_gsi = gsi;
+ res->ti_dport = port_number;
+
+ // If we are using UDP encapsulation update gsr or res.
+ if (udp_encapsulation_) {
+ res->ti_udp_encap_ucast_port = port_number;
+ res->ti_udp_encap_mcast_port = port_number;
+ }
+
+ if (!pgm_transport_create (&transport, res, &pgm_error)) {
+ if (pgm_error->domain == PGM_TRANSPORT_ERROR && (
+ pgm_error->code == PGM_TRANSPORT_ERROR_INVAL ||
+ pgm_error->code == PGM_TRANSPORT_ERROR_PERM ||
+ pgm_error->code == PGM_TRANSPORT_ERROR_NODEV)) {
+ pgm_if_free_transport_info (res);
+ g_error_free (pgm_error);
+ errno = EINVAL;
+ return -1;
+ }
+
+ zmq_assert (false);
+ }
+
+ pgm_if_free_transport_info (res);
+
+ // Common parameters for receiver and sender.
+
+ // Set maximum transport protocol data unit size (TPDU).
+ rc = pgm_transport_set_max_tpdu (transport, pgm_max_tpdu);
+ if (rc != TRUE) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ // Set maximum number of network hops to cross.
+ rc = pgm_transport_set_hops (transport, 16);
+ if (rc != TRUE) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ // Set nonblocking send/recv sockets.
+ if (!pgm_transport_set_nonblocking (transport, true)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (receiver) {
+
+ // Receiver transport.
+
+ // Note that NAKs are still generated by the transport.
+ rc = pgm_transport_set_recv_only (transport, true, false);
+ zmq_assert (rc == TRUE);
+
+ if (options.rcvbuf) {
+ rc = pgm_transport_set_rcvbuf (transport, (int) options.rcvbuf);
+ if (rc != TRUE)
+ return -1;
+ }
+
+ // Set NAK transmit back-off interval [us].
+ rc = pgm_transport_set_nak_bo_ivl (transport, 50 * 1000);
+ zmq_assert (rc == TRUE);
+
+ // Set timeout before repeating NAK [us].
+ rc = pgm_transport_set_nak_rpt_ivl (transport, 200 * 1000);
+ zmq_assert (rc == TRUE);
+
+ // Set timeout for receiving RDATA.
+ rc = pgm_transport_set_nak_rdata_ivl (transport, 200 * 1000);
+ zmq_assert (rc == TRUE);
+
+ // Set retries for NAK without NCF/DATA (NAK_DATA_RETRIES).
+ rc = pgm_transport_set_nak_data_retries (transport, 5);
+ zmq_assert (rc == TRUE);
+
+ // Set retries for NCF after NAK (NAK_NCF_RETRIES).
+ rc = pgm_transport_set_nak_ncf_retries (transport, 2);
+ zmq_assert (rc == TRUE);
+
+ // Set timeout for removing a dead peer [us].
+ rc = pgm_transport_set_peer_expiry (transport, 5 * 8192 * 1000);
+ zmq_assert (rc == TRUE);
+
+ // Set expiration time of SPM Requests [us].
+ rc = pgm_transport_set_spmr_expiry (transport, 25 * 1000);
+ zmq_assert (rc == TRUE);
+
+ // Set the size of the receive window.
+ // Data rate is in [B/s]. options.rate is in [kb/s].
+ if (options.rate <= 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ rc = pgm_transport_set_rxw_max_rte (transport,
+ options.rate * 1000 / 8);
+ if (rc != TRUE) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ // Recovery interval [s].
+ if (options.recovery_ivl <= 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ rc = pgm_transport_set_rxw_secs (transport, options.recovery_ivl);
+ if (rc != TRUE) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ } else {
+
+ // Sender transport.
+
+ // Waiting pipe won't be read.
+ rc = pgm_transport_set_send_only (transport, TRUE);
+ zmq_assert (rc == TRUE);
+
+ if (options.sndbuf) {
+ rc = pgm_transport_set_sndbuf (transport, (int) options.sndbuf);
+ if (rc != TRUE)
+ return -1;
+ }
+
+ // Set the size of the send window.
+ // Data rate is in [B/s] options.rate is in [kb/s].
+ if (options.rate <= 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ rc = pgm_transport_set_txw_max_rte (transport,
+ options.rate * 1000 / 8);
+ if (rc != TRUE) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ // Recovery interval [s].
+ if (options.recovery_ivl <= 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ rc = pgm_transport_set_txw_secs (transport, options.recovery_ivl);
+ if (rc != TRUE) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ // Set interval of background SPM packets [us].
+ rc = pgm_transport_set_ambient_spm (transport, 8192 * 1000);
+ zmq_assert (rc == TRUE);
+
+ // Set intervals of data flushing SPM packets [us].
+ guint spm_heartbeat[] = {4 * 1000, 4 * 1000, 8 * 1000, 16 * 1000,
+ 32 * 1000, 64 * 1000, 128 * 1000, 256 * 1000, 512 * 1000,
+ 1024 * 1000, 2048 * 1000, 4096 * 1000, 8192 * 1000};
+ rc = pgm_transport_set_heartbeat_spm (transport, spm_heartbeat,
+ G_N_ELEMENTS(spm_heartbeat));
+ zmq_assert (rc == TRUE);
+ }
+
+ // Enable multicast loopback.
+ if (options.use_multicast_loop) {
+ rc = pgm_transport_set_multicast_loop (transport, true);
+ zmq_assert (rc == TRUE);
+ }
+
+ // Bind a transport to the specified network devices.
+ if (!pgm_transport_bind (transport, &pgm_error)) {
+ if (pgm_error->domain == PGM_IF_ERROR && (
+ pgm_error->code == PGM_IF_ERROR_INVAL ||
+ pgm_error->code == PGM_IF_ERROR_XDEV ||
+ pgm_error->code == PGM_IF_ERROR_NODEV ||
+ pgm_error->code == PGM_IF_ERROR_NOTUNIQ ||
+ pgm_error->code == PGM_IF_ERROR_ADDRFAMILY ||
+ pgm_error->code == PGM_IF_ERROR_FAMILY ||
+ pgm_error->code == PGM_IF_ERROR_NODATA ||
+ pgm_error->code == PGM_IF_ERROR_NONAME ||
+ pgm_error->code == PGM_IF_ERROR_SERVICE)) {
+ g_error_free (pgm_error);
+ errno = EINVAL;
+ return -1;
+ }
+ if (pgm_error->domain == PGM_TRANSPORT_ERROR && (
+ pgm_error->code == PGM_TRANSPORT_ERROR_FAILED)) {
+ g_error_free (pgm_error);
+ errno = EINVAL;
+ return -1;
+ }
+
+ zmq_assert (false);
+ }
+
+ // For receiver transport preallocate pgm_msgv array.
+ // TODO: ?
+ if (receiver) {
+ zmq_assert (in_batch_size > 0);
+ size_t max_tsdu_size = get_max_tsdu_size ();
+ pgm_msgv_len = (int) in_batch_size / max_tsdu_size;
+ if ((int) in_batch_size % max_tsdu_size)
+ pgm_msgv_len++;
+ zmq_assert (pgm_msgv_len);
+
+ pgm_msgv = (pgm_msgv_t*) malloc (sizeof (pgm_msgv_t) * pgm_msgv_len);
+ }
+
+ return 0;
+}
+
+zmq::pgm_socket_t::~pgm_socket_t ()
+{
+ if (pgm_msgv)
+ free (pgm_msgv);
+ if (transport)
+ pgm_transport_destroy (transport, TRUE);
+}
+
+// Get receiver fds. recv_fd is from transport->recv_sock
+// waiting_pipe_fd is from transport->waiting_pipe [0]
+void zmq::pgm_socket_t::get_receiver_fds (int *receive_fd_,
+ int *waiting_pipe_fd_)
+{
+ zmq_assert (receive_fd_);
+ zmq_assert (waiting_pipe_fd_);
+
+ // recv_sock2 should not be used - check it.
+ zmq_assert (transport->recv_sock2 == -1);
+
+ // Check if transport can receive data and can not send.
+ zmq_assert (transport->can_recv_data);
+ zmq_assert (!transport->can_send_data);
+
+ // Take FDs directly from transport.
+ *receive_fd_ = pgm_transport_get_recv_fd (transport);
+ *waiting_pipe_fd_ = pgm_transport_get_pending_fd (transport);
+}
+
+// Get fds and store them into user allocated memory.
+// sender_fd is from pgm_transport->send_sock.
+// receive_fd_ is from transport->recv_sock.
+// rdata_notify_fd_ is from transport->rdata_notify.
+// pending_notify_fd_ is from transport->pending_notify.
+void zmq::pgm_socket_t::get_sender_fds (int *send_fd_, int *receive_fd_,
+ int *rdata_notify_fd_, int *pending_notify_fd_)
+{
+ zmq_assert (send_fd_);
+ zmq_assert (receive_fd_);
+
+ zmq_assert (rdata_notify_fd_);
+ zmq_assert (pending_notify_fd_);
+
+ // recv_sock2 should not be used - check it.
+ zmq_assert (transport->recv_sock2 == -1);
+
+ // Check if transport can send data and can not receive.
+ zmq_assert (transport->can_send_data);
+ zmq_assert (!transport->can_recv_data);
+
+ // Take FDs from transport.
+ *send_fd_ = pgm_transport_get_send_fd (transport);
+ *receive_fd_ = pgm_transport_get_recv_fd (transport);
+
+ *rdata_notify_fd_ = pgm_transport_get_repair_fd (transport);
+ *pending_notify_fd_ = pgm_transport_get_pending_fd (transport);
+}
+
+// Send one APDU, transmit window owned memory.
+size_t zmq::pgm_socket_t::send (unsigned char *data_, size_t data_len_)
+{
+ size_t nbytes = 0;
+
+ PGMIOStatus status = pgm_send (transport, data_, data_len_, &nbytes);
+
+ if (nbytes != data_len_) {
+ zmq_assert (status == PGM_IO_STATUS_RATE_LIMITED);
+ zmq_assert (nbytes == 0);
+ }
+
+ // We have to write all data as one packet.
+ if (nbytes > 0)
+ zmq_assert ((ssize_t) nbytes == (ssize_t) data_len_);
+
+ return nbytes;
+}
+
+// Return max TSDU size without fragmentation from current PGM transport.
+size_t zmq::pgm_socket_t::get_max_tsdu_size ()
+{
+ return (size_t) pgm_transport_max_tsdu (transport, false);
+}
+
+// pgm_transport_recvmsgv is called to fill the pgm_msgv array up to
+// pgm_msgv_len. In subsequent calls data from pgm_msgv structure are
+// returned.
+ssize_t zmq::pgm_socket_t::receive (void **raw_data_, const pgm_tsi_t **tsi_)
+{
+ size_t raw_data_len = 0;
+
+ // We just sent all data from pgm_transport_recvmsgv up
+ // and have to return 0 that another engine in this thread is scheduled.
+ if (nbytes_rec == nbytes_processed && nbytes_rec > 0) {
+
+ // Reset all the counters.
+ nbytes_rec = 0;
+ nbytes_processed = 0;
+ pgm_msgv_processed = 0;
+ return 0;
+ }
+
+ // If we have are going first time or if we have processed all pgm_msgv_t
+ // structure previously read from the pgm socket.
+ if (nbytes_rec == nbytes_processed) {
+
+ // Check program flow.
+ zmq_assert (pgm_msgv_processed == 0);
+ zmq_assert (nbytes_processed == 0);
+ zmq_assert (nbytes_rec == 0);
+
+ // Receive a vector of Application Protocol Domain Unit's (APDUs)
+ // from the transport.
+ GError *pgm_error = NULL;
+
+ const PGMIOStatus status = pgm_recvmsgv (transport, pgm_msgv,
+ pgm_msgv_len, MSG_DONTWAIT, &nbytes_rec, &pgm_error);
+
+ zmq_assert (status != PGM_IO_STATUS_ERROR);
+
+ // In a case when no ODATA/RDATA fired POLLIN event (SPM...)
+ // pgm_recvmsg returns ?.
+ if (status == PGM_IO_STATUS_TIMER_PENDING) {
+
+ zmq_assert (nbytes_rec == 0);
+
+ // In case if no RDATA/ODATA caused POLLIN 0 is
+ // returned.
+ nbytes_rec = 0;
+ return 0;
+ }
+
+ // Data loss.
+ if (status == PGM_IO_STATUS_RESET) {
+
+ pgm_peer_t* peer = (pgm_peer_t*) transport->peers_pending->data;
+
+ // Save lost data TSI.
+ *tsi_ = &peer->tsi;
+ nbytes_rec = 0;
+
+ // In case of dala loss -1 is returned.
+ errno = EINVAL;
+ g_error_free (pgm_error);
+ return -1;
+ }
+
+ zmq_assert (status == PGM_IO_STATUS_NORMAL);
+ }
+ else
+ {
+ zmq_assert (pgm_msgv_processed <= pgm_msgv_len);
+ }
+
+ zmq_assert (nbytes_rec > 0);
+
+ // Only one APDU per pgm_msgv_t structure is allowed.
+ zmq_assert (pgm_msgv [pgm_msgv_processed].msgv_len == 1);
+
+ struct pgm_sk_buff_t* skb =
+ pgm_msgv [pgm_msgv_processed].msgv_skb [0];
+
+ // Take pointers from pgm_msgv_t structure.
+ *raw_data_ = skb->data;
+ raw_data_len = skb->len;
+
+ // Save current TSI.
+ *tsi_ = &skb->tsi;
+
+ // Move the the next pgm_msgv_t structure.
+ pgm_msgv_processed++;
+ zmq_assert (pgm_msgv_processed <= pgm_msgv_len);
+ nbytes_processed +=raw_data_len;
+
+ return raw_data_len;
+}
+
+void zmq::pgm_socket_t::process_upstream ()
+{
+ pgm_msgv_t dummy_msg;
+
+ size_t dummy_bytes = 0;
+ GError *pgm_error = NULL;
+
+ PGMIOStatus status = pgm_recvmsgv (transport, &dummy_msg,
+ 1, MSG_DONTWAIT, &dummy_bytes, &pgm_error);
+
+ zmq_assert (status != PGM_IO_STATUS_ERROR);
+
+ // No data should be returned.
+ zmq_assert (dummy_bytes == 0 && (status == PGM_IO_STATUS_TIMER_PENDING ||
+ status == PGM_IO_STATUS_RATE_LIMITED));
+}
+
+#endif
+
diff --git a/src/pgm_socket.hpp b/src/pgm_socket.hpp
new file mode 100644
index 0000000..b9f55d1
--- /dev/null
+++ b/src/pgm_socket.hpp
@@ -0,0 +1,105 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __PGM_SOCKET_HPP_INCLUDED__
+#define __PGM_SOCKET_HPP_INCLUDED__
+
+#include "platform.hpp"
+
+#if defined ZMQ_HAVE_OPENPGM
+
+#ifdef ZMQ_HAVE_WINDOWS
+#include "windows.hpp"
+#endif
+
+#include <pgm/pgm.h>
+
+#include "options.hpp"
+
+namespace zmq
+{
+ // Encapsulates PGM socket.
+ class pgm_socket_t
+ {
+
+ public:
+ // If receiver_ is true PGM transport is not generating SPM packets.
+ // interface format: iface;mcast_group:port for raw PGM socket
+ // udp:iface;mcast_goup:port for UDP encapsulacion
+ pgm_socket_t (bool receiver_, const options_t &options_);
+
+ // Closes the transport.
+ ~pgm_socket_t ();
+
+ // Initialize PGM network structures (GSI, GSRs).
+ int init (bool udp_encapsulation_, const char *network_);
+
+ // Get receiver fds and store them into user allocated memory.
+ void get_receiver_fds (int *receive_fd_, int *waiting_pipe_fd_);
+
+ // Get sender and receiver fds and store it to user allocated
+ // memory. Receive fd is used to process NAKs from peers.
+ void get_sender_fds (int *send_fd_, int *receive_fd_,
+ int *rdata_notify_fd_, int *pending_notify_fd_);
+
+ // Send data as one APDU, transmit window owned memory.
+ size_t send (unsigned char *data_, size_t data_len_);
+
+ // Returns max tsdu size without fragmentation.
+ size_t get_max_tsdu_size ();
+
+ // Receive data from pgm socket.
+ ssize_t receive (void **data_, const pgm_tsi_t **tsi_);
+
+ // POLLIN on sender side should mean NAK or SPMR receiving.
+ // process_upstream function is used to handle such a situation.
+ void process_upstream ();
+
+ private:
+
+ // OpenPGM transport
+ pgm_transport_t* transport;
+
+ // Associated socket options.
+ options_t options;
+
+ // true when pgm_socket should create receiving side.
+ bool receiver;
+
+ // Array of pgm_msgv_t structures to store received data
+ // from the socket (pgm_transport_recvmsgv).
+ pgm_msgv_t *pgm_msgv;
+
+ // Size of pgm_msgv array.
+ size_t pgm_msgv_len;
+
+ // How many bytes were read from pgm socket.
+ size_t nbytes_rec;
+
+ // How many bytes were processed from last pgm socket read.
+ size_t nbytes_processed;
+
+ // How many messages from pgm_msgv were already sent up.
+ size_t pgm_msgv_processed;
+ };
+}
+#endif
+
+#endif
+
diff --git a/src/pipe.cpp b/src/pipe.cpp
new file mode 100644
index 0000000..1df64e9
--- /dev/null
+++ b/src/pipe.cpp
@@ -0,0 +1,281 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "../include/zmq.h"
+
+#include "pipe.hpp"
+
+zmq::reader_t::reader_t (object_t *parent_,
+ uint64_t hwm_, uint64_t lwm_) :
+ object_t (parent_),
+ pipe (NULL),
+ peer (NULL),
+ hwm (hwm_),
+ lwm (lwm_),
+ msgs_read (0),
+ endpoint (NULL)
+{
+ // Adjust lwm and hwm.
+ if (lwm == 0 || lwm > hwm)
+ lwm = hwm;
+}
+
+zmq::reader_t::~reader_t ()
+{
+ if (pipe)
+ unregister_pipe (pipe);
+}
+
+void zmq::reader_t::set_pipe (pipe_t *pipe_)
+{
+ zmq_assert (!pipe);
+ pipe = pipe_;
+ peer = &pipe->writer;
+ register_pipe (pipe);
+}
+
+bool zmq::reader_t::check_read ()
+{
+ // Check if there's an item in the pipe.
+ if (pipe->check_read ())
+ return true;
+
+ // If not, deactivate the pipe.
+ endpoint->kill (this);
+ return false;
+}
+
+bool zmq::reader_t::read (zmq_msg_t *msg_)
+{
+ if (!pipe->read (msg_)) {
+ endpoint->kill (this);
+ return false;
+ }
+
+ // If delimiter was read, start termination process of the pipe.
+ unsigned char *offset = 0;
+ if (msg_->content == (void*) (offset + ZMQ_DELIMITER)) {
+ if (endpoint)
+ endpoint->detach_inpipe (this);
+ term ();
+ return false;
+ }
+
+ if (!(msg_->flags & ZMQ_MSG_MORE))
+ msgs_read++;
+
+ if (lwm > 0 && msgs_read % lwm == 0)
+ send_reader_info (peer, msgs_read);
+
+ return true;
+}
+
+void zmq::reader_t::set_endpoint (i_endpoint *endpoint_)
+{
+ endpoint = endpoint_;
+}
+
+void zmq::reader_t::term ()
+{
+ endpoint = NULL;
+ send_pipe_term (peer);
+}
+
+void zmq::reader_t::process_revive ()
+{
+ // Beacuse of command throttling mechanism, incoming termination request
+ // may not have been processed before subsequent send.
+ // In that case endpoint is NULL.
+ if (endpoint)
+ endpoint->revive (this);
+}
+
+void zmq::reader_t::process_pipe_term_ack ()
+{
+ peer = NULL;
+ delete pipe;
+}
+
+zmq::writer_t::writer_t (object_t *parent_,
+ uint64_t hwm_, uint64_t lwm_) :
+ object_t (parent_),
+ pipe (NULL),
+ peer (NULL),
+ hwm (hwm_),
+ lwm (lwm_),
+ msgs_read (0),
+ msgs_written (0),
+ stalled (false),
+ endpoint (NULL)
+{
+ // Adjust lwm and hwm.
+ if (lwm == 0 || lwm > hwm)
+ lwm = hwm;
+}
+
+void zmq::writer_t::set_endpoint (i_endpoint *endpoint_)
+{
+ endpoint = endpoint_;
+}
+
+zmq::writer_t::~writer_t ()
+{
+}
+
+void zmq::writer_t::set_pipe (pipe_t *pipe_)
+{
+ zmq_assert (!pipe);
+ pipe = pipe_;
+ peer = &pipe->reader;
+}
+
+bool zmq::writer_t::check_write ()
+{
+ if (pipe_full ()) {
+ stalled = true;
+ return false;
+ }
+
+ return true;
+}
+
+bool zmq::writer_t::write (zmq_msg_t *msg_)
+{
+ if (pipe_full ()) {
+ stalled = true;
+ return false;
+ }
+
+ pipe->write (*msg_, msg_->flags & ZMQ_MSG_MORE);
+ if (!(msg_->flags & ZMQ_MSG_MORE))
+ msgs_written++;
+ return true;
+}
+
+void zmq::writer_t::rollback ()
+{
+ zmq_msg_t msg;
+
+ // Remove all incomplete messages from the pipe.
+ while (pipe->unwrite (&msg)) {
+ zmq_assert (msg.flags & ZMQ_MSG_MORE);
+ zmq_msg_close (&msg);
+ msgs_written--;
+ }
+
+ if (stalled && endpoint != NULL && !pipe_full()) {
+ stalled = false;
+ endpoint->revive (this);
+ }
+}
+
+void zmq::writer_t::flush ()
+{
+ if (!pipe->flush ())
+ send_revive (peer);
+}
+
+void zmq::writer_t::term ()
+{
+ endpoint = NULL;
+
+ // Rollback any unfinished messages.
+ rollback ();
+
+ // Push delimiter into the pipe.
+ // Trick the compiler to belive that the tag is a valid pointer.
+ zmq_msg_t msg;
+ const unsigned char *offset = 0;
+ msg.content = (void*) (offset + ZMQ_DELIMITER);
+ msg.flags = 0;
+ pipe->write (msg, false);
+ pipe->flush ();
+}
+
+void zmq::writer_t::process_reader_info (uint64_t msgs_read_)
+{
+ msgs_read = msgs_read_;
+ if (stalled && endpoint != NULL) {
+ stalled = false;
+ endpoint->revive (this);
+ }
+}
+
+void zmq::writer_t::process_pipe_term ()
+{
+ if (endpoint)
+ endpoint->detach_outpipe (this);
+
+ reader_t *p = peer;
+ peer = NULL;
+ send_pipe_term_ack (p);
+}
+
+bool zmq::writer_t::pipe_full ()
+{
+ return hwm > 0 && msgs_written - msgs_read == hwm;
+}
+
+zmq::pipe_t::pipe_t (object_t *reader_parent_, object_t *writer_parent_,
+ uint64_t hwm_) :
+ reader (reader_parent_, hwm_, compute_lwm (hwm_)),
+ writer (writer_parent_, hwm_, compute_lwm (hwm_))
+{
+ reader.set_pipe (this);
+ writer.set_pipe (this);
+}
+
+zmq::pipe_t::~pipe_t ()
+{
+ // Deallocate all the unread messages in the pipe. We have to do it by
+ // hand because zmq_msg_t is a POD, not a class, so there's no associated
+ // destructor.
+ zmq_msg_t msg;
+ while (read (&msg))
+ zmq_msg_close (&msg);
+}
+
+uint64_t zmq::pipe_t::compute_lwm (uint64_t hwm_)
+{
+ // Following point should be taken into consideration when computing
+ // low watermark:
+ //
+ // 1. LWM has to be less than HWM.
+ // 2. LWM cannot be set to very low value (such as zero) as after filling
+ // the queue it would start to refill only after all the messages are
+ // read from it and thus unnecessarily hold the progress back.
+ // 3. LWM cannot be set to very high value (such as HWM-1) as it would
+ // result in lock-step filling of the queue - if a single message is read
+ // from a full queue, writer thread is resumed to write exactly one
+ // message to the queue and go back to sleep immediately. This would
+ // result in low performance.
+ //
+ // Given the 3. it would be good to keep HWM and LWM as far apart as
+ // possible to reduce the thread switching overhead to almost zero,
+ // say HWM-LWM should be 500 (max_wm_delta).
+ //
+ // That done, we still we have to account for the cases where HWM<500 thus
+ // driving LWM to negative numbers. Let's make LWM 1/2 of HWM in such cases.
+
+ if (hwm_ > max_wm_delta * 2)
+ return hwm_ - max_wm_delta;
+ else
+ return hwm_ / 2;
+}
+
diff --git a/src/pipe.hpp b/src/pipe.hpp
new file mode 100644
index 0000000..9f57653
--- /dev/null
+++ b/src/pipe.hpp
@@ -0,0 +1,169 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_PIPE_HPP_INCLUDED__
+#define __ZMQ_PIPE_HPP_INCLUDED__
+
+#include "../include/zmq.h"
+
+#include "stdint.hpp"
+#include "i_endpoint.hpp"
+#include "yarray_item.hpp"
+#include "ypipe.hpp"
+#include "config.hpp"
+#include "object.hpp"
+
+namespace zmq
+{
+
+ class reader_t : public object_t, public yarray_item_t
+ {
+ public:
+
+ reader_t (class object_t *parent_,
+ uint64_t hwm_, uint64_t lwm_);
+ ~reader_t ();
+
+ void set_pipe (class pipe_t *pipe_);
+ void set_endpoint (i_endpoint *endpoint_);
+
+ // Returns true if there is at least one message to read in the pipe.
+ bool check_read ();
+
+ // Reads a message to the underlying pipe.
+ bool read (zmq_msg_t *msg_);
+
+ // Ask pipe to terminate.
+ void term ();
+
+ private:
+
+ // Command handlers.
+ void process_revive ();
+ void process_pipe_term_ack ();
+
+ // The underlying pipe.
+ class pipe_t *pipe;
+
+ // Pipe writer associated with the other side of the pipe.
+ class writer_t *peer;
+
+ // High and low watermarks for in-memory storage (in bytes).
+ uint64_t hwm;
+ uint64_t lwm;
+
+ // Number of messages read so far.
+ uint64_t msgs_read;
+
+ // Endpoint (either session or socket) the pipe is attached to.
+ i_endpoint *endpoint;
+
+ reader_t (const reader_t&);
+ void operator = (const reader_t&);
+ };
+
+ class writer_t : public object_t, public yarray_item_t
+ {
+ public:
+
+ writer_t (class object_t *parent_,
+ uint64_t hwm_, uint64_t lwm_);
+ ~writer_t ();
+
+ void set_pipe (class pipe_t *pipe_);
+ void set_endpoint (i_endpoint *endpoint_);
+
+ // Checks whether a message can be written to the pipe.
+ // If writing the message would cause high watermark to be
+ // exceeded, the function returns false.
+ bool check_write ();
+
+ // Writes a message to the underlying pipe. Returns false if the
+ // message cannot be written because high watermark was reached.
+ bool write (zmq_msg_t *msg_);
+
+ // Remove unfinished part of a message from the pipe.
+ void rollback ();
+
+ // Flush the messages downsteam.
+ void flush ();
+
+ // Ask pipe to terminate.
+ void term ();
+
+ private:
+
+ void process_reader_info (uint64_t msgs_read_);
+
+ // Command handlers.
+ void process_pipe_term ();
+
+ // Tests whether the pipe is already full.
+ bool pipe_full ();
+
+ // The underlying pipe.
+ class pipe_t *pipe;
+
+ // Pipe reader associated with the other side of the pipe.
+ class reader_t *peer;
+
+ // High and low watermarks for in-memory storage (in bytes).
+ uint64_t hwm;
+ uint64_t lwm;
+
+ // Last confirmed number of messages read from the pipe.
+ // The actual number can be higher.
+ uint64_t msgs_read;
+
+ // Number of messages we have written so far.
+ uint64_t msgs_written;
+
+ // True iff the last attempt to write a message has failed.
+ bool stalled;
+
+ // Endpoint (either session or socket) the pipe is attached to.
+ i_endpoint *endpoint;
+
+ writer_t (const writer_t&);
+ void operator = (const writer_t&);
+ };
+
+ // Message pipe.
+ class pipe_t : public ypipe_t <zmq_msg_t, message_pipe_granularity>
+ {
+ public:
+
+ pipe_t (object_t *reader_parent_, object_t *writer_parent_,
+ uint64_t hwm_);
+ ~pipe_t ();
+
+ reader_t reader;
+ writer_t writer;
+
+ private:
+
+ uint64_t compute_lwm (uint64_t hwm_);
+
+ pipe_t (const pipe_t&);
+ void operator = (const pipe_t&);
+ };
+
+}
+
+#endif
diff --git a/src/platform.hpp.in b/src/platform.hpp.in
new file mode 100644
index 0000000..a885c21
--- /dev/null
+++ b/src/platform.hpp.in
@@ -0,0 +1,228 @@
+/* src/platform.hpp.in. Generated from configure.in by autoheader. */
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#undef HAVE_ARPA_INET_H
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <errno.h> header file. */
+#undef HAVE_ERRNO_H
+
+/* Define to 1 if you have the `freeifaddrs' function. */
+#undef HAVE_FREEIFADDRS
+
+/* Define to 1 if you have the `getifaddrs' function. */
+#undef HAVE_GETIFADDRS
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+#undef HAVE_IFADDRS_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `iphlpapi' library (-liphlpapi). */
+#undef HAVE_LIBIPHLPAPI
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#undef HAVE_LIBNSL
+
+/* Define to 1 if you have the `pthread' library (-lpthread). */
+#undef HAVE_LIBPTHREAD
+
+/* Define to 1 if you have the `rpcrt4' library (-lrpcrt4). */
+#undef HAVE_LIBRPCRT4
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+#undef HAVE_LIBRT
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+#undef HAVE_LIBSOCKET
+
+/* Define to 1 if you have the `uuid' library (-luuid). */
+#undef HAVE_LIBUUID
+
+/* Define to 1 if you have the `ws2_32' library (-lws2_32). */
+#undef HAVE_LIBWS2_32
+
+/* Define to 1 if you have the <limits.h> header file. */
+#undef HAVE_LIMITS_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `memset' function. */
+#undef HAVE_MEMSET
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#undef HAVE_NETINET_TCP_H
+
+/* Define to 1 if you have the `perror' function. */
+#undef HAVE_PERROR
+
+/* Define to 1 if you have the `socket' function. */
+#undef HAVE_SOCKET
+
+/* Define to 1 if stdbool.h conforms to C99. */
+#undef HAVE_STDBOOL_H
+
+/* Define to 1 if you have the <stddef.h> header file. */
+#undef HAVE_STDDEF_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the <windows.h> header file. */
+#undef HAVE_WINDOWS_H
+
+/* Define to 1 if the system has the type `_Bool'. */
+#undef HAVE__BOOL
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#undef LT_OBJDIR
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+#undef NO_MINUS_C_MINUS_O
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* 0MQ major version */
+#undef PACKAGE_VERSION_MAJOR
+
+/* 0MQ minor version */
+#undef PACKAGE_VERSION_MINOR
+
+/* 0MQ patchlevel */
+#undef PACKAGE_VERSION_PATCH
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#undef RETSIGTYPE
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Version number of package */
+#undef VERSION
+
+/* Force to use mutexes */
+#undef ZMQ_FORCE_MUTEXES
+
+/* Have AIX OS */
+#undef ZMQ_HAVE_AIX
+
+/* Have Cygwin */
+#undef ZMQ_HAVE_CYGWIN
+
+/* Have FreeBSD OS */
+#undef ZMQ_HAVE_FREEBSD
+
+/* Have HPUX OS */
+#undef ZMQ_HAVE_HPUX
+
+/* Have ifaddrs.h header. */
+#undef ZMQ_HAVE_IFADDRS
+
+/* Have Linux OS */
+#undef ZMQ_HAVE_LINUX
+
+/* Have MinGW32 */
+#undef ZMQ_HAVE_MINGW32
+
+/* Have NetBSD OS */
+#undef ZMQ_HAVE_NETBSD
+
+/* Have OpenBSD OS */
+#undef ZMQ_HAVE_OPENBSD
+
+/* Have OpenPGM extension */
+#undef ZMQ_HAVE_OPENPGM
+
+/* Have DarwinOSX OS */
+#undef ZMQ_HAVE_OSX
+
+/* Have QNX Neutrino OS */
+#undef ZMQ_HAVE_QNXNTO
+
+/* Have Solaris OS */
+#undef ZMQ_HAVE_SOLARIS
+
+/* Have Windows OS */
+#undef ZMQ_HAVE_WINDOWS
+
+/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
+ <pthread.h>, or <semaphore.h> is not used. If the typedef was allowed, the
+ #define below would cause a syntax error. */
+#undef _UINT32_T
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+#undef inline
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef size_t
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef ssize_t
+
+/* Define to the type of an unsigned integer type of width exactly 32 bits if
+ such a type exists and the standard includes do not define it. */
+#undef uint32_t
+
+/* Define to empty if the keyword `volatile' does not work. Warning: valid
+ code using `volatile' can become incorrect without. Disable with care. */
+#undef volatile
diff --git a/src/poll.cpp b/src/poll.cpp
new file mode 100644
index 0000000..4214195
--- /dev/null
+++ b/src/poll.cpp
@@ -0,0 +1,207 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "platform.hpp"
+
+#if defined ZMQ_HAVE_LINUX || defined ZMQ_HAVE_FREEBSD ||\
+ defined ZMQ_HAVE_OPENBSD || defined ZMQ_HAVE_SOLARIS ||\
+ defined ZMQ_HAVE_OSX || defined ZMQ_HAVE_QNXNTO ||\
+ defined ZMQ_HAVE_HPUX || defined ZMQ_HAVE_AIX ||\
+ defined ZMQ_HAVE_NETBSD
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <poll.h>
+#include <algorithm>
+
+#include "poll.hpp"
+#include "err.hpp"
+#include "config.hpp"
+#include "i_poll_events.hpp"
+
+zmq::poll_t::poll_t () :
+ retired (false),
+ stopping (false)
+{
+ // Get the limit on open file descriptors. Resize fds so that it
+ // can hold all descriptors.
+ rlimit rl;
+ int rc = getrlimit (RLIMIT_NOFILE, &rl);
+ errno_assert (rc != -1);
+ fd_table.resize (rl.rlim_cur);
+
+ for (rlim_t i = 0; i < rl.rlim_cur; i ++)
+ fd_table [i].index = retired_fd;
+}
+
+zmq::poll_t::~poll_t ()
+{
+ worker.stop ();
+
+ // Make sure there are no fds registered on shutdown.
+ zmq_assert (load.get () == 0);
+}
+
+zmq::poll_t::handle_t zmq::poll_t::add_fd (fd_t fd_, i_poll_events *events_)
+{
+ pollfd pfd = {fd_, 0, 0};
+ pollset.push_back (pfd);
+ assert (fd_table [fd_].index == retired_fd);
+
+ fd_table [fd_].index = pollset.size() - 1;
+ fd_table [fd_].events = events_;
+
+ // Increase the load metric of the thread.
+ load.add (1);
+
+ return fd_;
+}
+
+void zmq::poll_t::rm_fd (handle_t handle_)
+{
+ fd_t index = fd_table [handle_].index;
+ assert (index != retired_fd);
+
+ // Mark the fd as unused.
+ pollset [index].fd = retired_fd;
+ fd_table [handle_].index = retired_fd;
+ retired = true;
+
+ // Decrease the load metric of the thread.
+ load.sub (1);
+}
+
+void zmq::poll_t::set_pollin (handle_t handle_)
+{
+ int index = fd_table [handle_].index;
+ pollset [index].events |= POLLIN;
+}
+
+void zmq::poll_t::reset_pollin (handle_t handle_)
+{
+ int index = fd_table [handle_].index;
+ pollset [index].events &= ~((short) POLLIN);
+}
+
+void zmq::poll_t::set_pollout (handle_t handle_)
+{
+ int index = fd_table [handle_].index;
+ pollset [index].events |= POLLOUT;
+}
+
+void zmq::poll_t::reset_pollout (handle_t handle_)
+{
+ int index = fd_table [handle_].index;
+ pollset [index].events &= ~((short) POLLOUT);
+}
+
+void zmq::poll_t::add_timer (i_poll_events *events_)
+{
+ timers.push_back (events_);
+}
+
+void zmq::poll_t::cancel_timer (i_poll_events *events_)
+{
+ timers_t::iterator it = std::find (timers.begin (), timers.end (), events_);
+ if (it != timers.end ())
+ timers.erase (it);
+}
+
+int zmq::poll_t::get_load ()
+{
+ return load.get ();
+}
+
+void zmq::poll_t::start ()
+{
+ worker.start (worker_routine, this);
+}
+
+void zmq::poll_t::stop ()
+{
+ stopping = true;
+}
+
+void zmq::poll_t::loop ()
+{
+ while (!stopping) {
+
+ // Wait for events.
+ int rc = poll (&pollset [0], pollset.size (),
+ timers.empty () ? -1 : max_timer_period);
+ if (rc == -1 && errno == EINTR)
+ continue;
+ errno_assert (rc != -1);
+
+ // Handle timer.
+ if (!rc) {
+
+ // Use local list of timers as timer handlers may fill new timers
+ // into the original array.
+ timers_t t;
+ std::swap (timers, t);
+
+ // Trigger all the timers.
+ for (timers_t::iterator it = t.begin (); it != t.end (); it ++)
+ (*it)->timer_event ();
+
+ continue;
+ }
+
+ for (pollset_t::iterator it = pollset.begin ();
+ it != pollset.end (); it ++) {
+
+ zmq_assert (!(it->revents & POLLNVAL));
+ if (it->fd == retired_fd)
+ continue;
+ if (it->revents & (POLLERR | POLLHUP))
+ fd_table [it->fd].events->in_event ();
+ if (it->fd == retired_fd)
+ continue;
+ if (it->revents & POLLOUT)
+ fd_table [it->fd].events->out_event ();
+ if (it->fd == retired_fd)
+ continue;
+ if (it->revents & POLLIN)
+ fd_table [it->fd].events->in_event ();
+ }
+
+ // Clean up the pollset and update the fd_table accordingly.
+ if (retired) {
+ pollset_t::size_type i = 0;
+ while (i < pollset.size ()) {
+ if (pollset [i].fd == retired_fd)
+ pollset.erase (pollset.begin () + i);
+ else {
+ fd_table [pollset [i].fd].index = i;
+ i ++;
+ }
+ }
+ retired = false;
+ }
+ }
+}
+
+void zmq::poll_t::worker_routine (void *arg_)
+{
+ ((poll_t*) arg_)->loop ();
+}
+
+#endif
diff --git a/src/poll.hpp b/src/poll.hpp
new file mode 100644
index 0000000..f4ae35a
--- /dev/null
+++ b/src/poll.hpp
@@ -0,0 +1,113 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_POLL_HPP_INCLUDED__
+#define __ZMQ_POLL_HPP_INCLUDED__
+
+#include "platform.hpp"
+
+#if defined ZMQ_HAVE_LINUX || defined ZMQ_HAVE_FREEBSD ||\
+ defined ZMQ_HAVE_OPENBSD || defined ZMQ_HAVE_SOLARIS ||\
+ defined ZMQ_HAVE_OSX || defined ZMQ_HAVE_QNXNTO ||\
+ defined ZMQ_HAVE_HPUX || defined ZMQ_HAVE_AIX ||\
+ defined ZMQ_HAVE_NETBSD
+
+#include <poll.h>
+#include <stddef.h>
+#include <vector>
+
+#include "fd.hpp"
+#include "thread.hpp"
+#include "atomic_counter.hpp"
+
+namespace zmq
+{
+
+ // Implements socket polling mechanism using the POSIX.1-2001
+ // poll() system call.
+
+ class poll_t
+ {
+ public:
+
+ typedef fd_t handle_t;
+
+ poll_t ();
+ ~poll_t ();
+
+ // "poller" concept.
+ handle_t add_fd (fd_t fd_, struct i_poll_events *events_);
+ void rm_fd (handle_t handle_);
+ void set_pollin (handle_t handle_);
+ void reset_pollin (handle_t handle_);
+ void set_pollout (handle_t handle_);
+ void reset_pollout (handle_t handle_);
+ void add_timer (struct i_poll_events *events_);
+ void cancel_timer (struct i_poll_events *events_);
+ int get_load ();
+ void start ();
+ void stop ();
+
+ private:
+
+ // Main worker thread routine.
+ static void worker_routine (void *arg_);
+
+ // Main event loop.
+ void loop ();
+
+ struct fd_entry_t
+ {
+ fd_t index;
+ struct i_poll_events *events;
+ };
+
+ // This table stores data for registered descriptors.
+ std::vector <fd_entry_t> fd_table;
+
+ // Pollset to pass to the poll function.
+ typedef std::vector <pollfd> pollset_t;
+ pollset_t pollset;
+
+ // If true, there's at least one retired event source.
+ bool retired;
+
+ // List of all the engines waiting for the timer event.
+ typedef std::vector <struct i_poll_events*> timers_t;
+ timers_t timers;
+
+ // If true, thread is in the process of shutting down.
+ bool stopping;
+
+ // Handle of the physical thread doing the I/O work.
+ thread_t worker;
+
+ // Load of the poller. Currently number of file descriptors
+ // registered with the poller.
+ atomic_counter_t load;
+
+ poll_t (const poll_t&);
+ void operator = (const poll_t&);
+ };
+
+}
+
+#endif
+
+#endif
diff --git a/src/poller.hpp b/src/poller.hpp
new file mode 100644
index 0000000..3c29603
--- /dev/null
+++ b/src/poller.hpp
@@ -0,0 +1,72 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_POLLER_HPP_INCLUDED__
+#define __ZMQ_POLLER_HPP_INCLUDED__
+
+#include "epoll.hpp"
+#include "poll.hpp"
+#include "select.hpp"
+#include "devpoll.hpp"
+#include "kqueue.hpp"
+
+namespace zmq
+{
+
+#if defined ZMQ_FORCE_SELECT
+ typedef select_t poller_t;
+#elif defined ZMQ_FORCE_POLL
+ typedef poll_t poller_t;
+#elif defined ZMQ_FORCE_EPOLL
+ typedef epoll_t poller_t;
+#elif defined ZMQ_FORCE_DEVPOLL
+ typedef devpoll_t poller_t;
+#elif defined ZMQ_FORCE_KQUEUE
+ typedef kqueue_t poller_t;
+#elif defined ZMQ_HAVE_LINUX
+ typedef epoll_t poller_t;
+#elif defined ZMQ_HAVE_WINDOWS
+ typedef select_t poller_t;
+#elif defined ZMQ_HAVE_FREEBSD
+ typedef kqueue_t poller_t;
+#elif defined ZMQ_HAVE_OPENBSD
+ typedef kqueue_t poller_t;
+#elif defined ZMQ_HAVE_NETBSD
+ typedef kqueue_t poller_t;
+#elif defined ZMQ_HAVE_SOLARIS
+ typedef devpoll_t poller_t;
+#elif defined ZMQ_HAVE_OSX
+ typedef kqueue_t poller_t;
+#elif defined ZMQ_HAVE_QNXNTO
+ typedef poll_t poller_t;
+#elif defined ZMQ_HAVE_AIX
+ typedef poll_t poller_t;
+#elif defined ZMQ_HAVE_HPUX
+ typedef devpoll_t poller_t;
+#elif defined ZMQ_HAVE_OPENVMS
+ typedef select_t poller_t;
+#elif defined ZMQ_HAVE_CYGWIN
+ typedef select_t poller_t;
+#else
+#error Unsupported platform
+#endif
+
+}
+
+#endif
diff --git a/src/prefix_tree.cpp b/src/prefix_tree.cpp
new file mode 100644
index 0000000..51225d6
--- /dev/null
+++ b/src/prefix_tree.cpp
@@ -0,0 +1,180 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdlib.h>
+
+#include <new>
+#include <algorithm>
+
+#include "platform.hpp"
+#if defined ZMQ_HAVE_WINDOWS
+#include "windows.hpp"
+#endif
+
+#include "err.hpp"
+#include "prefix_tree.hpp"
+
+zmq::prefix_tree_t::prefix_tree_t () :
+ refcnt (0),
+ min (0),
+ count (0)
+{
+}
+
+zmq::prefix_tree_t::~prefix_tree_t ()
+{
+ if (count == 1)
+ delete next.node;
+ else if (count > 1) {
+ for (unsigned char i = 0; i != count; ++i)
+ if (next.table [i])
+ delete next.table [i];
+ free (next.table);
+ }
+}
+
+void zmq::prefix_tree_t::add (unsigned char *prefix_, size_t size_)
+{
+ // We are at the node corresponding to the prefix. We are done.
+ if (!size_) {
+ ++refcnt;
+ return;
+ }
+
+ unsigned char c = *prefix_;
+ if (c < min || c >= min + count) {
+
+ // The character is out of range of currently handled
+ // charcters. We have to extend the table.
+ if (!count) {
+ min = c;
+ count = 1;
+ next.node = NULL;
+ }
+ else if (count == 1) {
+ unsigned char oldc = min;
+ prefix_tree_t *oldp = next.node;
+ count = (min < c ? c - min : min - c) + 1;
+ next.table = (prefix_tree_t**)
+ malloc (sizeof (prefix_tree_t*) * count);
+ zmq_assert (next.table);
+ for (unsigned char i = 0; i != count; ++i)
+ next.table [i] = 0;
+ min = std::min (min, c);
+ next.table [oldc - min] = oldp;
+ }
+ else if (min < c) {
+
+ // The new character is above the current character range.
+ unsigned char old_count = count;
+ count = c - min + 1;
+ next.table = (prefix_tree_t**) realloc ((void*) next.table,
+ sizeof (prefix_tree_t*) * count);
+ zmq_assert (next.table);
+ for (unsigned char i = old_count; i != count; i++)
+ next.table [i] = NULL;
+ }
+ else {
+
+ // The new character is below the current character range.
+ unsigned char old_count = count;
+ count = (min + old_count) - c;
+ next.table = (prefix_tree_t**) realloc ((void*) next.table,
+ sizeof (prefix_tree_t*) * count);
+ zmq_assert (next.table);
+ memmove (next.table + min - c, next.table,
+ old_count * sizeof (prefix_tree_t*));
+ for (unsigned char i = 0; i != min - c; i++)
+ next.table [i] = NULL;
+ min = c;
+ }
+ }
+
+ // If next node does not exist, create one.
+ if (count == 1) {
+ if (!next.node) {
+ next.node = new (std::nothrow) prefix_tree_t;
+ zmq_assert (next.node);
+ }
+ next.node->add (prefix_ + 1, size_ - 1);
+ }
+ else {
+ if (!next.table [c - min]) {
+ next.table [c - min] = new (std::nothrow) prefix_tree_t;
+ zmq_assert (next.table [c - min]);
+ }
+ next.table [c - min]->add (prefix_ + 1, size_ - 1);
+ }
+}
+
+bool zmq::prefix_tree_t::rm (unsigned char *prefix_, size_t size_)
+{
+ if (!size_) {
+ if (!refcnt)
+ return false;
+ refcnt--;
+ return true;
+ }
+
+ unsigned char c = *prefix_;
+ if (!count || c < min || c >= min + count)
+ return false;
+
+ prefix_tree_t *next_node =
+ count == 1 ? next.node : next.table [c - min];
+
+ if (!next_node)
+ return false;
+
+ return next_node->rm (prefix_ + 1, size_ - 1);
+}
+
+bool zmq::prefix_tree_t::check (unsigned char *data_, size_t size_)
+{
+ // This function is on critical path. It deliberately doesn't use
+ // recursion to get a bit better performance.
+ prefix_tree_t *current = this;
+ while (true) {
+
+ // We've found a corresponding subscription!
+ if (current->refcnt)
+ return true;
+
+ // We've checked all the data and haven't found matching subscription.
+ if (!size_)
+ return false;
+
+ // If there's no corresponding slot for the first character
+ // of the prefix, the message does not match.
+ unsigned char c = *data_;
+ if (c < current->min || c >= current->min + current->count)
+ return false;
+
+ // Move to the next character.
+ if (current->count == 1)
+ current = current->next.node;
+ else {
+ current = current->next.table [c - current->min];
+ if (!current)
+ return false;
+ }
+ data_++;
+ size_--;
+ }
+}
diff --git a/src/prefix_tree.hpp b/src/prefix_tree.hpp
new file mode 100644
index 0000000..53c7c18
--- /dev/null
+++ b/src/prefix_tree.hpp
@@ -0,0 +1,55 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_PREFIX_TREE_HPP_INCLUDED__
+#define __ZMQ_PREFIX_TREE_HPP_INCLUDED__
+
+#include <stddef.h>
+
+#include "stdint.hpp"
+
+namespace zmq
+{
+
+ class prefix_tree_t
+ {
+ public:
+
+ prefix_tree_t ();
+ ~prefix_tree_t ();
+
+ void add (unsigned char *prefix_, size_t size_);
+ bool rm (unsigned char *prefix_, size_t size_);
+ bool check (unsigned char *data_, size_t size_);
+
+ private:
+
+ uint32_t refcnt;
+ unsigned char min;
+ unsigned char count;
+ union {
+ class prefix_tree_t *node;
+ class prefix_tree_t **table;
+ } next;
+ };
+
+}
+
+#endif
+
diff --git a/src/pub.cpp b/src/pub.cpp
new file mode 100644
index 0000000..4e73b19
--- /dev/null
+++ b/src/pub.cpp
@@ -0,0 +1,177 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "../include/zmq.h"
+
+#include "pub.hpp"
+#include "err.hpp"
+#include "msg_content.hpp"
+#include "pipe.hpp"
+
+zmq::pub_t::pub_t (class app_thread_t *parent_) :
+ socket_base_t (parent_),
+ active (0)
+{
+ options.requires_in = false;
+ options.requires_out = true;
+}
+
+zmq::pub_t::~pub_t ()
+{
+ for (pipes_t::size_type i = 0; i != pipes.size (); i++)
+ pipes [i]->term ();
+ pipes.clear ();
+}
+
+void zmq::pub_t::xattach_pipes (class reader_t *inpipe_,
+ class writer_t *outpipe_, const blob_t &peer_identity_)
+{
+ zmq_assert (!inpipe_);
+ pipes.push_back (outpipe_);
+ pipes.swap (active, pipes.size () - 1);
+ active++;
+}
+
+void zmq::pub_t::xdetach_inpipe (class reader_t *pipe_)
+{
+ zmq_assert (false);
+}
+
+void zmq::pub_t::xdetach_outpipe (class writer_t *pipe_)
+{
+ // Remove the pipe from the list; adjust number of active pipes
+ // accordingly.
+ if (pipes.index (pipe_) < active)
+ active--;
+ pipes.erase (pipe_);
+}
+
+void zmq::pub_t::xkill (class reader_t *pipe_)
+{
+ zmq_assert (false);
+}
+
+void zmq::pub_t::xrevive (class reader_t *pipe_)
+{
+ zmq_assert (false);
+}
+
+void zmq::pub_t::xrevive (class writer_t *pipe_)
+{
+ // Move the pipe to the list of active pipes.
+ pipes.swap (pipes.index (pipe_), active);
+ active++;
+}
+
+int zmq::pub_t::xsetsockopt (int option_, const void *optval_,
+ size_t optvallen_)
+{
+ errno = EINVAL;
+ return -1;
+}
+
+int zmq::pub_t::xsend (zmq_msg_t *msg_, int flags_)
+{
+ // If there are no active pipes available, simply drop the message.
+ if (active == 0) {
+ int rc = zmq_msg_close (msg_);
+ zmq_assert (rc == 0);
+ rc = zmq_msg_init (msg_);
+ zmq_assert (rc == 0);
+ return 0;
+ }
+
+ msg_content_t *content = (msg_content_t*) msg_->content;
+
+ // For VSMs the copying is straighforward.
+ if (content == (msg_content_t*) ZMQ_VSM) {
+ for (pipes_t::size_type i = 0; i != active;)
+ if (write (pipes [i], msg_))
+ i++;
+ int rc = zmq_msg_init (msg_);
+ zmq_assert (rc == 0);
+ return 0;
+ }
+
+ // Optimisation for the case when there's only a single pipe
+ // to send the message to - no refcount adjustment i.e. no atomic
+ // operations are needed.
+ if (active == 1) {
+ if (!write (pipes [0], msg_)) {
+ int rc = zmq_msg_close (msg_);
+ zmq_assert (rc == 0);
+ }
+ int rc = zmq_msg_init (msg_);
+ zmq_assert (rc == 0);
+ return 0;
+ }
+
+ // There are at least 2 destinations for the message. That means we have
+ // to deal with reference counting. First add N-1 references to
+ // the content (we are holding one reference anyway, that's why -1).
+ if (msg_->flags & ZMQ_MSG_SHARED)
+ content->refcnt.add (active - 1);
+ else {
+ content->refcnt.set (active);
+ msg_->flags |= ZMQ_MSG_SHARED;
+ }
+
+ // Push the message to all destinations.
+ for (pipes_t::size_type i = 0; i != active;) {
+ if (!write (pipes [i], msg_))
+ content->refcnt.sub (1);
+ else
+ i++;
+ }
+
+ // Detach the original message from the data buffer.
+ int rc = zmq_msg_init (msg_);
+ zmq_assert (rc == 0);
+
+ return 0;
+}
+
+int zmq::pub_t::xrecv (zmq_msg_t *msg_, int flags_)
+{
+ errno = ENOTSUP;
+ return -1;
+}
+
+bool zmq::pub_t::xhas_in ()
+{
+ return false;
+}
+
+bool zmq::pub_t::xhas_out ()
+{
+ return true;
+}
+
+bool zmq::pub_t::write (class writer_t *pipe_, zmq_msg_t *msg_)
+{
+ if (!pipe_->write (msg_)) {
+ active--;
+ pipes.swap (pipes.index (pipe_), active);
+ return false;
+ }
+ if (!(msg_->flags & ZMQ_MSG_MORE))
+ pipe_->flush ();
+ return true;
+}
+
diff --git a/src/pub.hpp b/src/pub.hpp
new file mode 100644
index 0000000..ac3924a
--- /dev/null
+++ b/src/pub.hpp
@@ -0,0 +1,70 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_PUB_HPP_INCLUDED__
+#define __ZMQ_PUB_HPP_INCLUDED__
+
+#include "socket_base.hpp"
+#include "yarray.hpp"
+
+namespace zmq
+{
+
+ class pub_t : public socket_base_t
+ {
+ public:
+
+ pub_t (class app_thread_t *parent_);
+ ~pub_t ();
+
+ // Overloads of functions from socket_base_t.
+ void xattach_pipes (class reader_t *inpipe_, class writer_t *outpipe_,
+ const blob_t &peer_identity_);
+ void xdetach_inpipe (class reader_t *pipe_);
+ void xdetach_outpipe (class writer_t *pipe_);
+ void xkill (class reader_t *pipe_);
+ void xrevive (class reader_t *pipe_);
+ void xrevive (class writer_t *pipe_);
+ int xsetsockopt (int option_, const void *optval_, size_t optvallen_);
+ int xsend (zmq_msg_t *msg_, int flags_);
+ int xrecv (zmq_msg_t *msg_, int flags_);
+ bool xhas_in ();
+ bool xhas_out ();
+
+ private:
+
+ // Write the message to the pipe. Make the pipe inactive if writing
+ // fails. In such a case false is returned.
+ bool write (class writer_t *pipe_, zmq_msg_t *msg_);
+
+ // Outbound pipes, i.e. those the socket is sending messages to.
+ typedef yarray_t <class writer_t> pipes_t;
+ pipes_t pipes;
+
+ // Number of active pipes. All the active pipes are located at the
+ // beginning of the pipes array.
+ pipes_t::size_type active;
+
+ pub_t (const pub_t&);
+ void operator = (const pub_t&);
+ };
+
+}
+
+#endif
diff --git a/src/queue.cpp b/src/queue.cpp
new file mode 100644
index 0000000..470ea67
--- /dev/null
+++ b/src/queue.cpp
@@ -0,0 +1,101 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stddef.h>
+
+#include "../include/zmq.h"
+
+#include "queue.hpp"
+#include "socket_base.hpp"
+#include "err.hpp"
+
+int zmq::queue (class socket_base_t *insocket_,
+ class socket_base_t *outsocket_)
+{
+ zmq_msg_t msg;
+ int rc = zmq_msg_init (&msg);
+ zmq_assert (rc == 0);
+
+ int64_t more;
+ size_t moresz;
+
+ zmq_pollitem_t items [2];
+ items [0].socket = insocket_;
+ items [0].fd = 0;
+ items [0].events = ZMQ_POLLIN;
+ items [0].revents = 0;
+ items [1].socket = outsocket_;
+ items [1].fd = 0;
+ items [1].events = ZMQ_POLLIN;
+ items [1].revents = 0;
+
+ while (true) {
+
+ // Wait while there are either requests or replies to process.
+ rc = zmq_poll (&items [0], 2, -1);
+ errno_assert (rc > 0);
+
+ // The algorithm below asumes ratio of request and replies processed
+ // under full load to be 1:1. Although processing requests replies
+ // first is tempting it is suspectible to DoS attacks (overloading
+ // the system with unsolicited replies).
+
+ // Process a request.
+ if (items [0].revents & ZMQ_POLLIN) {
+ while (true) {
+
+ rc = insocket_->recv (&msg, 0);
+ errno_assert (rc == 0);
+
+ moresz = sizeof (more);
+ rc = insocket_->getsockopt (ZMQ_RCVMORE, &more, &moresz);
+ errno_assert (rc == 0);
+
+ rc = outsocket_->send (&msg, more ? ZMQ_SNDMORE : 0);
+ errno_assert (rc == 0);
+
+ if (!more)
+ break;
+ }
+ }
+
+ // Process a reply.
+ if (items [1].revents & ZMQ_POLLIN) {
+ while (true) {
+
+ rc = outsocket_->recv (&msg, 0);
+ errno_assert (rc == 0);
+
+ moresz = sizeof (more);
+ rc = outsocket_->getsockopt (ZMQ_RCVMORE, &more, &moresz);
+ errno_assert (rc == 0);
+
+ rc = insocket_->send (&msg, more ? ZMQ_SNDMORE : 0);
+ errno_assert (rc == 0);
+
+ if (!more)
+ break;
+ }
+ }
+
+ }
+
+ return 0;
+}
+
diff --git a/src/queue.hpp b/src/queue.hpp
new file mode 100644
index 0000000..dc968cb
--- /dev/null
+++ b/src/queue.hpp
@@ -0,0 +1,31 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_QUEUE_HPP_INCLUDED__
+#define __ZMQ_QUEUE_HPP_INCLUDED__
+
+namespace zmq
+{
+
+ int queue (class socket_base_t *insocket_,
+ class socket_base_t *outsocket_);
+
+}
+
+#endif
diff --git a/src/rep.cpp b/src/rep.cpp
new file mode 100644
index 0000000..34b77c4
--- /dev/null
+++ b/src/rep.cpp
@@ -0,0 +1,280 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "../include/zmq.h"
+
+#include "rep.hpp"
+#include "err.hpp"
+#include "pipe.hpp"
+
+zmq::rep_t::rep_t (class app_thread_t *parent_) :
+ socket_base_t (parent_),
+ active (0),
+ current (0),
+ sending_reply (false),
+ more (false),
+ reply_pipe (NULL)
+{
+ options.requires_in = true;
+ options.requires_out = true;
+
+ // We don't need immediate connect. We'll be able to send messages
+ // (replies) only when connection is established and thus requests
+ // can arrive anyway.
+ options.immediate_connect = false;
+}
+
+zmq::rep_t::~rep_t ()
+{
+}
+
+void zmq::rep_t::xattach_pipes (class reader_t *inpipe_,
+ class writer_t *outpipe_, const blob_t &peer_identity_)
+{
+ zmq_assert (inpipe_ && outpipe_);
+ zmq_assert (in_pipes.size () == out_pipes.size ());
+
+ in_pipes.push_back (inpipe_);
+ in_pipes.swap (active, in_pipes.size () - 1);
+ out_pipes.push_back (outpipe_);
+ out_pipes.swap (active, out_pipes.size () - 1);
+ active++;
+}
+
+void zmq::rep_t::xdetach_inpipe (class reader_t *pipe_)
+{
+ zmq_assert (sending_reply || !more || in_pipes [current] != pipe_);
+
+ zmq_assert (pipe_);
+ zmq_assert (in_pipes.size () == out_pipes.size ());
+
+ in_pipes_t::size_type index = in_pipes.index (pipe_);
+
+ if (index < active) {
+ active--;
+ if (current == active)
+ current = 0;
+ }
+
+ if (out_pipes [index])
+ out_pipes [index]->term ();
+ in_pipes.erase (index);
+ out_pipes.erase (index);
+}
+
+void zmq::rep_t::xdetach_outpipe (class writer_t *pipe_)
+{
+ zmq_assert (pipe_);
+ zmq_assert (in_pipes.size () == out_pipes.size ());
+
+ out_pipes_t::size_type index = out_pipes.index (pipe_);
+
+ // If the connection we've got the request from disconnects,
+ // there's nowhere to send the reply. Forget about the reply pipe.
+ // Once the reply is sent it will be dropped.
+ if (sending_reply && pipe_ == reply_pipe)
+ reply_pipe = NULL;
+
+ if (out_pipes.index (pipe_) < active) {
+ active--;
+ if (current == active)
+ current = 0;
+ }
+
+ if (in_pipes [index])
+ in_pipes [index]->term ();
+ in_pipes.erase (index);
+ out_pipes.erase (index);
+}
+
+void zmq::rep_t::xkill (class reader_t *pipe_)
+{
+ // Move the pipe to the list of inactive pipes.
+ in_pipes_t::size_type index = in_pipes.index (pipe_);
+ active--;
+ in_pipes.swap (index, active);
+ out_pipes.swap (index, active);
+}
+
+void zmq::rep_t::xrevive (class reader_t *pipe_)
+{
+ // Move the pipe to the list of active pipes.
+ in_pipes_t::size_type index = in_pipes.index (pipe_);
+ in_pipes.swap (index, active);
+ out_pipes.swap (index, active);
+ active++;
+}
+
+void zmq::rep_t::xrevive (class writer_t *pipe_)
+{
+}
+
+int zmq::rep_t::xsetsockopt (int option_, const void *optval_,
+ size_t optvallen_)
+{
+ errno = EINVAL;
+ return -1;
+}
+
+int zmq::rep_t::xsend (zmq_msg_t *msg_, int flags_)
+{
+ if (!sending_reply) {
+ errno = EFSM;
+ return -1;
+ }
+
+ if (reply_pipe) {
+
+ // Push message to the reply pipe.
+ bool written = reply_pipe->write (msg_);
+ zmq_assert (!more || written);
+
+ // The pipe is full...
+ // When this happens, we simply return an error.
+ // This makes REP sockets vulnerable to DoS attack when
+ // misbehaving requesters stop collecting replies.
+ // TODO: Tear down the underlying connection (?)
+ if (!written) {
+ errno = EAGAIN;
+ return -1;
+ }
+
+ more = msg_->flags & ZMQ_MSG_MORE;
+ }
+ else {
+
+ // If the requester have disconnected in the meantime, drop the reply.
+ more = msg_->flags & ZMQ_MSG_MORE;
+ zmq_msg_close (msg_);
+ }
+
+ // Flush the reply to the requester.
+ if (!more) {
+ if (reply_pipe)
+ reply_pipe->flush ();
+ sending_reply = false;
+ reply_pipe = NULL;
+ }
+
+ // Detach the message from the data buffer.
+ int rc = zmq_msg_init (msg_);
+ zmq_assert (rc == 0);
+
+ return 0;
+}
+
+int zmq::rep_t::xrecv (zmq_msg_t *msg_, int flags_)
+{
+ // If we are in middle of sending a reply, we cannot receive next request.
+ if (sending_reply) {
+ errno = EFSM;
+ return -1;
+ }
+
+ // Deallocate old content of the message.
+ zmq_msg_close (msg_);
+
+ // We haven't started reading a request yet...
+ if (!more) {
+
+ // Round-robin over the pipes to get next message.
+ int count;
+ for (count = active; count != 0; count--) {
+ if (in_pipes [current]->read (msg_))
+ break;
+ current++;
+ if (current >= active)
+ current = 0;
+ }
+
+ // No message is available. Initialise the output parameter
+ // to be a 0-byte message.
+ if (count == 0) {
+ zmq_msg_init (msg_);
+ errno = EAGAIN;
+ return -1;
+ }
+
+ // We are aware of a new message now. Setup the reply pipe.
+ reply_pipe = out_pipes [current];
+
+ // Copy the routing info to the reply pipe.
+ while (true) {
+
+ // Push message to the reply pipe.
+ // TODO: What if the pipe is full?
+ // Tear down the underlying connection?
+ bool written = reply_pipe->write (msg_);
+ zmq_assert (written);
+
+ // Message part of zero size delimits the traceback stack.
+ if (zmq_msg_size (msg_) == 0)
+ break;
+
+ // Get next part of the message.
+ bool fetched = in_pipes [current]->read (msg_);
+ zmq_assert (fetched);
+ }
+ }
+
+ // Now the routing info is processed. Get the first part
+ // of the message payload and exit.
+ bool fetched = in_pipes [current]->read (msg_);
+ zmq_assert (fetched);
+ more = msg_->flags & ZMQ_MSG_MORE;
+ if (!more) {
+ current++;
+ if (current >= active)
+ current = 0;
+ sending_reply = true;
+ }
+ return 0;
+}
+
+bool zmq::rep_t::xhas_in ()
+{
+ if (sending_reply)
+ return false;
+
+ if (more)
+ return true;
+
+ for (int count = active; count != 0; count--) {
+ if (in_pipes [current]->check_read ())
+ return !sending_reply;
+ current++;
+ if (current >= active)
+ current = 0;
+ }
+
+ return false;
+}
+
+bool zmq::rep_t::xhas_out ()
+{
+ if (!sending_reply)
+ return false;
+
+ if (more)
+ return true;
+
+ // TODO: No check for write here...
+ return sending_reply;
+}
+
diff --git a/src/rep.hpp b/src/rep.hpp
new file mode 100644
index 0000000..aef4318
--- /dev/null
+++ b/src/rep.hpp
@@ -0,0 +1,85 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_REP_HPP_INCLUDED__
+#define __ZMQ_REP_HPP_INCLUDED__
+
+#include "socket_base.hpp"
+#include "yarray.hpp"
+
+namespace zmq
+{
+
+ class rep_t : public socket_base_t
+ {
+ public:
+
+ rep_t (class app_thread_t *parent_);
+ ~rep_t ();
+
+ // Overloads of functions from socket_base_t.
+ void xattach_pipes (class reader_t *inpipe_, class writer_t *outpipe_,
+ const blob_t &peer_identity_);
+ void xdetach_inpipe (class reader_t *pipe_);
+ void xdetach_outpipe (class writer_t *pipe_);
+ void xkill (class reader_t *pipe_);
+ void xrevive (class reader_t *pipe_);
+ void xrevive (class writer_t *pipe_);
+ int xsetsockopt (int option_, const void *optval_, size_t optvallen_);
+ int xsend (zmq_msg_t *msg_, int flags_);
+ int xrecv (zmq_msg_t *msg_, int flags_);
+ bool xhas_in ();
+ bool xhas_out ();
+
+ private:
+
+ // List in outbound and inbound pipes. Note that the two lists are
+ // always in sync. I.e. outpipe with index N communicates with the
+ // same session as inpipe with index N.
+ typedef yarray_t <class writer_t> out_pipes_t;
+ out_pipes_t out_pipes;
+ typedef yarray_t <class reader_t> in_pipes_t;
+ in_pipes_t in_pipes;
+
+ // Number of active inpipes. All the active inpipes are located at the
+ // beginning of the in_pipes array.
+ in_pipes_t::size_type active;
+
+ // Index of the next inbound pipe to read a request from.
+ in_pipes_t::size_type current;
+
+ // If true, request was already received and reply wasn't completely
+ // sent yet.
+ bool sending_reply;
+
+ // True, if message processed at the moment (either sent or received)
+ // is processed only partially.
+ bool more;
+
+ // Pipe we are going to send reply to.
+ class writer_t *reply_pipe;
+
+ rep_t (const rep_t&);
+ void operator = (const rep_t&);
+
+ };
+
+}
+
+#endif
diff --git a/src/req.cpp b/src/req.cpp
new file mode 100644
index 0000000..f3695a2
--- /dev/null
+++ b/src/req.cpp
@@ -0,0 +1,286 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "../include/zmq.h"
+
+#include "req.hpp"
+#include "err.hpp"
+#include "pipe.hpp"
+
+zmq::req_t::req_t (class app_thread_t *parent_) :
+ socket_base_t (parent_),
+ active (0),
+ current (0),
+ receiving_reply (false),
+ reply_pipe_active (false),
+ more (false),
+ reply_pipe (NULL)
+{
+ options.requires_in = true;
+ options.requires_out = true;
+}
+
+zmq::req_t::~req_t ()
+{
+}
+
+void zmq::req_t::xattach_pipes (class reader_t *inpipe_,
+ class writer_t *outpipe_, const blob_t &peer_identity_)
+{
+ zmq_assert (inpipe_ && outpipe_);
+ zmq_assert (in_pipes.size () == out_pipes.size ());
+
+ in_pipes.push_back (inpipe_);
+ in_pipes.swap (active, in_pipes.size () - 1);
+
+ out_pipes.push_back (outpipe_);
+ out_pipes.swap (active, out_pipes.size () - 1);
+
+ active++;
+}
+
+void zmq::req_t::xdetach_inpipe (class reader_t *pipe_)
+{
+ zmq_assert (!receiving_reply || !more || reply_pipe != pipe_);
+
+ zmq_assert (pipe_);
+ zmq_assert (in_pipes.size () == out_pipes.size ());
+
+ // TODO: The pipe we are awaiting the reply from is detached. What now?
+ // Return ECONNRESET from subsequent recv?
+ if (receiving_reply && pipe_ == reply_pipe) {
+ zmq_assert (false);
+ }
+
+ in_pipes_t::size_type index = in_pipes.index (pipe_);
+
+ if (out_pipes [index])
+ out_pipes [index]->term ();
+ in_pipes.erase (index);
+ out_pipes.erase (index);
+ if (index < active) {
+ active--;
+ if (current == active)
+ current = 0;
+ }
+}
+
+void zmq::req_t::xdetach_outpipe (class writer_t *pipe_)
+{
+ zmq_assert (receiving_reply || !more || out_pipes [current] != pipe_);
+
+ zmq_assert (pipe_);
+ zmq_assert (in_pipes.size () == out_pipes.size ());
+
+ out_pipes_t::size_type index = out_pipes.index (pipe_);
+
+ if (in_pipes [index])
+ in_pipes [index]->term ();
+ in_pipes.erase (index);
+ out_pipes.erase (index);
+ if (index < active) {
+ active--;
+ if (current == active)
+ current = 0;
+ }
+}
+
+void zmq::req_t::xkill (class reader_t *pipe_)
+{
+ zmq_assert (receiving_reply);
+ zmq_assert (pipe_ == reply_pipe);
+
+ reply_pipe_active = false;
+}
+
+void zmq::req_t::xrevive (class reader_t *pipe_)
+{
+ // TODO: Actually, misbehaving peer can cause this kind of thing.
+ // Handle it decently, presumably kill the offending connection.
+ zmq_assert (pipe_ == reply_pipe);
+ reply_pipe_active = true;
+}
+
+void zmq::req_t::xrevive (class writer_t *pipe_)
+{
+ out_pipes_t::size_type index = out_pipes.index (pipe_);
+ zmq_assert (index >= active);
+
+ if (in_pipes [index] != NULL) {
+ in_pipes.swap (index, active);
+ out_pipes.swap (index, active);
+ active++;
+ }
+}
+
+int zmq::req_t::xsetsockopt (int option_, const void *optval_,
+ size_t optvallen_)
+{
+ errno = EINVAL;
+ return -1;
+}
+
+int zmq::req_t::xsend (zmq_msg_t *msg_, int flags_)
+{
+ // If we've sent a request and we still haven't got the reply,
+ // we can't send another request.
+ if (receiving_reply) {
+ errno = EFSM;
+ return -1;
+ }
+
+ while (active > 0) {
+ if (out_pipes [current]->check_write ())
+ break;
+
+ zmq_assert (!more);
+ active--;
+ if (current < active) {
+ in_pipes.swap (current, active);
+ out_pipes.swap (current, active);
+ }
+ else
+ current = 0;
+ }
+
+ if (active == 0) {
+ errno = EAGAIN;
+ return -1;
+ }
+
+ // If we are starting to send the request, generate a prefix.
+ if (!more) {
+ zmq_msg_t prefix;
+ int rc = zmq_msg_init (&prefix);
+ zmq_assert (rc == 0);
+ prefix.flags |= ZMQ_MSG_MORE;
+ bool written = out_pipes [current]->write (&prefix);
+ zmq_assert (written);
+ }
+
+ // Push the message to the selected pipe.
+ bool written = out_pipes [current]->write (msg_);
+ zmq_assert (written);
+ more = msg_->flags & ZMQ_MSG_MORE;
+ if (!more) {
+ out_pipes [current]->flush ();
+ receiving_reply = true;
+ reply_pipe = in_pipes [current];
+
+ // We can safely assume that the reply pipe is active as the last time
+ // we've used it we've read the reply and haven't tried to read from it
+ // anymore.
+ reply_pipe_active = true;
+
+ // Move to the next pipe (load-balancing).
+ current = (current + 1) % active;
+ }
+
+ // Detach the message from the data buffer.
+ int rc = zmq_msg_init (msg_);
+ zmq_assert (rc == 0);
+
+ return 0;
+}
+
+int zmq::req_t::xrecv (zmq_msg_t *msg_, int flags_)
+{
+ // Deallocate old content of the message.
+ int rc = zmq_msg_close (msg_);
+ zmq_assert (rc == 0);
+
+ // If request wasn't send, we can't wait for reply.
+ if (!receiving_reply) {
+ zmq_msg_init (msg_);
+ errno = EFSM;
+ return -1;
+ }
+
+ // Get the reply from the reply pipe.
+ if (!reply_pipe_active || !reply_pipe->read (msg_)) {
+ zmq_msg_init (msg_);
+ errno = EAGAIN;
+ return -1;
+ }
+
+ // If we are starting to receive new reply, check whether prefix
+ // is well-formed and drop it.
+ if (!more) {
+ zmq_assert (msg_->flags & ZMQ_MSG_MORE);
+ zmq_assert (zmq_msg_size (msg_) == 0);
+ rc = zmq_msg_close (msg_);
+ zmq_assert (rc == 0);
+
+ // Get the actual reply.
+ bool recvd = reply_pipe->read (msg_);
+ zmq_assert (recvd);
+ }
+
+ // If this was last part of the reply, switch to request phase.
+ more = msg_->flags & ZMQ_MSG_MORE;
+ if (!more) {
+ receiving_reply = false;
+ reply_pipe = NULL;
+ }
+
+ return 0;
+}
+
+bool zmq::req_t::xhas_in ()
+{
+ if (receiving_reply && more)
+ return true;
+
+ if (!receiving_reply || !reply_pipe_active)
+ return false;
+
+ zmq_assert (reply_pipe);
+ if (!reply_pipe->check_read ()) {
+ reply_pipe_active = false;
+ return false;
+ }
+
+ return true;
+}
+
+bool zmq::req_t::xhas_out ()
+{
+ if (!receiving_reply && more)
+ return true;
+
+ if (receiving_reply)
+ return false;
+
+ while (active > 0) {
+ if (out_pipes [current]->check_write ())
+ return true;;
+
+ active--;
+ if (current < active) {
+ in_pipes.swap (current, active);
+ out_pipes.swap (current, active);
+ }
+ else
+ current = 0;
+ }
+
+ return false;
+}
+
+
diff --git a/src/req.hpp b/src/req.hpp
new file mode 100644
index 0000000..5ab7bca
--- /dev/null
+++ b/src/req.hpp
@@ -0,0 +1,93 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_REQ_HPP_INCLUDED__
+#define __ZMQ_REQ_HPP_INCLUDED__
+
+#include "socket_base.hpp"
+#include "yarray.hpp"
+
+namespace zmq
+{
+
+ class req_t : public socket_base_t
+ {
+ public:
+
+ req_t (class app_thread_t *parent_);
+ ~req_t ();
+
+ // Overloads of functions from socket_base_t.
+ void xattach_pipes (class reader_t *inpipe_, class writer_t *outpipe_,
+ const blob_t &peer_identity_);
+ void xdetach_inpipe (class reader_t *pipe_);
+ void xdetach_outpipe (class writer_t *pipe_);
+ void xkill (class reader_t *pipe_);
+ void xrevive (class reader_t *pipe_);
+ void xrevive (class writer_t *pipe_);
+ int xsetsockopt (int option_, const void *optval_, size_t optvallen_);
+ int xsend (zmq_msg_t *msg_, int flags_);
+ int xrecv (zmq_msg_t *msg_, int flags_);
+ bool xhas_in ();
+ bool xhas_out ();
+
+ private:
+
+ // List in outbound and inbound pipes. Note that the two lists are
+ // always in sync. I.e. outpipe with index N communicates with the
+ // same session as inpipe with index N.
+ //
+ // TODO: Once we have queue limits in place, list of active outpipes
+ // is to be held (presumably by stacking active outpipes at
+ // the beginning of the array). We don't have to do the same thing for
+ // inpipes, because we know which pipe we want to read the
+ // reply from.
+ typedef yarray_t <class writer_t> out_pipes_t;
+ out_pipes_t out_pipes;
+ typedef yarray_t <class reader_t> in_pipes_t;
+ in_pipes_t in_pipes;
+
+ // Number of active pipes.
+ size_t active;
+
+ // Req_t load-balances the requests - 'current' points to the session
+ // that's processing the request at the moment.
+ out_pipes_t::size_type current;
+
+ // If true, request was already sent and reply wasn't received yet or
+ // was raceived partially.
+ bool receiving_reply;
+
+ // True, if read can be attempted from the reply pipe.
+ bool reply_pipe_active;
+
+ // True, if message processed at the moment (either sent or received)
+ // is processed only partially.
+ bool more;
+
+ // Pipe we are awaiting the reply from.
+ class reader_t *reply_pipe;
+
+ req_t (const req_t&);
+ void operator = (const req_t&);
+ };
+
+}
+
+#endif
diff --git a/src/select.cpp b/src/select.cpp
new file mode 100644
index 0000000..be5cd47
--- /dev/null
+++ b/src/select.cpp
@@ -0,0 +1,234 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "platform.hpp"
+
+#include <string.h>
+#include <algorithm>
+
+#ifdef ZMQ_HAVE_WINDOWS
+#include "winsock2.h"
+#elif defined ZMQ_HAVE_HPUX
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#elif defined ZMQ_HAVE_OPENVMS
+#include <sys/types.h>
+#include <sys/time.h>
+#else
+#include <sys/select.h>
+#endif
+
+#include "select.hpp"
+#include "err.hpp"
+#include "config.hpp"
+#include "i_poll_events.hpp"
+
+zmq::select_t::select_t () :
+ maxfd (retired_fd),
+ retired (false),
+ stopping (false)
+{
+ // Clear file descriptor sets.
+ FD_ZERO (&source_set_in);
+ FD_ZERO (&source_set_out);
+ FD_ZERO (&source_set_err);
+}
+
+zmq::select_t::~select_t ()
+{
+ worker.stop ();
+
+ // Make sure there are no fds registered on shutdown.
+ zmq_assert (load.get () == 0);
+}
+
+zmq::select_t::handle_t zmq::select_t::add_fd (fd_t fd_, i_poll_events *events_)
+{
+ // Store the file descriptor.
+ fd_entry_t entry = {fd_, events_};
+ fds.push_back (entry);
+
+ // Start polling on errors.
+ FD_SET (fd_, &source_set_err);
+
+ // Adjust maxfd if necessary.
+ if (fd_ > maxfd)
+ maxfd = fd_;
+
+ // Increase the load metric of the thread.
+ load.add (1);
+
+ return fd_;
+}
+
+void zmq::select_t::rm_fd (handle_t handle_)
+{
+ // Mark the descriptor as retired.
+ fd_set_t::iterator it;
+ for (it = fds.begin (); it != fds.end (); it ++)
+ if (it->fd == handle_)
+ break;
+ zmq_assert (it != fds.end ());
+ it->fd = retired_fd;
+ retired = true;
+
+ // Stop polling on the descriptor.
+ FD_CLR (handle_, &source_set_in);
+ FD_CLR (handle_, &source_set_out);
+ FD_CLR (handle_, &source_set_err);
+
+ // Discard all events generated on this file descriptor.
+ FD_CLR (handle_, &readfds);
+ FD_CLR (handle_, &writefds);
+ FD_CLR (handle_, &exceptfds);
+
+ // Adjust the maxfd attribute if we have removed the
+ // highest-numbered file descriptor.
+ if (handle_ == maxfd) {
+ maxfd = retired_fd;
+ for (fd_set_t::iterator it = fds.begin (); it != fds.end (); it ++)
+ if (it->fd > maxfd)
+ maxfd = it->fd;
+ }
+
+ // Decrease the load metric of the thread.
+ load.sub (1);
+}
+
+void zmq::select_t::set_pollin (handle_t handle_)
+{
+ FD_SET (handle_, &source_set_in);
+}
+
+void zmq::select_t::reset_pollin (handle_t handle_)
+{
+ FD_CLR (handle_, &source_set_in);
+}
+
+void zmq::select_t::set_pollout (handle_t handle_)
+{
+ FD_SET (handle_, &source_set_out);
+}
+
+void zmq::select_t::reset_pollout (handle_t handle_)
+{
+ FD_CLR (handle_, &source_set_out);
+}
+
+void zmq::select_t::add_timer (i_poll_events *events_)
+{
+ timers.push_back (events_);
+}
+
+void zmq::select_t::cancel_timer (i_poll_events *events_)
+{
+ timers_t::iterator it = std::find (timers.begin (), timers.end (), events_);
+ if (it != timers.end ())
+ timers.erase (it);
+}
+
+int zmq::select_t::get_load ()
+{
+ return load.get ();
+}
+
+void zmq::select_t::start ()
+{
+ worker.start (worker_routine, this);
+}
+
+void zmq::select_t::stop ()
+{
+ stopping = true;
+}
+
+void zmq::select_t::loop ()
+{
+ while (!stopping) {
+
+ // Intialise the pollsets.
+ memcpy (&readfds, &source_set_in, sizeof source_set_in);
+ memcpy (&writefds, &source_set_out, sizeof source_set_out);
+ memcpy (&exceptfds, &source_set_err, sizeof source_set_err);
+
+ // Compute the timout interval. Select is free to overwrite the
+ // value so we have to compute it each time anew.
+ timeval timeout = {max_timer_period / 1000,
+ (max_timer_period % 1000) * 1000};
+
+ // Wait for events.
+ int rc = select (maxfd + 1, &readfds, &writefds, &exceptfds,
+ timers.empty () ? NULL : &timeout);
+
+#ifdef ZMQ_HAVE_WINDOWS
+ wsa_assert (rc != SOCKET_ERROR);
+#else
+ if (rc == -1 && errno == EINTR)
+ continue;
+ errno_assert (rc != -1);
+#endif
+
+ // Handle timer.
+ if (!rc) {
+
+ // Use local list of timers as timer handlers may fill new timers
+ // into the original array.
+ timers_t t;
+ std::swap (timers, t);
+
+ // Trigger all the timers.
+ for (timers_t::iterator it = t.begin (); it != t.end (); it ++)
+ (*it)->timer_event ();
+
+ continue;
+ }
+
+ for (fd_set_t::size_type i = 0; i < fds.size (); i ++) {
+ if (fds [i].fd == retired_fd)
+ continue;
+ if (FD_ISSET (fds [i].fd, &exceptfds))
+ fds [i].events->in_event ();
+ if (fds [i].fd == retired_fd)
+ continue;
+ if (FD_ISSET (fds [i].fd, &writefds))
+ fds [i].events->out_event ();
+ if (fds [i].fd == retired_fd)
+ continue;
+ if (FD_ISSET (fds [i].fd, &readfds))
+ fds [i].events->in_event ();
+ }
+
+ // Destroy retired event sources.
+ if (retired) {
+ for (fd_set_t::size_type i = 0; i < fds.size (); i ++) {
+ if (fds [i].fd == retired_fd) {
+ fds.erase (fds.begin () + i);
+ i --;
+ }
+ }
+ retired = false;
+ }
+ }
+}
+
+void zmq::select_t::worker_routine (void *arg_)
+{
+ ((select_t*) arg_)->loop ();
+}
diff --git a/src/select.hpp b/src/select.hpp
new file mode 100644
index 0000000..01e9fa8
--- /dev/null
+++ b/src/select.hpp
@@ -0,0 +1,123 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_SELECT_HPP_INCLUDED__
+#define __ZMQ_SELECT_HPP_INCLUDED__
+
+#include "platform.hpp"
+
+#include <stddef.h>
+#include <vector>
+
+#ifdef ZMQ_HAVE_WINDOWS
+#include "winsock2.h"
+#elif defined ZMQ_HAVE_OPENVMS
+#include <sys/types.h>
+#include <sys/time.h>
+#else
+#include <sys/select.h>
+#endif
+
+#include "fd.hpp"
+#include "thread.hpp"
+#include "atomic_counter.hpp"
+
+namespace zmq
+{
+
+ // Implements socket polling mechanism using POSIX.1-2001 select()
+ // function.
+
+ class select_t
+ {
+ public:
+
+ typedef fd_t handle_t;
+
+ select_t ();
+ ~select_t ();
+
+ // "poller" concept.
+ handle_t add_fd (fd_t fd_, struct i_poll_events *events_);
+ void rm_fd (handle_t handle_);
+ void set_pollin (handle_t handle_);
+ void reset_pollin (handle_t handle_);
+ void set_pollout (handle_t handle_);
+ void reset_pollout (handle_t handle_);
+ void add_timer (struct i_poll_events *events_);
+ void cancel_timer (struct i_poll_events *events_);
+ int get_load ();
+ void start ();
+ void stop ();
+
+ private:
+
+ // Main worker thread routine.
+ static void worker_routine (void *arg_);
+
+ // Main event loop.
+ void loop ();
+
+ struct fd_entry_t
+ {
+ fd_t fd;
+ struct i_poll_events *events;
+ };
+
+ // Set of file descriptors that are used to retreive
+ // information for fd_set.
+ typedef std::vector <fd_entry_t> fd_set_t;
+ fd_set_t fds;
+
+ fd_set source_set_in;
+ fd_set source_set_out;
+ fd_set source_set_err;
+
+ fd_set readfds;
+ fd_set writefds;
+ fd_set exceptfds;
+
+ // Maximum file descriptor.
+ fd_t maxfd;
+
+ // If true, at least one file descriptor has retired.
+ bool retired;
+
+ // List of all the engines waiting for the timer event.
+ typedef std::vector <struct i_poll_events*> timers_t;
+ timers_t timers;
+
+ // If true, thread is shutting down.
+ bool stopping;
+
+ // Handle of the physical thread doing the I/O work.
+ thread_t worker;
+
+ // Load of the poller. Currently number of file descriptors
+ // registered with the poller.
+ atomic_counter_t load;
+
+ select_t (const select_t&);
+ void operator = (const select_t&);
+ };
+
+}
+
+#endif
+
diff --git a/src/session.cpp b/src/session.cpp
new file mode 100644
index 0000000..3cd27fb
--- /dev/null
+++ b/src/session.cpp
@@ -0,0 +1,291 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <new>
+
+#include "session.hpp"
+#include "i_engine.hpp"
+#include "err.hpp"
+#include "pipe.hpp"
+
+zmq::session_t::session_t (object_t *parent_, socket_base_t *owner_,
+ const options_t &options_) :
+ owned_t (parent_, owner_),
+ in_pipe (NULL),
+ incomplete_in (false),
+ active (true),
+ out_pipe (NULL),
+ engine (NULL),
+ options (options_)
+{
+ // It's possible to register the session at this point as it will be
+ // searched for only on reconnect, i.e. no race condition (session found
+ // before it is plugged into it's I/O thread) is possible.
+ ordinal = owner->register_session (this);
+}
+
+zmq::session_t::session_t (object_t *parent_, socket_base_t *owner_,
+ const options_t &options_, const blob_t &peer_identity_) :
+ owned_t (parent_, owner_),
+ in_pipe (NULL),
+ incomplete_in (false),
+ active (true),
+ out_pipe (NULL),
+ engine (NULL),
+ ordinal (0),
+ peer_identity (peer_identity_),
+ options (options_)
+{
+ if (!peer_identity.empty () && peer_identity [0] != 0) {
+ if (!owner->register_session (peer_identity, this)) {
+
+ // TODO: There's already a session with the specified
+ // identity. We should presumably syslog it and drop the
+ // session.
+ zmq_assert (false);
+ }
+ }
+}
+
+zmq::session_t::~session_t ()
+{
+ zmq_assert (!in_pipe);
+ zmq_assert (!out_pipe);
+}
+
+bool zmq::session_t::read (::zmq_msg_t *msg_)
+{
+ if (!in_pipe || !active)
+ return false;
+
+ if (!in_pipe->read (msg_))
+ return false;
+
+ incomplete_in = msg_->flags & ZMQ_MSG_MORE;
+ return true;
+}
+
+bool zmq::session_t::write (::zmq_msg_t *msg_)
+{
+ if (out_pipe && out_pipe->write (msg_)) {
+ zmq_msg_init (msg_);
+ return true;
+ }
+
+ return false;
+}
+
+void zmq::session_t::flush ()
+{
+ if (out_pipe)
+ out_pipe->flush ();
+}
+
+void zmq::session_t::detach (owned_t *reconnecter_)
+{
+ // Plug in the reconnecter object if any.
+ if (reconnecter_) {
+ send_plug (reconnecter_);
+ send_own (owner, reconnecter_);
+ }
+
+ // Engine is terminating itself. No need to deallocate it from here.
+ engine = NULL;
+
+ // Get rid of half-processed messages in the out pipe. Flush any
+ // unflushed messages upstream.
+ if (out_pipe) {
+ out_pipe->rollback ();
+ out_pipe->flush ();
+ }
+
+ // Remove any half-read message from the in pipe.
+ if (in_pipe) {
+ while (incomplete_in) {
+ zmq_msg_t msg;
+ zmq_msg_init (&msg);
+ if (!read (&msg)) {
+ zmq_assert (!incomplete_in);
+ break;
+ }
+ zmq_msg_close (&msg);
+ }
+ }
+
+ // Terminate transient session.
+ if (!ordinal && (peer_identity.empty () || peer_identity [0] == 0))
+ term ();
+}
+
+zmq::io_thread_t *zmq::session_t::get_io_thread ()
+{
+ return choose_io_thread (options.affinity);
+}
+
+class zmq::socket_base_t *zmq::session_t::get_owner ()
+{
+ return owner;
+}
+
+uint64_t zmq::session_t::get_ordinal ()
+{
+ zmq_assert (ordinal);
+ return ordinal;
+}
+
+void zmq::session_t::attach_pipes (class reader_t *inpipe_,
+ class writer_t *outpipe_, const blob_t &peer_identity_)
+{
+ if (inpipe_) {
+ zmq_assert (!in_pipe);
+ in_pipe = inpipe_;
+ active = true;
+ in_pipe->set_endpoint (this);
+ }
+
+ if (outpipe_) {
+ zmq_assert (!out_pipe);
+ out_pipe = outpipe_;
+ out_pipe->set_endpoint (this);
+ }
+}
+
+void zmq::session_t::detach_inpipe (reader_t *pipe_)
+{
+ active = false;
+ in_pipe = NULL;
+}
+
+void zmq::session_t::detach_outpipe (writer_t *pipe_)
+{
+ out_pipe = NULL;
+}
+
+void zmq::session_t::kill (reader_t *pipe_)
+{
+ active = false;
+}
+
+void zmq::session_t::revive (reader_t *pipe_)
+{
+ zmq_assert (in_pipe == pipe_);
+ active = true;
+ if (engine)
+ engine->revive ();
+}
+
+void zmq::session_t::revive (writer_t *pipe_)
+{
+ zmq_assert (out_pipe == pipe_);
+ if (engine)
+ engine->resume_input ();
+}
+
+void zmq::session_t::process_plug ()
+{
+}
+
+void zmq::session_t::process_unplug ()
+{
+ // Unregister the session from the socket.
+ if (ordinal)
+ owner->unregister_session (ordinal);
+ else if (!peer_identity.empty () && peer_identity [0] != 0)
+ owner->unregister_session (peer_identity);
+
+ // Ask associated pipes to terminate.
+ if (in_pipe) {
+ in_pipe->term ();
+ in_pipe = NULL;
+ }
+ if (out_pipe) {
+ out_pipe->term ();
+ out_pipe = NULL;
+ }
+
+ if (engine) {
+ engine->unplug ();
+ delete engine;
+ engine = NULL;
+ }
+}
+
+void zmq::session_t::process_attach (i_engine *engine_,
+ const blob_t &peer_identity_)
+{
+ if (!peer_identity.empty ()) {
+
+ // If both IDs are temporary, no checking is needed.
+ // TODO: Old ID should be reused in this case...
+ if (peer_identity.empty () || peer_identity [0] != 0 ||
+ peer_identity_.empty () || peer_identity_ [0] != 0) {
+
+ // If we already know the peer name do nothing, just check whether
+ // it haven't changed.
+ zmq_assert (peer_identity == peer_identity_);
+ }
+ }
+ else if (!peer_identity_.empty ()) {
+
+ // Store the peer identity.
+ peer_identity = peer_identity_;
+
+ // If the session is not registered with the ordinal, let's register
+ // it using the peer name.
+ if (!ordinal) {
+ if (!owner->register_session (peer_identity, this)) {
+
+ // TODO: There's already a session with the specified
+ // identity. We should presumably syslog it and drop the
+ // session.
+ zmq_assert (false);
+ }
+ }
+ }
+
+ // Check whether the required pipes already exist. If not so, we'll
+ // create them and bind them to the socket object.
+ reader_t *socket_reader = NULL;
+ writer_t *socket_writer = NULL;
+
+ if (options.requires_in && !out_pipe) {
+ pipe_t *pipe = new (std::nothrow) pipe_t (owner, this, options.hwm);
+ zmq_assert (pipe);
+ out_pipe = &pipe->writer;
+ out_pipe->set_endpoint (this);
+ socket_reader = &pipe->reader;
+ }
+
+ if (options.requires_out && !in_pipe) {
+ pipe_t *pipe = new (std::nothrow) pipe_t (this, owner, options.hwm);
+ zmq_assert (pipe);
+ in_pipe = &pipe->reader;
+ in_pipe->set_endpoint (this);
+ socket_writer = &pipe->writer;
+ }
+
+ if (socket_reader || socket_writer)
+ send_bind (owner, socket_reader, socket_writer, peer_identity);
+
+ // Plug in the engine.
+ zmq_assert (!engine);
+ zmq_assert (engine_);
+ engine = engine_;
+ engine->plug (this);
+}
diff --git a/src/session.hpp b/src/session.hpp
new file mode 100644
index 0000000..9bda1ad
--- /dev/null
+++ b/src/session.hpp
@@ -0,0 +1,104 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_SESSION_HPP_INCLUDED__
+#define __ZMQ_SESSION_HPP_INCLUDED__
+
+#include "i_inout.hpp"
+#include "i_endpoint.hpp"
+#include "owned.hpp"
+#include "options.hpp"
+#include "blob.hpp"
+
+namespace zmq
+{
+
+ class session_t : public owned_t, public i_inout, public i_endpoint
+ {
+ public:
+
+ // Creates unnamed session.
+ session_t (object_t *parent_, socket_base_t *owner_,
+ const options_t &options_);
+
+ // Creates named session.
+ session_t (object_t *parent_, socket_base_t *owner_,
+ const options_t &options_, const blob_t &peer_identity_);
+
+ // i_inout interface implementation.
+ bool read (::zmq_msg_t *msg_);
+ bool write (::zmq_msg_t *msg_);
+ void flush ();
+ void detach (owned_t *reconnecter_);
+ class io_thread_t *get_io_thread ();
+ class socket_base_t *get_owner ();
+ uint64_t get_ordinal ();
+
+ // i_endpoint interface implementation.
+ void attach_pipes (class reader_t *inpipe_, class writer_t *outpipe_,
+ const blob_t &peer_identity_);
+ void detach_inpipe (class reader_t *pipe_);
+ void detach_outpipe (class writer_t *pipe_);
+ void kill (class reader_t *pipe_);
+ void revive (class reader_t *pipe_);
+ void revive (class writer_t *pipe_);
+
+ private:
+
+ ~session_t ();
+
+ // Handlers for incoming commands.
+ void process_plug ();
+ void process_unplug ();
+ void process_attach (struct i_engine *engine_,
+ const blob_t &peer_identity_);
+
+ // Inbound pipe, i.e. one the session is getting messages from.
+ class reader_t *in_pipe;
+
+ // This flag is true if the remainder of the message being processed
+ // is still in the in pipe.
+ bool incomplete_in;
+
+ // If true, in_pipe is active. Otherwise there are no messages to get.
+ bool active;
+
+ // Outbound pipe, i.e. one the socket is sending messages to.
+ class writer_t *out_pipe;
+
+ struct i_engine *engine;
+
+ // Session is identified by ordinal in the case when it was created
+ // before connection to the peer was established and thus we are
+ // unaware of peer's identity.
+ uint64_t ordinal;
+
+ // Identity of the peer.
+ blob_t peer_identity;
+
+ // Inherited socket options.
+ options_t options;
+
+ session_t (const session_t&);
+ void operator = (const session_t&);
+ };
+
+}
+
+#endif
diff --git a/src/signaler.cpp b/src/signaler.cpp
new file mode 100644
index 0000000..592688b
--- /dev/null
+++ b/src/signaler.cpp
@@ -0,0 +1,339 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "signaler.hpp"
+#include "platform.hpp"
+#include "err.hpp"
+#include "fd.hpp"
+#include "ip.hpp"
+
+#if defined ZMQ_HAVE_OPENVMS
+#include <netinet/tcp.h>
+#include <unistd.h>
+#elif defined ZMQ_HAVE_WINDOWS
+#include "windows.hpp"
+#else
+#include <unistd.h>
+#include <fcntl.h>
+#include <limits.h>
+#endif
+
+zmq::fd_t zmq::signaler_t::get_fd ()
+{
+ return r;
+}
+
+#if defined ZMQ_HAVE_WINDOWS
+
+zmq::signaler_t::signaler_t ()
+{
+ // Windows have no 'socketpair' function. CreatePipe is no good as pipe
+ // handles cannot be polled on. Here we create the socketpair by hand.
+
+ struct sockaddr_in addr;
+ SOCKET listener;
+ int addrlen = sizeof (addr);
+
+ w = INVALID_SOCKET;
+ r = INVALID_SOCKET;
+
+ fd_t rcs = (listener = socket (AF_INET, SOCK_STREAM, 0));
+ wsa_assert (rcs != INVALID_SOCKET);
+
+ memset (&addr, 0, sizeof (addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+ addr.sin_port = 0;
+
+ int rc = bind (listener, (const struct sockaddr*) &addr, sizeof (addr));
+ wsa_assert (rc != SOCKET_ERROR);
+
+ rc = getsockname (listener, (struct sockaddr*) &addr, &addrlen);
+ wsa_assert (rc != SOCKET_ERROR);
+
+ // Listen for incomming connections.
+ rc = listen (listener, 1);
+ wsa_assert (rc != SOCKET_ERROR);
+
+ // Create the socket.
+ w = WSASocket (AF_INET, SOCK_STREAM, 0, NULL, 0, 0);
+ wsa_assert (w != INVALID_SOCKET);
+
+ // Connect to the remote peer.
+ rc = connect (w, (sockaddr *) &addr, sizeof (addr));
+ wsa_assert (rc != SOCKET_ERROR);
+
+ // Accept connection from w.
+ r = accept (listener, NULL, NULL);
+ wsa_assert (r != INVALID_SOCKET);
+
+ // Set the read site of the pair to non-blocking mode.
+ unsigned long argp = 1;
+ rc = ioctlsocket (r, FIONBIO, &argp);
+ wsa_assert (rc != SOCKET_ERROR);
+
+ // We don't need the listening socket anymore. Close it.
+ rc = closesocket (listener);
+ wsa_assert (rc != SOCKET_ERROR);
+}
+
+zmq::signaler_t::~signaler_t ()
+{
+ int rc = closesocket (w);
+ wsa_assert (rc != SOCKET_ERROR);
+
+ rc = closesocket (r);
+ wsa_assert (rc != SOCKET_ERROR);
+}
+
+void zmq::signaler_t::send (const command_t &cmd_)
+{
+ // TODO: Note that send is a blocking operation.
+ // How should we behave if the signal cannot be written to the signaler?
+ // Even worse: What if half of a command is written?
+ int rc = ::send (w, (char*) &cmd_, sizeof (command_t), 0);
+ win_assert (rc != SOCKET_ERROR);
+ zmq_assert (rc == sizeof (command_t));
+}
+
+bool zmq::signaler_t::recv (command_t *cmd_, bool block_)
+{
+ if (block_) {
+
+ // Switch to blocking mode.
+ unsigned long argp = 0;
+ int rc = ioctlsocket (r, FIONBIO, &argp);
+ wsa_assert (rc != SOCKET_ERROR);
+ }
+
+ bool result;
+ int nbytes = ::recv (r, (char*) cmd_, sizeof (command_t), 0);
+ if (nbytes == -1 && WSAGetLastError () == WSAEWOULDBLOCK) {
+ result = false;
+ }
+ else {
+ wsa_assert (nbytes != -1);
+
+ // Check whether we haven't got half of a signal.
+ zmq_assert (nbytes % sizeof (uint32_t) == 0);
+
+ result = true;
+ }
+
+ if (block_) {
+
+ // Switch back to non-blocking mode.
+ unsigned long argp = 1;
+ int rc = ioctlsocket (r, FIONBIO, &argp);
+ wsa_assert (rc != SOCKET_ERROR);
+ }
+
+ return result;
+}
+
+#elif defined ZMQ_HAVE_HPUX || defined ZMQ_HAVE_AIX
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+zmq::signaler_t::signaler_t ()
+{
+ int sv [2];
+ int rc = socketpair (AF_UNIX, SOCK_STREAM, 0, sv);
+ errno_assert (rc == 0);
+ w = sv [0];
+ r = sv [1];
+
+ // Set the reader to non-blocking mode.
+ int flags = fcntl (r, F_GETFL, 0);
+ if (flags == -1)
+ flags = 0;
+ rc = fcntl (r, F_SETFL, flags | O_NONBLOCK);
+ errno_assert (rc != -1);
+}
+
+zmq::signaler_t::~signaler_t ()
+{
+ close (w);
+ close (r);
+}
+
+void zmq::signaler_t::send (const command_t &cmd_)
+{
+ ssize_t nbytes = send (w, &cmd_, sizeof (command_t), 0);
+ errno_assert (nbytes != -1);
+ zmq_assert (nbytes == sizeof (command_t));
+}
+
+bool zmq::signaler_t::recv (command_t &cmd_, bool block_)
+{
+ if (block_) {
+
+ // Set the reader to blocking mode.
+ int flags = fcntl (r, F_GETFL, 0);
+ if (flags == -1)
+ flags = 0;
+ int rc = fcntl (r, F_SETFL, flags & ~O_NONBLOCK);
+ errno_assert (rc != -1);
+ }
+
+ bool result;
+ ssize_t nbytes = recv (r, buffer, sizeof (command_t), 0);
+ if (nbytes == -1 && errno == EAGAIN) {
+ result = false;
+ }
+ else {
+ zmq_assert (nbytes != -1);
+
+ // Check whether we haven't got half of command.
+ zmq_assert (nbytes == sizeof (command_t));
+
+ result = true;
+ }
+
+ if (block_)
+
+ // Set the reader to non-blocking mode.
+ int flags = fcntl (r, F_GETFL, 0);
+ if (flags == -1)
+ flags = 0;
+ int rc = fcntl (r, F_SETFL, flags | O_NONBLOCK);
+ errno_assert (rc != -1);
+ }
+
+ return result;
+}
+
+#else
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+zmq::signaler_t::signaler_t ()
+{
+ // Make sure that command can be written to the socket in atomic fashion.
+ // If this wasn't guaranteed, commands from different threads would be
+ // interleaved.
+ zmq_assert (sizeof (command_t) <= PIPE_BUF);
+
+ int sv [2];
+ int rc = socketpair (AF_UNIX, SOCK_STREAM, 0, sv);
+ errno_assert (rc == 0);
+ w = sv [0];
+ r = sv [1];
+}
+
+zmq::signaler_t::~signaler_t ()
+{
+ close (w);
+ close (r);
+}
+
+void zmq::signaler_t::send (const command_t &cmd_)
+{
+ // TODO: Note that send is a blocking operation.
+ // How should we behave if the command cannot be written to the signaler?
+ ssize_t nbytes = ::send (w, &cmd_, sizeof (command_t), 0);
+ errno_assert (nbytes != -1);
+
+ // This should never happen as we've already checked that command size is
+ // less than PIPE_BUF.
+ zmq_assert (nbytes == sizeof (command_t));
+}
+
+bool zmq::signaler_t::recv (command_t *cmd_, bool block_)
+{
+ ssize_t nbytes = ::recv (r, cmd_, sizeof (command_t),
+ block_ ? 0 : MSG_DONTWAIT);
+
+ // If there's no signal available return false.
+ if (nbytes == -1 && errno == EAGAIN)
+ return false;
+
+ errno_assert (nbytes != -1);
+
+ // Check whether we haven't got half of command.
+ zmq_assert (nbytes == sizeof (command_t));
+
+ return true;
+}
+
+#endif
+
+#if defined ZMQ_HAVE_OPENVMS
+
+int zmq::signaler_t::socketpair (int domain_, int type_, int protocol_,
+ int sv_ [2])
+{
+ int listener;
+ sockaddr_in lcladdr;
+ socklen_t lcladdr_len;
+ int rc;
+ int on = 1;
+
+ zmq_assert (type_ == SOCK_STREAM);
+
+ // Fill in the localhost address (127.0.0.1).
+ memset (&lcladdr, 0, sizeof (lcladdr));
+ lcladdr.sin_family = AF_INET;
+ lcladdr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+ lcladdr.sin_port = 0;
+
+ listener = socket (AF_INET, SOCK_STREAM, 0);
+ errno_assert (listener != -1);
+
+ rc = setsockopt (listener, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on));
+ errno_assert (rc != -1);
+
+ rc = setsockopt (listener, IPPROTO_TCP, TCP_NODELACK, &on, sizeof (on));
+ errno_assert (rc != -1);
+
+ rc = bind(listener, (struct sockaddr*) &lcladdr, sizeof (lcladdr));
+ errno_assert (rc != -1);
+
+ lcladdr_len = sizeof (lcladdr);
+
+ rc = getsockname (listener, (struct sockaddr*) &lcladdr, &lcladdr_len);
+ errno_assert (rc != -1);
+
+ rc = listen (listener, 1);
+ errno_assert (rc != -1);
+
+ sv_ [0] = socket (AF_INET, SOCK_STREAM, 0);
+ errno_assert (rc != -1);
+
+ rc = setsockopt (sv_ [0], IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on));
+ errno_assert (rc != -1);
+
+ rc = setsockopt (sv_ [0], IPPROTO_TCP, TCP_NODELACK, &on, sizeof (on));
+ errno_assert (rc != -1);
+
+ rc = connect (sv_ [0], (struct sockaddr*) &lcladdr, sizeof (lcladdr));
+ errno_assert (rc != -1);
+
+ sv_ [1] = accept (listener, NULL, NULL);
+ errno_assert (sv_ [1] != -1);
+
+ close (listener);
+
+ return 0;
+}
+
+#endif
+
diff --git a/src/signaler.hpp b/src/signaler.hpp
new file mode 100644
index 0000000..64a1899
--- /dev/null
+++ b/src/signaler.hpp
@@ -0,0 +1,71 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_SIGNALER_HPP_INCLUDED__
+#define __ZMQ_SIGNALER_HPP_INCLUDED__
+
+#include <stddef.h>
+
+#include "platform.hpp"
+#include "fd.hpp"
+#include "stdint.hpp"
+#include "config.hpp"
+#include "command.hpp"
+
+namespace zmq
+{
+
+ class signaler_t
+ {
+ public:
+
+ signaler_t ();
+ ~signaler_t ();
+
+ fd_t get_fd ();
+ void send (const command_t &cmd_);
+ bool recv (command_t *cmd_, bool block_);
+
+ private:
+
+#if defined ZMQ_HAVE_OPENVMS
+
+ // Whilst OpenVMS supports socketpair - it maps to AF_INET only.
+ // Further, it does not set the socket options TCP_NODELAY and
+ // TCP_NODELACK which can lead to performance problems. We'll
+ // overload the socketpair function for this class.
+ //
+ // The bug will be fixed in V5.6 ECO4 and beyond. In the
+ // meantime, we'll create the socket pair manually.
+ static int socketpair (int domain_, int type_, int protocol_,
+ int sv_ [2]);
+#endif
+
+ // Write & read end of the socketpair.
+ fd_t w;
+ fd_t r;
+
+ // Disable copying of fd_signeler object.
+ signaler_t (const signaler_t&);
+ void operator = (const signaler_t&);
+ };
+
+}
+
+#endif
diff --git a/src/socket_base.cpp b/src/socket_base.cpp
new file mode 100644
index 0000000..eddb297
--- /dev/null
+++ b/src/socket_base.cpp
@@ -0,0 +1,681 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <new>
+#include <string>
+#include <algorithm>
+
+#include "../include/zmq.h"
+
+#include "socket_base.hpp"
+#include "app_thread.hpp"
+
+#include "zmq_listener.hpp"
+#include "zmq_connecter.hpp"
+#include "io_thread.hpp"
+#include "session.hpp"
+#include "config.hpp"
+#include "owned.hpp"
+#include "pipe.hpp"
+#include "err.hpp"
+#include "ctx.hpp"
+#include "platform.hpp"
+#include "pgm_sender.hpp"
+#include "pgm_receiver.hpp"
+#include "likely.hpp"
+
+zmq::socket_base_t::socket_base_t (app_thread_t *parent_) :
+ object_t (parent_),
+ pending_term_acks (0),
+ ticks (0),
+ rcvmore (false),
+ app_thread (parent_),
+ shutting_down (false),
+ sent_seqnum (0),
+ processed_seqnum (0),
+ next_ordinal (1)
+{
+}
+
+zmq::socket_base_t::~socket_base_t ()
+{
+}
+
+int zmq::socket_base_t::setsockopt (int option_, const void *optval_,
+ size_t optvallen_)
+{
+ if (unlikely (app_thread->is_terminated ())) {
+ errno = ETERM;
+ return -1;
+ }
+
+ // First, check whether specific socket type overloads the option.
+ int rc = xsetsockopt (option_, optval_, optvallen_);
+ if (rc == 0 || errno != EINVAL)
+ return rc;
+
+ // If the socket type doesn't support the option, pass it to
+ // the generic option parser.
+ return options.setsockopt (option_, optval_, optvallen_);
+}
+
+int zmq::socket_base_t::getsockopt (int option_, void *optval_,
+ size_t *optvallen_)
+{
+ if (unlikely (app_thread->is_terminated ())) {
+ errno = ETERM;
+ return -1;
+ }
+
+ if (option_ == ZMQ_RCVMORE) {
+ if (*optvallen_ < sizeof (int64_t)) {
+ errno = EINVAL;
+ return -1;
+ }
+ *((int64_t*) optval_) = rcvmore ? 1 : 0;
+ *optvallen_ = sizeof (int64_t);
+ return 0;
+ }
+
+ return options.getsockopt (option_, optval_, optvallen_);
+}
+
+int zmq::socket_base_t::bind (const char *addr_)
+{
+ if (unlikely (app_thread->is_terminated ())) {
+ errno = ETERM;
+ return -1;
+ }
+
+ // Parse addr_ string.
+ std::string addr_type;
+ std::string addr_args;
+
+ std::string addr (addr_);
+ std::string::size_type pos = addr.find ("://");
+
+ if (pos == std::string::npos) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ addr_type = addr.substr (0, pos);
+ addr_args = addr.substr (pos + 3);
+
+ if (addr_type == "inproc")
+ return register_endpoint (addr_args.c_str (), this);
+
+ if (addr_type == "tcp" || addr_type == "ipc") {
+
+#if defined ZMQ_HAVE_WINDOWS || defined ZMQ_HAVE_OPENVMS
+ if (addr_type == "ipc") {
+ errno = EPROTONOSUPPORT;
+ return -1;
+ }
+#endif
+
+ zmq_listener_t *listener = new (std::nothrow) zmq_listener_t (
+ choose_io_thread (options.affinity), this, options);
+ zmq_assert (listener);
+ int rc = listener->set_address (addr_type.c_str(), addr_args.c_str ());
+ if (rc != 0) {
+ delete listener;
+ return -1;
+ }
+
+ send_plug (listener);
+ send_own (this, listener);
+ return 0;
+ }
+
+#if defined ZMQ_HAVE_OPENPGM
+ if (addr_type == "pgm" || addr_type == "epgm") {
+ // In the case of PGM bind behaves the same like connect.
+ return connect (addr_);
+ }
+#endif
+
+ // Unknown protocol.
+ errno = EPROTONOSUPPORT;
+ return -1;
+}
+
+int zmq::socket_base_t::connect (const char *addr_)
+{
+ if (unlikely (app_thread->is_terminated ())) {
+ errno = ETERM;
+ return -1;
+ }
+
+ // Parse addr_ string.
+ std::string addr_type;
+ std::string addr_args;
+
+ std::string addr (addr_);
+ std::string::size_type pos = addr.find ("://");
+
+ if (pos == std::string::npos) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ addr_type = addr.substr (0, pos);
+ addr_args = addr.substr (pos + 3);
+
+ if (addr_type == "inproc") {
+
+ // TODO: inproc connect is specific with respect to creating pipes
+ // as there's no 'reconnect' functionality implemented. Once that
+ // is in place we should follow generic pipe creation algorithm.
+
+ // Find the peer socket.
+ socket_base_t *peer = find_endpoint (addr_args.c_str ());
+ if (!peer)
+ return -1;
+
+ pipe_t *in_pipe = NULL;
+ pipe_t *out_pipe = NULL;
+
+ // Create inbound pipe, if required.
+ if (options.requires_in) {
+ in_pipe = new (std::nothrow) pipe_t (this, peer, options.hwm);
+ zmq_assert (in_pipe);
+ }
+
+ // Create outbound pipe, if required.
+ if (options.requires_out) {
+ out_pipe = new (std::nothrow) pipe_t (peer, this, options.hwm);
+ zmq_assert (out_pipe);
+ }
+
+ // Attach the pipes to this socket object.
+ attach_pipes (in_pipe ? &in_pipe->reader : NULL,
+ out_pipe ? &out_pipe->writer : NULL, blob_t ());
+
+ // Attach the pipes to the peer socket. Note that peer's seqnum
+ // was incremented in find_endpoint function. The callee is notified
+ // about the fact via the last parameter.
+ send_bind (peer, out_pipe ? &out_pipe->reader : NULL,
+ in_pipe ? &in_pipe->writer : NULL, options.identity, false);
+
+ return 0;
+ }
+
+ // Create unnamed session.
+ io_thread_t *io_thread = choose_io_thread (options.affinity);
+ session_t *session = new (std::nothrow) session_t (io_thread,
+ this, options);
+ zmq_assert (session);
+
+ // If 'immediate connect' feature is required, we'll created the pipes
+ // to the session straight away. Otherwise, they'll be created by the
+ // session once the connection is established.
+ if (options.immediate_connect) {
+
+ pipe_t *in_pipe = NULL;
+ pipe_t *out_pipe = NULL;
+
+ // Create inbound pipe, if required.
+ if (options.requires_in) {
+ in_pipe = new (std::nothrow) pipe_t (this, session, options.hwm);
+ zmq_assert (in_pipe);
+
+ }
+
+ // Create outbound pipe, if required.
+ if (options.requires_out) {
+ out_pipe = new (std::nothrow) pipe_t (session, this, options.hwm);
+ zmq_assert (out_pipe);
+ }
+
+ // Attach the pipes to the socket object.
+ attach_pipes (in_pipe ? &in_pipe->reader : NULL,
+ out_pipe ? &out_pipe->writer : NULL, blob_t ());
+
+ // Attach the pipes to the session object.
+ session->attach_pipes (out_pipe ? &out_pipe->reader : NULL,
+ in_pipe ? &in_pipe->writer : NULL, blob_t ());
+ }
+
+ // Activate the session.
+ send_plug (session);
+ send_own (this, session);
+
+ if (addr_type == "tcp" || addr_type == "ipc") {
+
+#if defined ZMQ_HAVE_WINDOWS || defined ZMQ_HAVE_OPENVMS
+ // Windows named pipes are not compatible with Winsock API.
+ // There's no UNIX domain socket implementation on OpenVMS.
+ if (addr_type == "ipc") {
+ errno = EPROTONOSUPPORT;
+ return -1;
+ }
+#endif
+
+ // Create the connecter object. Supply it with the session name
+ // so that it can bind the new connection to the session once
+ // it is established.
+ zmq_connecter_t *connecter = new (std::nothrow) zmq_connecter_t (
+ choose_io_thread (options.affinity), this, options,
+ session->get_ordinal (), false);
+ zmq_assert (connecter);
+ int rc = connecter->set_address (addr_type.c_str(), addr_args.c_str ());
+ if (rc != 0) {
+ delete connecter;
+ return -1;
+ }
+ send_plug (connecter);
+ send_own (this, connecter);
+
+ return 0;
+ }
+
+#if defined ZMQ_HAVE_OPENPGM
+ if (addr_type == "pgm" || addr_type == "epgm") {
+
+ // If the socket type requires bi-directional communication
+ // multicast is not an option (it is uni-directional).
+ if (options.requires_in && options.requires_out) {
+ errno = ENOCOMPATPROTO;
+ return -1;
+ }
+
+ // For epgm, pgm transport with UDP encapsulation is used.
+ bool udp_encapsulation = (addr_type == "epgm");
+
+ // At this point we'll create message pipes to the session straight
+ // away. There's no point in delaying it as no concept of 'connect'
+ // exists with PGM anyway.
+ if (options.requires_out) {
+
+ // PGM sender.
+ pgm_sender_t *pgm_sender = new (std::nothrow) pgm_sender_t (
+ choose_io_thread (options.affinity), options);
+ zmq_assert (pgm_sender);
+
+ int rc = pgm_sender->init (udp_encapsulation, addr_args.c_str ());
+ if (rc != 0) {
+ delete pgm_sender;
+ return -1;
+ }
+
+ send_attach (session, pgm_sender, blob_t ());
+ }
+ else if (options.requires_in) {
+
+ // PGM receiver.
+ pgm_receiver_t *pgm_receiver = new (std::nothrow) pgm_receiver_t (
+ choose_io_thread (options.affinity), options);
+ zmq_assert (pgm_receiver);
+
+ int rc = pgm_receiver->init (udp_encapsulation, addr_args.c_str ());
+ if (rc != 0) {
+ delete pgm_receiver;
+ return -1;
+ }
+
+ send_attach (session, pgm_receiver, blob_t ());
+ }
+ else
+ zmq_assert (false);
+
+ return 0;
+ }
+#endif
+
+ // Unknown protoco.
+ errno = EPROTONOSUPPORT;
+ return -1;
+}
+
+int zmq::socket_base_t::send (::zmq_msg_t *msg_, int flags_)
+{
+ // Process pending commands, if any.
+ if (unlikely (!app_thread->process_commands (false, true))) {
+ errno = ETERM;
+ return -1;
+ }
+
+ // At this point we impose the MORE flag on the message.
+ if (flags_ & ZMQ_SNDMORE)
+ msg_->flags |= ZMQ_MSG_MORE;
+
+ // Try to send the message.
+ int rc = xsend (msg_, flags_);
+ if (rc == 0)
+ return 0;
+
+ // In case of non-blocking send we'll simply propagate
+ // the error - including EAGAIN - upwards.
+ if (flags_ & ZMQ_NOBLOCK)
+ return -1;
+
+ // Oops, we couldn't send the message. Wait for the next
+ // command, process it and try to send the message again.
+ while (rc != 0) {
+ if (errno != EAGAIN)
+ return -1;
+ if (unlikely (!app_thread->process_commands (true, false))) {
+ errno = ETERM;
+ return -1;
+ }
+ rc = xsend (msg_, flags_);
+ }
+ return 0;
+}
+
+int zmq::socket_base_t::recv (::zmq_msg_t *msg_, int flags_)
+{
+ // Get the message.
+ int rc = xrecv (msg_, flags_);
+ int err = errno;
+
+ // Once every inbound_poll_rate messages check for signals and process
+ // incoming commands. This happens only if we are not polling altogether
+ // because there are messages available all the time. If poll occurs,
+ // ticks is set to zero and thus we avoid this code.
+ //
+ // Note that 'recv' uses different command throttling algorithm (the one
+ // described above) from the one used by 'send'. This is because counting
+ // ticks is more efficient than doing rdtsc all the time.
+ if (++ticks == inbound_poll_rate) {
+ if (unlikely (!app_thread->process_commands (false, false))) {
+ errno = ETERM;
+ return -1;
+ }
+ ticks = 0;
+ }
+
+ // If we have the message, return immediately.
+ if (rc == 0) {
+ rcvmore = msg_->flags & ZMQ_MSG_MORE;
+ if (rcvmore)
+ msg_->flags &= ~ZMQ_MSG_MORE;
+ return 0;
+ }
+
+ // If we don't have the message, restore the original cause of the problem.
+ errno = err;
+
+ // If the message cannot be fetched immediately, there are two scenarios.
+ // For non-blocking recv, commands are processed in case there's a revive
+ // command already waiting int a command pipe. If it's not, return EAGAIN.
+ if (flags_ & ZMQ_NOBLOCK) {
+ if (errno != EAGAIN)
+ return -1;
+ if (unlikely (!app_thread->process_commands (false, false))) {
+ errno = ETERM;
+ return -1;
+ }
+ ticks = 0;
+ return xrecv (msg_, flags_);
+ }
+
+ // In blocking scenario, commands are processed over and over again until
+ // we are able to fetch a message.
+ while (rc != 0) {
+ if (errno != EAGAIN)
+ return -1;
+ if (unlikely (!app_thread->process_commands (true, false))) {
+ errno = ETERM;
+ return -1;
+ }
+ rc = xrecv (msg_, flags_);
+ ticks = 0;
+ }
+
+ rcvmore = msg_->flags & ZMQ_MSG_MORE;
+ if (rcvmore)
+ msg_->flags &= ~ZMQ_MSG_MORE;
+ return 0;
+}
+
+int zmq::socket_base_t::close ()
+{
+ shutting_down = true;
+
+ // Let the thread know that the socket is no longer available.
+ app_thread->remove_socket (this);
+
+ // Pointer to the context must be retrieved before the socket is
+ // deallocated. Afterwards it is not available.
+ ctx_t *ctx = get_ctx ();
+
+ // Unregister all inproc endpoints associated with this socket.
+ // From this point we are sure that inc_seqnum won't be called again
+ // on this object.
+ ctx->unregister_endpoints (this);
+
+ // Wait till all undelivered commands are delivered. This should happen
+ // very quickly. There's no way to wait here for extensive period of time.
+ while (processed_seqnum != sent_seqnum.get ())
+ app_thread->process_commands (true, false);
+
+ while (true) {
+
+ // On third pass of the loop there should be no more I/O objects
+ // because all connecters and listerners were destroyed during
+ // the first pass and all engines delivered by delayed 'own' commands
+ // are destroyed during the second pass.
+ if (io_objects.empty () && !pending_term_acks)
+ break;
+
+ // Send termination request to all associated I/O objects.
+ for (io_objects_t::iterator it = io_objects.begin ();
+ it != io_objects.end (); it++)
+ send_term (*it);
+
+ // Move the objects to the list of pending term acks.
+ pending_term_acks += io_objects.size ();
+ io_objects.clear ();
+
+ // Process commands till we get all the termination acknowledgements.
+ while (pending_term_acks)
+ app_thread->process_commands (true, false);
+ }
+
+ // Check whether there are no session leaks.
+ sessions_sync.lock ();
+ zmq_assert (named_sessions.empty ());
+ zmq_assert (unnamed_sessions.empty ());
+ sessions_sync.unlock ();
+
+ delete this;
+
+ // This function must be called after the socket is completely deallocated
+ // as it may cause termination of the whole 0MQ infrastructure.
+ ctx->destroy_socket ();
+
+ return 0;
+}
+
+void zmq::socket_base_t::inc_seqnum ()
+{
+ // NB: This function may be called from a different thread!
+ sent_seqnum.add (1);
+}
+
+zmq::app_thread_t *zmq::socket_base_t::get_thread ()
+{
+ return app_thread;
+}
+
+bool zmq::socket_base_t::has_in ()
+{
+ return xhas_in ();
+}
+
+bool zmq::socket_base_t::has_out ()
+{
+ return xhas_out ();
+}
+
+bool zmq::socket_base_t::register_session (const blob_t &peer_identity_,
+ session_t *session_)
+{
+ sessions_sync.lock ();
+ bool registered = named_sessions.insert (
+ std::make_pair (peer_identity_, session_)).second;
+ sessions_sync.unlock ();
+ return registered;
+}
+
+void zmq::socket_base_t::unregister_session (const blob_t &peer_identity_)
+{
+ sessions_sync.lock ();
+ named_sessions_t::iterator it = named_sessions.find (peer_identity_);
+ zmq_assert (it != named_sessions.end ());
+ named_sessions.erase (it);
+ sessions_sync.unlock ();
+}
+
+zmq::session_t *zmq::socket_base_t::find_session (const blob_t &peer_identity_)
+{
+ sessions_sync.lock ();
+ named_sessions_t::iterator it = named_sessions.find (peer_identity_);
+ if (it == named_sessions.end ()) {
+ sessions_sync.unlock ();
+ return NULL;
+ }
+ session_t *session = it->second;
+
+ // Prepare the session for subsequent attach command.
+ session->inc_seqnum ();
+
+ sessions_sync.unlock ();
+ return session;
+}
+
+uint64_t zmq::socket_base_t::register_session (session_t *session_)
+{
+ sessions_sync.lock ();
+ uint64_t ordinal = next_ordinal;
+ next_ordinal++;
+ unnamed_sessions.insert (std::make_pair (ordinal, session_));
+ sessions_sync.unlock ();
+ return ordinal;
+}
+
+void zmq::socket_base_t::unregister_session (uint64_t ordinal_)
+{
+ sessions_sync.lock ();
+ unnamed_sessions_t::iterator it = unnamed_sessions.find (ordinal_);
+ zmq_assert (it != unnamed_sessions.end ());
+ unnamed_sessions.erase (it);
+ sessions_sync.unlock ();
+}
+
+zmq::session_t *zmq::socket_base_t::find_session (uint64_t ordinal_)
+{
+ sessions_sync.lock ();
+
+ unnamed_sessions_t::iterator it = unnamed_sessions.find (ordinal_);
+ if (it == unnamed_sessions.end ()) {
+ sessions_sync.unlock ();
+ return NULL;
+ }
+ session_t *session = it->second;
+
+ // Prepare the session for subsequent attach command.
+ session->inc_seqnum ();
+
+ sessions_sync.unlock ();
+ return session;
+}
+
+void zmq::socket_base_t::kill (reader_t *pipe_)
+{
+ xkill (pipe_);
+}
+
+void zmq::socket_base_t::revive (reader_t *pipe_)
+{
+ xrevive (pipe_);
+}
+
+void zmq::socket_base_t::revive (writer_t *pipe_)
+{
+ xrevive (pipe_);
+}
+
+void zmq::socket_base_t::attach_pipes (class reader_t *inpipe_,
+ class writer_t *outpipe_, const blob_t &peer_identity_)
+{
+ if (inpipe_)
+ inpipe_->set_endpoint (this);
+ if (outpipe_)
+ outpipe_->set_endpoint (this);
+ xattach_pipes (inpipe_, outpipe_, peer_identity_);
+}
+
+void zmq::socket_base_t::detach_inpipe (class reader_t *pipe_)
+{
+ xdetach_inpipe (pipe_);
+ pipe_->set_endpoint (NULL); // ?
+}
+
+void zmq::socket_base_t::detach_outpipe (class writer_t *pipe_)
+{
+ xdetach_outpipe (pipe_);
+ pipe_->set_endpoint (NULL); // ?
+}
+
+void zmq::socket_base_t::process_own (owned_t *object_)
+{
+ io_objects.insert (object_);
+}
+
+void zmq::socket_base_t::process_bind (reader_t *in_pipe_, writer_t *out_pipe_,
+ const blob_t &peer_identity_)
+{
+ attach_pipes (in_pipe_, out_pipe_, peer_identity_);
+}
+
+void zmq::socket_base_t::process_term_req (owned_t *object_)
+{
+ // When shutting down we can ignore termination requests from owned
+ // objects. They are going to be terminated anyway.
+ if (shutting_down)
+ return;
+
+ // If I/O object is well and alive ask it to terminate.
+ io_objects_t::iterator it = std::find (io_objects.begin (),
+ io_objects.end (), object_);
+
+ // If not found, we assume that termination request was already sent to
+ // the object so we can sagely ignore the request.
+ if (it == io_objects.end ())
+ return;
+
+ pending_term_acks++;
+ io_objects.erase (it);
+ send_term (object_);
+}
+
+void zmq::socket_base_t::process_term_ack ()
+{
+ zmq_assert (pending_term_acks);
+ pending_term_acks--;
+}
+
+void zmq::socket_base_t::process_seqnum ()
+{
+ processed_seqnum++;
+}
+
diff --git a/src/socket_base.hpp b/src/socket_base.hpp
new file mode 100644
index 0000000..3d95cec
--- /dev/null
+++ b/src/socket_base.hpp
@@ -0,0 +1,177 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_SOCKET_BASE_HPP_INCLUDED__
+#define __ZMQ_SOCKET_BASE_HPP_INCLUDED__
+
+#include <set>
+#include <map>
+#include <vector>
+
+#include "../include/zmq.h"
+
+#include "i_endpoint.hpp"
+#include "object.hpp"
+#include "yarray_item.hpp"
+#include "mutex.hpp"
+#include "options.hpp"
+#include "stdint.hpp"
+#include "atomic_counter.hpp"
+#include "stdint.hpp"
+#include "blob.hpp"
+
+namespace zmq
+{
+
+ class socket_base_t :
+ public object_t, public i_endpoint, public yarray_item_t
+ {
+ public:
+
+ socket_base_t (class app_thread_t *parent_);
+
+ // Interface for communication with the API layer.
+ int setsockopt (int option_, const void *optval_, size_t optvallen_);
+ int getsockopt (int option_, void *optval_, size_t *optvallen_);
+ int bind (const char *addr_);
+ int connect (const char *addr_);
+ int send (zmq_msg_t *msg_, int flags_);
+ int recv (zmq_msg_t *msg_, int flags_);
+ int close ();
+
+ // When another owned object wants to send command to this object
+ // it calls this function to let it know it should not shut down
+ // before the command is delivered.
+ void inc_seqnum ();
+
+ // This function is used by the polling mechanism to determine
+ // whether the socket belongs to the application thread the poll
+ // is called from.
+ class app_thread_t *get_thread ();
+
+ // These functions are used by the polling mechanism to determine
+ // which events are to be reported from this socket.
+ bool has_in ();
+ bool has_out ();
+
+ // The list of sessions cannot be accessed via inter-thread
+ // commands as it is unacceptable to wait for the completion of the
+ // action till user application yields control of the application
+ // thread to 0MQ. Locking is used instead.
+ // There are two distinct types of sessions: those identified by name
+ // and those identified by ordinal number. Thus two sets of session
+ // management functions.
+ bool register_session (const blob_t &peer_identity_,
+ class session_t *session_);
+ void unregister_session (const blob_t &peer_identity_);
+ class session_t *find_session (const blob_t &peer_identity_);
+ uint64_t register_session (class session_t *session_);
+ void unregister_session (uint64_t ordinal_);
+ class session_t *find_session (uint64_t ordinal_);
+
+ // i_endpoint interface implementation.
+ void attach_pipes (class reader_t *inpipe_, class writer_t *outpipe_,
+ const blob_t &peer_identity_);
+ void detach_inpipe (class reader_t *pipe_);
+ void detach_outpipe (class writer_t *pipe_);
+ void kill (class reader_t *pipe_);
+ void revive (class reader_t *pipe_);
+ void revive (class writer_t *pipe_);
+
+ protected:
+
+ // Destructor is protected. Socket is closed using 'close' function.
+ virtual ~socket_base_t ();
+
+ // Pipe management is done by individual socket types.
+ virtual void xattach_pipes (class reader_t *inpipe_,
+ class writer_t *outpipe_, const blob_t &peer_identity_) = 0;
+ virtual void xdetach_inpipe (class reader_t *pipe_) = 0;
+ virtual void xdetach_outpipe (class writer_t *pipe_) = 0;
+ virtual void xkill (class reader_t *pipe_) = 0;
+ virtual void xrevive (class reader_t *pipe_) = 0;
+ virtual void xrevive (class writer_t *pipe_) = 0;
+
+ // Actual algorithms are to be defined by individual socket types.
+ virtual int xsetsockopt (int option_, const void *optval_,
+ size_t optvallen_) = 0;
+ virtual int xsend (zmq_msg_t *msg_, int options_) = 0;
+ virtual int xrecv (zmq_msg_t *msg_, int options_) = 0;
+ virtual bool xhas_in () = 0;
+ virtual bool xhas_out () = 0;
+
+ // Socket options.
+ options_t options;
+
+ private:
+
+ // Handlers for incoming commands.
+ void process_own (class owned_t *object_);
+ void process_bind (class reader_t *in_pipe_, class writer_t *out_pipe_,
+ const blob_t &peer_identity_);
+ void process_term_req (class owned_t *object_);
+ void process_term_ack ();
+ void process_seqnum ();
+
+ // List of all I/O objects owned by this socket. The socket is
+ // responsible for deallocating them before it quits.
+ typedef std::set <class owned_t*> io_objects_t;
+ io_objects_t io_objects;
+
+ // Number of I/O objects that were already asked to terminate
+ // but haven't acknowledged it yet.
+ int pending_term_acks;
+
+ // Number of messages received since last command processing.
+ int ticks;
+
+ // If true there's a half-read message in the socket.
+ bool rcvmore;
+
+ // Application thread the socket lives in.
+ class app_thread_t *app_thread;
+
+ // If true, socket is already shutting down. No new work should be
+ // started.
+ bool shutting_down;
+
+ // Sequence number of the last command sent to this object.
+ atomic_counter_t sent_seqnum;
+
+ // Sequence number of the last command processed by this object.
+ uint64_t processed_seqnum;
+
+ // Lists of existing sessions. This lists are never referenced from
+ // within the socket, instead they are used by I/O objects owned by
+ // the socket. As those objects can live in different threads,
+ // the access is synchronised by mutex.
+ typedef std::map <blob_t, session_t*> named_sessions_t;
+ named_sessions_t named_sessions;
+ typedef std::map <uint64_t, session_t*> unnamed_sessions_t;
+ unnamed_sessions_t unnamed_sessions;
+ uint64_t next_ordinal;
+ mutex_t sessions_sync;
+
+ socket_base_t (const socket_base_t&);
+ void operator = (const socket_base_t&);
+ };
+
+}
+
+#endif
diff --git a/src/stdint.hpp b/src/stdint.hpp
new file mode 100644
index 0000000..fe1bff6
--- /dev/null
+++ b/src/stdint.hpp
@@ -0,0 +1,70 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_STDINT_HPP_INCLUDED__
+#define __ZMQ_STDINT_HPP_INCLUDED__
+
+#include "platform.hpp"
+
+#ifdef ZMQ_HAVE_SOLARIS
+
+#include <inttypes.h>
+
+#elif defined _MSC_VER
+
+#ifndef int8_t
+typedef __int8 int8_t;
+#endif
+#ifndef int16_t
+typedef __int16 int16_t;
+#endif
+#ifndef int32_t
+typedef __int32 int32_t;
+#endif
+#ifndef int64_t
+typedef __int64 int64_t;
+#endif
+#ifndef uint8_t
+typedef unsigned __int8 uint8_t;
+#endif
+#ifndef uint16_t
+typedef unsigned __int16 uint16_t;
+#endif
+#ifndef uint32_t
+typedef unsigned __int32 uint32_t;
+#endif
+#ifndef uint64_t
+typedef unsigned __int64 uint64_t;
+#endif
+
+#elif defined ZMQ_HAVE_OPENVMS
+
+#include <types.h>
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+
+#else
+
+#include <stdint.h>
+
+#endif
+
+#endif
diff --git a/src/streamer.cpp b/src/streamer.cpp
new file mode 100644
index 0000000..796771b
--- /dev/null
+++ b/src/streamer.cpp
@@ -0,0 +1,38 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "../include/zmq.h"
+
+#include "streamer.hpp"
+#include "socket_base.hpp"
+#include "err.hpp"
+
+int zmq::streamer (socket_base_t *insocket_, socket_base_t *outsocket_)
+{
+ zmq_msg_t msg;
+ int rc = zmq_msg_init (&msg);
+ errno_assert (rc == 0);
+
+ while (true) {
+ insocket_->recv (&msg, 0);
+ outsocket_->send (&msg, 0);
+ }
+
+ return 0;
+}
diff --git a/src/streamer.hpp b/src/streamer.hpp
new file mode 100644
index 0000000..8827cff
--- /dev/null
+++ b/src/streamer.hpp
@@ -0,0 +1,31 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_STREAMER_HPP_INCLUDED__
+#define __ZMQ_STREAMER_HPP_INCLUDED__
+
+namespace zmq
+{
+
+ int streamer (class socket_base_t *insocket_,
+ class socket_base_t *outsocket_);
+
+}
+
+#endif
diff --git a/src/sub.cpp b/src/sub.cpp
new file mode 100644
index 0000000..eeb50cd
--- /dev/null
+++ b/src/sub.cpp
@@ -0,0 +1,191 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <string.h>
+
+#include "../include/zmq.h"
+
+#include "sub.hpp"
+#include "err.hpp"
+
+zmq::sub_t::sub_t (class app_thread_t *parent_) :
+ socket_base_t (parent_),
+ has_message (false),
+ more (false)
+{
+ options.requires_in = true;
+ options.requires_out = false;
+ zmq_msg_init (&message);
+}
+
+zmq::sub_t::~sub_t ()
+{
+ zmq_msg_close (&message);
+}
+
+void zmq::sub_t::xattach_pipes (class reader_t *inpipe_,
+ class writer_t *outpipe_, const blob_t &peer_identity_)
+{
+ zmq_assert (inpipe_ && !outpipe_);
+ fq.attach (inpipe_);
+}
+
+void zmq::sub_t::xdetach_inpipe (class reader_t *pipe_)
+{
+ zmq_assert (pipe_);
+ fq.detach (pipe_);
+}
+
+void zmq::sub_t::xdetach_outpipe (class writer_t *pipe_)
+{
+ // SUB socket is read-only thus there should be no outpipes.
+ zmq_assert (false);
+}
+
+void zmq::sub_t::xkill (class reader_t *pipe_)
+{
+ fq.kill (pipe_);
+}
+
+void zmq::sub_t::xrevive (class reader_t *pipe_)
+{
+ fq.revive (pipe_);
+}
+
+void zmq::sub_t::xrevive (class writer_t *pipe_)
+{
+ zmq_assert (false);
+}
+
+int zmq::sub_t::xsetsockopt (int option_, const void *optval_,
+ size_t optvallen_)
+{
+ if (option_ == ZMQ_SUBSCRIBE) {
+ subscriptions.add ((unsigned char*) optval_, optvallen_);
+ return 0;
+ }
+
+ if (option_ == ZMQ_UNSUBSCRIBE) {
+ if (!subscriptions.rm ((unsigned char*) optval_, optvallen_)) {
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+ }
+
+ errno = EINVAL;
+ return -1;
+}
+
+int zmq::sub_t::xsend (zmq_msg_t *msg_, int flags_)
+{
+ errno = ENOTSUP;
+ return -1;
+}
+
+int zmq::sub_t::xrecv (zmq_msg_t *msg_, int flags_)
+{
+ // If there's already a message prepared by a previous call to zmq_poll,
+ // return it straight ahead.
+ if (has_message) {
+ zmq_msg_move (msg_, &message);
+ has_message = false;
+ more = msg_->flags & ZMQ_MSG_MORE;
+ return 0;
+ }
+
+ // TODO: This can result in infinite loop in the case of continuous
+ // stream of non-matching messages which breaks the non-blocking recv
+ // semantics.
+ while (true) {
+
+ // Get a message using fair queueing algorithm.
+ int rc = fq.recv (msg_, flags_);
+
+ // If there's no message available, return immediately.
+ // The same when error occurs.
+ if (rc != 0)
+ return -1;
+
+ // Check whether the message matches at least one subscription.
+ // Non-initial parts of the message are passed
+ if (more || match (msg_)) {
+ more = msg_->flags & ZMQ_MSG_MORE;
+ return 0;
+ }
+
+ // Message doesn't match. Pop any remaining parts of the message
+ // from the pipe.
+ while (msg_->flags & ZMQ_MSG_MORE) {
+ rc = fq.recv (msg_, ZMQ_NOBLOCK);
+ zmq_assert (rc == 0);
+ }
+ }
+}
+
+bool zmq::sub_t::xhas_in ()
+{
+ // There are subsequent parts of the partly-read message available.
+ if (more)
+ return true;
+
+ // If there's already a message prepared by a previous call to zmq_poll,
+ // return straight ahead.
+ if (has_message)
+ return true;
+
+ // TODO: This can result in infinite loop in the case of continuous
+ // stream of non-matching messages.
+ while (true) {
+
+ // Get a message using fair queueing algorithm.
+ int rc = fq.recv (&message, ZMQ_NOBLOCK);
+
+ // If there's no message available, return immediately.
+ // The same when error occurs.
+ if (rc != 0) {
+ zmq_assert (errno == EAGAIN);
+ return false;
+ }
+
+ // Check whether the message matches at least one subscription.
+ if (match (&message)) {
+ has_message = true;
+ return true;
+ }
+
+ // Message doesn't match. Pop any remaining parts of the message
+ // from the pipe.
+ while (message.flags & ZMQ_MSG_MORE) {
+ rc = fq.recv (&message, ZMQ_NOBLOCK);
+ zmq_assert (rc == 0);
+ }
+ }
+}
+
+bool zmq::sub_t::xhas_out ()
+{
+ return false;
+}
+
+bool zmq::sub_t::match (zmq_msg_t *msg_)
+{
+ return subscriptions.check ((unsigned char*) zmq_msg_data (msg_),
+ zmq_msg_size (msg_));
+}
diff --git a/src/sub.hpp b/src/sub.hpp
new file mode 100644
index 0000000..7b997c9
--- /dev/null
+++ b/src/sub.hpp
@@ -0,0 +1,81 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_SUB_HPP_INCLUDED__
+#define __ZMQ_SUB_HPP_INCLUDED__
+
+#include "../include/zmq.h"
+
+#include "prefix_tree.hpp"
+#include "socket_base.hpp"
+#include "fq.hpp"
+
+namespace zmq
+{
+
+ class sub_t : public socket_base_t
+ {
+ public:
+
+ sub_t (class app_thread_t *parent_);
+ ~sub_t ();
+
+ protected:
+
+ // Overloads of functions from socket_base_t.
+ void xattach_pipes (class reader_t *inpipe_, class writer_t *outpipe_,
+ const blob_t &peer_identity_);
+ void xdetach_inpipe (class reader_t *pipe_);
+ void xdetach_outpipe (class writer_t *pipe_);
+ void xkill (class reader_t *pipe_);
+ void xrevive (class reader_t *pipe_);
+ void xrevive (class writer_t *pipe_);
+ int xsetsockopt (int option_, const void *optval_, size_t optvallen_);
+ int xsend (zmq_msg_t *msg_, int flags_);
+ int xrecv (zmq_msg_t *msg_, int flags_);
+ bool xhas_in ();
+ bool xhas_out ();
+
+ private:
+
+ // Check whether the message matches at least one subscription.
+ bool match (zmq_msg_t *msg_);
+
+ // Fair queueing object for inbound pipes.
+ fq_t fq;
+
+ // The repository of subscriptions.
+ prefix_tree_t subscriptions;
+
+ // If true, 'message' contains a matching message to return on the
+ // next recv call.
+ bool has_message;
+ zmq_msg_t message;
+
+ // If true, part of a multipart message was already received, but
+ // there are following parts still waiting.
+ bool more;
+
+ sub_t (const sub_t&);
+ void operator = (const sub_t&);
+ };
+
+}
+
+#endif
diff --git a/src/tcp_connecter.cpp b/src/tcp_connecter.cpp
new file mode 100644
index 0000000..17c0257
--- /dev/null
+++ b/src/tcp_connecter.cpp
@@ -0,0 +1,307 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <string.h>
+
+#include <string>
+
+#include "../include/zmq.h"
+
+#include "tcp_connecter.hpp"
+#include "platform.hpp"
+#include "ip.hpp"
+#include "err.hpp"
+
+#ifdef ZMQ_HAVE_WINDOWS
+
+zmq::tcp_connecter_t::tcp_connecter_t () :
+ s (retired_fd)
+{
+ memset (&addr, 0, sizeof (addr));
+ addr_len = 0;
+}
+
+zmq::tcp_connecter_t::~tcp_connecter_t ()
+{
+ if (s != retired_fd)
+ close ();
+}
+
+int zmq::tcp_connecter_t::set_address (const char *protocol_, const char *addr_)
+{
+ if (strcmp (protocol_, "tcp") == 0)
+ return resolve_ip_hostname (&addr, &addr_len, addr_);
+
+ errno = EPROTONOSUPPORT;
+ return -1;
+}
+
+int zmq::tcp_connecter_t::open ()
+{
+ zmq_assert (s == retired_fd);
+
+ // Create the socket.
+ s = socket (addr.ss_family, SOCK_STREAM, IPPROTO_TCP);
+ if (s == INVALID_SOCKET) {
+ wsa_error_to_errno ();
+ return -1;
+ }
+
+ // Set to non-blocking mode.
+ unsigned long argp = 1;
+ int rc = ioctlsocket (s, FIONBIO, &argp);
+ wsa_assert (rc != SOCKET_ERROR);
+
+ // Disable Nagle's algorithm.
+ int flag = 1;
+ rc = setsockopt (s, IPPROTO_TCP, TCP_NODELAY, (char*) &flag,
+ sizeof (int));
+ wsa_assert (rc != SOCKET_ERROR);
+
+ // Connect to the remote peer.
+ rc = ::connect (s, (sockaddr*) &addr, addr_len);
+
+ // Connect was successfull immediately.
+ if (rc == 0)
+ return 0;
+
+ // Asynchronous connect was launched.
+ if (rc == SOCKET_ERROR && (WSAGetLastError () == WSAEINPROGRESS ||
+ WSAGetLastError () == WSAEWOULDBLOCK)) {
+ errno = EAGAIN;
+ return -1;
+ }
+
+ wsa_error_to_errno ();
+ return -1;
+}
+
+int zmq::tcp_connecter_t::close ()
+{
+ zmq_assert (s != retired_fd);
+ int rc = closesocket (s);
+ wsa_assert (rc != SOCKET_ERROR);
+ s = retired_fd;
+ return 0;
+}
+
+zmq::fd_t zmq::tcp_connecter_t::get_fd ()
+{
+ return s;
+}
+
+zmq::fd_t zmq::tcp_connecter_t::connect ()
+{
+ // Nonblocking connect have finished. Check whether an error occured.
+ int err = 0;
+ socklen_t len = sizeof err;
+ int rc = getsockopt (s, SOL_SOCKET, SO_ERROR, (char*) &err, &len);
+ zmq_assert (rc == 0);
+ if (err != 0) {
+
+ // Assert that the error was caused by the networking problems
+ // rather than 0MQ bug.
+ zmq_assert (err == WSAECONNREFUSED || err == WSAETIMEDOUT ||
+ err == WSAECONNABORTED);
+
+ errno = err;
+ return retired_fd;
+ }
+
+ // Return the newly connected socket.
+ fd_t result = s;
+ s = retired_fd;
+ return result;
+}
+
+#else
+
+#include <unistd.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/tcp.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <fcntl.h>
+
+#ifdef ZMQ_HAVE_OPENVMS
+#include <ioctl.h>
+#endif
+
+zmq::tcp_connecter_t::tcp_connecter_t () :
+ s (retired_fd)
+{
+ memset (&addr, 0, sizeof (addr));
+}
+
+zmq::tcp_connecter_t::~tcp_connecter_t ()
+{
+ if (s != retired_fd)
+ close ();
+}
+
+int zmq::tcp_connecter_t::set_address (const char *protocol_, const char *addr_)
+{
+ if (strcmp (protocol_, "tcp") == 0)
+ return resolve_ip_hostname (&addr, &addr_len, addr_);
+ else if (strcmp (protocol_, "ipc") == 0)
+ return resolve_local_path (&addr, &addr_len, addr_);
+
+ errno = EPROTONOSUPPORT;
+ return -1;
+}
+
+int zmq::tcp_connecter_t::open ()
+{
+ zmq_assert (s == retired_fd);
+ struct sockaddr *sa = (struct sockaddr*) &addr;
+
+ if (AF_UNIX != sa->sa_family) {
+
+ // Create the socket.
+ s = socket (sa->sa_family, SOCK_STREAM, IPPROTO_TCP);
+ if (s == -1)
+ return -1;
+
+ // Set to non-blocking mode.
+#ifdef ZMQ_HAVE_OPENVMS
+ int flags = 1;
+ int rc = ioctl (s, FIONBIO, &flags);
+ errno_assert (rc != -1);
+#else
+ int flags = fcntl (s, F_GETFL, 0);
+ if (flags == -1)
+ flags = 0;
+ int rc = fcntl (s, F_SETFL, flags | O_NONBLOCK);
+ errno_assert (rc != -1);
+#endif
+
+ // Disable Nagle's algorithm.
+ int flag = 1;
+ rc = setsockopt (s, IPPROTO_TCP, TCP_NODELAY, (char*) &flag,
+ sizeof (int));
+ errno_assert (rc == 0);
+
+#ifdef ZMQ_HAVE_OPENVMS
+ // Disable delayed acknowledgements.
+ flag = 1;
+ rc = setsockopt (s, IPPROTO_TCP, TCP_NODELACK, (char*) &flag,
+ sizeof (int));
+ errno_assert (rc != SOCKET_ERROR);
+#endif
+
+ // Connect to the remote peer.
+ rc = ::connect (s, (struct sockaddr*) &addr, addr_len);
+
+ // Connect was successfull immediately.
+ if (rc == 0)
+ return 0;
+
+ // Asynchronous connect was launched.
+ if (rc == -1 && errno == EINPROGRESS) {
+ errno = EAGAIN;
+ return -1;
+ }
+
+ // Error occured.
+ int err = errno;
+ close ();
+ errno = err;
+ return -1;
+ }
+
+#ifndef ZMQ_HAVE_OPENVMS
+ else {
+
+ // Create the socket.
+ zmq_assert (AF_UNIX == sa->sa_family);
+ s = socket (AF_UNIX, SOCK_STREAM, 0);
+ if (s == -1)
+ return -1;
+
+ // Set the non-blocking flag.
+ int flag = fcntl (s, F_GETFL, 0);
+ if (flag == -1)
+ flag = 0;
+ int rc = fcntl (s, F_SETFL, flag | O_NONBLOCK);
+ errno_assert (rc != -1);
+
+ // Connect to the remote peer.
+ rc = ::connect (s, (struct sockaddr*) &addr, sizeof (sockaddr_un));
+
+ // Connect was successfull immediately.
+ if (rc == 0)
+ return 0;
+
+ // Error occured.
+ int err = errno;
+ close ();
+ errno = err;
+ return -1;
+ }
+#endif
+
+ zmq_assert (false);
+ return -1;
+}
+
+int zmq::tcp_connecter_t::close ()
+{
+ zmq_assert (s != retired_fd);
+ int rc = ::close (s);
+ if (rc != 0)
+ return -1;
+ s = retired_fd;
+ return 0;
+}
+
+zmq::fd_t zmq::tcp_connecter_t::get_fd ()
+{
+ return s;
+}
+
+zmq::fd_t zmq::tcp_connecter_t::connect ()
+{
+ // Following code should handle both Berkeley-derived socket
+ // implementations and Solaris.
+ int err = 0;
+#if defined ZMQ_HAVE_HPUX
+ int len = sizeof (err);
+#else
+ socklen_t len = sizeof (err);
+#endif
+ int rc = getsockopt (s, SOL_SOCKET, SO_ERROR, (char*) &err, &len);
+ if (rc == -1)
+ err = errno;
+ if (err != 0) {
+
+ // Assert that the error was caused by the networking problems
+ // rather than 0MQ bug.
+ zmq_assert (err == ECONNREFUSED || err == ETIMEDOUT);
+
+ errno = err;
+ return retired_fd;
+ }
+
+ fd_t result = s;
+ s = retired_fd;
+ return result;
+}
+
+#endif
diff --git a/src/tcp_connecter.hpp b/src/tcp_connecter.hpp
new file mode 100644
index 0000000..f1a124f
--- /dev/null
+++ b/src/tcp_connecter.hpp
@@ -0,0 +1,80 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_TCP_CONNECTER_HPP_INCLUDED__
+#define __ZMQ_TCP_CONNECTER_HPP_INCLUDED__
+
+#include "platform.hpp"
+#include "fd.hpp"
+
+#ifdef ZMQ_HAVE_WINDOWS
+#include "windows.hpp"
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif
+
+namespace zmq
+{
+
+ // The class encapsulating simple TCP listening socket.
+
+ class tcp_connecter_t
+ {
+ public:
+
+ tcp_connecter_t ();
+ ~tcp_connecter_t ();
+
+ // Set address to connect to.
+ int set_address (const char *protocol, const char *addr_);
+
+ // Open TCP connecting socket. Address is in
+ // <hostname>:<port-number> format. Returns -1 in case of error,
+ // 0 if connect was successfull immediately and 1 if async connect
+ // was launched.
+ int open ();
+
+ // Close the connecting socket.
+ int close ();
+
+ // Get the file descriptor to poll on to get notified about
+ // connection success.
+ fd_t get_fd ();
+
+ // Get the file descriptor of newly created connection. Returns
+ // retired_fd if the connection was unsuccessfull.
+ fd_t connect ();
+
+ private:
+
+ // Address to connect to.
+ sockaddr_storage addr;
+ socklen_t addr_len;
+
+ // Underlying socket.
+ fd_t s;
+
+ tcp_connecter_t (const tcp_connecter_t&);
+ void operator = (const tcp_connecter_t&);
+ };
+
+}
+
+#endif
diff --git a/src/tcp_listener.cpp b/src/tcp_listener.cpp
new file mode 100644
index 0000000..0cb9a6e
--- /dev/null
+++ b/src/tcp_listener.cpp
@@ -0,0 +1,352 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <string.h>
+
+#include "../include/zmq.h"
+
+#include "tcp_listener.hpp"
+#include "platform.hpp"
+#include "ip.hpp"
+#include "config.hpp"
+#include "err.hpp"
+
+#ifdef ZMQ_HAVE_WINDOWS
+
+zmq::tcp_listener_t::tcp_listener_t () :
+ s (retired_fd)
+{
+ memset (&addr, 0, sizeof (addr));
+ addr_len = 0;
+}
+
+zmq::tcp_listener_t::~tcp_listener_t ()
+{
+ if (s != retired_fd)
+ close ();
+}
+
+int zmq::tcp_listener_t::set_address (const char *protocol_, const char *addr_)
+{
+ // IPC protocol is not supported on Windows platform.
+ if (strcmp (protocol_, "tcp") != 0 ) {
+ errno = EPROTONOSUPPORT;
+ return -1;
+ }
+
+ // Convert the interface into sockaddr_in structure.
+ int rc = resolve_ip_interface (&addr, &addr_len, addr_);
+ if (rc != 0)
+ return rc;
+
+ // Create a listening socket.
+ s = socket (addr.ss_family, SOCK_STREAM, IPPROTO_TCP);
+ if (s == INVALID_SOCKET) {
+ wsa_error_to_errno ();
+ return -1;
+ }
+
+ // Allow reusing of the address.
+ int flag = 1;
+ rc = setsockopt (s, SOL_SOCKET, SO_REUSEADDR,
+ (const char*) &flag, sizeof (int));
+ wsa_assert (rc != SOCKET_ERROR);
+
+ // Set the non-blocking flag.
+ u_long uflag = 1;
+ rc = ioctlsocket (s, FIONBIO, &uflag);
+ wsa_assert (rc != SOCKET_ERROR);
+
+ // Bind the socket to the network interface and port.
+ rc = bind (s, (struct sockaddr*) &addr, addr_len);
+ if (rc == SOCKET_ERROR) {
+ wsa_error_to_errno ();
+ return -1;
+ }
+
+ // Listen for incomming connections.
+ rc = listen (s, 1);
+ if (rc == SOCKET_ERROR) {
+ wsa_error_to_errno ();
+ return -1;
+ }
+
+ return 0;
+}
+
+int zmq::tcp_listener_t::close ()
+{
+ zmq_assert (s != retired_fd);
+ int rc = closesocket (s);
+ wsa_assert (rc != SOCKET_ERROR);
+ s = retired_fd;
+ return 0;
+}
+
+zmq::fd_t zmq::tcp_listener_t::get_fd ()
+{
+ return s;
+}
+
+zmq::fd_t zmq::tcp_listener_t::accept ()
+{
+ zmq_assert (s != retired_fd);
+
+ // Accept one incoming connection.
+ fd_t sock = ::accept (s, NULL, NULL);
+ if (sock == INVALID_SOCKET &&
+ (WSAGetLastError () == WSAEWOULDBLOCK ||
+ WSAGetLastError () == WSAECONNRESET))
+ return retired_fd;
+
+ zmq_assert (sock != INVALID_SOCKET);
+
+ // Set to non-blocking mode.
+ unsigned long argp = 1;
+ int rc = ioctlsocket (sock, FIONBIO, &argp);
+ wsa_assert (rc != SOCKET_ERROR);
+
+ // Disable Nagle's algorithm.
+ int flag = 1;
+ rc = setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, (char*) &flag,
+ sizeof (int));
+ wsa_assert (rc != SOCKET_ERROR);
+
+ return sock;
+}
+
+#else
+
+#include <unistd.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/tcp.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <fcntl.h>
+
+#ifndef ZMQ_HAVE_OPENVMS
+#include <sys/un.h>
+#endif
+
+#ifdef ZMQ_HAVE_OPENVMS
+#include <ioctl.h>
+#endif
+
+zmq::tcp_listener_t::tcp_listener_t () :
+ s (retired_fd)
+{
+ memset (&addr, 0, sizeof (addr));
+}
+
+zmq::tcp_listener_t::~tcp_listener_t ()
+{
+ if (s != retired_fd)
+ close ();
+}
+
+int zmq::tcp_listener_t::set_address (const char *protocol_, const char *addr_)
+{
+ if (strcmp (protocol_, "tcp") == 0 ) {
+
+ // Resolve the sockaddr to bind to.
+ int rc = resolve_ip_interface (&addr, &addr_len, addr_);
+ if (rc != 0)
+ return -1;
+
+ // Create a listening socket.
+ s = socket (addr.ss_family, SOCK_STREAM, IPPROTO_TCP);
+ if (s == -1)
+ return -1;
+
+ // Allow reusing of the address.
+ int flag = 1;
+ rc = setsockopt (s, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof (int));
+ errno_assert (rc == 0);
+
+ // Set the non-blocking flag.
+#ifdef ZMQ_HAVE_OPENVMS
+ flag = 1;
+ rc = ioctl (s, FIONBIO, &flag);
+ errno_assert (rc != -1);
+#else
+ flag = fcntl (s, F_GETFL, 0);
+ if (flag == -1)
+ flag = 0;
+ rc = fcntl (s, F_SETFL, flag | O_NONBLOCK);
+ errno_assert (rc != -1);
+#endif
+
+ // Bind the socket to the network interface and port.
+ rc = bind (s, (struct sockaddr*) &addr, addr_len);
+ if (rc != 0) {
+ close ();
+ return -1;
+ }
+
+ // Listen for incomming connections.
+ rc = listen (s, tcp_connection_backlog);
+ if (rc != 0) {
+ close ();
+ return -1;
+ }
+
+ return 0;
+ }
+#ifndef ZMQ_HAVE_OPENVMS
+ else if (strcmp (protocol_, "ipc") == 0) {
+
+ // Get rid of the file associated with the UNIX domain socket that
+ // may have been left behind by the previous run of the application.
+ ::unlink (addr_);
+
+ // Convert the address into sockaddr_un structure.
+ int rc = resolve_local_path (&addr, &addr_len, addr_);
+ if (rc != 0)
+ return -1;
+
+ // Create a listening socket.
+ s = socket (AF_UNIX, SOCK_STREAM, 0);
+ if (s == -1)
+ return -1;
+
+ // Set the non-blocking flag.
+ int flag = fcntl (s, F_GETFL, 0);
+ if (flag == -1)
+ flag = 0;
+ rc = fcntl (s, F_SETFL, flag | O_NONBLOCK);
+ errno_assert (rc != -1);
+
+ // Bind the socket to the file path.
+ rc = bind (s, (struct sockaddr*) &addr, sizeof (sockaddr_un));
+ if (rc != 0) {
+ close ();
+ return -1;
+ }
+
+ // Listen for incomming connections.
+ rc = listen (s, tcp_connection_backlog);
+ if (rc != 0) {
+ close ();
+ return -1;
+ }
+
+ return 0;
+ }
+#endif
+ else {
+ errno = EPROTONOSUPPORT;
+ return -1;
+ }
+}
+
+int zmq::tcp_listener_t::close ()
+{
+ zmq_assert (s != retired_fd);
+ int rc = ::close (s);
+ if (rc != 0)
+ return -1;
+ s = retired_fd;
+
+#ifndef ZMQ_HAVE_OPENVMS
+ // If there's an underlying UNIX domain socket, get rid of the file it
+ // is associated with.
+ struct sockaddr_un *su = (struct sockaddr_un*) &addr;
+ if (AF_UNIX == su->sun_family) {
+ rc = ::unlink(su->sun_path);
+ if (rc != 0)
+ return -1;
+ }
+#endif
+
+ return 0;
+}
+
+zmq::fd_t zmq::tcp_listener_t::get_fd ()
+{
+ return s;
+}
+
+zmq::fd_t zmq::tcp_listener_t::accept ()
+{
+ zmq_assert (s != retired_fd);
+
+ // Accept one incoming connection.
+ fd_t sock = ::accept (s, NULL, NULL);
+
+#if (defined ZMQ_HAVE_LINUX || defined ZMQ_HAVE_FREEBSD || \
+ defined ZMQ_HAVE_OPENBSD || defined ZMQ_HAVE_OSX || \
+ defined ZMQ_HAVE_OPENVMS || defined ZMQ_HAVE_NETBSD)
+ if (sock == -1 &&
+ (errno == EAGAIN || errno == EWOULDBLOCK ||
+ errno == EINTR || errno == ECONNABORTED))
+ return retired_fd;
+#elif (defined ZMQ_HAVE_SOLARIS || defined ZMQ_HAVE_AIX)
+ if (sock == -1 &&
+ (errno == EWOULDBLOCK || errno == EINTR ||
+ errno == ECONNABORTED || errno == EPROTO))
+ return retired_fd;
+#elif defined ZMQ_HAVE_HPUX
+ if (sock == -1 &&
+ (errno == EAGAIN || errno == EWOULDBLOCK ||
+ errno == EINTR || errno == ECONNABORTED || errno == ENOBUFS))
+ return retired_fd;
+#elif defined ZMQ_HAVE_QNXNTO
+ if (sock == -1 &&
+ (errno == EWOULDBLOCK || errno == EINTR || errno == ECONNABORTED))
+ return retired_fd;
+#endif
+
+ errno_assert (sock != -1);
+
+ // Set to non-blocking mode.
+#ifdef ZMQ_HAVE_OPENVMS
+ int flags = 1;
+ int rc = ioctl (sock, FIONBIO, &flags);
+ errno_assert (rc != -1);
+#else
+ int flags = fcntl (s, F_GETFL, 0);
+ if (flags == -1)
+ flags = 0;
+ int rc = fcntl (sock, F_SETFL, flags | O_NONBLOCK);
+ errno_assert (rc != -1);
+#endif
+
+ struct sockaddr *sa = (struct sockaddr*) &addr;
+ if (AF_UNIX != sa->sa_family) {
+
+ // Disable Nagle's algorithm.
+ int flag = 1;
+ rc = setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, (char*) &flag,
+ sizeof (int));
+ errno_assert (rc == 0);
+
+#ifdef ZMQ_HAVE_OPENVMS
+ // Disable delayed acknowledgements.
+ flag = 1;
+ rc = setsockopt (sock, IPPROTO_TCP, TCP_NODELACK, (char*) &flag,
+ sizeof (int));
+ errno_assert (rc != SOCKET_ERROR);
+#endif
+ }
+
+ return sock;
+}
+
+#endif
diff --git a/src/tcp_listener.hpp b/src/tcp_listener.hpp
new file mode 100644
index 0000000..3b60719
--- /dev/null
+++ b/src/tcp_listener.hpp
@@ -0,0 +1,68 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_TCP_LISTENER_HPP_INCLUDED__
+#define __ZMQ_TCP_LISTENER_HPP_INCLUDED__
+
+#include "fd.hpp"
+#include "ip.hpp"
+
+namespace zmq
+{
+
+ // The class encapsulating simple TCP listening socket.
+
+ class tcp_listener_t
+ {
+ public:
+
+ tcp_listener_t ();
+ ~tcp_listener_t ();
+
+ // Start listening on the interface.
+ int set_address (const char *protocol_, const char *addr_);
+
+ // Close the listening socket.
+ int close ();
+
+ // Get the file descriptor to poll on to get notified about
+ // newly created connections.
+ fd_t get_fd ();
+
+ // Accept the new connection. Returns the file descriptor of the
+ // newly created connection. The function may return retired_fd
+ // if the connection was dropped while waiting in the listen backlog.
+ fd_t accept ();
+
+ private:
+
+ // Address to listen on.
+ sockaddr_storage addr;
+ socklen_t addr_len;
+
+ // Underlying socket.
+ fd_t s;
+
+ tcp_listener_t (const tcp_listener_t&);
+ void operator = (const tcp_listener_t&);
+ };
+
+}
+
+#endif
diff --git a/src/tcp_socket.cpp b/src/tcp_socket.cpp
new file mode 100644
index 0000000..cc426d7
--- /dev/null
+++ b/src/tcp_socket.cpp
@@ -0,0 +1,226 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "tcp_socket.hpp"
+#include "platform.hpp"
+#include "err.hpp"
+
+#ifdef ZMQ_HAVE_WINDOWS
+
+zmq::tcp_socket_t::tcp_socket_t () :
+ s (retired_fd)
+{
+}
+
+zmq::tcp_socket_t::~tcp_socket_t ()
+{
+ if (s != retired_fd)
+ close ();
+}
+
+int zmq::tcp_socket_t::open (fd_t fd_, uint64_t sndbuf_, uint64_t rcvbuf_)
+{
+ zmq_assert (s == retired_fd);
+ s = fd_;
+
+ if (sndbuf_) {
+ int sz = (int) sndbuf_;
+ int rc = setsockopt (s, SOL_SOCKET, SO_SNDBUF,
+ (char*) &sz, sizeof (int));
+ errno_assert (rc == 0);
+ }
+
+ if (rcvbuf_) {
+ int sz = (int) rcvbuf_;
+ int rc = setsockopt (s, SOL_SOCKET, SO_RCVBUF,
+ (char*) &sz, sizeof (int));
+ errno_assert (rc == 0);
+ }
+
+ return 0;
+}
+
+int zmq::tcp_socket_t::close ()
+{
+ zmq_assert (s != retired_fd);
+ int rc = closesocket (s);
+ wsa_assert (rc != SOCKET_ERROR);
+ s = retired_fd;
+ return 0;
+}
+
+zmq::fd_t zmq::tcp_socket_t::get_fd ()
+{
+ return s;
+}
+
+int zmq::tcp_socket_t::write (const void *data, int size)
+{
+ int nbytes = send (s, (char*) data, size, 0);
+
+ // If not a single byte can be written to the socket in non-blocking mode
+ // we'll get an error (this may happen during the speculative write).
+ if (nbytes == SOCKET_ERROR && WSAGetLastError () == WSAEWOULDBLOCK)
+ return 0;
+
+ // Signalise peer failure.
+ if (nbytes == -1 && (
+ WSAGetLastError () == WSAENETDOWN ||
+ WSAGetLastError () == WSAENETRESET ||
+ WSAGetLastError () == WSAEHOSTUNREACH ||
+ WSAGetLastError () == WSAECONNABORTED ||
+ WSAGetLastError () == WSAETIMEDOUT ||
+ WSAGetLastError () == WSAECONNRESET))
+ return -1;
+
+ wsa_assert (nbytes != SOCKET_ERROR);
+
+ return (size_t) nbytes;
+}
+
+int zmq::tcp_socket_t::read (void *data, int size)
+{
+ int nbytes = recv (s, (char*) data, size, 0);
+
+ // If not a single byte can be read from the socket in non-blocking mode
+ // we'll get an error (this may happen during the speculative read).
+ if (nbytes == SOCKET_ERROR && WSAGetLastError () == WSAEWOULDBLOCK)
+ return 0;
+
+ // Connection failure.
+ if (nbytes == -1 && (
+ WSAGetLastError () == WSAENETDOWN ||
+ WSAGetLastError () == WSAENETRESET ||
+ WSAGetLastError () == WSAECONNABORTED ||
+ WSAGetLastError () == WSAETIMEDOUT ||
+ WSAGetLastError () == WSAECONNRESET ||
+ WSAGetLastError () == WSAECONNREFUSED ||
+ WSAGetLastError () == WSAENOTCONN))
+ return -1;
+
+ wsa_assert (nbytes != SOCKET_ERROR);
+
+ // Orderly shutdown by the other peer.
+ if (nbytes == 0)
+ return -1;
+
+ return (size_t) nbytes;
+}
+
+#else
+
+#include <unistd.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/tcp.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <fcntl.h>
+
+zmq::tcp_socket_t::tcp_socket_t () :
+ s (retired_fd)
+{
+}
+
+zmq::tcp_socket_t::~tcp_socket_t ()
+{
+ if (s != retired_fd)
+ close ();
+}
+
+int zmq::tcp_socket_t::open (fd_t fd_, uint64_t sndbuf_, uint64_t rcvbuf_)
+{
+ assert (s == retired_fd);
+ s = fd_;
+
+ if (sndbuf_) {
+ int sz = (int) sndbuf_;
+ int rc = setsockopt (s, SOL_SOCKET, SO_SNDBUF, &sz, sizeof (int));
+ errno_assert (rc == 0);
+ }
+
+ if (rcvbuf_) {
+ int sz = (int) rcvbuf_;
+ int rc = setsockopt (s, SOL_SOCKET, SO_RCVBUF, &sz, sizeof (int));
+ errno_assert (rc == 0);
+ }
+
+ return 0;
+}
+
+int zmq::tcp_socket_t::close ()
+{
+ zmq_assert (s != retired_fd);
+ int rc = ::close (s);
+ if (rc != 0)
+ return -1;
+ s = retired_fd;
+ return 0;
+}
+
+zmq::fd_t zmq::tcp_socket_t::get_fd ()
+{
+ return s;
+}
+
+int zmq::tcp_socket_t::write (const void *data, int size)
+{
+ ssize_t nbytes = send (s, data, size, 0);
+
+ // Several errors are OK. When speculative write is being done we may not
+ // be able to write a single byte to the socket. Also, SIGSTOP issued
+ // by a debugging tool can result in EINTR error.
+ if (nbytes == -1 && (errno == EAGAIN || errno == EWOULDBLOCK ||
+ errno == EINTR))
+ return 0;
+
+ // Signalise peer failure.
+ if (nbytes == -1 && (errno == ECONNRESET || errno == EPIPE))
+ return -1;
+
+ errno_assert (nbytes != -1);
+ return (size_t) nbytes;
+}
+
+int zmq::tcp_socket_t::read (void *data, int size)
+{
+ ssize_t nbytes = recv (s, data, size, 0);
+
+ // Several errors are OK. When speculative read is being done we may not
+ // be able to read a single byte to the socket. Also, SIGSTOP issued
+ // by a debugging tool can result in EINTR error.
+ if (nbytes == -1 && (errno == EAGAIN || errno == EWOULDBLOCK ||
+ errno == EINTR))
+ return 0;
+
+ // Signalise peer failure.
+ if (nbytes == -1 && (errno == ECONNRESET || errno == ECONNREFUSED))
+ return -1;
+
+ errno_assert (nbytes != -1);
+
+ // Orderly shutdown by the other peer.
+ if (nbytes == 0)
+ return -1;
+
+ return (size_t) nbytes;
+}
+
+#endif
+
diff --git a/src/tcp_socket.hpp b/src/tcp_socket.hpp
new file mode 100644
index 0000000..3aae060
--- /dev/null
+++ b/src/tcp_socket.hpp
@@ -0,0 +1,71 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_TCP_SOCKET_HPP_INCLUDED__
+#define __ZMQ_TCP_SOCKET_HPP_INCLUDED__
+
+#include "fd.hpp"
+#include "stdint.hpp"
+
+namespace zmq
+{
+
+ // The class encapsulating simple TCP read/write socket.
+
+ class tcp_socket_t
+ {
+ public:
+
+ tcp_socket_t ();
+ ~tcp_socket_t ();
+
+ // Associates a socket with a native socket descriptor.
+ int open (fd_t fd_, uint64_t sndbuf_, uint64_t rcvbuf_);
+
+ // Closes the underlying socket.
+ int close ();
+
+ // Returns the underlying socket. Returns retired_fd when the socket
+ // is in the closed state.
+ fd_t get_fd ();
+
+ // Writes data to the socket. Returns the number of bytes actually
+ // written (even zero is to be considered to be a success). In case
+ // of error or orderly shutdown by the other peer -1 is returned.
+ int write (const void *data, int size);
+
+ // Reads data from the socket (up to 'size' bytes). Returns the number
+ // of bytes actually read (even zero is to be considered to be
+ // a success). In case of error or orderly shutdown by the other
+ // peer -1 is returned.
+ int read (void *data, int size);
+
+ private:
+
+ // Underlying socket.
+ fd_t s;
+
+ // Disable copy construction of tcp_socket.
+ tcp_socket_t (const tcp_socket_t&);
+ void operator = (const tcp_socket_t&);
+ };
+
+}
+
+#endif
diff --git a/src/thread.cpp b/src/thread.cpp
new file mode 100644
index 0000000..602ca8b
--- /dev/null
+++ b/src/thread.cpp
@@ -0,0 +1,108 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "thread.hpp"
+#include "err.hpp"
+#include "platform.hpp"
+
+#ifdef ZMQ_HAVE_WINDOWS
+
+void zmq::thread_t::start (thread_fn *tfn_, void *arg_)
+{
+ tfn = tfn_;
+ arg =arg_;
+ descriptor = (HANDLE) _beginthreadex (NULL, 0,
+ &zmq::thread_t::thread_routine, this, 0 , NULL);
+ win_assert (descriptor != NULL);
+}
+
+void zmq::thread_t::stop ()
+{
+ DWORD rc = WaitForSingleObject (descriptor, INFINITE);
+ win_assert (rc != WAIT_FAILED);
+}
+
+zmq::thread_t::id_t zmq::thread_t::id ()
+{
+ return GetCurrentThreadId ();
+}
+
+bool zmq::thread_t::equal (id_t id1_, id_t id2_)
+{
+ return id1_ == id2_;
+}
+
+unsigned int __stdcall zmq::thread_t::thread_routine (void *arg_)
+{
+ thread_t *self = (thread_t*) arg_;
+ self->tfn (self->arg);
+ return 0;
+}
+
+#else
+
+#include <signal.h>
+
+void zmq::thread_t::start (thread_fn *tfn_, void *arg_)
+{
+ tfn = tfn_;
+ arg =arg_;
+ int rc = pthread_create (&descriptor, NULL, thread_routine, this);
+ errno_assert (rc == 0);
+}
+
+void zmq::thread_t::stop ()
+{
+ int rc = pthread_join (descriptor, NULL);
+ errno_assert (rc == 0);
+}
+
+zmq::thread_t::id_t zmq::thread_t::id ()
+{
+ return pthread_self ();
+}
+
+bool zmq::thread_t::equal (id_t id1_, id_t id2_)
+{
+ return pthread_equal (id1_, id2_) != 0;
+}
+
+void *zmq::thread_t::thread_routine (void *arg_)
+{
+#if !defined ZMQ_HAVE_OPENVMS
+ // Following code will guarantee more predictable latecnies as it'll
+ // disallow any signal handling in the I/O thread.
+ sigset_t signal_set;
+ int rc = sigfillset (&signal_set);
+ errno_assert (rc == 0);
+ rc = pthread_sigmask (SIG_BLOCK, &signal_set, NULL);
+ errno_assert (rc == 0);
+#endif
+
+ thread_t *self = (thread_t*) arg_;
+ self->tfn (self->arg);
+ return NULL;
+}
+
+#endif
+
+
+
+
+
diff --git a/src/thread.hpp b/src/thread.hpp
new file mode 100644
index 0000000..432770c
--- /dev/null
+++ b/src/thread.hpp
@@ -0,0 +1,86 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_THREAD_HPP_INCLUDED__
+#define __ZMQ_THREAD_HPP_INCLUDED__
+
+#include "platform.hpp"
+
+#ifdef ZMQ_HAVE_WINDOWS
+#include "windows.hpp"
+#else
+#include <pthread.h>
+#endif
+
+namespace zmq
+{
+
+ typedef void (thread_fn) (void*);
+
+ // Class encapsulating OS thread. Thread initiation/termination is done
+ // using special functions rather than in constructor/destructor so that
+ // thread isn't created during object construction by accident, causing
+ // newly created thread to access half-initialised object. Same applies
+ // to the destruction process: Thread should be terminated before object
+ // destruction begins, otherwise it can access half-destructed object.
+
+ class thread_t
+ {
+ public:
+
+ inline thread_t ()
+ {
+ }
+
+ // Creates OS thread. 'tfn' is main thread function. It'll be passed
+ // 'arg' as an argument.
+ void start (thread_fn *tfn_, void *arg_);
+
+ // Waits for thread termination.
+ void stop ();
+
+#ifdef ZMQ_HAVE_WINDOWS
+ typedef DWORD id_t;
+#else
+ typedef pthread_t id_t;
+#endif
+
+ static id_t id ();
+ static bool equal (id_t id1_, id_t id2_);
+
+ private:
+
+#ifdef ZMQ_HAVE_WINDOWS
+ static unsigned int __stdcall thread_routine (void *arg_);
+ HANDLE descriptor;
+#else
+ static void *thread_routine (void *arg_);
+ pthread_t descriptor;
+#endif
+
+ thread_fn *tfn;
+ void *arg;
+
+ thread_t (const thread_t&);
+ void operator = (const thread_t&);
+ };
+
+}
+
+#endif
diff --git a/src/upstream.cpp b/src/upstream.cpp
new file mode 100644
index 0000000..1498c31
--- /dev/null
+++ b/src/upstream.cpp
@@ -0,0 +1,98 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "../include/zmq.h"
+
+#include "upstream.hpp"
+#include "err.hpp"
+
+zmq::upstream_t::upstream_t (class app_thread_t *parent_) :
+ socket_base_t (parent_)
+{
+ options.requires_in = true;
+ options.requires_out = false;
+}
+
+zmq::upstream_t::~upstream_t ()
+{
+}
+
+void zmq::upstream_t::xattach_pipes (class reader_t *inpipe_,
+ class writer_t *outpipe_, const blob_t &peer_identity_)
+{
+ zmq_assert (inpipe_ && !outpipe_);
+ fq.attach (inpipe_);
+}
+
+void zmq::upstream_t::xdetach_inpipe (class reader_t *pipe_)
+{
+ zmq_assert (pipe_);
+ fq.detach (pipe_);
+}
+
+void zmq::upstream_t::xdetach_outpipe (class writer_t *pipe_)
+{
+ // There are no outpipes, so this function shouldn't be called at all.
+ zmq_assert (false);
+}
+
+void zmq::upstream_t::xkill (class reader_t *pipe_)
+{
+ fq.kill (pipe_);
+}
+
+void zmq::upstream_t::xrevive (class reader_t *pipe_)
+{
+ fq.revive (pipe_);
+}
+
+void zmq::upstream_t::xrevive (class writer_t *pipe_)
+{
+ zmq_assert (false);
+}
+
+int zmq::upstream_t::xsetsockopt (int option_, const void *optval_,
+ size_t optvallen_)
+{
+ // No special options for this socket type.
+ errno = EINVAL;
+ return -1;
+}
+
+int zmq::upstream_t::xsend (zmq_msg_t *msg_, int flags_)
+{
+ errno = ENOTSUP;
+ return -1;
+}
+
+int zmq::upstream_t::xrecv (zmq_msg_t *msg_, int flags_)
+{
+ return fq.recv (msg_, flags_);
+}
+
+bool zmq::upstream_t::xhas_in ()
+{
+ return fq.has_in ();
+}
+
+bool zmq::upstream_t::xhas_out ()
+{
+ return false;
+}
+
diff --git a/src/upstream.hpp b/src/upstream.hpp
new file mode 100644
index 0000000..5fe42ae
--- /dev/null
+++ b/src/upstream.hpp
@@ -0,0 +1,62 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_UPSTREAM_HPP_INCLUDED__
+#define __ZMQ_UPSTREAM_HPP_INCLUDED__
+
+#include "socket_base.hpp"
+#include "fq.hpp"
+
+namespace zmq
+{
+
+ class upstream_t : public socket_base_t
+ {
+ public:
+
+ upstream_t (class app_thread_t *parent_);
+ ~upstream_t ();
+
+ // Overloads of functions from socket_base_t.
+ void xattach_pipes (class reader_t *inpipe_, class writer_t *outpipe_,
+ const blob_t &peer_identity_);
+ void xdetach_inpipe (class reader_t *pipe_);
+ void xdetach_outpipe (class writer_t *pipe_);
+ void xkill (class reader_t *pipe_);
+ void xrevive (class reader_t *pipe_);
+ void xrevive (class writer_t *pipe_);
+ int xsetsockopt (int option_, const void *optval_, size_t optvallen_);
+ int xsend (zmq_msg_t *msg_, int flags_);
+ int xrecv (zmq_msg_t *msg_, int flags_);
+ bool xhas_in ();
+ bool xhas_out ();
+
+ private:
+
+ // Fair queueing object for inbound pipes.
+ fq_t fq;
+
+ upstream_t (const upstream_t&);
+ void operator = (const upstream_t&);
+
+ };
+
+}
+
+#endif
diff --git a/src/uuid.cpp b/src/uuid.cpp
new file mode 100644
index 0000000..406bbb4
--- /dev/null
+++ b/src/uuid.cpp
@@ -0,0 +1,235 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "uuid.hpp"
+#include "err.hpp"
+
+#if defined ZMQ_HAVE_WINDOWS
+
+zmq::uuid_t::uuid_t ()
+{
+ RPC_STATUS ret = UuidCreate (&uuid);
+ zmq_assert (ret == RPC_S_OK);
+ ret = UuidToString (&uuid, &string_buf);
+ zmq_assert (ret == RPC_S_OK);
+
+ /*
+ HRESULT hr = CoCreateGUID (&uuid);
+ zmq_assert (hr == S_OK);
+ int rc = StringFromGUID2 (uuid, string_buf, 40);
+ zmq_assert (rc != 0);
+ */
+
+ create_blob ();
+}
+
+zmq::uuid_t::~uuid_t ()
+{
+}
+
+const char *zmq::uuid_t::to_string ()
+{
+ return (char*) string_buf;
+}
+
+#elif defined ZMQ_HAVE_FREEBSD || defined ZMQ_HAVE_NETBSD
+
+#include <stdlib.h>
+#include <uuid.h>
+
+zmq::uuid_t::uuid_t ()
+{
+ uint32_t status;
+ uuid_create (&uuid, &status);
+ zmq_assert (status == uuid_s_ok);
+ uuid_to_string (&uuid, &string_buf, &status);
+ zmq_assert (status == uuid_s_ok);
+
+ create_blob ();
+}
+
+zmq::uuid_t::~uuid_t ()
+{
+ free (string_buf);
+}
+
+const char *zmq::uuid_t::to_string ()
+{
+ return string_buf;
+}
+
+#elif defined ZMQ_HAVE_LINUX || defined ZMQ_HAVE_SOLARIS ||\
+ defined ZMQ_HAVE_OSX || defined ZMQ_HAVE_CYGWIN
+
+#include <uuid/uuid.h>
+
+zmq::uuid_t::uuid_t ()
+{
+ uuid_generate (uuid);
+ uuid_unparse (uuid, string_buf);
+
+ create_blob ();
+}
+
+zmq::uuid_t::~uuid_t ()
+{
+}
+
+const char *zmq::uuid_t::to_string ()
+{
+ return string_buf;
+}
+
+#elif defined ZMQ_HAVE_OPENVMS
+
+#include <starlet.h>
+
+#define uuid_generate(x) sys$create_uid(&(x))
+
+#define uuid_unparse(x, y) \
+ sprintf (y, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", \
+ x.data0, x.data1, x.data2, \
+ x.data3 [0], x.data3 [1], \
+ x.data3 [2], x.data3 [3], \
+ x.data3 [4], x.data3 [5], \
+ x.data3 [6], x.data3 [7]);
+
+zmq::uuid_t::uuid_t ()
+{
+ uuid_generate (uuid);
+ uuid_unparse (uuid, string_buf);
+}
+
+zmq::uuid_t::~uuid_t ()
+{
+}
+
+const char *zmq::uuid_t::to_string ()
+{
+ return string_buf;
+}
+
+#else
+
+#include <stdio.h>
+#include <string.h>
+#include <openssl/rand.h>
+
+zmq::uuid_t::uuid_t ()
+{
+ unsigned char rand_buf [16];
+ int ret = RAND_bytes (rand_buf, sizeof rand_buf);
+ zmq_assert (ret == 1);
+
+ // Read in UUID fields.
+ memcpy (&time_low, rand_buf, sizeof time_low);
+ memcpy (&time_mid, rand_buf + 4, sizeof time_mid);
+ memcpy (&time_hi_and_version, rand_buf + 6, sizeof time_hi_and_version);
+ memcpy (&clock_seq_hi_and_reserved, rand_buf + 8,
+ sizeof clock_seq_hi_and_reserved);
+ memcpy (&clock_seq_low, rand_buf + 9, sizeof clock_seq_low);
+ memcpy (&node [0], rand_buf + 10, sizeof node);
+
+ // Store UUID version number.
+ time_hi_and_version = (time_hi_and_version & 0x0fff) | 4 << 12;
+
+ // Store UUID type.
+ clock_seq_hi_and_reserved = (clock_seq_hi_and_reserved & 0x3f) | 0x80;
+
+ snprintf (string_buf, sizeof string_buf,
+ "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ time_low,
+ time_mid,
+ time_hi_and_version,
+ clock_seq_hi_and_reserved,
+ clock_seq_low,
+ node [0], node [1], node [2], node [3], node [4], node [5]);
+
+ create_blob ();
+}
+
+zmq::uuid_t::~uuid_t ()
+{
+}
+
+const char *zmq::uuid_t::to_string ()
+{
+ return string_buf;
+}
+
+#endif
+
+const unsigned char *zmq::uuid_t::to_blob ()
+{
+ return blob_buf;
+}
+
+unsigned char zmq::uuid_t::convert_byte (const char *hexa_)
+{
+ unsigned char byte;
+
+ if (*hexa_ >= '0' && *hexa_ <= '9')
+ byte = *hexa_ - '0';
+ else if (*hexa_ >= 'A' && *hexa_ <= 'F')
+ byte = *hexa_ - 'A' + 10;
+ else if (*hexa_ >= 'a' && *hexa_ <= 'f')
+ byte = *hexa_ - 'a' + 10;
+ else
+ zmq_assert (false);
+
+ byte *= 16;
+
+ hexa_++;
+ if (*hexa_ >= '0' && *hexa_ <= '9')
+ byte += *hexa_ - '0';
+ else if (*hexa_ >= 'A' && *hexa_ <= 'F')
+ byte += *hexa_ - 'A' + 10;
+ else if (*hexa_ >= 'a' && *hexa_ <= 'f')
+ byte += *hexa_ - 'a' + 10;
+ else
+ zmq_assert (false);
+
+ return byte;
+}
+
+void zmq::uuid_t::create_blob ()
+{
+ const char *buf = (const char*) string_buf;
+
+ blob_buf [0] = convert_byte (buf + 0);
+ blob_buf [1] = convert_byte (buf + 2);
+ blob_buf [2] = convert_byte (buf + 4);
+ blob_buf [3] = convert_byte (buf + 6);
+
+ blob_buf [4] = convert_byte (buf + 9);
+ blob_buf [5] = convert_byte (buf + 11);
+
+ blob_buf [6] = convert_byte (buf + 14);
+ blob_buf [7] = convert_byte (buf + 16);
+
+ blob_buf [8] = convert_byte (buf + 19);
+ blob_buf [9] = convert_byte (buf + 21);
+
+ blob_buf [10] = convert_byte (buf + 24);
+ blob_buf [11] = convert_byte (buf + 26);
+ blob_buf [12] = convert_byte (buf + 28);
+ blob_buf [13] = convert_byte (buf + 30);
+ blob_buf [14] = convert_byte (buf + 32);
+ blob_buf [15] = convert_byte (buf + 34);
+}
diff --git a/src/uuid.hpp b/src/uuid.hpp
new file mode 100644
index 0000000..871f827
--- /dev/null
+++ b/src/uuid.hpp
@@ -0,0 +1,110 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_UUID_HPP_INCLUDED__
+#define __ZMQ_UUID_HPP_INCLUDED__
+
+#include "platform.hpp"
+#include "stdint.hpp"
+
+#if defined ZMQ_HAVE_FREEBSD || defined ZMQ_HAVE_NETBSD
+#include <uuid.h>
+#elif defined ZMQ_HAVE_LINUX || defined ZMQ_HAVE_SOLARIS ||\
+ defined ZMQ_HAVE_OSX || defined ZMQ_HAVE_CYGWIN
+#include <uuid/uuid.h>
+#elif defined ZMQ_HAVE_WINDOWS
+#include "windows.hpp"
+#include <rpc.h>
+#elif defined ZMQ_HAVE_OPENVMS
+typedef struct
+{
+ unsigned long data0;
+ unsigned short data1;
+ unsigned short data2;
+ unsigned char data3 [8];
+} uuid_t;
+#endif
+
+namespace zmq
+{
+
+ // This class provides RFC 4122 (a Universally Unique IDentifier)
+ // implementation.
+
+ class uuid_t
+ {
+ public:
+
+ uuid_t ();
+ ~uuid_t ();
+
+ // The length of textual representation of UUID.
+ enum { uuid_string_len = 36 };
+
+ // Returns a pointer to buffer containing the textual
+ // representation of the UUID. The caller is reponsible to
+ // free the allocated memory.
+ const char *to_string ();
+
+ // The length of binary representation of UUID.
+ enum { uuid_blob_len = 16 };
+
+ const unsigned char *to_blob ();
+
+ private:
+
+ // Converts one byte from hexa representation to binary.
+ unsigned char convert_byte (const char *hexa_);
+
+ // Converts string representation of UUID into standardised BLOB.
+ // The function is endianness agnostic.
+ void create_blob ();
+
+#if defined ZMQ_HAVE_WINDOWS
+#ifdef ZMQ_HAVE_MINGW32
+ typedef unsigned char* RPC_CSTR;
+#endif
+ ::UUID uuid;
+ RPC_CSTR string_buf;
+#elif defined ZMQ_HAVE_FREEBSD || defined ZMQ_HAVE_NETBSD
+ ::uuid_t uuid;
+ char *string_buf;
+#elif defined ZMQ_HAVE_LINUX || defined ZMQ_HAVE_SOLARIS ||\
+ defined ZMQ_HAVE_OSX || defined ZMQ_HAVE_CYGWIN ||\
+ defined ZMQ_HAVE_OPENVMS
+ ::uuid_t uuid;
+ char string_buf [uuid_string_len + 1];
+#else
+ // RFC 4122 UUID's fields
+ uint32_t time_low;
+ uint16_t time_mid;
+ uint16_t time_hi_and_version;
+ uint8_t clock_seq_hi_and_reserved;
+ uint8_t clock_seq_low;
+ uint8_t node [6];
+
+ char string_buf [uuid_string_len + 1];
+#endif
+
+ unsigned char blob_buf [uuid_blob_len];
+ };
+
+}
+
+#endif
diff --git a/src/windows.hpp b/src/windows.hpp
new file mode 100644
index 0000000..8fc98b0
--- /dev/null
+++ b/src/windows.hpp
@@ -0,0 +1,78 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_WINDOWS_HPP_INCLUDED__
+#define __ZMQ_WINDOWS_HPP_INCLUDED__
+
+// The purpose of this header file is to turn on only the items actually needed
+// on the windows platform.
+
+#define _WINSOCKAPI_
+#ifndef NOMINMAX
+#define NOMINMAX // No min and max functions, these clash with C++.
+#endif
+#define _CRT_SECURE_NO_WARNINGS
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#ifndef NOUSER // No USER defines and routines.
+#define NOUSER
+#endif
+#ifndef NOMCX // No Modem Configuration Extensions.
+#define NOMCX
+#endif
+#ifndef NOIME // No Input Method Editor.
+#define NOIME
+#endif
+#ifndef NOSOUND // No Sound driver routines.
+#define NOSOUND
+#endif
+
+#ifdef ZMQ_HAVE_MINGW32
+#ifdef WINVER
+#undef WINVER
+#endif
+#define WINVER 0x0501
+#endif
+
+#include <windows.h>
+
+// MSVC++ 2005 on Win2000 does not define _WIN32_WINNT.
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT WINVER
+#endif
+
+// Enable winsock (not included when WIN32_LEAN_AND_MEAN is defined).
+#if(_WIN32_WINNT >= 0x0400)
+#include <winsock2.h>
+#include <mswsock.h>
+#else
+#include <winsock.h>
+#endif
+
+#include <ws2tcpip.h>
+#include <ipexport.h>
+#include <process.h>
+
+// On mingw environment AI_NUMERICSERV is not defined, needed in ip.cpp.
+#ifndef AI_NUMERICSERV
+#define AI_NUMERICSERV 0x0400
+#endif
+#endif
diff --git a/src/wire.hpp b/src/wire.hpp
new file mode 100644
index 0000000..9534cf6
--- /dev/null
+++ b/src/wire.hpp
@@ -0,0 +1,98 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_WIRE_HPP_INCLUDED__
+#define __ZMQ_WIRE_HPP_INCLUDED__
+
+#include "stdint.hpp"
+
+namespace zmq
+{
+
+ // Helper functions to convert different integer types to/from network
+ // byte order.
+
+ inline void put_uint8 (unsigned char *buffer_, uint8_t value)
+ {
+ *buffer_ = value;
+ }
+
+ inline uint8_t get_uint8 (unsigned char *buffer_)
+ {
+ return *buffer_;
+ }
+
+ inline void put_uint16 (unsigned char *buffer_, uint16_t value)
+ {
+ buffer_ [0] = (unsigned char) (((value) >> 8) & 0xff);
+ buffer_ [1] = (unsigned char) (value & 0xff);
+ }
+
+ inline uint16_t get_uint16 (unsigned char *buffer_)
+ {
+ return
+ (((uint16_t) buffer_ [0]) << 8) |
+ ((uint16_t) buffer_ [1]);
+ }
+
+ inline void put_uint32 (unsigned char *buffer_, uint32_t value)
+ {
+ buffer_ [0] = (unsigned char) (((value) >> 24) & 0xff);
+ buffer_ [1] = (unsigned char) (((value) >> 16) & 0xff);
+ buffer_ [2] = (unsigned char) (((value) >> 8) & 0xff);
+ buffer_ [3] = (unsigned char) (value & 0xff);
+ }
+
+ inline uint32_t get_uint32 (unsigned char *buffer_)
+ {
+ return
+ (((uint32_t) buffer_ [0]) << 24) |
+ (((uint32_t) buffer_ [1]) << 16) |
+ (((uint32_t) buffer_ [2]) << 8) |
+ ((uint32_t) buffer_ [3]);
+ }
+
+ inline void put_uint64 (unsigned char *buffer_, uint64_t value)
+ {
+ buffer_ [0] = (unsigned char) (((value) >> 56) & 0xff);
+ buffer_ [1] = (unsigned char) (((value) >> 48) & 0xff);
+ buffer_ [2] = (unsigned char) (((value) >> 40) & 0xff);
+ buffer_ [3] = (unsigned char) (((value) >> 32) & 0xff);
+ buffer_ [4] = (unsigned char) (((value) >> 24) & 0xff);
+ buffer_ [5] = (unsigned char) (((value) >> 16) & 0xff);
+ buffer_ [6] = (unsigned char) (((value) >> 8) & 0xff);
+ buffer_ [7] = (unsigned char) (value & 0xff);
+ }
+
+ inline uint64_t get_uint64 (unsigned char *buffer_)
+ {
+ return
+ (((uint64_t) buffer_ [0]) << 56) |
+ (((uint64_t) buffer_ [1]) << 48) |
+ (((uint64_t) buffer_ [2]) << 40) |
+ (((uint64_t) buffer_ [3]) << 32) |
+ (((uint64_t) buffer_ [4]) << 24) |
+ (((uint64_t) buffer_ [5]) << 16) |
+ (((uint64_t) buffer_ [6]) << 8) |
+ ((uint64_t) buffer_ [7]);
+ }
+
+}
+
+#endif
diff --git a/src/xrep.cpp b/src/xrep.cpp
new file mode 100644
index 0000000..4e8d18a
--- /dev/null
+++ b/src/xrep.cpp
@@ -0,0 +1,271 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "../include/zmq.h"
+
+#include "xrep.hpp"
+#include "err.hpp"
+#include "pipe.hpp"
+
+zmq::xrep_t::xrep_t (class app_thread_t *parent_) :
+ socket_base_t (parent_),
+ current_in (0),
+ more_in (false),
+ current_out (NULL),
+ more_out (false)
+{
+ options.requires_in = true;
+ options.requires_out = true;
+
+ // On connect, pipes are created only after initial handshaking.
+ // That way we are aware of the peer's identity when binding to the pipes.
+ options.immediate_connect = false;
+}
+
+zmq::xrep_t::~xrep_t ()
+{
+ for (inpipes_t::iterator it = inpipes.begin (); it != inpipes.end (); it++)
+ it->reader->term ();
+ for (outpipes_t::iterator it = outpipes.begin (); it != outpipes.end ();
+ it++)
+ it->second.writer->term ();
+}
+
+void zmq::xrep_t::xattach_pipes (class reader_t *inpipe_,
+ class writer_t *outpipe_, const blob_t &peer_identity_)
+{
+ zmq_assert (inpipe_ && outpipe_);
+
+ // TODO: What if new connection has same peer identity as the old one?
+ outpipe_t outpipe = {outpipe_, true};
+ bool ok = outpipes.insert (std::make_pair (
+ peer_identity_, outpipe)).second;
+ zmq_assert (ok);
+
+ inpipe_t inpipe = {inpipe_, peer_identity_, true};
+ inpipes.push_back (inpipe);
+}
+
+void zmq::xrep_t::xdetach_inpipe (class reader_t *pipe_)
+{
+// TODO:!
+ for (inpipes_t::iterator it = inpipes.begin (); it != inpipes.end ();
+ it++) {
+ if (it->reader == pipe_) {
+ inpipes.erase (it);
+ return;
+ }
+ }
+ zmq_assert (false);
+}
+
+void zmq::xrep_t::xdetach_outpipe (class writer_t *pipe_)
+{
+ for (outpipes_t::iterator it = outpipes.begin ();
+ it != outpipes.end (); ++it) {
+ if (it->second.writer == pipe_) {
+ outpipes.erase (it);
+ if (pipe_ == current_out)
+ current_out = NULL;
+ return;
+ }
+ }
+ zmq_assert (false);
+}
+
+void zmq::xrep_t::xkill (class reader_t *pipe_)
+{
+ for (inpipes_t::iterator it = inpipes.begin (); it != inpipes.end ();
+ it++) {
+ if (it->reader == pipe_) {
+ zmq_assert (it->active);
+ it->active = false;
+ return;
+ }
+ }
+ zmq_assert (false);
+}
+
+void zmq::xrep_t::xrevive (class reader_t *pipe_)
+{
+ for (inpipes_t::iterator it = inpipes.begin (); it != inpipes.end ();
+ it++) {
+ if (it->reader == pipe_) {
+ zmq_assert (!it->active);
+ it->active = true;
+ return;
+ }
+ }
+ zmq_assert (false);
+}
+
+void zmq::xrep_t::xrevive (class writer_t *pipe_)
+{
+ for (outpipes_t::iterator it = outpipes.begin ();
+ it != outpipes.end (); ++it) {
+ if (it->second.writer == pipe_) {
+ zmq_assert (!it->second.active);
+ it->second.active = true;
+ return;
+ }
+ }
+ zmq_assert (false);
+}
+
+int zmq::xrep_t::xsetsockopt (int option_, const void *optval_,
+ size_t optvallen_)
+{
+ errno = EINVAL;
+ return -1;
+}
+
+int zmq::xrep_t::xsend (zmq_msg_t *msg_, int flags_)
+{
+ // If this is the first part of the message it's the identity of the
+ // peer to send the message to.
+ if (!more_out) {
+ zmq_assert (!current_out);
+
+ // There's no such thing as prefix with no subsequent message.
+ zmq_assert (msg_->flags & ZMQ_MSG_MORE);
+ more_out = true;
+
+ // Find the pipe associated with the identity stored in the prefix.
+ // If there's no such pipe just silently drop the message.
+ blob_t identity ((unsigned char*) zmq_msg_data (msg_),
+ zmq_msg_size (msg_));
+ outpipes_t::iterator it = outpipes.find (identity);
+ if (it == outpipes.end ())
+ return 0;
+
+ // Remember the outgoing pipe.
+ current_out = it->second.writer;
+
+ return 0;
+ }
+
+ // Check whether this is the last part of the message.
+ more_out = msg_->flags & ZMQ_MSG_MORE;
+
+ // Push the message into the pipe. If there's no out pipe, just drop it.
+ if (current_out) {
+ bool ok = current_out->write (msg_);
+ zmq_assert (ok);
+ if (!more_out) {
+ current_out->flush ();
+ current_out = NULL;
+ }
+ }
+ else {
+ int rc = zmq_msg_close (msg_);
+ zmq_assert (rc == 0);
+ }
+
+ // Detach the message from the data buffer.
+ int rc = zmq_msg_init (msg_);
+ zmq_assert (rc == 0);
+
+ return 0;
+}
+
+int zmq::xrep_t::xrecv (zmq_msg_t *msg_, int flags_)
+{
+ // Deallocate old content of the message.
+ zmq_msg_close (msg_);
+
+ // If we are in the middle of reading a message, just grab next part of it.
+ if (more_in) {
+ zmq_assert (inpipes [current_in].active);
+ bool fetched = inpipes [current_in].reader->read (msg_);
+ zmq_assert (fetched);
+ more_in = msg_->flags & ZMQ_MSG_MORE;
+ if (!more_in) {
+ current_in++;
+ if (current_in >= inpipes.size ())
+ current_in = 0;
+ }
+ return 0;
+ }
+
+ // Round-robin over the pipes to get the next message.
+ for (int count = inpipes.size (); count != 0; count--) {
+
+ // Try to fetch new message.
+ bool fetched;
+ if (!inpipes [current_in].active)
+ fetched = false;
+ else
+ fetched = inpipes [current_in].reader->check_read ();
+
+ // If we have a message, create a prefix and return it to the caller.
+ if (fetched) {
+ int rc = zmq_msg_init_size (msg_,
+ inpipes [current_in].identity.size ());
+ zmq_assert (rc == 0);
+ memcpy (zmq_msg_data (msg_), inpipes [current_in].identity.data (),
+ zmq_msg_size (msg_));
+ msg_->flags = ZMQ_MSG_MORE;
+ more_in = true;
+ return 0;
+ }
+
+ // If me don't have a message, move to next pipe.
+ current_in++;
+ if (current_in >= inpipes.size ())
+ current_in = 0;
+ }
+
+ // No message is available. Initialise the output parameter
+ // to be a 0-byte message.
+ zmq_msg_init (msg_);
+ errno = EAGAIN;
+ return -1;
+}
+
+bool zmq::xrep_t::xhas_in ()
+{
+ // There are subsequent parts of the partly-read message available.
+ if (more_in)
+ return true;
+
+ // Note that messing with current doesn't break the fairness of fair
+ // queueing algorithm. If there are no messages available current will
+ // get back to its original value. Otherwise it'll point to the first
+ // pipe holding messages, skipping only pipes with no messages available.
+ for (int count = inpipes.size (); count != 0; count--) {
+ if (inpipes [current_in].active &&
+ inpipes [current_in].reader->check_read ())
+ return true;
+ current_in++;
+ if (current_in >= inpipes.size ())
+ current_in = 0;
+ }
+
+ return false;
+}
+
+bool zmq::xrep_t::xhas_out ()
+{
+ // In theory, XREP socket is always ready for writing. Whether actual
+ // attempt to write succeeds depends on whitch pipe the message is going
+ // to be routed to.
+ return true;
+}
+
+
diff --git a/src/xrep.hpp b/src/xrep.hpp
new file mode 100644
index 0000000..940d288
--- /dev/null
+++ b/src/xrep.hpp
@@ -0,0 +1,95 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_XREP_HPP_INCLUDED__
+#define __ZMQ_XREP_HPP_INCLUDED__
+
+#include <map>
+#include <vector>
+
+#include "socket_base.hpp"
+#include "blob.hpp"
+
+namespace zmq
+{
+
+ // TODO: This class uses O(n) scheduling. Rewrite it to use O(1) algorithm.
+ class xrep_t : public socket_base_t
+ {
+ public:
+
+ xrep_t (class app_thread_t *parent_);
+ ~xrep_t ();
+
+ // Overloads of functions from socket_base_t.
+ void xattach_pipes (class reader_t *inpipe_, class writer_t *outpipe_,
+ const blob_t &peer_identity_);
+ void xdetach_inpipe (class reader_t *pipe_);
+ void xdetach_outpipe (class writer_t *pipe_);
+ void xkill (class reader_t *pipe_);
+ void xrevive (class reader_t *pipe_);
+ void xrevive (class writer_t *pipe_);
+ int xsetsockopt (int option_, const void *optval_, size_t optvallen_);
+ int xsend (zmq_msg_t *msg_, int flags_);
+ int xrecv (zmq_msg_t *msg_, int flags_);
+ bool xhas_in ();
+ bool xhas_out ();
+
+ private:
+
+ struct inpipe_t
+ {
+ class reader_t *reader;
+ blob_t identity;
+ bool active;
+ };
+
+ // Inbound pipes with the names of corresponging peers.
+ typedef std::vector <inpipe_t> inpipes_t;
+ inpipes_t inpipes;
+
+ // The pipe we are currently reading from.
+ inpipes_t::size_type current_in;
+
+ // If true, more incoming message parts are expected.
+ bool more_in;
+
+ struct outpipe_t
+ {
+ class writer_t *writer;
+ bool active;
+ };
+
+ // Outbound pipes indexed by the peer names.
+ typedef std::map <blob_t, outpipe_t> outpipes_t;
+ outpipes_t outpipes;
+
+ // The pipe we are currently writing to.
+ class writer_t *current_out;
+
+ // If true, more outgoing message parts are expected.
+ bool more_out;
+
+ xrep_t (const xrep_t&);
+ void operator = (const xrep_t&);
+ };
+
+}
+
+#endif
diff --git a/src/xreq.cpp b/src/xreq.cpp
new file mode 100644
index 0000000..ab90f68
--- /dev/null
+++ b/src/xreq.cpp
@@ -0,0 +1,118 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "../include/zmq.h"
+
+#include "xreq.hpp"
+#include "err.hpp"
+
+zmq::xreq_t::xreq_t (class app_thread_t *parent_) :
+ socket_base_t (parent_),
+ dropping (false)
+{
+ options.requires_in = true;
+ options.requires_out = true;
+}
+
+zmq::xreq_t::~xreq_t ()
+{
+}
+
+void zmq::xreq_t::xattach_pipes (class reader_t *inpipe_,
+ class writer_t *outpipe_, const blob_t &peer_identity_)
+{
+ zmq_assert (inpipe_ && outpipe_);
+ fq.attach (inpipe_);
+ lb.attach (outpipe_);
+}
+
+void zmq::xreq_t::xdetach_inpipe (class reader_t *pipe_)
+{
+ zmq_assert (pipe_);
+ fq.detach (pipe_);
+}
+
+void zmq::xreq_t::xdetach_outpipe (class writer_t *pipe_)
+{
+ zmq_assert (pipe_);
+ lb.detach (pipe_);
+}
+
+void zmq::xreq_t::xkill (class reader_t *pipe_)
+{
+ fq.kill (pipe_);
+}
+
+void zmq::xreq_t::xrevive (class reader_t *pipe_)
+{
+ fq.revive (pipe_);
+}
+
+void zmq::xreq_t::xrevive (class writer_t *pipe_)
+{
+ lb.revive (pipe_);
+}
+
+int zmq::xreq_t::xsetsockopt (int option_, const void *optval_,
+ size_t optvallen_)
+{
+ errno = EINVAL;
+ return -1;
+}
+
+int zmq::xreq_t::xsend (zmq_msg_t *msg_, int flags_)
+{
+ while (true) {
+
+ // If we are ignoring the current message, just drop it and return.
+ if (dropping) {
+ if (!(msg_->flags & ZMQ_MSG_MORE))
+ dropping = false;
+ int rc = zmq_msg_close (msg_);
+ zmq_assert (rc == 0);
+ rc = zmq_msg_init (msg_);
+ zmq_assert (rc == 0);
+ return 0;
+ }
+
+ int rc = lb.send (msg_, flags_);
+ if (rc != 0 && errno == EAGAIN)
+ dropping = true;
+ else
+ return rc;
+ }
+}
+
+int zmq::xreq_t::xrecv (zmq_msg_t *msg_, int flags_)
+{
+ return fq.recv (msg_, flags_);
+}
+
+bool zmq::xreq_t::xhas_in ()
+{
+ return fq.has_in ();
+}
+
+bool zmq::xreq_t::xhas_out ()
+{
+ // Socket is always ready for writing. When the queue is full, message
+ // will be silently dropped.
+ return true;
+}
+
diff --git a/src/xreq.hpp b/src/xreq.hpp
new file mode 100644
index 0000000..25a97f1
--- /dev/null
+++ b/src/xreq.hpp
@@ -0,0 +1,67 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_XREQ_HPP_INCLUDED__
+#define __ZMQ_XREQ_HPP_INCLUDED__
+
+#include "socket_base.hpp"
+#include "fq.hpp"
+#include "lb.hpp"
+
+namespace zmq
+{
+
+ class xreq_t : public socket_base_t
+ {
+ public:
+
+ xreq_t (class app_thread_t *parent_);
+ ~xreq_t ();
+
+ // Overloads of functions from socket_base_t.
+ void xattach_pipes (class reader_t *inpipe_, class writer_t *outpipe_,
+ const blob_t &peer_identity_);
+ void xdetach_inpipe (class reader_t *pipe_);
+ void xdetach_outpipe (class writer_t *pipe_);
+ void xkill (class reader_t *pipe_);
+ void xrevive (class reader_t *pipe_);
+ void xrevive (class writer_t *pipe_);
+ int xsetsockopt (int option_, const void *optval_, size_t optvallen_);
+ int xsend (zmq_msg_t *msg_, int flags_);
+ int xrecv (zmq_msg_t *msg_, int flags_);
+ bool xhas_in ();
+ bool xhas_out ();
+
+ private:
+
+ // Messages are fair-queued from inbound pipes. And load-balanced to
+ // the outbound pipes.
+ fq_t fq;
+ lb_t lb;
+
+ // If true, curently sent message is being dropped.
+ bool dropping;
+
+ xreq_t (const xreq_t&);
+ void operator = (const xreq_t&);
+ };
+
+}
+
+#endif
diff --git a/src/yarray.hpp b/src/yarray.hpp
new file mode 100644
index 0000000..8c79b99
--- /dev/null
+++ b/src/yarray.hpp
@@ -0,0 +1,110 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_YARRAY_INCLUDED__
+#define __ZMQ_YARRAY_INCLUDED__
+
+#include <vector>
+#include <algorithm>
+
+namespace zmq
+{
+
+ // Fast array implementation with O(1) access to item, insertion and
+ // removal. Yarray stores pointers rather than objects. The objects have
+ // to be derived from yarray_item_t class.
+
+ template <typename T> class yarray_t
+ {
+ public:
+
+ typedef typename std::vector <T*>::size_type size_type;
+
+ inline yarray_t ()
+ {
+ }
+
+ inline ~yarray_t ()
+ {
+ }
+
+ inline size_type size ()
+ {
+ return items.size ();
+ }
+
+ inline bool empty ()
+ {
+ return items.empty ();
+ }
+
+ inline T *&operator [] (size_type index_)
+ {
+ return items [index_];
+ }
+
+ inline void push_back (T *item_)
+ {
+ if (item_)
+ item_->set_yarray_index (items.size ());
+ items.push_back (item_);
+ }
+
+ inline void erase (T *item_) {
+ erase (item_->get_yarray_index ());
+ }
+
+ inline void erase (size_type index_) {
+ if (items.back ())
+ items.back ()->set_yarray_index (index_);
+ items [index_] = items.back ();
+ items.pop_back ();
+ }
+
+ inline void swap (size_type index1_, size_type index2_)
+ {
+ if (items [index1_])
+ items [index1_]->set_yarray_index (index2_);
+ if (items [index2_])
+ items [index2_]->set_yarray_index (index1_);
+ std::swap (items [index1_], items [index2_]);
+ }
+
+ inline void clear ()
+ {
+ items.clear ();
+ }
+
+ inline size_type index (T *item_)
+ {
+ return (size_type) item_->get_yarray_index ();
+ }
+
+ private:
+
+ typedef std::vector <T*> items_t;
+ items_t items;
+
+ yarray_t (const yarray_t&);
+ void operator = (const yarray_t&);
+ };
+
+}
+
+#endif
diff --git a/src/yarray_item.hpp b/src/yarray_item.hpp
new file mode 100644
index 0000000..b6d89cc
--- /dev/null
+++ b/src/yarray_item.hpp
@@ -0,0 +1,62 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_YARRAY_ITEM_INCLUDED__
+#define __ZMQ_YARRAY_ITEM_INCLUDED__
+
+namespace zmq
+{
+
+ // Base class for objects stored in yarray. Note that each object can
+ // be stored in at most one yarray.
+
+ class yarray_item_t
+ {
+ public:
+
+ inline yarray_item_t () :
+ yarray_index (-1)
+ {
+ }
+
+ inline ~yarray_item_t ()
+ {
+ }
+
+ inline void set_yarray_index (int index_)
+ {
+ yarray_index = index_;
+ }
+
+ inline int get_yarray_index ()
+ {
+ return yarray_index;
+ }
+
+ private:
+
+ int yarray_index;
+
+ yarray_item_t (const yarray_item_t&);
+ void operator = (const yarray_item_t&);
+ };
+
+}
+
+#endif
diff --git a/src/ypipe.hpp b/src/ypipe.hpp
new file mode 100644
index 0000000..df5b3d0
--- /dev/null
+++ b/src/ypipe.hpp
@@ -0,0 +1,191 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_YPIPE_HPP_INCLUDED__
+#define __ZMQ_YPIPE_HPP_INCLUDED__
+
+#include "atomic_ptr.hpp"
+#include "yqueue.hpp"
+#include "platform.hpp"
+
+namespace zmq
+{
+
+ // Lock-free queue implementation.
+ // Only a single thread can read from the pipe at any specific moment.
+ // Only a single thread can write to the pipe at any specific moment.
+ // T is the type of the object in the queue.
+ // N is granularity of the pipe, i.e. how many items are needed to
+ // perform next memory allocation.
+
+ template <typename T, int N> class ypipe_t
+ {
+ public:
+
+ // Initialises the pipe.
+ inline ypipe_t ()
+ {
+ // Insert terminator element into the queue.
+ queue.push ();
+
+ // Let all the pointers to point to the terminator.
+ // (unless pipe is dead, in which case c is set to NULL).
+ r = w = f = &queue.back ();
+ c.set (&queue.back ());
+ }
+
+ // Following function (write) deliberately copies uninitialised data
+ // when used with zmq_msg. Initialising the VSM body for
+ // non-VSM messages won't be good for performance.
+
+#ifdef ZMQ_HAVE_OPENVMS
+#pragma message save
+#pragma message disable(UNINIT)
+#endif
+
+ // Write an item to the pipe. Don't flush it yet. If incomplete is
+ // set to true the item is assumed to be continued by items
+ // subsequently written to the pipe. Incomplete items are never
+ // flushed down the stream.
+ inline void write (const T &value_, bool incomplete_)
+ {
+ // Place the value to the queue, add new terminator element.
+ queue.back () = value_;
+ queue.push ();
+
+ // Move the "flush up to here" poiter.
+ if (!incomplete_)
+ f = &queue.back ();
+ }
+
+#ifdef ZMQ_HAVE_OPENVMS
+#pragma message restore
+#endif
+
+ // Pop an incomplete item from the pipe. Returns true is such
+ // item exists, false otherwise.
+ inline bool unwrite (T *value_)
+ {
+ if (f == &queue.back ())
+ return false;
+ queue.unpush ();
+ *value_ = queue.back ();
+ return true;
+ }
+
+ // Flush all the completed items into the pipe. Returns false if
+ // the reader thread is sleeping. In that case, caller is obliged to
+ // wake the reader up before using the pipe again.
+ inline bool flush ()
+ {
+ // If there are no un-flushed items, do nothing.
+ if (w == f)
+ return true;
+
+ // Try to set 'c' to 'f'.
+ if (c.cas (w, f) != w) {
+
+ // Compare-and-swap was unseccessful because 'c' is NULL.
+ // This means that the reader is asleep. Therefore we don't
+ // care about thread-safeness and update c in non-atomic
+ // manner. We'll return false to let the caller know
+ // that reader is sleeping.
+ c.set (f);
+ w = f;
+ return false;
+ }
+
+ // Reader is alive. Nothing special to do now. Just move
+ // the 'first un-flushed item' pointer to 'f'.
+ w = f;
+ return true;
+ }
+
+ // Check whether item is available for reading.
+ inline bool check_read ()
+ {
+ // Was the value prefetched already? If so, return.
+ if (&queue.front () != r)
+ return true;
+
+ // There's no prefetched value, so let us prefetch more values.
+ // Prefetching is to simply retrieve the
+ // pointer from c in atomic fashion. If there are no
+ // items to prefetch, set c to NULL (using compare-and-swap).
+ r = c.cas (&queue.front (), NULL);
+
+ // If there are no elements prefetched, exit.
+ // During pipe's lifetime r should never be NULL, however,
+ // it can happen during pipe shutdown when items
+ // are being deallocated.
+ if (&queue.front () == r || !r)
+ return false;
+
+ // There was at least one value prefetched.
+ return true;
+ }
+
+ // Reads an item from the pipe. Returns false if there is no value.
+ // available.
+ inline bool read (T *value_)
+ {
+ // Try to prefetch a value.
+ if (!check_read ())
+ return false;
+
+ // There was at least one value prefetched.
+ // Return it to the caller.
+ *value_ = queue.front ();
+ queue.pop ();
+ return true;
+ }
+
+ protected:
+
+ // Allocation-efficient queue to store pipe items.
+ // Front of the queue points to the first prefetched item, back of
+ // the pipe points to last un-flushed item. Front is used only by
+ // reader thread, while back is used only by writer thread.
+ yqueue_t <T, N> queue;
+
+ // Points to the first un-flushed item. This variable is used
+ // exclusively by writer thread.
+ T *w;
+
+ // Points to the first un-prefetched item. This variable is used
+ // exclusively by reader thread.
+ T *r;
+
+ // Points to the first item to be flushed in the future.
+ T *f;
+
+ // The single point of contention between writer and reader thread.
+ // Points past the last flushed item. If it is NULL,
+ // reader is asleep. This pointer should be always accessed using
+ // atomic operations.
+ atomic_ptr_t <T> c;
+
+ // Disable copying of ypipe object.
+ ypipe_t (const ypipe_t&);
+ void operator = (const ypipe_t&);
+ };
+
+}
+
+#endif
diff --git a/src/yqueue.hpp b/src/yqueue.hpp
new file mode 100644
index 0000000..9eaceb5
--- /dev/null
+++ b/src/yqueue.hpp
@@ -0,0 +1,197 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_YQUEUE_HPP_INCLUDED__
+#define __ZMQ_YQUEUE_HPP_INCLUDED__
+
+#include <stdlib.h>
+#include <stddef.h>
+
+#include "err.hpp"
+#include "atomic_ptr.hpp"
+
+namespace zmq
+{
+
+ // yqueue is an efficient queue implementation. The main goal is
+ // to minimise number of allocations/deallocations needed. Thus yqueue
+ // allocates/deallocates elements in batches of N.
+ //
+ // yqueue allows one thread to use push/back function and another one
+ // to use pop/front functions. However, user must ensure that there's no
+ // pop on the empty queue and that both threads don't access the same
+ // element in unsynchronised manner.
+ //
+ // T is the type of the object in the queue.
+ // N is granularity of the queue (how many pushes have to be done till
+ // actual memory allocation is required).
+
+ template <typename T, int N> class yqueue_t
+ {
+ public:
+
+ // Create the queue.
+ inline yqueue_t ()
+ {
+ begin_chunk = (chunk_t*) malloc (sizeof (chunk_t));
+ zmq_assert (begin_chunk);
+ begin_pos = 0;
+ back_chunk = NULL;
+ back_pos = 0;
+ end_chunk = begin_chunk;
+ end_pos = 0;
+ }
+
+ // Destroy the queue.
+ inline ~yqueue_t ()
+ {
+ while (true) {
+ if (begin_chunk == end_chunk) {
+ free (begin_chunk);
+ break;
+ }
+ chunk_t *o = begin_chunk;
+ begin_chunk = begin_chunk->next;
+ free (o);
+ }
+
+ chunk_t *sc = spare_chunk.xchg (NULL);
+ if (sc)
+ free (sc);
+ }
+
+ // Returns reference to the front element of the queue.
+ // If the queue is empty, behaviour is undefined.
+ inline T &front ()
+ {
+ return begin_chunk->values [begin_pos];
+ }
+
+ // Returns reference to the back element of the queue.
+ // If the queue is empty, behaviour is undefined.
+ inline T &back ()
+ {
+ return back_chunk->values [back_pos];
+ }
+
+ // Adds an element to the back end of the queue.
+ inline void push ()
+ {
+ back_chunk = end_chunk;
+ back_pos = end_pos;
+
+ if (++end_pos != N)
+ return;
+
+ chunk_t *sc = spare_chunk.xchg (NULL);
+ if (sc) {
+ end_chunk->next = sc;
+ sc->prev = end_chunk;
+ } else {
+ end_chunk->next = (chunk_t*) malloc (sizeof (chunk_t));
+ zmq_assert (end_chunk->next);
+ end_chunk->next->prev = end_chunk;
+ }
+ end_chunk = end_chunk->next;
+ end_pos = 0;
+ }
+
+ // Removes element from the back end of the queue. In other words
+ // it rollbacks last push to the queue. Take care: Caller is
+ // responsible for destroying the object being unpushed.
+ // The caller must also guarantee that the queue isn't empty when
+ // unpush is called. It cannot be done automatically as the read
+ // side of the queue can be managed by different, completely
+ // unsynchronised thread.
+ inline void unpush ()
+ {
+ // First, move 'back' one position backwards.
+ if (back_pos)
+ --back_pos;
+ else {
+ back_pos = N - 1;
+ back_chunk = back_chunk->prev;
+ }
+
+ // Now, move 'end' position backwards. Note that obsolete end chunk
+ // is not used as a spare chunk. The analysis shows that doing so
+ // would require free and atomic operation per chunk deallocated
+ // instead of a simple free.
+ if (end_pos)
+ --end_pos;
+ else {
+ end_pos = N - 1;
+ end_chunk = end_chunk->prev;
+ free (end_chunk->next);
+ end_chunk->next = NULL;
+ }
+ }
+
+ // Removes an element from the front end of the queue.
+ inline void pop ()
+ {
+ if (++ begin_pos == N) {
+ chunk_t *o = begin_chunk;
+ begin_chunk = begin_chunk->next;
+ begin_chunk->prev = NULL;
+ begin_pos = 0;
+
+ // 'o' has been more recently used than spare_chunk,
+ // so for cache reasons we'll get rid of the spare and
+ // use 'o' as the spare.
+ chunk_t *cs = spare_chunk.xchg (o);
+ if (cs)
+ free (cs);
+ }
+ }
+
+ private:
+
+ // Individual memory chunk to hold N elements.
+ struct chunk_t
+ {
+ T values [N];
+ chunk_t *prev;
+ chunk_t *next;
+ };
+
+ // Back position may point to invalid memory if the queue is empty,
+ // while begin & end positions are always valid. Begin position is
+ // accessed exclusively be queue reader (front/pop), while back and
+ // end positions are accessed exclusively by queue writer (back/push).
+ chunk_t *begin_chunk;
+ int begin_pos;
+ chunk_t *back_chunk;
+ int back_pos;
+ chunk_t *end_chunk;
+ int end_pos;
+
+ // People are likely to produce and consume at similar rates. In
+ // this scenario holding onto the most recently freed chunk saves
+ // us from having to call malloc/free.
+ atomic_ptr_t<chunk_t> spare_chunk;
+
+ // Disable copying of yqueue.
+ yqueue_t (const yqueue_t&);
+ void operator = (const yqueue_t&);
+ };
+
+}
+
+#endif
diff --git a/src/zmq.cpp b/src/zmq.cpp
new file mode 100644
index 0000000..c8f419a
--- /dev/null
+++ b/src/zmq.cpp
@@ -0,0 +1,663 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "../include/zmq.h"
+
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <new>
+
+#include "forwarder.hpp"
+#include "queue.hpp"
+#include "streamer.hpp"
+#include "socket_base.hpp"
+#include "app_thread.hpp"
+#include "msg_content.hpp"
+#include "platform.hpp"
+#include "stdint.hpp"
+#include "config.hpp"
+#include "ctx.hpp"
+#include "err.hpp"
+#include "fd.hpp"
+
+#if defined ZMQ_HAVE_LINUX || defined ZMQ_HAVE_FREEBSD ||\
+ defined ZMQ_HAVE_OPENBSD || defined ZMQ_HAVE_SOLARIS ||\
+ defined ZMQ_HAVE_OSX || defined ZMQ_HAVE_QNXNTO ||\
+ defined ZMQ_HAVE_HPUX || defined ZMQ_HAVE_AIX ||\
+ defined ZMQ_HAVE_NETBSD
+#include <poll.h>
+#endif
+
+#if !defined ZMQ_HAVE_WINDOWS
+#include <unistd.h>
+#include <sys/time.h>
+#endif
+
+#if defined ZMQ_HAVE_OPENPGM
+#include <pgm/pgm.h>
+#endif
+
+void zmq_version (int *major_, int *minor_, int *patch_)
+{
+ *major_ = PACKAGE_VERSION_MAJOR;
+ *minor_ = PACKAGE_VERSION_MINOR;
+ *patch_ = PACKAGE_VERSION_PATCH;
+}
+
+const char *zmq_strerror (int errnum_)
+{
+ switch (errnum_) {
+#if defined ZMQ_HAVE_WINDOWS
+ case ENOTSUP:
+ return "Not supported";
+ case EPROTONOSUPPORT:
+ return "Protocol not supported";
+ case ENOBUFS:
+ return "No buffer space available";
+ case ENETDOWN:
+ return "Network is down";
+ case EADDRINUSE:
+ return "Address in use";
+ case EADDRNOTAVAIL:
+ return "Address not available";
+ case ECONNREFUSED:
+ return "Connection refused";
+ case EINPROGRESS:
+ return "Operation in progress";
+#endif
+ case EMTHREAD:
+ return "Number of preallocated application threads exceeded";
+ case EFSM:
+ return "Operation cannot be accomplished in current state";
+ case ENOCOMPATPROTO:
+ return "The protocol is not compatible with the socket type";
+ case ETERM:
+ return "Context was terminated";
+ default:
+#if defined _MSC_VER
+#pragma warning (push)
+#pragma warning (disable:4996)
+#endif
+ return strerror (errnum_);
+#if defined _MSC_VER
+#pragma warning (pop)
+#endif
+ }
+}
+
+int zmq_msg_init (zmq_msg_t *msg_)
+{
+ msg_->content = (zmq::msg_content_t*) ZMQ_VSM;
+ msg_->flags = 0;
+ msg_->vsm_size = 0;
+ return 0;
+}
+
+int zmq_msg_init_size (zmq_msg_t *msg_, size_t size_)
+{
+ if (size_ <= ZMQ_MAX_VSM_SIZE) {
+ msg_->content = (zmq::msg_content_t*) ZMQ_VSM;
+ msg_->flags = 0;
+ msg_->vsm_size = (uint8_t) size_;
+ }
+ else {
+ msg_->content =
+ (zmq::msg_content_t*) malloc (sizeof (zmq::msg_content_t) + size_);
+ if (!msg_->content) {
+ errno = ENOMEM;
+ return -1;
+ }
+ msg_->flags = 0;
+
+ zmq::msg_content_t *content = (zmq::msg_content_t*) msg_->content;
+ content->data = (void*) (content + 1);
+ content->size = size_;
+ content->ffn = NULL;
+ content->hint = NULL;
+ new (&content->refcnt) zmq::atomic_counter_t ();
+ }
+ return 0;
+}
+
+int zmq_msg_init_data (zmq_msg_t *msg_, void *data_, size_t size_,
+ zmq_free_fn *ffn_, void *hint_)
+{
+ msg_->content = (zmq::msg_content_t*) malloc (sizeof (zmq::msg_content_t));
+ zmq_assert (msg_->content);
+ msg_->flags = 0;
+ zmq::msg_content_t *content = (zmq::msg_content_t*) msg_->content;
+ content->data = data_;
+ content->size = size_;
+ content->ffn = ffn_;
+ content->hint = hint_;
+ new (&content->refcnt) zmq::atomic_counter_t ();
+ return 0;
+}
+
+int zmq_msg_close (zmq_msg_t *msg_)
+{
+ // For VSMs and delimiters there are no resources to free.
+ if (msg_->content == (zmq::msg_content_t*) ZMQ_DELIMITER ||
+ msg_->content == (zmq::msg_content_t*) ZMQ_VSM)
+ return 0;
+
+ // If the content is not shared, or if it is shared and the reference.
+ // count has dropped to zero, deallocate it.
+ zmq::msg_content_t *content = (zmq::msg_content_t*) msg_->content;
+ if (!(msg_->flags & ZMQ_MSG_SHARED) || !content->refcnt.sub (1)) {
+
+ // We used "placement new" operator to initialize the reference.
+ // counter so we call its destructor now.
+ content->refcnt.~atomic_counter_t ();
+
+ if (content->ffn)
+ content->ffn (content->data, content->hint);
+ free (content);
+ }
+
+ return 0;
+}
+
+int zmq_msg_move (zmq_msg_t *dest_, zmq_msg_t *src_)
+{
+ zmq_msg_close (dest_);
+ *dest_ = *src_;
+ zmq_msg_init (src_);
+ return 0;
+}
+
+int zmq_msg_copy (zmq_msg_t *dest_, zmq_msg_t *src_)
+{
+ zmq_msg_close (dest_);
+
+ // VSMs and delimiters require no special handling.
+ if (src_->content != (zmq::msg_content_t*) ZMQ_DELIMITER &&
+ src_->content != (zmq::msg_content_t*) ZMQ_VSM) {
+
+ // One reference is added to shared messages. Non-shared messages
+ // are turned into shared messages and reference count is set to 2.
+ zmq::msg_content_t *content = (zmq::msg_content_t*) src_->content;
+ if (src_->flags & ZMQ_MSG_SHARED)
+ content->refcnt.add (1);
+ else {
+ src_->flags |= ZMQ_MSG_SHARED;
+ content->refcnt.set (2);
+ }
+ }
+
+ *dest_ = *src_;
+ return 0;
+}
+
+void *zmq_msg_data (zmq_msg_t *msg_)
+{
+ if (msg_->content == (zmq::msg_content_t*) ZMQ_VSM)
+ return msg_->vsm_data;
+ if (msg_->content == (zmq::msg_content_t*) ZMQ_DELIMITER)
+ return NULL;
+
+ return ((zmq::msg_content_t*) msg_->content)->data;
+}
+
+size_t zmq_msg_size (zmq_msg_t *msg_)
+{
+ if (msg_->content == (zmq::msg_content_t*) ZMQ_VSM)
+ return msg_->vsm_size;
+ if (msg_->content == (zmq::msg_content_t*) ZMQ_DELIMITER)
+ return 0;
+
+ return ((zmq::msg_content_t*) msg_->content)->size;
+}
+
+void *zmq_init (int io_threads_)
+{
+ if (io_threads_ < 0) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+#if defined ZMQ_HAVE_OPENPGM
+ // Unfortunately, OpenPGM doesn't support refcounted init/shutdown, thus,
+ // let's fail if it was initialised beforehand.
+ zmq_assert (!pgm_supported ());
+
+ // Init PGM transport. Ensure threading and timer are enabled. Find PGM
+ // protocol ID. Note that if you want to use gettimeofday and sleep for
+ // openPGM timing, set environment variables PGM_TIMER to "GTOD" and
+ // PGM_SLEEP to "USLEEP".
+ GError *pgm_error = NULL;
+ int rc = pgm_init (&pgm_error);
+ if (rc != TRUE) {
+ if (pgm_error->domain == PGM_IF_ERROR && (
+ pgm_error->code == PGM_IF_ERROR_INVAL ||
+ pgm_error->code == PGM_IF_ERROR_XDEV ||
+ pgm_error->code == PGM_IF_ERROR_NODEV ||
+ pgm_error->code == PGM_IF_ERROR_NOTUNIQ ||
+ pgm_error->code == PGM_IF_ERROR_ADDRFAMILY ||
+ pgm_error->code == PGM_IF_ERROR_FAMILY ||
+ pgm_error->code == PGM_IF_ERROR_NODATA ||
+ pgm_error->code == PGM_IF_ERROR_NONAME ||
+ pgm_error->code == PGM_IF_ERROR_SERVICE)) {
+ g_error_free (pgm_error);
+ errno = EINVAL;
+ return NULL;
+ }
+ zmq_assert (false);
+ }
+#endif
+
+ // Create 0MQ context.
+ zmq::ctx_t *ctx = new (std::nothrow) zmq::ctx_t ((uint32_t) io_threads_);
+ zmq_assert (ctx);
+ return (void*) ctx;
+}
+
+int zmq_term (void *ctx_)
+{
+ int rc = ((zmq::ctx_t*) ctx_)->term ();
+ int en = errno;
+
+#if defined ZMQ_HAVE_OPENPGM
+ // Shut down the OpenPGM library.
+ if (pgm_shutdown () != TRUE)
+ zmq_assert (false);
+#endif
+
+ errno = en;
+ return rc;
+}
+
+void *zmq_socket (void *ctx_, int type_)
+{
+ return (void*) (((zmq::ctx_t*) ctx_)->create_socket (type_));
+}
+
+int zmq_close (void *s_)
+{
+ ((zmq::socket_base_t*) s_)->close ();
+ return 0;
+}
+
+int zmq_setsockopt (void *s_, int option_, const void *optval_,
+ size_t optvallen_)
+{
+ return (((zmq::socket_base_t*) s_)->setsockopt (option_, optval_,
+ optvallen_));
+}
+
+int zmq_getsockopt (void *s_, int option_, void *optval_, size_t *optvallen_)
+{
+ return (((zmq::socket_base_t*) s_)->getsockopt (option_, optval_,
+ optvallen_));
+}
+
+int zmq_bind (void *s_, const char *addr_)
+{
+ return (((zmq::socket_base_t*) s_)->bind (addr_));
+}
+
+int zmq_connect (void *s_, const char *addr_)
+{
+ return (((zmq::socket_base_t*) s_)->connect (addr_));
+}
+
+int zmq_send (void *s_, zmq_msg_t *msg_, int flags_)
+{
+ return (((zmq::socket_base_t*) s_)->send (msg_, flags_));
+}
+
+int zmq_recv (void *s_, zmq_msg_t *msg_, int flags_)
+{
+ return (((zmq::socket_base_t*) s_)->recv (msg_, flags_));
+}
+
+int zmq_poll (zmq_pollitem_t *items_, int nitems_, long timeout_)
+{
+#if defined ZMQ_HAVE_LINUX || defined ZMQ_HAVE_FREEBSD ||\
+ defined ZMQ_HAVE_OPENBSD || defined ZMQ_HAVE_SOLARIS ||\
+ defined ZMQ_HAVE_OSX || defined ZMQ_HAVE_QNXNTO ||\
+ defined ZMQ_HAVE_HPUX || defined ZMQ_HAVE_AIX ||\
+ defined ZMQ_HAVE_NETBSD
+
+ pollfd *pollfds = (pollfd*) malloc (nitems_ * sizeof (pollfd));
+ zmq_assert (pollfds);
+ int npollfds = 0;
+ int nsockets = 0;
+
+ zmq::app_thread_t *app_thread = NULL;
+
+ for (int i = 0; i != nitems_; i++) {
+
+ // 0MQ sockets.
+ if (items_ [i].socket) {
+
+ // Get the app_thread the socket is living in. If there are two
+ // sockets in the same pollset with different app threads, fail.
+ zmq::socket_base_t *s = (zmq::socket_base_t*) items_ [i].socket;
+ if (app_thread) {
+ if (app_thread != s->get_thread ()) {
+ free (pollfds);
+ errno = EFAULT;
+ return -1;
+ }
+ }
+ else
+ app_thread = s->get_thread ();
+
+ nsockets++;
+ continue;
+ }
+
+ // Raw file descriptors.
+ pollfds [npollfds].fd = items_ [i].fd;
+ pollfds [npollfds].events =
+ (items_ [i].events & ZMQ_POLLIN ? POLLIN : 0) |
+ (items_ [i].events & ZMQ_POLLOUT ? POLLOUT : 0);
+ npollfds++;
+ }
+
+ // If there's at least one 0MQ socket in the pollset we have to poll
+ // for 0MQ commands. If ZMQ_POLL was not set, fail.
+ if (nsockets) {
+ pollfds [npollfds].fd = app_thread->get_signaler ()->get_fd ();
+ if (pollfds [npollfds].fd == zmq::retired_fd) {
+ free (pollfds);
+ errno = ENOTSUP;
+ return -1;
+ }
+ pollfds [npollfds].events = POLLIN;
+ npollfds++;
+ }
+
+ // First iteration just check for events, don't block. Waiting would
+ // prevent exiting on any events that may already been signaled on
+ // 0MQ sockets.
+ int rc = poll (pollfds, npollfds, 0);
+ if (rc == -1 && errno == EINTR && timeout_ >= 0) {
+ free (pollfds);
+ return 0;
+ }
+ errno_assert (rc >= 0 || (rc == -1 && errno == EINTR));
+
+ int timeout = timeout_ > 0 ? timeout_ / 1000 : -1;
+ int nevents = 0;
+
+ while (true) {
+
+ // Process 0MQ commands if needed.
+ if (nsockets && pollfds [npollfds -1].revents & POLLIN)
+ if (!app_thread->process_commands (false, false)) {
+ free (pollfds);
+ errno = ETERM;
+ return -1;
+ }
+
+ // Check for the events.
+ int pollfd_pos = 0;
+ for (int i = 0; i != nitems_; i++) {
+
+ // If the poll item is a raw file descriptor, simply convert
+ // the events to zmq_pollitem_t-style format.
+ if (!items_ [i].socket) {
+ items_ [i].revents = 0;
+ if (pollfds [pollfd_pos].revents & POLLIN)
+ items_ [i].revents |= ZMQ_POLLIN;
+ if (pollfds [pollfd_pos].revents & POLLOUT)
+ items_ [i].revents |= ZMQ_POLLOUT;
+ if (pollfds [pollfd_pos].revents & ~(POLLIN | POLLOUT))
+ items_ [i].revents |= ZMQ_POLLERR;
+
+ if (items_ [i].revents)
+ nevents++;
+ pollfd_pos++;
+ continue;
+ }
+
+ // The poll item is a 0MQ socket.
+ zmq::socket_base_t *s = (zmq::socket_base_t*) items_ [i].socket;
+ items_ [i].revents = 0;
+ if ((items_ [i].events & ZMQ_POLLOUT) && s->has_out ())
+ items_ [i].revents |= ZMQ_POLLOUT;
+ if ((items_ [i].events & ZMQ_POLLIN) && s->has_in ())
+ items_ [i].revents |= ZMQ_POLLIN;
+ if (items_ [i].revents)
+ nevents++;
+ }
+
+ // If there's at least one event, or if we are asked not to block,
+ // return immediately.
+ if (nevents || !timeout_)
+ break;
+
+ // Wait for events. Ignore interrupts if there's infinite timeout.
+ while (true) {
+ rc = poll (pollfds, npollfds, timeout);
+ if (rc == -1 && errno == EINTR) {
+ if (timeout_ < 0)
+ continue;
+ else {
+ rc = 0;
+ break;
+ }
+ }
+ errno_assert (rc >= 0);
+ break;
+ }
+
+ // If timeout was hit with no events signaled, return zero.
+ if (rc == 0)
+ break;
+
+ // If timeout was already applied, we don't want to poll anymore.
+ // Setting timeout to zero will cause termination of the function
+ // once the events we've got are processed.
+ if (timeout > 0)
+ timeout = 0;
+ }
+
+ free (pollfds);
+ return nevents;
+
+#elif defined ZMQ_HAVE_WINDOWS || defined ZMQ_HAVE_OPENVMS
+
+ fd_set pollset_in;
+ FD_ZERO (&pollset_in);
+ fd_set pollset_out;
+ FD_ZERO (&pollset_out);
+ fd_set pollset_err;
+ FD_ZERO (&pollset_err);
+
+ zmq::app_thread_t *app_thread = NULL;
+ int nsockets = 0;
+ zmq::fd_t maxfd = zmq::retired_fd;
+ zmq::fd_t notify_fd = zmq::retired_fd;
+
+ for (int i = 0; i != nitems_; i++) {
+
+ // 0MQ sockets.
+ if (items_ [i].socket) {
+
+ // Get the app_thread the socket is living in. If there are two
+ // sockets in the same pollset with different app threads, fail.
+ zmq::socket_base_t *s = (zmq::socket_base_t*) items_ [i].socket;
+ if (app_thread) {
+ if (app_thread != s->get_thread ()) {
+ errno = EFAULT;
+ return -1;
+ }
+ }
+ else
+ app_thread = s->get_thread ();
+
+ nsockets++;
+ continue;
+ }
+
+ // Raw file descriptors.
+ if (items_ [i].events & ZMQ_POLLIN)
+ FD_SET (items_ [i].fd, &pollset_in);
+ if (items_ [i].events & ZMQ_POLLOUT)
+ FD_SET (items_ [i].fd, &pollset_out);
+ if (items_ [i].events & ZMQ_POLLERR)
+ FD_SET (items_ [i].fd, &pollset_err);
+ if (maxfd == zmq::retired_fd || maxfd < items_ [i].fd)
+ maxfd = items_ [i].fd;
+ }
+
+ // If there's at least one 0MQ socket in the pollset we have to poll
+ // for 0MQ commands. If ZMQ_POLL was not set, fail.
+ if (nsockets) {
+ notify_fd = app_thread->get_signaler ()->get_fd ();
+ if (notify_fd == zmq::retired_fd) {
+ errno = ENOTSUP;
+ return -1;
+ }
+ FD_SET (notify_fd, &pollset_in);
+ if (maxfd == zmq::retired_fd || maxfd < notify_fd)
+ maxfd = notify_fd;
+ }
+
+ bool block = (timeout_ < 0);
+ timeval timeout = {timeout_ / 1000000, timeout_ % 1000000};
+ timeval zero_timeout = {0, 0};
+ int nevents = 0;
+
+ // First iteration just check for events, don't block. Waiting would
+ // prevent exiting on any events that may already been signaled on
+ // 0MQ sockets.
+ fd_set inset, outset, errset;
+ memcpy (&inset, &pollset_in, sizeof (fd_set));
+ memcpy (&outset, &pollset_out, sizeof (fd_set));
+ memcpy (&errset, &pollset_err, sizeof (fd_set));
+ int rc = select (maxfd, &inset, &outset, &errset, &zero_timeout);
+#if defined ZMQ_HAVE_WINDOWS
+ wsa_assert (rc != SOCKET_ERROR);
+#else
+ if (rc == -1 && errno == EINTR && timeout_ >= 0)
+ return 0;
+ errno_assert (rc >= 0 || (rc == -1 && errno == EINTR));
+#endif
+
+ while (true) {
+
+ // Process 0MQ commands if needed.
+ if (nsockets && FD_ISSET (notify_fd, &inset))
+ if (!app_thread->process_commands (false, false)) {
+ errno = ETERM;
+ return -1;
+ }
+
+ // Check for the events.
+ for (int i = 0; i != nitems_; i++) {
+
+ // If the poll item is a raw file descriptor, simply convert
+ // the events to zmq_pollitem_t-style format.
+ if (!items_ [i].socket) {
+ items_ [i].revents = 0;
+ if (FD_ISSET (items_ [i].fd, &inset))
+ items_ [i].revents |= ZMQ_POLLIN;
+ if (FD_ISSET (items_ [i].fd, &outset))
+ items_ [i].revents |= ZMQ_POLLOUT;
+ if (FD_ISSET (items_ [i].fd, &errset))
+ items_ [i].revents |= ZMQ_POLLERR;
+ if (items_ [i].revents)
+ nevents++;
+ continue;
+ }
+
+ // The poll item is a 0MQ socket.
+ zmq::socket_base_t *s = (zmq::socket_base_t*) items_ [i].socket;
+ items_ [i].revents = 0;
+ if ((items_ [i].events & ZMQ_POLLOUT) && s->has_out ())
+ items_ [i].revents |= ZMQ_POLLOUT;
+ if ((items_ [i].events & ZMQ_POLLIN) && s->has_in ())
+ items_ [i].revents |= ZMQ_POLLIN;
+ if (items_ [i].revents)
+ nevents++;
+ }
+
+ // If there's at least one event, or if we are asked not to block,
+ // return immediately.
+ if (nevents || (timeout.tv_sec == 0 && timeout.tv_usec == 0))
+ break;
+
+ // Wait for events. Ignore interrupts if there's infinite timeout.
+ while (true) {
+ memcpy (&inset, &pollset_in, sizeof (fd_set));
+ memcpy (&outset, &pollset_out, sizeof (fd_set));
+ memcpy (&errset, &pollset_err, sizeof (fd_set));
+ rc = select (maxfd, &inset, &outset, &errset,
+ block ? NULL : &timeout);
+#if defined ZMQ_HAVE_WINDOWS
+ wsa_assert (rc != SOCKET_ERROR);
+#else
+ if (rc == -1 && errno == EINTR) {
+ if (timeout_ < 0)
+ continue;
+ else {
+ rc = 0;
+ break;
+ }
+ }
+ errno_assert (rc >= 0);
+#endif
+ break;
+ }
+
+ // If timeout was hit with no events signaled, return zero.
+ if (rc == 0)
+ break;
+
+ // If timeout was already applied, we don't want to poll anymore.
+ // Setting timeout to zero will cause termination of the function
+ // once the events we've got are processed.
+ if (!block)
+ timeout = zero_timeout;
+ }
+
+ return nevents;
+
+#else
+ errno = ENOTSUP;
+ return -1;
+#endif
+}
+
+int zmq_errno ()
+{
+ return errno;
+}
+
+int zmq_device (int device_, void *insocket_, void *outsocket_)
+{
+ switch (device_) {
+ case ZMQ_FORWARDER:
+ return zmq::forwarder ((zmq::socket_base_t*) insocket_,
+ (zmq::socket_base_t*) outsocket_);
+ case ZMQ_QUEUE:
+ return zmq::queue ((zmq::socket_base_t*) insocket_,
+ (zmq::socket_base_t*) outsocket_);
+ case ZMQ_STREAMER:
+ return zmq::streamer ((zmq::socket_base_t*) insocket_,
+ (zmq::socket_base_t*) outsocket_);
+ default:
+ return EINVAL;
+ }
+}
diff --git a/src/zmq_connecter.cpp b/src/zmq_connecter.cpp
new file mode 100644
index 0000000..ebd7572
--- /dev/null
+++ b/src/zmq_connecter.cpp
@@ -0,0 +1,136 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <new>
+
+#include "zmq_connecter.hpp"
+#include "zmq_engine.hpp"
+#include "zmq_init.hpp"
+#include "io_thread.hpp"
+#include "err.hpp"
+
+zmq::zmq_connecter_t::zmq_connecter_t (io_thread_t *parent_,
+ socket_base_t *owner_, const options_t &options_,
+ uint64_t session_ordinal_, bool wait_) :
+ owned_t (parent_, owner_),
+ io_object_t (parent_),
+ handle_valid (false),
+ wait (wait_),
+ session_ordinal (session_ordinal_),
+ options (options_)
+{
+}
+
+zmq::zmq_connecter_t::~zmq_connecter_t ()
+{
+}
+
+int zmq::zmq_connecter_t::set_address (const char *protocol_,
+ const char *address_)
+{
+ int rc = tcp_connecter.set_address (protocol_, address_);
+ if (rc != 0)
+ return rc;
+ protocol = protocol_;
+ address = address_;
+ return 0;
+}
+
+void zmq::zmq_connecter_t::process_plug ()
+{
+ if (wait)
+ add_timer ();
+ else
+ start_connecting ();
+}
+
+void zmq::zmq_connecter_t::process_unplug ()
+{
+ if (wait)
+ cancel_timer ();
+ if (handle_valid)
+ rm_fd (handle);
+}
+
+void zmq::zmq_connecter_t::in_event ()
+{
+ // We are not polling for incomming data, so we are actually called
+ // because of error here. However, we can get error on out event as well
+ // on some platforms, so we'll simply handle both events in the same way.
+ out_event ();
+}
+
+void zmq::zmq_connecter_t::out_event ()
+{
+ fd_t fd = tcp_connecter.connect ();
+ rm_fd (handle);
+ handle_valid = false;
+
+ // Handle the error condition by attempt to reconnect.
+ if (fd == retired_fd) {
+ tcp_connecter.close ();
+ wait = true;
+ add_timer ();
+ return;
+ }
+
+ // Create an init object.
+ zmq_init_t *init = new (std::nothrow) zmq_init_t (
+ choose_io_thread (options.affinity), owner,
+ fd, options, true, protocol.c_str (), address.c_str (),
+ session_ordinal);
+ zmq_assert (init);
+ send_plug (init);
+ send_own (owner, init);
+
+ // Ask owner socket to shut the connecter down.
+ term ();
+}
+
+void zmq::zmq_connecter_t::timer_event ()
+{
+ wait = false;
+ start_connecting ();
+}
+
+void zmq::zmq_connecter_t::start_connecting ()
+{
+ // Open the connecting socket.
+ int rc = tcp_connecter.open ();
+
+ // Connect may succeed in synchronous manner.
+ if (rc == 0) {
+ handle = add_fd (tcp_connecter.get_fd ());
+ handle_valid = true;
+ out_event ();
+ return;
+ }
+
+ // Connection establishment may be dealyed. Poll for its completion.
+ else if (rc == -1 && errno == EAGAIN) {
+ handle = add_fd (tcp_connecter.get_fd ());
+ handle_valid = true;
+ set_pollout (handle);
+ return;
+ }
+
+ // Handle any other error condition by eventual reconnect.
+ wait = true;
+ add_timer ();
+}
diff --git a/src/zmq_connecter.hpp b/src/zmq_connecter.hpp
new file mode 100644
index 0000000..328dd6a
--- /dev/null
+++ b/src/zmq_connecter.hpp
@@ -0,0 +1,88 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_ZMQ_CONNECTER_HPP_INCLUDED__
+#define __ZMQ_ZMQ_CONNECTER_HPP_INCLUDED__
+
+#include <string>
+
+#include "owned.hpp"
+#include "io_object.hpp"
+#include "tcp_connecter.hpp"
+#include "options.hpp"
+#include "stdint.hpp"
+
+namespace zmq
+{
+
+ class zmq_connecter_t : public owned_t, public io_object_t
+ {
+ public:
+
+ zmq_connecter_t (class io_thread_t *parent_, socket_base_t *owner_,
+ const options_t &options_, uint64_t session_ordinal_, bool wait_);
+ ~zmq_connecter_t ();
+
+ // Set address to connect to.
+ int set_address (const char *protocol_, const char *address_);
+
+ private:
+
+ // Handlers for incoming commands.
+ void process_plug ();
+ void process_unplug ();
+
+ // Handlers for I/O events.
+ void in_event ();
+ void out_event ();
+ void timer_event ();
+
+ // Internal function to start the actual connection establishment.
+ void start_connecting ();
+
+ // Actual connecting socket.
+ tcp_connecter_t tcp_connecter;
+
+ // Handle corresponding to the listening socket.
+ handle_t handle;
+
+ // If true file descriptor is registered with the poller and 'handle'
+ // contains valid value.
+ bool handle_valid;
+
+ // If true, connecter is waiting a while before trying to connect.
+ bool wait;
+
+ // Ordinal of the session to attach to.
+ uint64_t session_ordinal;
+
+ // Associated socket options.
+ options_t options;
+
+ // Protocol and address to connect to.
+ std::string protocol;
+ std::string address;
+
+ zmq_connecter_t (const zmq_connecter_t&);
+ void operator = (const zmq_connecter_t&);
+ };
+
+}
+
+#endif
diff --git a/src/zmq_decoder.cpp b/src/zmq_decoder.cpp
new file mode 100644
index 0000000..8e335c9
--- /dev/null
+++ b/src/zmq_decoder.cpp
@@ -0,0 +1,107 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "zmq_decoder.hpp"
+#include "i_inout.hpp"
+#include "wire.hpp"
+#include "err.hpp"
+
+zmq::zmq_decoder_t::zmq_decoder_t (size_t bufsize_) :
+ decoder_t <zmq_decoder_t> (bufsize_),
+ destination (NULL)
+{
+ zmq_msg_init (&in_progress);
+
+ // At the beginning, read one byte and go to one_byte_size_ready state.
+ next_step (tmpbuf, 1, &zmq_decoder_t::one_byte_size_ready);
+}
+
+zmq::zmq_decoder_t::~zmq_decoder_t ()
+{
+ zmq_msg_close (&in_progress);
+}
+
+void zmq::zmq_decoder_t::set_inout (i_inout *destination_)
+{
+ destination = destination_;
+}
+
+bool zmq::zmq_decoder_t::one_byte_size_ready ()
+{
+ // First byte of size is read. If it is 0xff read 8-byte size.
+ // Otherwise allocate the buffer for message data and read the
+ // message data into it.
+ if (*tmpbuf == 0xff)
+ next_step (tmpbuf, 8, &zmq_decoder_t::eight_byte_size_ready);
+ else {
+
+ // TODO: Handle over-sized message decently.
+
+ // in_progress is initialised at this point so in theory we should
+ // close it before calling zmq_msg_init_size, however, it's a 0-byte
+ // message and thus we can treat it as uninitialised...
+ int rc = zmq_msg_init_size (&in_progress, *tmpbuf - 1);
+ errno_assert (rc == 0);
+ next_step (tmpbuf, 1, &zmq_decoder_t::flags_ready);
+ }
+ return true;
+}
+
+bool zmq::zmq_decoder_t::eight_byte_size_ready ()
+{
+ // 8-byte size is read. Allocate the buffer for message body and
+ // read the message data into it.
+ size_t size = (size_t) get_uint64 (tmpbuf);
+
+ // TODO: Handle over-sized message decently.
+
+ // in_progress is initialised at this point so in theory we should
+ // close it before calling zmq_msg_init_size, however, it's a 0-byte
+ // message and thus we can treat it as uninitialised...
+ int rc = zmq_msg_init_size (&in_progress, size - 1);
+ errno_assert (rc == 0);
+ next_step (tmpbuf, 1, &zmq_decoder_t::flags_ready);
+
+ return true;
+}
+
+bool zmq::zmq_decoder_t::flags_ready ()
+{
+ // Store the flags from the wire into the message structure.
+ in_progress.flags = tmpbuf [0];
+
+ next_step (zmq_msg_data (&in_progress), zmq_msg_size (&in_progress),
+ &zmq_decoder_t::message_ready);
+
+ return true;
+}
+
+bool zmq::zmq_decoder_t::message_ready ()
+{
+ // Message is completely read. Push it further and start reading
+ // new message. (in_progress is a 0-byte message after this point.)
+ if (!destination || !destination->write (&in_progress))
+ return false;
+
+ next_step (tmpbuf, 1, &zmq_decoder_t::one_byte_size_ready);
+ return true;
+}
diff --git a/src/zmq_decoder.hpp b/src/zmq_decoder.hpp
new file mode 100644
index 0000000..c1e3e3e
--- /dev/null
+++ b/src/zmq_decoder.hpp
@@ -0,0 +1,59 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_ZMQ_DECODER_HPP_INCLUDED__
+#define __ZMQ_ZMQ_DECODER_HPP_INCLUDED__
+
+#include "../include/zmq.h"
+
+#include "decoder.hpp"
+#include "blob.hpp"
+
+namespace zmq
+{
+ // Decoder for 0MQ backend protocol. Converts data batches into messages.
+
+ class zmq_decoder_t : public decoder_t <zmq_decoder_t>
+ {
+ public:
+
+ zmq_decoder_t (size_t bufsize_);
+ ~zmq_decoder_t ();
+
+ void set_inout (struct i_inout *destination_);
+
+ private:
+
+ bool one_byte_size_ready ();
+ bool eight_byte_size_ready ();
+ bool flags_ready ();
+ bool message_ready ();
+
+ struct i_inout *destination;
+ unsigned char tmpbuf [8];
+ ::zmq_msg_t in_progress;
+
+ zmq_decoder_t (const zmq_decoder_t&);
+ void operator = (const zmq_decoder_t&);
+ };
+
+}
+
+#endif
+
diff --git a/src/zmq_encoder.cpp b/src/zmq_encoder.cpp
new file mode 100644
index 0000000..077286f
--- /dev/null
+++ b/src/zmq_encoder.cpp
@@ -0,0 +1,89 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "zmq_encoder.hpp"
+#include "i_inout.hpp"
+#include "wire.hpp"
+
+zmq::zmq_encoder_t::zmq_encoder_t (size_t bufsize_) :
+ encoder_t <zmq_encoder_t> (bufsize_),
+ source (NULL)
+{
+ zmq_msg_init (&in_progress);
+
+ // Write 0 bytes to the batch and go to message_ready state.
+ next_step (NULL, 0, &zmq_encoder_t::message_ready, true);
+}
+
+zmq::zmq_encoder_t::~zmq_encoder_t ()
+{
+ zmq_msg_close (&in_progress);
+}
+
+void zmq::zmq_encoder_t::set_inout (i_inout *source_)
+{
+ source = source_;
+}
+
+bool zmq::zmq_encoder_t::size_ready ()
+{
+ // Write message body into the buffer.
+ next_step (zmq_msg_data (&in_progress), zmq_msg_size (&in_progress),
+ &zmq_encoder_t::message_ready, false);
+ return true;
+}
+
+bool zmq::zmq_encoder_t::message_ready ()
+{
+ // Destroy content of the old message.
+ zmq_msg_close(&in_progress);
+
+ // Read new message. If there is none, return false.
+ // Note that new state is set only if write is successful. That way
+ // unsuccessful write will cause retry on the next state machine
+ // invocation.
+ if (!source || !source->read (&in_progress)) {
+ zmq_msg_init (&in_progress);
+ return false;
+ }
+
+ // Get the message size.
+ size_t size = zmq_msg_size (&in_progress);
+
+ // Account for the 'flags' byte.
+ size++;
+
+ // For messages less than 255 bytes long, write one byte of message size.
+ // For longer messages write 0xff escape character followed by 8-byte
+ // message size. In both cases 'flags' field follows.
+ if (size < 255) {
+ tmpbuf [0] = (unsigned char) size;
+ tmpbuf [1] = (in_progress.flags & ~ZMQ_MSG_SHARED);
+ next_step (tmpbuf, 2, &zmq_encoder_t::size_ready,
+ !(in_progress.flags & ZMQ_MSG_MORE));
+ }
+ else {
+ tmpbuf [0] = 0xff;
+ put_uint64 (tmpbuf + 1, size);
+ tmpbuf [9] = (in_progress.flags & ~ZMQ_MSG_SHARED);
+ next_step (tmpbuf, 10, &zmq_encoder_t::size_ready,
+ !(in_progress.flags & ZMQ_MSG_MORE));
+ }
+ return true;
+}
diff --git a/src/zmq_encoder.hpp b/src/zmq_encoder.hpp
new file mode 100644
index 0000000..61899f4
--- /dev/null
+++ b/src/zmq_encoder.hpp
@@ -0,0 +1,55 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_ZMQ_ENCODER_HPP_INCLUDED__
+#define __ZMQ_ZMQ_ENCODER_HPP_INCLUDED__
+
+#include "../include/zmq.h"
+
+#include "encoder.hpp"
+
+namespace zmq
+{
+ // Encoder for 0MQ backend protocol. Converts messages into data batches.
+
+ class zmq_encoder_t : public encoder_t <zmq_encoder_t>
+ {
+ public:
+
+ zmq_encoder_t (size_t bufsize_);
+ ~zmq_encoder_t ();
+
+ void set_inout (struct i_inout *source_);
+
+ private:
+
+ bool size_ready ();
+ bool message_ready ();
+
+ struct i_inout *source;
+ ::zmq_msg_t in_progress;
+ unsigned char tmpbuf [10];
+
+ zmq_encoder_t (const zmq_encoder_t&);
+ void operator = (const zmq_encoder_t&);
+ };
+}
+
+#endif
+
diff --git a/src/zmq_engine.cpp b/src/zmq_engine.cpp
new file mode 100644
index 0000000..41b10c8
--- /dev/null
+++ b/src/zmq_engine.cpp
@@ -0,0 +1,195 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "platform.hpp"
+#if defined ZMQ_HAVE_WINDOWS
+#include "windows.hpp"
+#endif
+
+#include <string.h>
+#include <new>
+
+#include "zmq_engine.hpp"
+#include "zmq_connecter.hpp"
+#include "io_thread.hpp"
+#include "i_inout.hpp"
+#include "config.hpp"
+#include "err.hpp"
+
+zmq::zmq_engine_t::zmq_engine_t (io_thread_t *parent_, fd_t fd_,
+ const options_t &options_, bool reconnect_,
+ const char *protocol_, const char *address_) :
+ io_object_t (parent_),
+ inpos (NULL),
+ insize (0),
+ decoder (in_batch_size),
+ outpos (NULL),
+ outsize (0),
+ encoder (out_batch_size),
+ inout (NULL),
+ options (options_),
+ reconnect (reconnect_)
+{
+ if (reconnect) {
+ protocol = protocol_;
+ address = address_;
+ }
+
+ // Initialise the underlying socket.
+ int rc = tcp_socket.open (fd_, options.sndbuf, options.rcvbuf);
+ zmq_assert (rc == 0);
+}
+
+zmq::zmq_engine_t::~zmq_engine_t ()
+{
+}
+
+void zmq::zmq_engine_t::plug (i_inout *inout_)
+{
+ zmq_assert (!inout);
+
+ encoder.set_inout (inout_);
+ decoder.set_inout (inout_);
+
+ handle = add_fd (tcp_socket.get_fd ());
+ set_pollin (handle);
+ set_pollout (handle);
+
+ inout = inout_;
+
+ // Flush all the data that may have been already received downstream.
+ in_event ();
+}
+
+void zmq::zmq_engine_t::unplug ()
+{
+ rm_fd (handle);
+ encoder.set_inout (NULL);
+ decoder.set_inout (NULL);
+ inout = NULL;
+}
+
+void zmq::zmq_engine_t::in_event ()
+{
+ bool disconnection = false;
+
+ // If there's no data to process in the buffer...
+ if (!insize) {
+
+ // Retrieve the buffer and read as much data as possible.
+ decoder.get_buffer (&inpos, &insize);
+ insize = tcp_socket.read (inpos, insize);
+
+ // Check whether the peer has closed the connection.
+ if (insize == (size_t) -1) {
+ insize = 0;
+ disconnection = true;
+ }
+ }
+
+ // Push the data to the decoder.
+ size_t processed = decoder.process_buffer (inpos, insize);
+
+ // Stop polling for input if we got stuck.
+ if (processed < insize) {
+
+ // This may happen if queue limits are in effect or when
+ // init object reads all required information from the socket
+ // and rejects to read more data.
+ reset_pollin (handle);
+ }
+
+ // Adjust the buffer.
+ inpos += processed;
+ insize -= processed;
+
+ // Flush all messages the decoder may have produced.
+ inout->flush ();
+
+ if (disconnection)
+ error ();
+}
+
+void zmq::zmq_engine_t::out_event ()
+{
+ // If write buffer is empty, try to read new data from the encoder.
+ if (!outsize) {
+
+ outpos = NULL;
+ encoder.get_data (&outpos, &outsize);
+
+ // If there is no data to send, stop polling for output.
+ if (outsize == 0) {
+ reset_pollout (handle);
+ return;
+ }
+ }
+
+ // If there are any data to write in write buffer, write as much as
+ // possible to the socket.
+ int nbytes = tcp_socket.write (outpos, outsize);
+
+ // Handle problems with the connection.
+ if (nbytes == -1) {
+ error ();
+ return;
+ }
+
+ outpos += nbytes;
+ outsize -= nbytes;
+}
+
+void zmq::zmq_engine_t::revive ()
+{
+ set_pollout (handle);
+
+ // Speculative write: The assumption is that at the moment new message
+ // was sent by the user the socket is probably available for writing.
+ // Thus we try to write the data to socket avoiding polling for POLLOUT.
+ // Consequently, the latency should be better in request/reply scenarios.
+ out_event ();
+}
+
+void zmq::zmq_engine_t::resume_input ()
+{
+ set_pollin (handle);
+
+ in_event ();
+}
+
+void zmq::zmq_engine_t::error ()
+{
+ zmq_assert (inout);
+
+ zmq_connecter_t *reconnecter = NULL;
+ if (reconnect) {
+
+ // Create a connecter object to attempt reconnect.
+ // Ask it to wait for a while before reconnecting.
+ reconnecter = new (std::nothrow) zmq_connecter_t (
+ inout->get_io_thread (), inout->get_owner (),
+ options, inout->get_ordinal (), true);
+ zmq_assert (reconnecter);
+ reconnecter->set_address (protocol.c_str(), address.c_str ());
+ }
+
+ inout->detach (reconnecter);
+ unplug ();
+ delete this;
+}
diff --git a/src/zmq_engine.hpp b/src/zmq_engine.hpp
new file mode 100644
index 0000000..d89dccc
--- /dev/null
+++ b/src/zmq_engine.hpp
@@ -0,0 +1,86 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_ZMQ_ENGINE_HPP_INCLUDED__
+#define __ZMQ_ZMQ_ENGINE_HPP_INCLUDED__
+
+#include <stddef.h>
+
+#include <string>
+
+#include "i_engine.hpp"
+#include "io_object.hpp"
+#include "tcp_socket.hpp"
+#include "zmq_encoder.hpp"
+#include "zmq_decoder.hpp"
+#include "options.hpp"
+
+namespace zmq
+{
+
+ class zmq_engine_t : public io_object_t, public i_engine
+ {
+ public:
+
+ zmq_engine_t (class io_thread_t *parent_, fd_t fd_,
+ const options_t &options_, bool reconnect_,
+ const char *protocol_, const char *address_);
+ ~zmq_engine_t ();
+
+ // i_engine interface implementation.
+ void plug (struct i_inout *inout_);
+ void unplug ();
+ void revive ();
+ void resume_input ();
+
+ // i_poll_events interface implementation.
+ void in_event ();
+ void out_event ();
+
+ private:
+
+ // Function to handle network disconnections.
+ void error ();
+
+ tcp_socket_t tcp_socket;
+ handle_t handle;
+
+ unsigned char *inpos;
+ size_t insize;
+ zmq_decoder_t decoder;
+
+ unsigned char *outpos;
+ size_t outsize;
+ zmq_encoder_t encoder;
+
+ i_inout *inout;
+
+ options_t options;
+
+ bool reconnect;
+ std::string protocol;
+ std::string address;
+
+ zmq_engine_t (const zmq_engine_t&);
+ void operator = (const zmq_engine_t&);
+ };
+
+}
+
+#endif
diff --git a/src/zmq_init.cpp b/src/zmq_init.cpp
new file mode 100644
index 0000000..5824f5c
--- /dev/null
+++ b/src/zmq_init.cpp
@@ -0,0 +1,195 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <string.h>
+
+#include "zmq_init.hpp"
+#include "zmq_engine.hpp"
+#include "io_thread.hpp"
+#include "session.hpp"
+#include "uuid.hpp"
+#include "err.hpp"
+
+zmq::zmq_init_t::zmq_init_t (io_thread_t *parent_, socket_base_t *owner_,
+ fd_t fd_, const options_t &options_, bool reconnect_,
+ const char *protocol_, const char *address_, uint64_t session_ordinal_) :
+ owned_t (parent_, owner_),
+ sent (false),
+ received (false),
+ session_ordinal (session_ordinal_),
+ options (options_)
+{
+ // Create the engine object for this connection.
+ engine = new (std::nothrow) zmq_engine_t (parent_, fd_, options,
+ reconnect_, protocol_, address_);
+ zmq_assert (engine);
+}
+
+zmq::zmq_init_t::~zmq_init_t ()
+{
+ if (engine)
+ delete engine;
+}
+
+bool zmq::zmq_init_t::read (::zmq_msg_t *msg_)
+{
+ // If the identity was already sent, do nothing.
+ if (sent)
+ return false;
+
+ // Send the identity.
+ int rc = zmq_msg_init_size (msg_, options.identity.size ());
+ zmq_assert (rc == 0);
+ memcpy (zmq_msg_data (msg_), options.identity.c_str (),
+ options.identity.size ());
+ sent = true;
+
+ // If initialisation is done, pass the engine to the session and
+ // destroy the init object.
+ finalise ();
+
+ return true;
+}
+
+bool zmq::zmq_init_t::write (::zmq_msg_t *msg_)
+{
+ // If identity was already received, we are not interested
+ // in subsequent messages.
+ if (received)
+ return false;
+
+ // Retreieve the remote identity. If it's empty, generate a unique name.
+ if (!zmq_msg_size (msg_)) {
+ unsigned char identity [uuid_t::uuid_blob_len + 1];
+ identity [0] = 0;
+ memcpy (identity + 1, uuid_t ().to_blob (), uuid_t::uuid_blob_len);
+ peer_identity.assign (identity, uuid_t::uuid_blob_len + 1);
+ }
+ else {
+ peer_identity.assign ((const unsigned char*) zmq_msg_data (msg_),
+ zmq_msg_size (msg_));
+ }
+
+ received = true;
+
+ return true;
+}
+
+void zmq::zmq_init_t::flush ()
+{
+ // Check if there's anything to flush.
+ if (!received)
+ return;
+
+ // If initialisation is done, pass the engine to the session and
+ // destroy the init object.
+ finalise ();
+}
+
+void zmq::zmq_init_t::detach (owned_t *reconnecter_)
+{
+ // This function is called by engine when disconnection occurs.
+
+ // If required, launch the reconnecter.
+ if (reconnecter_) {
+ send_plug (reconnecter_);
+ send_own (owner, reconnecter_);
+ }
+
+ // The engine will destroy itself, so let's just drop the pointer here and
+ // start termination of the init object.
+ engine = NULL;
+ term ();
+}
+
+zmq::io_thread_t *zmq::zmq_init_t::get_io_thread ()
+{
+ return choose_io_thread (options.affinity);
+}
+
+class zmq::socket_base_t *zmq::zmq_init_t::get_owner ()
+{
+ return owner;
+}
+
+uint64_t zmq::zmq_init_t::get_ordinal ()
+{
+ return session_ordinal;
+}
+
+void zmq::zmq_init_t::process_plug ()
+{
+ zmq_assert (engine);
+ engine->plug (this);
+}
+
+void zmq::zmq_init_t::process_unplug ()
+{
+ if (engine)
+ engine->unplug ();
+}
+
+void zmq::zmq_init_t::finalise ()
+{
+ if (sent && received) {
+
+ // Disconnect the engine from the init object.
+ engine->unplug ();
+
+ session_t *session = NULL;
+
+ // If we have the session ordinal, let's use it to find the session.
+ // If it is not found, it means socket is already being shut down
+ // and the session have been deallocated.
+ // TODO: We should check whether the name of the peer haven't changed
+ // upon reconnection.
+ if (session_ordinal) {
+ session = owner->find_session (session_ordinal);
+ if (!session) {
+ term ();
+ return;
+ }
+ }
+ else {
+
+ // If the peer has a unique name, find the associated session.
+ // If it does not exist, create it.
+ zmq_assert (!peer_identity.empty ());
+ session = owner->find_session (peer_identity);
+ if (!session) {
+ session = new (std::nothrow) session_t (
+ choose_io_thread (options.affinity), owner, options,
+ peer_identity);
+ zmq_assert (session);
+ send_plug (session);
+ send_own (owner, session);
+
+ // Reserve a sequence number for following 'attach' command.
+ session->inc_seqnum ();
+ }
+ }
+
+ // No need to increment seqnum as it was already incremented above.
+ send_attach (session, engine, peer_identity, false);
+
+ // Destroy the init object.
+ engine = NULL;
+ term ();
+ }
+}
diff --git a/src/zmq_init.hpp b/src/zmq_init.hpp
new file mode 100644
index 0000000..6f935c2
--- /dev/null
+++ b/src/zmq_init.hpp
@@ -0,0 +1,89 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_ZMQ_INIT_HPP_INCLUDED__
+#define __ZMQ_ZMQ_INIT_HPP_INCLUDED__
+
+#include "i_inout.hpp"
+#include "i_engine.hpp"
+#include "owned.hpp"
+#include "fd.hpp"
+#include "stdint.hpp"
+#include "options.hpp"
+#include "stdint.hpp"
+#include "blob.hpp"
+
+namespace zmq
+{
+
+ // The class handles initialisation phase of 0MQ wire-level protocol.
+
+ class zmq_init_t : public owned_t, public i_inout
+ {
+ public:
+
+ zmq_init_t (class io_thread_t *parent_, socket_base_t *owner_,
+ fd_t fd_, const options_t &options_, bool reconnect_,
+ const char *protocol_, const char *address_,
+ uint64_t session_ordinal_);
+ ~zmq_init_t ();
+
+ private:
+
+ void finalise ();
+
+ // i_inout interface implementation.
+ bool read (::zmq_msg_t *msg_);
+ bool write (::zmq_msg_t *msg_);
+ void flush ();
+ void detach (owned_t *reconnecter_);
+ class io_thread_t *get_io_thread ();
+ class socket_base_t *get_owner ();
+ uint64_t get_ordinal ();
+
+ // Handlers for incoming commands.
+ void process_plug ();
+ void process_unplug ();
+
+ // Associated wite-protocol engine.
+ i_engine *engine;
+
+ // True if our own identity was already sent to the peer.
+ bool sent;
+
+ // True if peer's identity was already received.
+ bool received;
+
+ // Identity of the peer socket.
+ blob_t peer_identity;
+
+ // TCP connecter creates session before the name of the peer is known.
+ // Thus we know only its ordinal number.
+ uint64_t session_ordinal;
+
+ // Associated socket options.
+ options_t options;
+
+ zmq_init_t (const zmq_init_t&);
+ void operator = (const zmq_init_t&);
+ };
+
+}
+
+#endif
diff --git a/src/zmq_listener.cpp b/src/zmq_listener.cpp
new file mode 100644
index 0000000..d7cf292
--- /dev/null
+++ b/src/zmq_listener.cpp
@@ -0,0 +1,75 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <new>
+
+#include "zmq_listener.hpp"
+#include "zmq_init.hpp"
+#include "io_thread.hpp"
+#include "err.hpp"
+
+zmq::zmq_listener_t::zmq_listener_t (io_thread_t *parent_,
+ socket_base_t *owner_, const options_t &options_) :
+ owned_t (parent_, owner_),
+ io_object_t (parent_),
+ options (options_)
+{
+}
+
+zmq::zmq_listener_t::~zmq_listener_t ()
+{
+}
+
+int zmq::zmq_listener_t::set_address (const char *protocol_, const char *addr_)
+{
+ return tcp_listener.set_address (protocol_, addr_);
+}
+
+void zmq::zmq_listener_t::process_plug ()
+{
+ // Start polling for incoming connections.
+ handle = add_fd (tcp_listener.get_fd ());
+ set_pollin (handle);
+}
+
+void zmq::zmq_listener_t::process_unplug ()
+{
+ rm_fd (handle);
+}
+
+void zmq::zmq_listener_t::in_event ()
+{
+ fd_t fd = tcp_listener.accept ();
+
+ // If connection was reset by the peer in the meantime, just ignore it.
+ // TODO: Handle specific errors like ENFILE/EMFILE etc.
+ if (fd == retired_fd)
+ return;
+
+ // Create an init object.
+ io_thread_t *io_thread = choose_io_thread (options.affinity);
+ zmq_init_t *init = new (std::nothrow) zmq_init_t (
+ io_thread, owner, fd, options, false, NULL, NULL, 0);
+ zmq_assert (init);
+ send_plug (init);
+ send_own (owner, init);
+}
+
+
+
diff --git a/src/zmq_listener.hpp b/src/zmq_listener.hpp
new file mode 100644
index 0000000..c990b02
--- /dev/null
+++ b/src/zmq_listener.hpp
@@ -0,0 +1,67 @@
+/*
+ Copyright (c) 2007-2010 iMatix Corporation
+
+ This file is part of 0MQ.
+
+ 0MQ is free software; you can redistribute it and/or modify it under
+ the terms of the Lesser GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 0MQ 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
+ Lesser GNU General Public License for more details.
+
+ You should have received a copy of the Lesser GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ZMQ_ZMQ_LISTENER_HPP_INCLUDED__
+#define __ZMQ_ZMQ_LISTENER_HPP_INCLUDED__
+
+#include "owned.hpp"
+#include "io_object.hpp"
+#include "tcp_listener.hpp"
+#include "options.hpp"
+#include "stdint.hpp"
+
+namespace zmq
+{
+
+ class zmq_listener_t : public owned_t, public io_object_t
+ {
+ public:
+
+ zmq_listener_t (class io_thread_t *parent_, socket_base_t *owner_,
+ const options_t &options_);
+ ~zmq_listener_t ();
+
+ // Set address to listen on.
+ int set_address (const char* protocol_, const char *addr_);
+
+ private:
+
+ // Handlers for incoming commands.
+ void process_plug ();
+ void process_unplug ();
+
+ // Handlers for I/O events.
+ void in_event ();
+
+ // Actual listening socket.
+ tcp_listener_t tcp_listener;
+
+ // Handle corresponding to the listening socket.
+ handle_t handle;
+
+ // Associated socket options.
+ options_t options;
+
+ zmq_listener_t (const zmq_listener_t&);
+ void operator = (const zmq_listener_t&);
+ };
+
+}
+
+#endif