[ this is more an APR usage question, thanks to redirect me to another
more appropriate list if any ]


Platform: Windows (XP SP2), MS Visual C++ 2003 7.1.3088


I'm trying to setup multicast reception with polling sockets.

Q? Is this possible: multicast + DGRAM (UDP) + polling ?


If no, what would be the better way to process (I tried to avoid having
N threads suspended each on its own socket... and to avoid having active
wait with a loop testing N sockets with immediate return for each) ?


If yes, here is my current usage and problem with APR and polling:

apr_pool_create 
apr_pcalloc
        => create a memory pool associated to the socket
                for my management, allocate memory in the
                pool
apr_parse_addr_port
        => resolve DNS things if any
apr_sockaddr_info_get
        => fill'in apr_sockaddr_t structure from address string
                (using family APR_UNSPEC and flags APR_IPV4_ADDR_OK)
apr_socket_create
        => make the socket
                (using type SOCK_DGRAM and protocol APR_PROTO_UDP
                and same sock_addr family as sockaddr_info)
apr_socket_opt_set
        => set socket blocking (APR_SO_NONBLOCK, 0) [see note 1]
apr_socket_timeout_set
        => set infinite timeout (-1) [see note 1]
apr_socket_opt_set
        => allow address reuse (APR_SO_REUSEADDR, 1)
apr_socket_bind
        => bind socket to sock_addr

*** I have a failure here, using address 239.192.10.10:12345       ***
*** Error APR 730049                                               ***
*** [in english ~= requested address is not valid in its context]  ***
*** I tried blocking/non-blocking socket options, same result      ***

For multicast, I have the following operations:
        apr_mcast_hops
                => setup mcast routing zone
        apr_mcast_loopback
                => allow loopback on mcast
        apr_mcast_join
                => join mcast group

apr_pollset_add
        => add socket to poll for APR_POLLIN


The listing is at the end of this email (note 2).


Thanks for any help/idea.

L.Pointal.




[note 1] I read for portable blocking in
http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial-13.html#ss13.4

[note 2] Partial source (I removed status tests and logs generation for
readability):

...........................;

/** A specific socket management structure. */
struct _bvnet_socket_management_t
    {
    /** Internal check code.
    _BVNET_INTERNAL_MAGIC
    */
    u_long internal_magic ;
    /** Memory pool for this socket related operations. */
    apr_pool_t* mempool ;
    /** Host and port used to bind socket. */
    char* hostnameport ;
    /** Multicast use on this socket. */
    int ttlmcast ;
    /** Address for binding. */
        char* addr ;
        /** Port for binding. */
    apr_port_t port ;
    /** Socket address binding informations. */
    apr_sockaddr_t* sock_addr ;
    /** Socket reference. */
    apr_socket_t* sock ;
    /** Socket poll file descriptor. */
    apr_pollfd_t pfd ;
    } ;
typedef struct _bvnet_socket_management_t _bvnet_socket_management_t ;


/** The global application listening structure.
*/
struct _bvnet_listening_t
    {
    /** Memory pool for listening structures. */
    apr_pool_t* mempool ;
    /** Socket management to use when listener work in a separate
        thread. */
    _bvnet_socket_management_t* listener_ctrl_sm ;
    /** Currently receiving messages.
    This is a hash on message identifier giving message reception
         structures.
    */
    apr_hash_t* running_messages_hash ;
    /** Messages which have been completly received.
    Here we just keep a time stamp for each received message.
    From time to time, a function must process this map and remove all
    entries where time stamps
    */
    apr_hash_t* received_messages_hash ;
    /** Pool of sockets to listen to. */
    apr_pollset_t* listening_sockets_poll ;
    /** Descriptors for these sockets. */
    apr_pollfd_t* sockets_table ;
    /** Number of descriptors. */
    int sockets_table_count ;
    } ;

typedef struct _bvnet_listening_t _bvnet_listening_t ;

/** Data for all listenings.
*/
_bvnet_listening_t my_listenings ;


................


