[ 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