summaryrefslogtreecommitdiff
path: root/gnuradio-core
diff options
context:
space:
mode:
Diffstat (limited to 'gnuradio-core')
-rw-r--r--gnuradio-core/gnuradio-core.pc.in2
-rw-r--r--gnuradio-core/src/gen_interpolator_taps/Makefile.am18
-rw-r--r--gnuradio-core/src/lib/Makefile.am9
-rw-r--r--gnuradio-core/src/lib/general/Makefile.am3
-rw-r--r--gnuradio-core/src/lib/general/general.i2
-rw-r--r--gnuradio-core/src/lib/general/gr_dd_mpsk_sync_cc.cc196
-rw-r--r--gnuradio-core/src/lib/general/gr_dd_mpsk_sync_cc.h93
-rw-r--r--gnuradio-core/src/lib/general/gr_dd_mpsk_sync_cc.i34
-rw-r--r--gnuradio-core/src/lib/io/gr_udp_sink.cc314
-rw-r--r--gnuradio-core/src/lib/io/gr_udp_sink.h98
-rw-r--r--gnuradio-core/src/lib/io/gr_udp_sink.i22
-rw-r--r--gnuradio-core/src/lib/io/gr_udp_source.cc273
-rw-r--r--gnuradio-core/src/lib/io/gr_udp_source.h90
-rw-r--r--gnuradio-core/src/lib/io/gr_udp_source.i15
-rw-r--r--gnuradio-core/src/python/gnuradio/gr/Makefile.am3
-rwxr-xr-xgnuradio-core/src/python/gnuradio/gr/qa_udp_sink_source.py99
16 files changed, 623 insertions, 648 deletions
diff --git a/gnuradio-core/gnuradio-core.pc.in b/gnuradio-core/gnuradio-core.pc.in
index 9ff835041..5d743a4e9 100644
--- a/gnuradio-core/gnuradio-core.pc.in
+++ b/gnuradio-core/gnuradio-core.pc.in
@@ -6,7 +6,7 @@ includedir=@includedir@/gnuradio
Name: gnuradio-core
Description: GNU Software Radio toolkit
Requires: gruel fftw3f gsl
-Version: @VERSION@
+Version: @LIBVER@
Libs.private: @BOOST_LDFLAGS@ @BOOST_THREAD_LIB@ @BOOST_DATE_TIME_LIB@
Libs: -L${libdir} -lgnuradio-core
Cflags: @BOOST_CPPFLAGS@ @BOOST_CXXFLAGS@ -I${includedir}
diff --git a/gnuradio-core/src/gen_interpolator_taps/Makefile.am b/gnuradio-core/src/gen_interpolator_taps/Makefile.am
index 5f3a6cb25..d244e7f54 100644
--- a/gnuradio-core/src/gen_interpolator_taps/Makefile.am
+++ b/gnuradio-core/src/gen_interpolator_taps/Makefile.am
@@ -21,13 +21,13 @@
include $(top_srcdir)/Makefile.common
-EXTRA_DIST = praxis.txt simpson.h
+EXTRA_DIST = praxis.txt simpson.h objective_fct.c gen_interpolator_taps.c simpson.c praxis.f
-if ENABLE_FORTRAN
-noinst_PROGRAMS = gen_interpolator_taps
-noinst_HEADERS = simpson.h
-
-gen_interpolator_taps_SOURCES = gen_interpolator_taps.c objective_fct.c simpson.c praxis.f
-gen_interpolator_taps_LDADD = $(FLIBS) -lm
-
-endif
+# if ENABLE_FORTRAN
+# noinst_PROGRAMS = gen_interpolator_taps
+# noinst_HEADERS = simpson.h
+#
+# gen_interpolator_taps_SOURCES = gen_interpolator_taps.c objective_fct.c simpson.c praxis.f
+# gen_interpolator_taps_LDADD = $(FLIBS) -lm
+#
+# endif
diff --git a/gnuradio-core/src/lib/Makefile.am b/gnuradio-core/src/lib/Makefile.am
index 477ba6725..f3a3accdb 100644
--- a/gnuradio-core/src/lib/Makefile.am
+++ b/gnuradio-core/src/lib/Makefile.am
@@ -1,5 +1,5 @@
#
-# Copyright 2001,2004,2009 Free Software Foundation, Inc.
+# Copyright 2001,2004,2009,2010 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -33,10 +33,11 @@ AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(CPPUNIT_INCLUDES) $(WITH_INCLUDES)
# generate libgnuradio-core.la from the convenience libraries in subdirs
-lib_LTLIBRARIES = libgnuradio-core.la libgnuradio-core-qa.la
+lib_LTLIBRARIES = libgnuradio-core.la
+noinst_LTLIBRARIES = libgnuradio-core-qa.la
libgnuradio_core_la_SOURCES = bug_work_around_6.cc
-libgnuradio_core_la_LDFLAGS = $(NO_UNDEFINED) -version-info 0:0:0
+libgnuradio_core_la_LDFLAGS = $(NO_UNDEFINED) $(LTVERSIONFLAGS)
libgnuradio_core_qa_la_SOURCES = bug_work_around_6.cc
libgnuradio_core_qa_la_LDFLAGS = $(NO_UNDEFINED) -version-info 0:0:0 \
@@ -68,4 +69,4 @@ libgnuradio_core_qa_la_LIBADD = \
bin_PROGRAMS = gnuradio-config-info
gnuradio_config_info_SOURCES = gnuradio-config-info.cc
-gnuradio_config_info_LDADD = libgnuradio-core.la $(BOOST_PROGRAM_OPTIONS_LIB) \ No newline at end of file
+gnuradio_config_info_LDADD = libgnuradio-core.la $(BOOST_LDFLAGS) $(BOOST_PROGRAM_OPTIONS_LIB)
diff --git a/gnuradio-core/src/lib/general/Makefile.am b/gnuradio-core/src/lib/general/Makefile.am
index b5f5c346b..3d8a42805 100644
--- a/gnuradio-core/src/lib/general/Makefile.am
+++ b/gnuradio-core/src/lib/general/Makefile.am
@@ -60,7 +60,6 @@ libgeneral_la_SOURCES = \
gr_cpfsk_bc.cc \
gr_crc32.cc \
gr_ctcss_squelch_ff.cc \
- gr_dd_mpsk_sync_cc.cc \
gr_decode_ccsds_27_fb.cc \
gr_deinterleave.cc \
gr_delay.cc \
@@ -215,7 +214,6 @@ grinclude_HEADERS = \
gr_cpfsk_bc.h \
gr_crc32.h \
gr_ctcss_squelch_ff.h \
- gr_dd_mpsk_sync_cc.h \
gr_decode_ccsds_27_fb.h \
gr_diff_decoder_bb.h \
gr_diff_encoder_bb.h \
@@ -386,7 +384,6 @@ swiginclude_HEADERS = \
gr_cpfsk_bc.i \
gr_crc32.i \
gr_ctcss_squelch_ff.i \
- gr_dd_mpsk_sync_cc.i \
gr_decode_ccsds_27_fb.i \
gr_diff_decoder_bb.i \
gr_diff_encoder_bb.i \
diff --git a/gnuradio-core/src/lib/general/general.i b/gnuradio-core/src/lib/general/general.i
index 6929f1e6e..68cafce2e 100644
--- a/gnuradio-core/src/lib/general/general.i
+++ b/gnuradio-core/src/lib/general/general.i
@@ -80,7 +80,6 @@
#include <gr_threshold_ff.h>
#include <gr_clock_recovery_mm_ff.h>
#include <gr_clock_recovery_mm_cc.h>
-#include <gr_dd_mpsk_sync_cc.h>
#include <gr_packet_sink.h>
#include <gr_lms_dfe_cc.h>
#include <gr_lms_dfe_ff.h>
@@ -202,7 +201,6 @@
%include "gr_threshold_ff.i"
%include "gr_clock_recovery_mm_ff.i"
%include "gr_clock_recovery_mm_cc.i"
-%include "gr_dd_mpsk_sync_cc.i"
%include "gr_packet_sink.i"
%include "gr_lms_dfe_cc.i"
%include "gr_lms_dfe_ff.i"
diff --git a/gnuradio-core/src/lib/general/gr_dd_mpsk_sync_cc.cc b/gnuradio-core/src/lib/general/gr_dd_mpsk_sync_cc.cc
deleted file mode 100644
index d4141efc7..000000000
--- a/gnuradio-core/src/lib/general/gr_dd_mpsk_sync_cc.cc
+++ /dev/null
@@ -1,196 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2004 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <gr_dd_mpsk_sync_cc.h>
-#include <gr_io_signature.h>
-#include <gr_sincos.h>
-#include <gri_mmse_fir_interpolator_cc.h>
-#include <math.h>
-#include <stdexcept>
-#include <cstdio>
-
-#include <gr_complex.h>
-
-#define M_TWOPI (2*M_PI)
-
-gr_dd_mpsk_sync_cc_sptr
-gr_make_dd_mpsk_sync_cc (float alpha, float beta, float max_freq, float min_freq, float ref_phase,
- float omega, float gain_omega, float mu, float gain_mu)
-{
- return gr_dd_mpsk_sync_cc_sptr (new gr_dd_mpsk_sync_cc (alpha, beta, max_freq, min_freq,ref_phase,
- omega,gain_omega,mu,gain_mu));
-}
-
-gr_dd_mpsk_sync_cc::gr_dd_mpsk_sync_cc (float alpha, float beta, float max_freq, float min_freq,
- float ref_phase,
- float omega, float gain_omega, float mu, float gain_mu)
- : gr_block ("dd_mpsk_sync_cc",
- gr_make_io_signature (1, 1, sizeof (gr_complex)),
- gr_make_io_signature (1, 1, sizeof (gr_complex))),
- d_alpha(alpha), d_beta(beta),
- d_max_freq(max_freq), d_min_freq(min_freq),
- d_ref_phase(ref_phase),d_omega(omega), d_gain_omega(gain_omega),
- d_mu(mu), d_gain_mu(gain_mu),
- d_phase(0), d_freq((max_freq+min_freq)/2), d_last_sample(0),
- d_interp(new gri_mmse_fir_interpolator_cc()),
- d_dl_idx(0)
-{
- if (omega <= 0.0)
- throw std::out_of_range ("clock rate must be > 0");
- if (gain_mu < 0 || gain_omega < 0)
- throw std::out_of_range ("Gains must be non-negative");
-
- assert(d_interp->ntaps() <= DLLEN);
-
- // zero double length delay line.
- for (unsigned int i = 0; i < 2 * DLLEN; i++)
- d_dl[i] = gr_complex(0.0,0.0);
-}
-
-gr_dd_mpsk_sync_cc::~gr_dd_mpsk_sync_cc()
-{
- delete d_interp;
-}
-
-float
-gr_dd_mpsk_sync_cc::phase_detector(gr_complex sample,float ref_phase)
-{
- return ((sample.real()>0 ? 1.0 : -1.0) * sample.imag() -
- (sample.imag()>0 ? 1.0 : -1.0) * sample.real());
-}
-
-void
-gr_dd_mpsk_sync_cc::forecast(int noutput_items, gr_vector_int &ninput_items_required)
-{
- unsigned ninputs = ninput_items_required.size();
- for (unsigned i=0; i < ninputs; i++)
- ninput_items_required[i] =
- (int) ceil((noutput_items * d_omega) + d_interp->ntaps());
-}
-gr_complex
-gr_dd_mpsk_sync_cc::slicer_45deg (gr_complex sample)
-{
- float real,imag;
- if(sample.real() > 0)
- real=1;
- else
- real=-1;
- if(sample.imag() > 0)
- imag = 1;
- else
- imag = -1;
- return gr_complex(real,imag);
-}
-
-gr_complex
-gr_dd_mpsk_sync_cc::slicer_0deg (gr_complex sample)
-{
- gr_complex out;
- if( fabs(sample.real()) > fabs(sample.imag()) ) {
- if(sample.real() > 0)
- return gr_complex(1.0,0.0);
- else
- return gr_complex(-1.0,0.0);
- }
- else {
- if(sample.imag() > 0)
- return gr_complex(0.0, 1.0);
- else
- return gr_complex(0.0, -1.0);
- }
-}
-
-int
-gr_dd_mpsk_sync_cc::general_work (int noutput_items,
- gr_vector_int &ninput_items,
- gr_vector_const_void_star &input_items,
- gr_vector_void_star &output_items)
-{
- const gr_complex *in = (gr_complex *) input_items[0];
- gr_complex *out = (gr_complex *) output_items[0];
-
- int ii, oo;
- ii = 0; oo = 0;
-
- float error;
- float t_imag, t_real;
- gr_complex nco_out;
- float mm_val;
-
- while (oo < noutput_items) {
- //
- // generate an output sample by interpolating between the carrier
- // tracked samples in the delay line. d_mu, the fractional
- // interpolation amount (in [0.0, 1.0]) is controlled by the
- // symbol timing loop below.
- //
- out[oo] = d_interp->interpolate (&d_dl[d_dl_idx], d_mu);
-
- error = phase_detector(out[oo], d_ref_phase);
-
- d_freq = d_freq + d_beta * error;
- d_phase = d_phase + d_alpha * error;
- while(d_phase>M_TWOPI)
- d_phase -= M_TWOPI;
- while(d_phase<-M_TWOPI)
- d_phase += M_TWOPI;
-
- if (d_freq > d_max_freq)
- d_freq = d_max_freq;
- else if (d_freq < d_min_freq)
- d_freq = d_min_freq;
-
- mm_val = real(d_last_sample * slicer_0deg(out[oo]) - out[oo] * slicer_0deg(d_last_sample));
- d_last_sample = out[oo];
-
- d_omega = d_omega + d_gain_omega * mm_val;
- d_mu = d_mu + d_omega + d_gain_mu * mm_val;
-
- while(d_mu >= 1.0) {
- //
- // Generate more carrier tracked samples for the delay line
- //
- d_mu -= 1.0;
- gr_sincosf(d_phase, &t_imag, &t_real);
- nco_out = gr_complex(t_real, -t_imag);
- gr_complex new_sample = in[ii] * nco_out;
-
- d_dl[d_dl_idx] = new_sample; // overwrite oldest sample
- d_dl[(d_dl_idx + DLLEN)] = new_sample; // and second copy
- d_dl_idx = (d_dl_idx+1) % DLLEN; // point to the new oldest sample
- d_phase = d_phase + d_freq;
- ii++;
- }
- oo++;
- printf("%f\t%f\t%f\t%f\t%f\n",d_mu,d_omega,mm_val,d_freq,d_phase);
- //printf("%f\t%f\t%f\t%f\t%f\t%f\t%f\n",mple).real(),slicer_0deg(d_last_sample).imag(),mm_val,d_omega,d_mu);
- }
-
- assert(ii <= ninput_items[0]);
-
- consume_each (ii);
- return noutput_items;
-}
diff --git a/gnuradio-core/src/lib/general/gr_dd_mpsk_sync_cc.h b/gnuradio-core/src/lib/general/gr_dd_mpsk_sync_cc.h
deleted file mode 100644
index 4ffcd3771..000000000
--- a/gnuradio-core/src/lib/general/gr_dd_mpsk_sync_cc.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2004,2006 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef INCLUDED_GR_DD_MPSK_SYNC_CC_H
-#define INCLUDED_GR_DD_MPSK_SYNC_CC_H
-
-#include <gr_sync_block.h>
-
-class gri_mmse_fir_interpolator_cc;
-
-class gr_dd_mpsk_sync_cc;
-typedef boost::shared_ptr<gr_dd_mpsk_sync_cc> gr_dd_mpsk_sync_cc_sptr;
-
-gr_dd_mpsk_sync_cc_sptr
-gr_make_dd_mpsk_sync_cc (float alpha, float beta,
- float max_freq, float min_freq, float ref_phase,
- float omega, float gain_omega, float mu, float gain_mu);
-
-/*!
- * \brief Decision directed M-PSK synchronous demod
- * \ingroup sync_blk
- * This block performs joint carrier tracking and symbol timing recovery.
- *
- * input: complex baseband; output: properly timed complex samples ready for slicing.
- *
- * N.B, at this point, it handles only QPSK.
- */
-
-class gr_dd_mpsk_sync_cc : public gr_block
-{
- friend gr_dd_mpsk_sync_cc_sptr gr_make_dd_mpsk_sync_cc (float alpha, float beta,
- float max_freq, float min_freq, float ref_phase,
- float omega, float gain_omega, float mu, float gain_mu);
-public:
- ~gr_dd_mpsk_sync_cc ();
- void forecast(int noutput_items, gr_vector_int &ninput_items_required);
- float mu() const { return d_mu;}
- float omega() const { return d_omega;}
- float gain_mu() const { return d_gain_mu;}
- float gain_omega() const { return d_gain_omega;}
-
- void set_gain_mu (float gain_mu) { d_gain_mu = gain_mu; }
- void set_gain_omega (float gain_omega) { d_gain_omega = gain_omega; }
- void set_mu (float mu) { d_mu = mu; }
- void set_omega (float omega) { d_omega = omega; }
-
-protected:
- gr_dd_mpsk_sync_cc (float alpha, float beta, float max_freq, float min_freq, float ref_phase,
- float omega, float gain_omega, float mu, float gain_mu);
-
- int general_work (int noutput_items,
- gr_vector_int &ninput_items,
- gr_vector_const_void_star &input_items,
- gr_vector_void_star &output_items);
-
-private:
- static const unsigned int DLLEN = 8; // delay line length.
-
- float d_alpha,d_beta,d_max_freq,d_min_freq,d_ref_phase;
- float d_omega, d_gain_omega, d_mu, d_gain_mu;
- float d_phase, d_freq;
- gr_complex slicer_45deg (gr_complex sample);
- gr_complex slicer_0deg (gr_complex sample);
- gr_complex d_last_sample;
- gri_mmse_fir_interpolator_cc *d_interp;
-
- gr_complex d_dl[2 * DLLEN]; // Holds post carrier tracking samples.
- // double length delay line to avoid wraps.
- unsigned int d_dl_idx; // indexes oldest sample in delay line.
-
- float phase_detector(gr_complex sample,float ref_phase);
-};
-
-#endif
diff --git a/gnuradio-core/src/lib/general/gr_dd_mpsk_sync_cc.i b/gnuradio-core/src/lib/general/gr_dd_mpsk_sync_cc.i
deleted file mode 100644
index 17739248e..000000000
--- a/gnuradio-core/src/lib/general/gr_dd_mpsk_sync_cc.i
+++ /dev/null
@@ -1,34 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2005 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-GR_SWIG_BLOCK_MAGIC(gr,dd_mpsk_sync_cc)
-
- gr_dd_mpsk_sync_cc_sptr gr_make_dd_mpsk_sync_cc (float alpha, float beta,
- float max_freq, float min_freq, float ref_phase,
- float omega, float gain_omega, float mu, float gain_mu);
-
-class gr_dd_mpsk_sync_cc : public gr_block
-{
- private:
- gr_dd_mpsk_sync_cc (float alpha, float beta, float max_freq, float min_freq, float ref_phase,
- float omega, float gain_omega, float mu, float gain_mu);
-};
diff --git a/gnuradio-core/src/lib/io/gr_udp_sink.cc b/gnuradio-core/src/lib/io/gr_udp_sink.cc
index d37adfb8a..3084a848b 100644
--- a/gnuradio-core/src/lib/io/gr_udp_sink.cc
+++ b/gnuradio-core/src/lib/io/gr_udp_sink.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2007,2008,2009 Free Software Foundation, Inc.
+ * Copyright 2007,2008,2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -26,13 +26,24 @@
#include <gr_udp_sink.h>
#include <gr_io_signature.h>
#include <stdexcept>
-#if defined(HAVE_SOCKET)
-#include <netdb.h>
+#include <errno.h>
#include <stdio.h>
+#include <string.h>
+#if defined(HAVE_NETDB_H)
+#include <netdb.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h> //usually included by <netdb.h>?
+#endif
typedef void* optval_t;
-#else
+#elif defined(HAVE_WINDOWS_H)
+// if not posix, assume winsock
+#define USING_WINSOCK
+#include <winsock2.h>
+#include <ws2tcpip.h>
#define SHUT_RDWR 2
-#define inet_aton(N,A) ( (A)->s_addr = inet_addr(N), ( (A)->s_addr != INADDR_NONE ) )
typedef char* optval_t;
#endif
@@ -40,91 +51,67 @@ typedef char* optval_t;
#define SNK_VERBOSE 0
-gr_udp_sink::gr_udp_sink (size_t itemsize,
- const char *src, unsigned short port_src,
- const char *dst, unsigned short port_dst,
- int payload_size)
- : gr_sync_block ("udp_sink",
- gr_make_io_signature (1, 1, itemsize),
- gr_make_io_signature (0, 0, 0)),
- d_itemsize (itemsize), d_updated(false), d_payload_size(payload_size)
+static int is_error( int perr )
{
- int ret = 0;
-
- // Set up the address stucture for the source address and port numbers
- // Get the source IP address from the host name
- struct hostent *hsrc = gethostbyname(src);
- if(hsrc) { // if the source was provided as a host namex
- d_ip_src = *(struct in_addr*)hsrc->h_addr_list[0];
+ // Compare error to posix error code; return nonzero if match.
+#if defined(USING_WINSOCK)
+#define ENOPROTOOPT 109
+#define ECONNREFUSED 111
+ // All codes to be checked for must be defined below
+ int werr = WSAGetLastError();
+ switch( werr ) {
+ case WSAETIMEDOUT:
+ return( perr == EAGAIN );
+ case WSAENOPROTOOPT:
+ return( perr == ENOPROTOOPT );
+ case WSAECONNREFUSED:
+ return( perr == ECONNREFUSED );
+ default:
+ fprintf(stderr,"gr_udp_source/is_error: unknown error %d\n", perr );
+ throw std::runtime_error("internal error");
}
- else { // assume it was specified as an IP address
- if((ret=inet_aton(src, &d_ip_src)) == 0) { // format IP address
- perror("Not a valid source IP address or host name");
- throw std::runtime_error("can't initialize source socket");
- }
- }
-
- // Get the destination IP address from the host name
- struct hostent *hdst = gethostbyname(dst);
- if(hdst) { // if the source was provided as a host namex
- d_ip_dst = *(struct in_addr*)hdst->h_addr_list[0];
- }
- else { // assume it was specified as an IP address
- if((ret=inet_aton(dst, &d_ip_dst)) == 0) { // format IP address
- perror("Not a valid destination IP address or host name");
- throw std::runtime_error("can't initialize destination socket");
- }
- }
-
- d_port_src = htons(port_src); // format port number
- d_port_dst = htons(port_dst); // format port number
-
- d_sockaddr_src.sin_family = AF_INET;
- d_sockaddr_src.sin_addr = d_ip_src;
- d_sockaddr_src.sin_port = d_port_src;
-
- d_sockaddr_dst.sin_family = AF_INET;
- d_sockaddr_dst.sin_addr = d_ip_dst;
- d_sockaddr_dst.sin_port = d_port_dst;
-
- open();
-}
-
-// public constructor that returns a shared_ptr
-
-gr_udp_sink_sptr
-gr_make_udp_sink (size_t itemsize,
- const char *src, unsigned short port_src,
- const char *dst, unsigned short port_dst,
- int payload_size)
-{
- return gr_udp_sink_sptr (new gr_udp_sink (itemsize,
- src, port_src,
- dst, port_dst,
- payload_size));
+ return 0;
+#else
+ return( perr == errno );
+#endif
}
-gr_udp_sink::~gr_udp_sink ()
+static void report_error( const char *msg1, const char *msg2 )
{
- close();
+ // Deal with errors, both posix and winsock
+#if defined(USING_WINSOCK)
+ int werr = WSAGetLastError();
+ fprintf(stderr, "%s: winsock error %d\n", msg1, werr );
+#else
+ perror(msg1);
+#endif
+ if( msg2 != NULL )
+ throw std::runtime_error(msg2);
+ return;
}
-bool
-gr_udp_sink::open()
+gr_udp_sink::gr_udp_sink (size_t itemsize,
+ const char *host, unsigned short port,
+ int payload_size, bool eof)
+ : gr_sync_block ("udp_sink",
+ gr_make_io_signature (1, 1, itemsize),
+ gr_make_io_signature (0, 0, 0)),
+ d_itemsize (itemsize), d_payload_size(payload_size), d_eof(eof),
+ d_socket(-1), d_connected(false)
{
- gruel::scoped_lock guard(d_mutex); // hold mutex for duration of this function
-
- // create socket
- if((d_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
- perror("socket open");
- throw std::runtime_error("can't open socket");
+#if defined(USING_WINSOCK) // for Windows (with MinGW)
+ // initialize winsock DLL
+ WSADATA wsaData;
+ int iResult = WSAStartup( MAKEWORD(2,2), &wsaData );
+ if( iResult != NO_ERROR ) {
+ report_error( "gr_udp_source WSAStartup", "can't open socket" );
}
+#endif
- // Turn on reuse address
- int opt_val = true;
- if(setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR, (optval_t)&opt_val, sizeof(int)) == -1) {
- perror("SO_REUSEADDR");
- throw std::runtime_error("can't set socket option SO_REUSEADDR");
+ // create socket
+ d_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if(d_socket == -1) {
+ report_error("socket open","can't open socket");
}
// Don't wait when shutting down
@@ -132,36 +119,46 @@ gr_udp_sink::open()
lngr.l_onoff = 1;
lngr.l_linger = 0;
if(setsockopt(d_socket, SOL_SOCKET, SO_LINGER, (optval_t)&lngr, sizeof(linger)) == -1) {
- perror("SO_LINGER");
- throw std::runtime_error("can't set socket option SO_LINGER");
+ if( !is_error(ENOPROTOOPT) ) { // no SO_LINGER for SOCK_DGRAM on Windows
+ report_error("SO_LINGER","can't set socket option SO_LINGER");
+ }
}
- // bind socket to an address and port number to listen on
- if(bind (d_socket, (sockaddr*)&d_sockaddr_src, sizeof(struct sockaddr)) == -1) {
- perror("socket bind");
- throw std::runtime_error("can't bind socket");
- }
+ // Get the destination address
+ connect(host, port);
+}
- // Not sure if we should throw here or allow retries
- if(connect(d_socket, (sockaddr*)&d_sockaddr_dst, sizeof(struct sockaddr)) == -1) {
- perror("socket connect");
- throw std::runtime_error("can't connect to socket");
- }
+// public constructor that returns a shared_ptr
- d_updated = true;
- return d_socket != 0;
+gr_udp_sink_sptr
+gr_make_udp_sink (size_t itemsize,
+ const char *host, unsigned short port,
+ int payload_size, bool eof)
+{
+ return gr_udp_sink_sptr (new gr_udp_sink (itemsize,
+ host, port,
+ payload_size, eof));
}
-void
-gr_udp_sink::close()
+gr_udp_sink::~gr_udp_sink ()
{
- gruel::scoped_lock guard(d_mutex); // hold mutex for duration of this function
+ if (d_connected)
+ disconnect();
- if (d_socket){
+ if (d_socket != -1){
shutdown(d_socket, SHUT_RDWR);
- d_socket = 0;
+#if defined(USING_WINSOCK)
+ closesocket(d_socket);
+#else
+ ::close(d_socket);
+#endif
+ d_socket = -1;
}
- d_updated = true;
+
+#if defined(USING_WINSOCK) // for Windows (with MinGW)
+ // free winsock resources
+ WSACleanup();
+#endif
}
int
@@ -174,21 +171,31 @@ gr_udp_sink::work (int noutput_items,
ssize_t total_size = noutput_items*d_itemsize;
#if SNK_VERBOSE
- printf("Entered upd_sink\n");
+ printf("Entered udp_sink\n");
#endif
+ gruel::scoped_lock guard(d_mutex); // protect d_socket
+
while(bytes_sent < total_size) {
bytes_to_send = std::min((ssize_t)d_payload_size, (total_size-bytes_sent));
- r = send(d_socket, (in+bytes_sent), bytes_to_send, 0);
- if(r == -1) { // error on send command
- perror("udp_sink"); // there should be no error case where this function
- return -1; // should not exit immediately
+ if(d_connected) {
+ r = send(d_socket, (in+bytes_sent), bytes_to_send, 0);
+ if(r == -1) { // error on send command
+ if( is_error(ECONNREFUSED) )
+ r = bytes_to_send; // discard data until receiver is started
+ else {
+ report_error("udp_sink",NULL); // there should be no error case where
+ return -1; // this function should not exit immediately
+ }
+ }
}
+ else
+ r = bytes_to_send; // discarded for lack of connection
bytes_sent += r;
#if SNK_VERBOSE
- printf("\tbyte sent: %d bytes\n", bytes);
+ printf("\tbyte sent: %d bytes\n", r);
#endif
}
@@ -198,3 +205,98 @@ gr_udp_sink::work (int noutput_items,
return noutput_items;
}
+
+void gr_udp_sink::connect( const char *host, unsigned short port )
+{
+ if(d_connected)
+ disconnect();
+
+ if(host != NULL ) {
+ // Get the destination address
+ struct addrinfo *ip_dst;
+ struct addrinfo hints;
+ memset( (void*)&hints, 0, sizeof(hints) );
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ char port_str[12];
+ sprintf( port_str, "%d", port );
+
+ // FIXME leaks if report_error throws below
+ int ret = getaddrinfo( host, port_str, &hints, &ip_dst );
+ if( ret != 0 )
+ report_error("gr_udp_source/getaddrinfo",
+ "can't initialize destination socket" );
+
+ // don't need d_mutex lock when !d_connected
+ if(::connect(d_socket, ip_dst->ai_addr, ip_dst->ai_addrlen) == -1) {
+ report_error("socket connect","can't connect to socket");
+ }
+ d_connected = true;
+
+ freeaddrinfo(ip_dst);
+ }
+
+ return;
+}
+
+void gr_udp_sink::disconnect()
+{
+ if(!d_connected)
+ return;
+
+ #if SNK_VERBOSE
+ printf("gr_udp_sink disconnecting\n");
+ #endif
+
+ gruel::scoped_lock guard(d_mutex); // protect d_socket from work()
+
+ // Send a few zero-length packets to signal receiver we are done
+ if(d_eof) {
+ int i;
+ for( i = 0; i < 3; i++ )
+ (void) send( d_socket, NULL, 0, 0 ); // ignore errors
+ }
+
+ // Sending EOF can produce ERRCONNREFUSED errors that won't show up
+ // until the next send or recv, which might confuse us if it happens
+ // on a new connection. The following does a nonblocking recv to
+ // clear any such errors.
+ timeval timeout;
+ timeout.tv_sec = 0; // zero time for immediate return
+ timeout.tv_usec = 0;
+ fd_set readfds;
+ FD_ZERO(&readfds);
+ FD_SET(d_socket, &readfds);
+ int r = select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);
+ if(r < 0) {
+ #if SNK_VERBOSE
+ report_error("udp_sink/select",NULL);
+ #endif
+ }
+ else if(r > 0) { // call recv() to get error return
+ r = recv(d_socket, (char*)&readfds, sizeof(readfds), 0);
+ if(r < 0) {
+ #if SNK_VERBOSE
+ report_error("udp_sink/recv",NULL);
+ #endif
+ }
+ }
+
+ // Since I can't find any way to disconnect a datagram socket in Cygwin,
+ // we just leave it connected but disable sending.
+#if 0
+ // zeroed address structure should reset connection
+ struct sockaddr addr;
+ memset( (void*)&addr, 0, sizeof(addr) );
+ // addr.sa_family = AF_UNSPEC; // doesn't work on Cygwin
+ // addr.sa_family = AF_INET; // doesn't work on Cygwin
+
+ if(::connect(d_socket, &addr, sizeof(addr)) == -1)
+ report_error("socket connect","can't connect to socket");
+#endif
+
+ d_connected = false;
+
+ return;
+}
diff --git a/gnuradio-core/src/lib/io/gr_udp_sink.h b/gnuradio-core/src/lib/io/gr_udp_sink.h
index f22b92dd0..421d514a4 100644
--- a/gnuradio-core/src/lib/io/gr_udp_sink.h
+++ b/gnuradio-core/src/lib/io/gr_udp_sink.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2007,2008,2009 Free Software Foundation, Inc.
+ * Copyright 2007,2008,2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -24,18 +24,6 @@
#define INCLUDED_GR_UDP_SINK_H
#include <gr_sync_block.h>
-#include <boost/thread.hpp>
-#if defined(HAVE_SOCKET)
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#elif defined(HAVE_WINDOWS_H)
-#include <winsock2.h>
-#include <windows.h>
-#endif
-#if defined(HAVE_NETINET_IN_H)
-#include <netinet/in.h>
-#endif
-
#include <gruel/thread.h>
class gr_udp_sink;
@@ -43,85 +31,75 @@ typedef boost::shared_ptr<gr_udp_sink> gr_udp_sink_sptr;
gr_udp_sink_sptr
gr_make_udp_sink (size_t itemsize,
- const char *src, unsigned short port_src,
- const char *dst, unsigned short port_dst,
- int payload_size=1472);
+ const char *host, unsigned short port,
+ int payload_size=1472, bool eof=true);
/*!
* \brief Write stream to an UDP socket.
* \ingroup sink_blk
*
* \param itemsize The size (in bytes) of the item datatype
- * \param src The source address as either the host name or the 'numbers-and-dots'
- * IP address
- * \param port_src Destination port to bind to (0 allows socket to choose an appropriate port)
- * \param dst The destination address as either the host name or the 'numbers-and-dots'
- * IP address
- * \param port_dst Destination port to connect to
- * \param payload_size UDP payload size by default set to
- * 1472 = (1500 MTU - (8 byte UDP header) - (20 byte IP header))
+ * \param host The name or IP address of the receiving host; use
+ * NULL or None for no connection
+ * \param port Destination port to connect to on receiving host
+ * \param payload_size UDP payload size by default set to 1472 =
+ * (1500 MTU - (8 byte UDP header) - (20 byte IP header))
+ * \param eof Send zero-length packet on disconnect
*/
class gr_udp_sink : public gr_sync_block
{
friend gr_udp_sink_sptr gr_make_udp_sink (size_t itemsize,
- const char *src, unsigned short port_src,
- const char *dst, unsigned short port_dst,
- int payload_size);
+ const char *host,
+ unsigned short port,
+ int payload_size, bool eof);
private:
size_t d_itemsize;
- bool d_updated;
- gruel::mutex d_mutex;
- int d_payload_size; // maximum transmission unit (packet length)
- int d_socket; // handle to socket
- int d_socket_rcv; // handle to socket retuned in the accept call
- struct in_addr d_ip_src; // store the source ip info
- struct in_addr d_ip_dst; // store the destination ip info
- unsigned short d_port_src; // the port number to open for connections to this service
- unsigned short d_port_dst; // port number of the remove system
- struct sockaddr_in d_sockaddr_src; // store the source sockaddr data (formatted IP address and port number)
- struct sockaddr_in d_sockaddr_dst; // store the destination sockaddr data (formatted IP address and port number)
+ int d_payload_size; // maximum transmission unit (packet length)
+ bool d_eof; // send zero-length packet on disconnect
+ int d_socket; // handle to socket
+ bool d_connected; // are we connected?
+ gruel::mutex d_mutex; // protects d_socket and d_connected
protected:
/*!
* \brief UDP Sink Constructor
*
* \param itemsize The size (in bytes) of the item datatype
- * \param src The source address as either the host name or the 'numbers-and-dots'
- * IP address
- * \param port_src Destination port to bind to (0 allows socket to choose an appropriate port)
- * \param dst The destination address as either the host name or the 'numbers-and-dots'
- * IP address
- * \param port_dst Destination port to connect to
+ * \param host The name or IP address of the receiving host; use
+ * NULL or None for no connection
+ * \param port Destination port to connect to on receiving host
* \param payload_size UDP payload size by default set to
* 1472 = (1500 MTU - (8 byte UDP header) - (20 byte IP header))
+ * \param eof Send zero-length packet on disconnect
*/
gr_udp_sink (size_t itemsize,
- const char *src, unsigned short port_src,
- const char *dst, unsigned short port_dst,
- int payload_size);
+ const char *host, unsigned short port,
+ int payload_size, bool eof);
public:
~gr_udp_sink ();
- /*!
- * \brief open a socket specified by the port and ip address info
- *
- * Opens a socket, binds to the address, and makes connectionless association
- * over UDP. If any of these fail, the fuction retuns the error and exits.
- */
- bool open();
+ /*! \brief return the PAYLOAD_SIZE of the socket */
+ int payload_size() { return d_payload_size; }
- /*!
- * \brief Close current socket.
+ /*! \brief Change the connection to a new destination
+ *
+ * \param host The name or IP address of the receiving host; use
+ * NULL or None to break the connection without closing
+ * \param port Destination port to connect to on receiving host
*
- * Shuts down read/write on the socket
+ * Calls disconnect() to terminate any current connection first.
*/
- void close();
+ void connect( const char *host, unsigned short port );
- /*! \brief return the PAYLOAD_SIZE of the socket */
- int payload_size() { return d_payload_size; }
+ /*! \brief Send zero-length packet (if eof is requested) then stop sending
+ *
+ * Zero-byte packets can be interpreted as EOF by gr_udp_source. Note that
+ * disconnect occurs automatically when the sink is destroyed, but not when
+ * its top_block stops.*/
+ void disconnect();
// should we export anything else?
diff --git a/gnuradio-core/src/lib/io/gr_udp_sink.i b/gnuradio-core/src/lib/io/gr_udp_sink.i
index 0f37b477b..a71006ae0 100644
--- a/gnuradio-core/src/lib/io/gr_udp_sink.i
+++ b/gnuradio-core/src/lib/io/gr_udp_sink.i
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2007 Free Software Foundation, Inc.
+ * Copyright 2007,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -25,22 +25,22 @@ GR_SWIG_BLOCK_MAGIC(gr,udp_sink)
gr_udp_sink_sptr
gr_make_udp_sink (size_t itemsize,
- const char *src, unsigned short port_src,
- const char *dst, unsigned short port_dst,
- int payload_size=1472);
+ const char *host, unsigned short port,
+ int payload_size=1472, bool eof=true) throw (std::runtime_error);
class gr_udp_sink : public gr_sync_block
{
protected:
gr_udp_sink (size_t itemsize,
- const char *src, unsigned short port_src,
- const char *dst, unsigned short port_dst,
- int payload_size);
-
- bool open();
- void close();
- int payload_size() { return d_payload_size; }
+ const char *host, unsigned short port,
+ int payload_size, bool eof)
+ throw (std::runtime_error);
public:
~gr_udp_sink ();
+
+ int payload_size() { return d_payload_size; }
+ void connect( const char *host, unsigned short port );
+ void disconnect();
+
};
diff --git a/gnuradio-core/src/lib/io/gr_udp_source.cc b/gnuradio-core/src/lib/io/gr_udp_source.cc
index d76d0ee32..fea9a26ba 100644
--- a/gnuradio-core/src/lib/io/gr_udp_source.cc
+++ b/gnuradio-core/src/lib/io/gr_udp_source.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2007,2008,2009 Free Software Foundation, Inc.
+ * Copyright 2007,2008,2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -29,80 +29,126 @@
#include <errno.h>
#include <stdio.h>
#include <string.h>
-#if defined(HAVE_SOCKET)
+
+#if defined(HAVE_NETDB_H)
#include <netdb.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
typedef void* optval_t;
-#else
+
+// ntohs() on FreeBSD may require both netinet/in.h and arpa/inet.h, in order
+#if defined(HAVE_NETINET_IN_H)
+#include <netinet/in.h>
+#endif
+#if defined(HAVE_ARPA_INET_H)
+#include <arpa/inet.h>
+#endif
+
+#elif defined(HAVE_WINDOWS_H)
+// if not posix, assume winsock
+#define USING_WINSOCK
+#include <winsock2.h>
+#include <ws2tcpip.h>
#define SHUT_RDWR 2
-#define inet_aton(N,A) ( (A)->s_addr = inet_addr(N), ( (A)->s_addr != INADDR_NONE ) )
typedef char* optval_t;
#endif
+#define USE_SELECT 1 // non-blocking receive on all platforms
+#define USE_RCV_TIMEO 0 // non-blocking receive on all but Cygwin
#define SRC_VERBOSE 0
-gr_udp_source::gr_udp_source(size_t itemsize, const char *src,
- unsigned short port_src, int payload_size)
+static int is_error( int perr )
+{
+ // Compare error to posix error code; return nonzero if match.
+#if defined(USING_WINSOCK)
+#define ENOPROTOOPT 109
+ // All codes to be checked for must be defined below
+ int werr = WSAGetLastError();
+ switch( werr ) {
+ case WSAETIMEDOUT:
+ return( perr == EAGAIN );
+ case WSAENOPROTOOPT:
+ return( perr == ENOPROTOOPT );
+ default:
+ fprintf(stderr,"gr_udp_source/is_error: unknown error %d\n", perr );
+ throw std::runtime_error("internal error");
+ }
+ return 0;
+#else
+ return( perr == errno );
+#endif
+}
+
+static void report_error( const char *msg1, const char *msg2 )
+{
+ // Deal with errors, both posix and winsock
+#if defined(USING_WINSOCK)
+ int werr = WSAGetLastError();
+ fprintf(stderr, "%s: winsock error %d\n", msg1, werr );
+#else
+ perror(msg1);
+#endif
+ if( msg2 != NULL )
+ throw std::runtime_error(msg2);
+ return;
+}
+
+gr_udp_source::gr_udp_source(size_t itemsize, const char *host,
+ unsigned short port, int payload_size,
+ bool eof, bool wait)
: gr_sync_block ("udp_source",
gr_make_io_signature(0, 0, 0),
gr_make_io_signature(1, 1, itemsize)),
- d_itemsize(itemsize), d_updated(false), d_payload_size(payload_size), d_residual(0), d_temp_offset(0)
+ d_itemsize(itemsize), d_payload_size(payload_size),
+ d_eof(eof), d_wait(wait), d_socket(-1), d_residual(0), d_temp_offset(0)
{
int ret = 0;
+
+#if defined(USING_WINSOCK) // for Windows (with MinGW)
+ // initialize winsock DLL
+ WSADATA wsaData;
+ int iResult = WSAStartup( MAKEWORD(2,2), &wsaData );
+ if( iResult != NO_ERROR ) {
+ report_error( "gr_udp_source WSAStartup", "can't open socket" );
+ }
+#endif
// Set up the address stucture for the source address and port numbers
// Get the source IP address from the host name
- struct hostent *hsrc = gethostbyname(src);
- if(hsrc) { // if the source was provided as a host namex
- d_ip_src = *(struct in_addr*)hsrc->h_addr_list[0];
- }
- else { // assume it was specified as an IP address
- if((ret=inet_aton(src, &d_ip_src)) == 0) { // format IP address
- perror("Not a valid source IP address or host name");
- throw std::runtime_error("can't initialize source socket");
- }
- }
+ struct addrinfo *ip_src; // store the source IP address to use
+ struct addrinfo hints;
+ memset( (void*)&hints, 0, sizeof(hints) );
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ hints.ai_flags = AI_PASSIVE;
+ char port_str[12];
+ sprintf( port_str, "%d", port );
- d_port_src = htons(port_src); // format port number
-
- d_sockaddr_src.sin_family = AF_INET;
- d_sockaddr_src.sin_addr = d_ip_src;
- d_sockaddr_src.sin_port = d_port_src;
+ // FIXME leaks if report_error throws below
+ ret = getaddrinfo( host, port_str, &hints, &ip_src );
+ if( ret != 0 )
+ report_error("gr_udp_source/getaddrinfo",
+ "can't initialize source socket" );
+ // FIXME leaks if report_error throws below
d_temp_buff = new char[d_payload_size]; // allow it to hold up to payload_size bytes
-
- open();
-}
-gr_udp_source_sptr
-gr_make_udp_source (size_t itemsize, const char *ipaddr,
- unsigned short port, int payload_size)
-{
- return gr_udp_source_sptr (new gr_udp_source (itemsize, ipaddr,
- port, payload_size));
-}
-
-gr_udp_source::~gr_udp_source ()
-{
- delete [] d_temp_buff;
- close();
-}
-
-bool
-gr_udp_source::open()
-{
- gruel::scoped_lock guard(d_mutex); // hold mutex for duration of this function
// create socket
- d_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ d_socket = socket(ip_src->ai_family, ip_src->ai_socktype,
+ ip_src->ai_protocol);
if(d_socket == -1) {
- perror("socket open");
- throw std::runtime_error("can't open socket");
+ report_error("socket open","can't open socket");
}
// Turn on reuse address
int opt_val = 1;
if(setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR, (optval_t)&opt_val, sizeof(int)) == -1) {
- perror("SO_REUSEADDR");
- throw std::runtime_error("can't set socket option SO_REUSEADDR");
+ report_error("SO_REUSEADDR","can't set socket option SO_REUSEADDR");
}
// Don't wait when shutting down
@@ -110,40 +156,61 @@ gr_udp_source::open()
lngr.l_onoff = 1;
lngr.l_linger = 0;
if(setsockopt(d_socket, SOL_SOCKET, SO_LINGER, (optval_t)&lngr, sizeof(linger)) == -1) {
- perror("SO_LINGER");
- throw std::runtime_error("can't set socket option SO_LINGER");
+ if( !is_error(ENOPROTOOPT) ) { // no SO_LINGER for SOCK_DGRAM on Windows
+ report_error("SO_LINGER","can't set socket option SO_LINGER");
+ }
}
+#if USE_RCV_TIMEO
// Set a timeout on the receive function to not block indefinitely
// This value can (and probably should) be changed
+ // Ignored on Cygwin
+#if defined(USING_WINSOCK)
+ DWORD timeout = 1000; // milliseconds
+#else
timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
+#endif
if(setsockopt(d_socket, SOL_SOCKET, SO_RCVTIMEO, (optval_t)&timeout, sizeof(timeout)) == -1) {
- perror("SO_RCVTIMEO");
- throw std::runtime_error("can't set socket option SO_RCVTIMEO");
+ report_error("SO_RCVTIMEO","can't set socket option SO_RCVTIMEO");
}
+#endif // USE_RCV_TIMEO
// bind socket to an address and port number to listen on
- if(bind (d_socket, (sockaddr*)&d_sockaddr_src, sizeof(struct sockaddr)) == -1) {
- perror("socket bind");
- throw std::runtime_error("can't bind socket");
+ if(bind (d_socket, ip_src->ai_addr, ip_src->ai_addrlen) == -1) {
+ report_error("socket bind","can't bind socket");
}
-
- d_updated = true;
- return d_socket != 0;
+ freeaddrinfo(ip_src);
+
}
-void
-gr_udp_source::close()
+gr_udp_source_sptr
+gr_make_udp_source (size_t itemsize, const char *ipaddr,
+ unsigned short port, int payload_size, bool eof, bool wait)
{
- gruel::scoped_lock guard(d_mutex); // hold mutex for duration of this function
+ return gr_udp_source_sptr (new gr_udp_source (itemsize, ipaddr,
+ port, payload_size, eof, wait));
+}
+
+gr_udp_source::~gr_udp_source ()
+{
+ delete [] d_temp_buff;
- if (d_socket){
+ if (d_socket != -1){
shutdown(d_socket, SHUT_RDWR);
- d_socket = 0;
+#if defined(USING_WINSOCK)
+ closesocket(d_socket);
+#else
+ ::close(d_socket);
+#endif
+ d_socket = -1;
}
- d_updated = true;
+
+#if defined(USING_WINSOCK) // for Windows (with MinGW)
+ // free winsock resources
+ WSACleanup();
+#endif
}
int
@@ -175,29 +242,85 @@ gr_udp_source::work (int noutput_items,
// Update indexing of amount of bytes left in the buffer
d_residual -= nbytes;
- d_temp_offset = d_temp_offset+d_residual;
+ d_temp_offset += nbytes;
+
+ // Return now with what we've got.
+ assert(nbytes % d_itemsize == 0);
+ return nbytes/d_itemsize;
}
while(1) {
// get the data into our output buffer and record the number of bytes
+
+#if USE_SELECT
+ // RCV_TIMEO doesn't work on all systems (e.g., Cygwin)
+ // use select() instead of, or in addition to RCV_TIMEO
+ fd_set readfds;
+ timeval timeout;
+ timeout.tv_sec = 1; // Init timeout each iteration. Select can modify it.
+ timeout.tv_usec = 0;
+ FD_ZERO(&readfds);
+ FD_SET(d_socket, &readfds);
+ r = select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);
+ if(r < 0) {
+ report_error("udp_source/select",NULL);
+ return -1;
+ }
+ else if(r == 0 ) { // timed out
+ if( d_wait ) {
+ // Allow boost thread interrupt, then try again
+ boost::this_thread::interruption_point();
+ continue;
+ }
+ else
+ return -1;
+ }
+#endif // USE_SELECT
+
// This is a non-blocking call with a timeout set in the constructor
r = recv(d_socket, d_temp_buff, d_payload_size, 0); // get the entire payload or the what's available
+ // If r > 0, round it down to a multiple of d_itemsize
+ // (If sender is broken, don't propagate problem)
+ if (r > 0)
+ r = (r/d_itemsize) * d_itemsize;
+
// Check if there was a problem; forget it if the operation just timed out
if(r == -1) {
- if(errno == EAGAIN) { // handle non-blocking call timeout
+ if( is_error(EAGAIN) ) { // handle non-blocking call timeout
#if SRC_VERBOSE
printf("UDP receive timed out\n");
#endif
- // Break here to allow the rest of the flow graph time to run and so ctrl-C breaks
- break;
+ if( d_wait ) {
+ // Allow boost thread interrupt, then try again
+ boost::this_thread::interruption_point();
+ continue;
+ }
+ else
+ return -1;
}
else {
- perror("udp_source");
+ report_error("udp_source/recv",NULL);
return -1;
}
}
+ else if(r==0) {
+ if(d_eof) {
+ // zero-length packet interpreted as EOF
+
+ #if SNK_VERBOSE
+ printf("\tzero-length packet received; returning EOF\n");
+ #endif
+
+ return -1;
+ }
+ else{
+ // do we need to allow boost thread interrupt?
+ boost::this_thread::interruption_point();
+ continue;
+ }
+ }
else {
// Calculate the number of bytes we can take from the buffer in this call
nbytes = std::min(r, total_bytes-bytes_received);
@@ -235,3 +358,15 @@ gr_udp_source::work (int noutput_items,
return bytes_received/d_itemsize;
}
+// Return port number of d_socket
+int gr_udp_source::get_port(void)
+{
+ sockaddr_in name;
+ socklen_t len = sizeof(name);
+ int ret = getsockname( d_socket, (sockaddr*)&name, &len );
+ if( ret ) {
+ report_error("gr_udp_source/getsockname",NULL);
+ return -1;
+ }
+ return ntohs(name.sin_port);
+}
diff --git a/gnuradio-core/src/lib/io/gr_udp_source.h b/gnuradio-core/src/lib/io/gr_udp_source.h
index 61d719e4d..5d30fad30 100644
--- a/gnuradio-core/src/lib/io/gr_udp_source.h
+++ b/gnuradio-core/src/lib/io/gr_udp_source.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2007,2008,2009 Free Software Foundation, Inc.
+ * Copyright 2007,2008,2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -24,54 +24,48 @@
#define INCLUDED_GR_UDP_SOURCE_H
#include <gr_sync_block.h>
-#if defined(HAVE_SOCKET)
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#elif defined(HAVE_WINDOWS_H)
-#include <winsock2.h>
-#include <windows.h>
-#endif
-#if defined(HAVE_NETINET_IN_H)
-#include <netinet/in.h>
-#endif
-
#include <gruel/thread.h>
class gr_udp_source;
typedef boost::shared_ptr<gr_udp_source> gr_udp_source_sptr;
-gr_udp_source_sptr gr_make_udp_source(size_t itemsize, const char *src,
- unsigned short port_src, int payload_size=1472);
+gr_udp_source_sptr gr_make_udp_source(size_t itemsize, const char *host,
+ unsigned short port,
+ int payload_size=1472,
+ bool eof=true, bool wait=true);
/*!
* \brief Read stream from an UDP socket.
* \ingroup source_blk
*
* \param itemsize The size (in bytes) of the item datatype
- * \param src The source address as either the host name or the 'numbers-and-dots'
- * IP address
- * \param port_src The port number on which the socket listens for data
- * \param payload_size UDP payload size by default set to
- * 1472 = (1500 MTU - (8 byte UDP header) - (20 byte IP header))
+ * \param host The name or IP address of the receiving host; can be
+ * NULL, None, or "0.0.0.0" to allow reading from any
+ * interface on the host
+ * \param port The port number on which to receive data; use 0 to
+ * have the system assign an unused port number
+ * \param payload_size UDP payload size by default set to 1472 =
+ * (1500 MTU - (8 byte UDP header) - (20 byte IP header))
+ * \param eof Interpret zero-length packet as EOF (default: true)
+ * \param wait Wait for data if not immediately available
+ * (default: true)
*
*/
class gr_udp_source : public gr_sync_block
{
- friend gr_udp_source_sptr gr_make_udp_source(size_t itemsize, const char *src,
- unsigned short port_src, int payload_size);
+ friend gr_udp_source_sptr gr_make_udp_source(size_t itemsize,
+ const char *host,
+ unsigned short port,
+ int payload_size,
+ bool eof, bool wait);
private:
size_t d_itemsize;
- bool d_updated;
- gruel::mutex d_mutex;
-
- int d_payload_size; // maximum transmission unit (packet length)
- int d_socket; // handle to socket
- int d_socket_rcv; // handle to socket retuned in the accept call
- struct in_addr d_ip_src; // store the source IP address to use
- unsigned short d_port_src; // the port number to open for connections to this service
- struct sockaddr_in d_sockaddr_src; // store the source sockaddr data (formatted IP address and port number)
+ int d_payload_size; // maximum transmission unit (packet length)
+ bool d_eof; // zero-length packet is EOF
+ bool d_wait; // wait if data if not immediately available
+ int d_socket; // handle to socket
char *d_temp_buff; // hold buffer between calls
ssize_t d_residual; // hold information about number of bytes stored in the temp buffer
size_t d_temp_offset; // point to temp buffer location offset
@@ -81,35 +75,29 @@ class gr_udp_source : public gr_sync_block
* \brief UDP Source Constructor
*
* \param itemsize The size (in bytes) of the item datatype
- * \param src The source address as either the host name or the 'numbers-and-dots'
- * IP address
- * \param port_src The port number on which the socket listens for data
- * \param payload_size UDP payload size by default set to
- * 1472 = (1500 MTU - (8 byte UDP header) - (20 byte IP header))
+ * \param host The name or IP address of the receiving host; can be
+ * NULL, None, or "0.0.0.0" to allow reading from any
+ * interface on the host
+ * \param port The port number on which to receive data; use 0 to
+ * have the system assign an unused port number
+ * \param payload_size UDP payload size by default set to 1472 =
+ * (1500 MTU - (8 byte UDP header) - (20 byte IP header))
+ * \param eof Interpret zero-length packet as EOF (default: true)
+ * \param wait Wait for data if not immediately available
+ * (default: true)
*/
- gr_udp_source(size_t itemsize, const char *src, unsigned short port_src, int payload_size);
+ gr_udp_source(size_t itemsize, const char *host, unsigned short port,
+ int payload_size, bool eof, bool wait);
public:
~gr_udp_source();
- /*!
- * \brief open a socket specified by the port and ip address info
- *
- * Opens a socket, binds to the address, and waits for a connection
- * over UDP. If any of these fail, the fuction retuns the error and exits.
- */
- bool open();
-
- /*!
- * \brief Close current socket.
- *
- * Shuts down read/write on the socket
- */
- void close();
-
/*! \brief return the PAYLOAD_SIZE of the socket */
int payload_size() { return d_payload_size; }
+ /*! \brief return the port number of the socket */
+ int get_port();
+
// should we export anything else?
int work(int noutput_items,
diff --git a/gnuradio-core/src/lib/io/gr_udp_source.i b/gnuradio-core/src/lib/io/gr_udp_source.i
index fb39dad68..2001f33e9 100644
--- a/gnuradio-core/src/lib/io/gr_udp_source.i
+++ b/gnuradio-core/src/lib/io/gr_udp_source.i
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2007 Free Software Foundation, Inc.
+ * Copyright 2007,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -23,20 +23,19 @@
GR_SWIG_BLOCK_MAGIC(gr,udp_source)
gr_udp_source_sptr
-gr_make_udp_source (size_t itemsize, const char *src,
- unsigned short port_src, int payload_size=1472);
+gr_make_udp_source (size_t itemsize, const char *host,
+ unsigned short port, int payload_size=1472,
+ bool eof=true, bool wait=true) throw (std::runtime_error);
class gr_udp_source : public gr_sync_block
{
protected:
- gr_udp_source (size_t itemsize, const char *src,
- unsigned short port_src, int payload_size);
+ gr_udp_source (size_t itemsize, const char *host,
+ unsigned short port, int payload_size, bool eof, bool wait) throw (std::runtime_error);
public:
~gr_udp_source ();
- bool open();
- void close();
int payload_size() { return d_payload_size; }
-
+ int get_port();
};
diff --git a/gnuradio-core/src/python/gnuradio/gr/Makefile.am b/gnuradio-core/src/python/gnuradio/gr/Makefile.am
index 3aff89ee7..341f58812 100644
--- a/gnuradio-core/src/python/gnuradio/gr/Makefile.am
+++ b/gnuradio-core/src/python/gnuradio/gr/Makefile.am
@@ -1,5 +1,5 @@
#
-# Copyright 2004,2005,2006,2008 Free Software Foundation, Inc.
+# Copyright 2004,2005,2006,2008,2010 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -97,4 +97,5 @@ noinst_PYTHON = \
qa_unpack_k_bits.py \
qa_repeat.py \
qa_scrambler.py \
+ qa_udp_sink_source.py \
qa_vector_sink_source.py
diff --git a/gnuradio-core/src/python/gnuradio/gr/qa_udp_sink_source.py b/gnuradio-core/src/python/gnuradio/gr/qa_udp_sink_source.py
new file mode 100755
index 000000000..b00b26bbe
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/gr/qa_udp_sink_source.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python
+#
+# Copyright 2008,2010 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+from gnuradio import gr, gr_unittest
+from threading import Timer
+
+class test_sink_source(gr_unittest.TestCase):
+
+ def setUp(self):
+ self.tb_snd = gr.top_block()
+ self.tb_rcv = gr.top_block()
+
+ def tearDown(self):
+ self.tb_rcv = None
+ self.tb_snd = None
+
+ def test_001(self):
+ port = 65500
+
+ n_data = 16
+ src_data = [float(x) for x in range(n_data)]
+ expected_result = tuple(src_data)
+ src = gr.vector_source_f(src_data)
+ udp_snd = gr.udp_sink( gr.sizeof_float, 'localhost', port )
+ self.tb_snd.connect( src, udp_snd )
+
+ udp_rcv = gr.udp_source( gr.sizeof_float, 'localhost', port )
+ dst = gr.vector_sink_f()
+ self.tb_rcv.connect( udp_rcv, dst )
+
+ self.tb_rcv.start()
+ self.tb_snd.run()
+ udp_snd.disconnect()
+ self.timeout = False
+ q = Timer(3.0,self.stop_rcv)
+ q.start()
+ self.tb_rcv.wait()
+ q.cancel()
+
+ result_data = dst.data()
+ self.assertEqual(expected_result, result_data)
+ self.assert_(not self.timeout)
+
+ def test_002(self):
+ udp_rcv = gr.udp_source( gr.sizeof_float, '0.0.0.0', 0, eof=False )
+ rcv_port = udp_rcv.get_port()
+
+ udp_snd = gr.udp_sink( gr.sizeof_float, '127.0.0.1', 65500 )
+ udp_snd.connect( 'localhost', rcv_port )
+
+ n_data = 16
+ src_data = [float(x) for x in range(n_data)]
+ expected_result = tuple(src_data)
+ src = gr.vector_source_f(src_data)
+ dst = gr.vector_sink_f()
+
+ self.tb_snd.connect( src, udp_snd )
+ self.tb_rcv.connect( udp_rcv, dst )
+
+ self.tb_rcv.start()
+ self.tb_snd.run()
+ udp_snd.disconnect()
+ self.timeout = False
+ q = Timer(3.0,self.stop_rcv)
+ q.start()
+ self.tb_rcv.wait()
+ q.cancel()
+
+ result_data = dst.data()
+ self.assertEqual(expected_result, result_data)
+ self.assert_(self.timeout) # source ignores EOF?
+
+ def stop_rcv(self):
+ self.timeout = True
+ self.tb_rcv.stop()
+ #print "tb_rcv stopped by Timer"
+
+if __name__ == '__main__':
+ gr_unittest.main ()
+