//=========================================================================
apr_status_t
_bvnet_make_listen_to(const char* hostnameport, int makewritable, int
ttlmcast, _bvnet_socket_management_t** return_sm)
{
apr_status_t status ;
apr_pool_t* mempool = NULL ;
_bvnet_socket_management_t* sm = NULL ;
char* scope_id ;

*return_sm = NULL ;

// Make a poll for the socket.
status = apr_pool_create(&mempool,my_listenings.mempool) ;

// Allocate room in the poll for socket management (set it to zeroes).
sm =  apr_pcalloc(mempool,sizeof(_bvnet_socket_management_t)) ;
sm->internal_magic = _BVNET_INTERNAL_MAGIC ;
sm->ttlmcast = ttlmcast ;
sm->mempool = mempool ;

// We keep a copy of original hostname and port - may be nice for logs.
sm->hostnameport = apr_pstrdup (sm->mempool,hostnameport) ;

// Extract port from hosname and port.
status = apr_parse_addr_port (
        &sm->addr, //   char **          addr,
        &scope_id, // char **   scope_id,
        &sm->port, // apr_port_t *      port,
        sm->hostnameport, // const char *        str,
        sm->mempool// apr_pool_t *      p       
        ) ;


// Create socket address to bind to.
status = apr_sockaddr_info_get(
        &sm->sock_addr, //apr_sockaddr_t **      sa,
        sm->addr,       //const char *          hostname,
        // family: Let the system decide which address family to use,
        //in place of APR_INET[6].
        APR_UNSPEC,     //apr_int32_t   family,
        sm->port,           //apr_port_t        port,
        // flags: Use IPV4 if available, and fallback to IPV6
        // only if cant find IPV4.
        APR_IPV4_ADDR_OK,              //apr_int32_t    flags,
        sm->mempool // apr_pool_t *     p       
        ) ;

// Create socket.
status = apr_socket_create(     
        &sm->sock, //apr_socket_t **     new_sock,
        sm->sock_addr->family,     //int        family,
        SOCK_DGRAM,     //int   type,
        APR_PROTO_UDP,  //int            protocol,
        sm->mempool //apr_pool_t *      cont    
        ) ;

// Set socket options.
// !!! See portability issue in INOUE Seiichiro tutorial !!!
// !!! (section 13.4 - real network programming)         !!!
// !!! Options selected to have indefinitely blocking.   !!!
// !!! => modified to become non-blocking (blocking commented out)
status = apr_socket_opt_set(sm->sock,APR_SO_NONBLOCK, 0) ;  // blocking

apr_socket_timeout_set(sm->sock, -1) ;             // blocking forever

apr_socket_opt_set(sm->sock,APR_SO_REUSEADDR, 1) ; // can reuse address

// Now, can bind socket to address, and set it listening.
status = apr_socket_bind(sm->sock, sm->sock_addr) ;

// Not found many documentation about APR and its multicast functions
// (there is the ref doc, but no more general guidelines and example
// like in Inoue tutorial).
if (sm->ttlmcast != BVNET_TTL_NO_MCAST)
    {
    // Set maximum TTL - this set the maximum zone that
    // multicast packets
    // can reach (host, service, enterprise...).
    status = apr_mcast_hops(sm->sock, //apr_socket_t * sock,
                sm->ttlmcast //apr_byte_t       ttl     
            )  ;

    // ? Is the loopback notion only process relative or complete
    // host relative.
    // Because we may want no loopback on different parts of
    // same process (considering better alternatives), but want
    // loopback between different
    // process on the same host.
    // In doubt, set it to true (want loopback). At least, this is an
    // existing solution for in-process communications.
    status = apr_mcast_loopback(
        sm->sock, //apr_socket_t *       sock,
        1 //apr_byte_t          opt     
        ) ;     
        
    // Join the multicast group to listen on it.
    status = apr_mcast_join(
        sm->sock, // apr_socket_t *      sock,
        sm->sock_addr, // apr_sockaddr_t *      join,
        NULL, // apr_sockaddr_t *       iface,
        NULL // apr_sockaddr_t *        source  
        ) ;
    }
        
// Install the socket in the poll.
sm->pfd.p = sm->mempool ;  //apr_pool_t *       p
sm->pfd.desc_type = APR_POLL_SOCKET ; //apr_datatype_e  desc_type
sm->pfd.reqevents = APR_POLLIN ; //apr_int16_t  reqevents
sm->pfd.rtnevents = 0 ; //apr_int16_t   rtnevents
sm->pfd.desc.s = sm->sock ; //apr_descriptor    desc
sm->pfd.client_data = sm ; //void *     client_data

status = apr_pollset_add(my_listenings.listening_sockets_poll,&sm->pfd) ;

*return_sm = sm ;
return APR_SUCCESS ;
}







-- 
Laurent POINTAL
CNRS-LIMSI dépt. CHM, groupes AMI et PS
Courriel: [EMAIL PROTECTED]    (prof)
          [EMAIL PROTECTED] (perso)
Ouebe: http://www.limsi.fr/Individu/pointal/
Tél. 01 69 85 81 06 (prof)
Fax. 01 69 85 80 88


Reply via email to