apr-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Martin Schlapfer <mar...@schlapfer.com>
Subject Re: Help with non-blocking UDP datagram receive
Date Tue, 07 Apr 2009 00:49:14 GMT
Hi Eric,

It looks like on windows, apr_pollset_poll() sits on top of select().  
I'm new to APR, so excuse me if there is some other way of doing this. 
However, on windows, I tried the following (program below) to catch the 
interrupt by installing a signal handler that then writes to a socket.  
This acts to notify select() that an interrupt has occurred.

What you could do is add your UDP socket to the pollset as well.  This 
way, on return from the apr_pollset_poll() you test for either (1) 
timeout, (2) interrupted (by way of data in socket "s"), (3) or data 
from your socket.

- Martin.

Note, no: error checking, thread safety, etc....

#include <apr_poll.h>
#include <apr_network_io.h>

apr_socket_t *s;
apr_sockaddr_t *sa;

extern "C" void sigint_handler(int sig) {
    char buf = 'x';
    apr_size_t len = 1;
    apr_socket_sendto(s, sa, 0, &buf, &len);
}

int main()
{
    apr_pool_t         *pool;
    apr_pollset_t      *poll_set;
    int                 rv = 0;
    const apr_pollfd_t *descs = NULL;
    apr_pollfd_t        socket_pollfd;

    /* Initialize APR */
    apr_initialize();
    apr_pool_create(&pool, NULL);
   
    /* Create a socket */
    apr_sockaddr_info_get(&sa, "127.0.0.1", APR_UNSPEC, 0, 0, pool);
    apr_socket_create(&s, sa->family, SOCK_DGRAM, 0, pool);
    apr_socket_bind(s, sa);

    /* Set the interrupt signal handler */
    signal(SIGINT,sigint_handler);

    /* Create a poll set and add the socket to the poll set */
    apr_pollset_create(&poll_set,1,pool,0);

    socket_pollfd.desc_type = APR_POLL_SOCKET;
    socket_pollfd.reqevents = APR_POLLIN;
    socket_pollfd.desc.s = s;
    socket_pollfd.client_data = s;

    apr_pollset_add(poll_set, &socket_pollfd);
   
    /* Sit in select() for 30 secs.  If interrupted before then,
     * socket will have data (rv == 1), otherwise rv = 0.
     */
    apr_pollset_poll(poll_set, 30000000,&rv,&descs);
   
    printf("result = %d\n",rv);

    return 0;
}

ERIC WOOD wrote:
> Thanks for the response.
>
> I was unaware apr had a select(); I thought that is what pollset() was
> for.  In any case, I don't see how it would help my blocking problem. 
> As I mentioned at my comments after my code:
>
>   
>> This code on Windows causes a WSAEWOULDBLOCK error when no data is
>> received and a WSAEMSGSIZE when a datagram is received.  If I set it
>>     
> to
>   
>> block and specify a timeout, then I get a WSAETIMEDOUT error when no
>> data is received and a WSAEMSGSIZE when a datagram is received.  If
>>     
> I
>   
>> set it to block AND do not set a timeout, I receive the datagram
>> correctly, but then I can't do anything else while waiting for a
>> datagram (like catch the exit signal).  Any guidance you can provide
>>     
> is
>   
>> appreciated.
>>     
>
>  If I configure non-blocking, I get Winsock errors.  If I block(), then
> I don't get to sleep() til after I receive a message.  I'm looking for
> an answer as to why I can't configure non-blocking.
>
>   
>>>> Martin Schlapfer <martin@schlapfer.com> 4/3/2009 12:51 PM >>>
>>>>         
> Have you tried sitting on select() rather than sleeping?
> -Martin.
>
> ERIC WOOD wrote:
>   
>> I am having trouble receiving UDP datagrams without blocking:  Here
>>     
> is
>   
>> my code snippet:
>>
>>   // Create the socket address
>>   rv = apr_sockaddr_info_get(&sa, "localhost", APR_INET, iPort, 0,
>> mp);
>>   if( rv != APR_SUCCESS )
>>   {
>>     std::cout << "Failed to get socket address for receiving
>>     
> messages"
>   
>> 		      << std::endl; 
>> 	return -1;
>>   }
>>    
>>   // Create the socket
>>   rv = apr_socket_create(&s, sa->family, SOCK_DGRAM, APR_PROTO_UDP,
>> mp);
>> //  rv = apr_socket_create(&s, sa->family, SOCK_STREAM,
>>     
> APR_PROTO_TCP,
>   
>> mp);
>>   if( rv != APR_SUCCESS )
>>   {
>>     std::cout << "Failed to create socket for receiving messages" <<
>> std::endl; 
>> 	return -1;
>>   }
>>
>>   // Set options
>>   apr_socket_opt_set( s, APR_SO_NONBLOCK, 1 );
>>   apr_socket_timeout_set( s, APR_USEC_PER_SEC );
>>
>>
>>   // Bind the socket.  
>>   rv = apr_socket_bind( s, sa );
>>   if( rv != APR_SUCCESS )
>>   {
>>     std::cout << "Failed to bind socket for receiving messages" <<
>> std::endl; 
>> 	return -1;
>>   }
>>
>>   finished = 0;
>>
>>   char buf[1048];
>>   apr_size_t len = 1048;
>>   apr_sockaddr_t * saRecvdFrom;
>>
>>   // Main loop
>>   std::cout << "\n\nUGCS Security Banner Client started. Enter
>>     
> CTRL+C
>   
>> to \
>> exit.\n\n" << std::endl;
>>   while(!finished)
>>   {
>>     // Do blocking reads with 1 sec timeout to allow for signal
>> catching
>>     apr_status_t rv = apr_socket_recvfrom(sa, s, 0, buf, &len);
>> 	if( rv != APR_SUCCESS && rv != APR_TIMEUP )
>>     {
>> 	  char sError[1048];
>> 	  apr_strerror( rv, sError, 1048 );
>> 	  std::cout << "Error receiving data from socket.  Error: " 
>> 		        << sError << "(" << rv << ")" << std::endl;

>> 	 // return -1;
>>     }
>> 	
>> 	if ( len > 0 )
>> 	{
>> 	  std::cout << "Data received" << std::endl;
>> 	}
>> 	std::cout << "tick" << std::endl;
>> 	sleep( 1000 );
>>   }
>>
>>  
>> This code on Windows causes a WSAEWOULDBLOCK error when no data is
>> received and a WSAEMSGSIZE when a datagram is received.  If I set it
>>     
> to
>   
>> block and specify a timeout, then I get a WSAETIMEDOUT error when no
>> data is received and a WSAEMSGSIZE when a datagram is received.  If
>>     
> I
>   
>> set it to block AND do not set a timeout, I receive the datagram
>> correctly, but then I can't do anything else while waiting for a
>> datagram (like catch the exit signal).  Any guidance you can provide
>>     
> is
>   
>> appreciated.
>>
>>
>>
>>   
>>     
>
>
>   


Mime
View raw message