From 545901e335f27600c460f749b66d60155a179492 Mon Sep 17 00:00:00 2001 From: U-DON-WORKBENCH\Don Date: Sun, 18 Apr 2010 10:19:30 -0400 Subject: Changes to gr_udp_{source,sink} for MinGW Initialize and cleanup after winsock DLL. Interpret winsock error codes. Use DWORD instead of timeval for setting timeout. --- gnuradio-core/src/lib/io/gr_udp_sink.cc | 80 +++++++++++++++++++++++------- gnuradio-core/src/lib/io/gr_udp_source.cc | 82 +++++++++++++++++++++++++------ 2 files changed, 130 insertions(+), 32 deletions(-) diff --git a/gnuradio-core/src/lib/io/gr_udp_sink.cc b/gnuradio-core/src/lib/io/gr_udp_sink.cc index a837e731e..dff066288 100755 --- a/gnuradio-core/src/lib/io/gr_udp_sink.cc +++ b/gnuradio-core/src/lib/io/gr_udp_sink.cc @@ -31,15 +31,52 @@ #include typedef void* optval_t; #else +#define USING_WINSOCK #define SHUT_RDWR 2 #define inet_aton(N,A) ( (A)->s_addr = inet_addr(N), ( (A)->s_addr != INADDR_NONE ) ) typedef char* optval_t; +#define ENOPROTOOPT 109 #endif #include #define SNK_VERBOSE 0 +static int is_error( int perr ) +{ + // Compare error to posix error code; return nonzero if match. +#if defined(USING_WINSOCK) + // 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( char *msg1, 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_sink::gr_udp_sink (size_t itemsize, const char *src, unsigned short port_src, const char *dst, unsigned short port_dst, @@ -50,6 +87,15 @@ gr_udp_sink::gr_udp_sink (size_t itemsize, d_itemsize (itemsize), d_updated(false), d_payload_size(payload_size) { int ret = 0; + +#if !defined(HAVE_SOCKET) // 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 @@ -59,8 +105,8 @@ gr_udp_sink::gr_udp_sink (size_t itemsize, } 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"); + report_error("Not a valid source IP address or host name", + "can't initialize source socket"); } } @@ -71,8 +117,8 @@ gr_udp_sink::gr_udp_sink (size_t itemsize, } 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"); + report_error("Not a valid destination IP address or host name", + "can't initialize destination socket"); } } @@ -107,6 +153,11 @@ gr_make_udp_sink (size_t itemsize, gr_udp_sink::~gr_udp_sink () { close(); + +#if !defined(HAVE_SOCKET) // for Windows (with MinGW) + // free winsock resources + WSACleanup(); +#endif } bool @@ -116,15 +167,13 @@ gr_udp_sink::open() // create socket if((d_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -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 = 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"); + report_error("SO_REUSEADDR","can't set socket option SO_REUSEADDR"); } // Don't wait when shutting down @@ -132,22 +181,19 @@ 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) { - if(errno != ENOPROTOOPT) { // no SO_LINGER for SOCK_DGRAM on Windows - 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"); + report_error("socket bind","can't bind socket"); } // 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"); + report_error("socket connect","can't connect to socket"); } d_updated = true; @@ -184,8 +230,8 @@ gr_udp_sink::work (int noutput_items, 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 + report_error("udp_sink",NULL); // there should be no error case where + return -1; // this function should not exit immediately } bytes_sent += r; diff --git a/gnuradio-core/src/lib/io/gr_udp_source.cc b/gnuradio-core/src/lib/io/gr_udp_source.cc index fed5b6142..9df47da2e 100755 --- a/gnuradio-core/src/lib/io/gr_udp_source.cc +++ b/gnuradio-core/src/lib/io/gr_udp_source.cc @@ -33,13 +33,51 @@ #include typedef void* optval_t; #else +// Not posix, assume winsock +#define USING_WINSOCK #define SHUT_RDWR 2 #define inet_aton(N,A) ( (A)->s_addr = inet_addr(N), ( (A)->s_addr != INADDR_NONE ) ) typedef char* optval_t; +#define ENOPROTOOPT 109 #endif #define SRC_VERBOSE 0 +static int is_error( int perr ) +{ + // Compare error to posix error code; return nonzero if match. +#if defined(USING_WINSOCK) + // 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( char *msg1, 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 *src, unsigned short port_src, int payload_size) : gr_sync_block ("udp_source", @@ -48,6 +86,15 @@ gr_udp_source::gr_udp_source(size_t itemsize, const char *src, d_itemsize(itemsize), d_updated(false), d_payload_size(payload_size), d_residual(0), d_temp_offset(0) { int ret = 0; + +#if !defined(HAVE_SOCKET) // 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 @@ -57,8 +104,8 @@ gr_udp_source::gr_udp_source(size_t itemsize, const char *src, } 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"); + report_error("Not a valid source IP address or host name", + "can't initialize source socket"); } } @@ -85,6 +132,11 @@ gr_udp_source::~gr_udp_source () { delete [] d_temp_buff; close(); + +#if !defined(HAVE_SOCKET) // for Windows (with MinGW) + // free winsock resources + WSACleanup(); +#endif } bool @@ -94,15 +146,13 @@ gr_udp_source::open() // create socket d_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 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,26 +160,28 @@ 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) { - if(errno != ENOPROTOOPT) { // no SO_LINGER for SOCK_DGRAM on Windows - 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"); } } // 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"); } // 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"); + report_error("socket bind","can't bind socket"); } d_updated = true; @@ -187,7 +239,7 @@ gr_udp_source::work (int noutput_items, // 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 @@ -196,7 +248,7 @@ gr_udp_source::work (int noutput_items, break; } else { - perror("udp_source"); + report_error("udp_source",NULL); return -1; } } -- cgit