/* -*- Mode:C; c-basic-offset:4; tab-width:8; indent-tabs-mode:t -*- */
/* vim:set sts=4 ts=8: */
/*
* Copyright (c) 2001
* YOID Project.
* University of Southern California/Information Sciences Institute.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ident "$XORP: xorp/libcomm/comm_user.c,v 1.23 2006/10/12 01:24:45 pavlin Exp $"
/*
* COMM socket library higher `sock' level implementation.
*/
#include "comm_module.h"
#include "libxorp/xorp.h"
#include "libxorp/xlog.h"
#include "libxorp/debug.h"
#include <signal.h>
#ifdef HAVE_WINDOWS_H
#include <windows.h>
#endif
#ifdef HAVE_WINSOCK2_H
#include <winsock2.h>
#endif
#ifdef HAVE_WS2TCPIP_H
#include <ws2tcpip.h>
#endif
#include "comm_api.h"
#include "comm_private.h"
/**
* comm_init:
* @void:
*
* Library initialization. Need be called only once, during startup.
* XXX: Not currently thread-safe.
*
* Return value: %XORP_OK on success, otherwise %XORP_ERROR.
**/
int
comm_init(void)
{
static int init_flag = 0;
if (init_flag)
return (XORP_OK);
#ifdef HOST_OS_WINDOWS
{
int result;
WORD version;
WSADATA wsadata;
version = MAKEWORD(2, 2);
result = WSAStartup(version, &wsadata);
if (result != 0) {
return (XORP_ERROR);
}
if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wVersion) != 2) {
(void)WSACleanup();
return (XORP_ERROR);
}
}
#endif /* HOST_OS_WINDOWS */
init_flag = 1;
return (XORP_OK);
}
/**
* comm_exit:
* @void:
*
* Library termination/cleanup. Must be called at process exit.
* XXX: Not currently thread-safe.
*
**/
void
comm_exit(void)
{
#ifdef HOST_OS_WINDOWS
(void)WSACleanup();
#endif
}
/**
* comm_get_last_error:
*
* Retrieve the most recently occured socket error.
* XXX: This is inherently single threaded.
*
* Return value: Operating system specific error code for this thread's
* last socket operation.
*/
int
comm_get_last_error(void)
{
return _comm_serrno;
}
/**
* Retrieve a human readable string (in English) for the given error code.
* XXX: This is essentially a duplicate of win_strerror() now.
* XXX: Not currently thread-safe.
*
* @param serrno the socket error number returned by comm_get_last_error().
* @return Pointer to a string giving more information about the error.
*/
char const *
comm_get_error_str(int serrno)
{
#ifdef HOST_OS_WINDOWS
static char msgbuf[1024];
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, serrno,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)msgbuf, sizeof(msgbuf), NULL);
return (const char *)msgbuf;
#else
return (const char *)strerror(serrno);
#endif
}
/**
* comm_get_last_error_str:
*
* @return a human readable string of the last error.
*/
char const *
comm_get_last_error_str(void)
{
return comm_get_error_str(comm_get_last_error());
}
/**
* comm_ipv4_present:
*
* Return value: %XORP_OK if IPv4 support present, otherwise %XORP_ERROR
*/
int
comm_ipv4_present(void)
{
return XORP_OK;
}
/**
* comm_ipv6_present:
*
* XXX: Windows: This could be compiled on a system with IPv6 visible,
* but run on a system without IPv6 loaded.
*
* Return value: %XORP_OK if IPv6 support present, otherwise %XORP_ERROR
*/
int
comm_ipv6_present(void)
{
#ifdef HAVE_IPV6
return XORP_OK;
#else
return XORP_ERROR;
#endif /* HAVE_IPV6 */
}
/**
* comm_open_tcp:
* @family: The address family.
* @is_blocking: If true, then the socket will be blocking, otherwise
* non-blocking.
*
* Open a TCP socket.
*
* Return value: The new socket on success, otherwsise %XORP_BAD_SOCKET.
**/
xsock_t
comm_open_tcp(int family, int is_blocking)
{
xsock_t sock;
comm_init();
sock = comm_sock_open(family, SOCK_STREAM, 0, is_blocking);
if (sock == XORP_BAD_SOCKET)
return (XORP_BAD_SOCKET);
return (sock);
}
/**
* comm_open_udp:
* @family: The address family.
* @is_blocking: If true, then the socket will be blocking, otherwise
* non-blocking.
*
* Open an UDP socket.
*
* Return value: The new socket on success, otherwsise %XORP_BAD_SOCKET.
**/
xsock_t
comm_open_udp(int family, int is_blocking)
{
xsock_t sock;
comm_init();
sock = comm_sock_open(family, SOCK_DGRAM, 0, is_blocking);
if (sock == XORP_BAD_SOCKET)
return (XORP_BAD_SOCKET);
return (sock);
}
/**
* comm_close:
* @sock: The socket to close.
*
* Close a socket.
*
* Return value: %XORP_OK on success, otherwise %XORP_ERROR.
**/
int
comm_close(xsock_t sock)
{
if (comm_sock_close(sock) != XORP_OK)
return (XORP_ERROR);
return (XORP_OK);
}
/**
* comm_bind_tcp4:
* @my_addr: The local IPv4 address to bind to (in network order).
* If it is NULL, will bind to `any' local address.
* @my_port: The local port to bind to (in network order).
* @is_blocking: If true, then the socket will be blocking, otherwise
* non-blocking.
*
* Open an IPv4 TCP socket and bind it to a local address and a port.
*
* Return value: The new socket on success, otherwise %XORP_BAD_SOCKET.
**/
xsock_t
comm_bind_tcp4(const struct in_addr *my_addr, unsigned short my_port,
int is_blocking)
{
xsock_t sock;
comm_init();
sock = comm_sock_open(AF_INET, SOCK_STREAM, 0, is_blocking);
if (sock == XORP_BAD_SOCKET)
return (XORP_BAD_SOCKET);
if (comm_set_reuseaddr(sock, 1) != XORP_OK) {
comm_sock_close(sock);
return (XORP_BAD_SOCKET);
}
if (comm_sock_bind4(sock, my_addr, my_port) != XORP_OK) {
comm_sock_close(sock);
return (XORP_BAD_SOCKET);
}
if (listen(sock, 5) < 0) {
_comm_set_serrno();
XLOG_ERROR("Error listen() on socket %d: %s",
sock, comm_get_error_str(comm_get_last_error()));
comm_sock_close(sock);
return (XORP_BAD_SOCKET);
}
return (sock);
}
/**
* comm_bind_tcp6:
* @my_addr: The local IPv6 address to bind to (in network order).
* If it is NULL, will bind to `any' local address.
* @my_port: The local port to bind to (in network order).
* @is_blocking: If true, then the socket will be blocking, otherwise
* non-blocking.
*
* Open an IPv6 TCP socket and bind it to a local address and a port.
*
* Return value: The new socket on success, otherwise %XORP_BAD_SOCKET.
**/
xsock_t
comm_bind_tcp6(const struct in6_addr *my_addr, unsigned short my_port,
int is_blocking)
{
#ifdef HAVE_IPV6
xsock_t sock;
comm_init();
sock = comm_sock_open(AF_INET6, SOCK_STREAM, 0, is_blocking);
if (sock == XORP_BAD_SOCKET)
return (XORP_BAD_SOCKET);
if (comm_set_reuseaddr(sock, 1) != XORP_OK) {
comm_sock_close(sock);
return (XORP_BAD_SOCKET);
}
if (comm_sock_bind6(sock, my_addr, my_port) != XORP_OK) {
comm_sock_close(sock);
return (XORP_BAD_SOCKET);
}
if (listen(sock, 5) < 0) {
_comm_set_serrno();
XLOG_ERROR("Error listen() on socket %d: %s",
sock, comm_get_error_str(comm_get_last_error()));
comm_sock_close(sock);
return (XORP_BAD_SOCKET);
}
return (sock);
#else /* ! HAVE_IPV6 */
comm_sock_no_ipv6("comm_bind_tcp6", my_addr, my_port, is_blocking);
return (XORP_BAD_SOCKET);
#endif /* ! HAVE_IPV6 */
}
/**
* Open a TCP (IPv4 or IPv6) socket and bind it to a local address and a port.
*
* @param sin agnostic sockaddr containing the local address (If it is
* NULL, will bind to `any' local address.) and the local port to
* bind to all in network order.
* @param is_blocking if true then the socket will be blocking, otherwise
* non-blocking.
* @return the new socket on success, otherwise XORP_BAD_SOCKET.
*/
xsock_t
comm_bind_tcp(const struct sockaddr *sock, int is_blocking)
{
switch (sock->sa_family) {
case AF_INET:
{
const struct sockaddr_in *sin = (const struct sockaddr_in *)((const void *)sock);
return comm_bind_tcp4(&sin->sin_addr, sin->sin_port, is_blocking);
}
break;
#ifdef HAVE_IPV6
case AF_INET6:
{
const struct sockaddr_in6 *sin = (const struct sockaddr_in6 *)((const void *)sock);
return comm_bind_tcp6(&sin->sin6_addr, sin->sin6_port,
is_blocking);
}
break;
#endif /* HAVE_IPV6 */
default:
XLOG_FATAL("Error comm_bind_tcp invalid family = %d", sock->sa_family);
return (XORP_ERROR);
}
XLOG_UNREACHABLE();
return XORP_ERROR;
}
/**
* comm_bind_udp4:
* @my_addr: The local IPv4 address to bind to (in network order).
* If it is NULL, will bind to `any' local address.
* @my_port: The local port to bind to (in network order).
* @is_blocking: If true, then the socket will be blocking, otherwise
* non-blocking.
*
* Open an IPv4 UDP socket and bind it to a local address and a port.
*
* Return value: The new socket on success, otherwise %XORP_BAD_SOCKET.
**/
xsock_t
comm_bind_udp4(const struct in_addr *my_addr, unsigned short my_port,
int is_blocking)
{
xsock_t sock;
comm_init();
sock = comm_sock_open(AF_INET, SOCK_DGRAM, 0, is_blocking);
if (sock == XORP_BAD_SOCKET)
return (XORP_BAD_SOCKET);
if (comm_sock_bind4(sock, my_addr, my_port) != XORP_OK) {
comm_sock_close(sock);
return (XORP_BAD_SOCKET);
}
return (sock);
}
/**
* comm_bind_udp6:
* @my_addr: The local IPv6 address to bind to (in network order).
* If it is NULL, will bind to `any' local address.
* @my_port: The local port to bind to (in network order).
* @is_blocking: If true, then the socket will be blocking, otherwise
* non-blocking.
*
* Open an IPv6 UDP socket and bind it to a local address and a port.
*
* Return value: The new socket on success, otherwise %XORP_BAD_SOCKET.
**/
xsock_t
comm_bind_udp6(const struct in6_addr *my_addr, unsigned short my_port,
int is_blocking)
{
#ifdef HAVE_IPV6
xsock_t sock;
comm_init();
sock = comm_sock_open(AF_INET6, SOCK_DGRAM, 0, is_blocking);
if (sock == XORP_BAD_SOCKET)
return (XORP_BAD_SOCKET);
if (comm_sock_bind6(sock, my_addr, my_port) != XORP_OK) {
comm_sock_close(sock);
return (XORP_BAD_SOCKET);
}
return (sock);
#else /* ! HAVE_IPV6 */
comm_sock_no_ipv6("comm_bind_udp6", my_addr, my_port, is_blocking);
return (XORP_BAD_SOCKET);
#endif /* ! HAVE_IPV6 */
}
/**
* comm_bind_join_udp4:
* @mcast_addr: The multicast address to join.
* @join_if_addr: The local unicast interface address (in network order)
* to join the multicast group on.
* If it is NULL, the system will choose the interface each
* time a datagram is sent.
* @my_port: The port to bind to (in network order).
* @reuse_flag: If true, allow other sockets to bind to the same multicast
* address and port, otherwise disallow it.
* @is_blocking: If true, then the socket will be blocking, otherwise
* non-blocking.
*
* Open an IPv4 UDP socket on an interface, bind it to a port,
* and join a multicast group.
*
* Note that we bind to ANY address instead of the multicast address
* only. If we bind to the multicast address instead, then using
* the same socket for sending multicast packets will trigger a bug
* in the FreeBSD kernel: the source IP address will be set to the
* multicast address. Hence, the application itself may want to filter
* the UDP unicast packets that may have arrived with a destination address
* one of the local interface addresses and the same port number.
*
* Return value: The new socket on success, otherwise %XORP_BAD_SOCKET.
**/
xsock_t
comm_bind_join_udp4(const struct in_addr *mcast_addr,
const struct in_addr *join_if_addr,
unsigned short my_port,
int reuse_flag, int is_blocking)
{
xsock_t sock;
comm_init();
sock = comm_sock_open(AF_INET, SOCK_DGRAM, 0, is_blocking);
if (sock == XORP_BAD_SOCKET)
return (XORP_BAD_SOCKET);
if (reuse_flag) {
if (comm_set_reuseaddr(sock, 1) != XORP_OK) {
comm_sock_close(sock);
return (XORP_BAD_SOCKET);
}
if (comm_set_reuseport(sock, 1) != XORP_OK) {
comm_sock_close(sock);
return (XORP_BAD_SOCKET);
}
}
/* Bind the socket */
if (comm_sock_bind4(sock, NULL, my_port) != XORP_OK) {
comm_sock_close(sock);
return (XORP_BAD_SOCKET);
}
/* Join the multicast group */
if (comm_sock_join4(sock, mcast_addr, join_if_addr) != XORP_OK) {
comm_sock_close(sock);
return (XORP_BAD_SOCKET);
}
return (sock);
}
/**
* comm_bind_join_udp6:
* @mcast_addr: The multicast address to join.
* @join_if_index: The local unicast interface index to join the multicast
* group on. If it is 0, the system will choose the interface each
* time a datagram is sent.
* @my_port: The port to bind to (in network order).
* @reuse_flag: If true, allow other sockets to bind to the same multicast
* address and port, otherwise disallow it.
* @is_blocking: If true, then the socket will be blocking, otherwise
* non-blocking.
*
* Open an IPv6 UDP socket on an interface, bind it to a port,
* and join a multicast group.
*
* Note that we bind to ANY address instead of the multicast address
* only. If we bind to the multicast address instead, then using
* the same socket for sending multicast packets will trigger a bug
* in the FreeBSD kernel: the source IP address will be set to the
* multicast address. Hence, the application itself may want to filter
* the UDP unicast packets that may have arrived with a destination address
* one of the local interface addresses and the same port number.
*
* Return value: The new socket on success, otherwise %XORP_BAD_SOCKET.
**/
xsock_t
comm_bind_join_udp6(const struct in6_addr *mcast_addr,
unsigned int join_if_index,
unsigned short my_port,
int reuse_flag, int is_blocking)
{
#ifdef HAVE_IPV6
xsock_t sock;
comm_init();
sock = comm_sock_open(AF_INET6, SOCK_DGRAM, 0, is_blocking);
if (sock == XORP_BAD_SOCKET)
return (XORP_BAD_SOCKET);
if (reuse_flag) {
if (comm_set_reuseaddr(sock, 1) != XORP_OK) {
comm_sock_close(sock);
return (XORP_BAD_SOCKET);
}
if (comm_set_reuseport(sock, 1) != XORP_OK) {
comm_sock_close(sock);
return (XORP_BAD_SOCKET);
}
}
/* Bind the socket */
if (comm_sock_bind6(sock, NULL, my_port) != XORP_OK) {
comm_sock_close(sock);
return (XORP_BAD_SOCKET);
}
/* Join the multicast group */
if (comm_sock_join6(sock, mcast_addr, join_if_index) != XORP_OK) {
comm_sock_close(sock);
return (XORP_BAD_SOCKET);
}
return (sock);
#else /* ! HAVE_IPV6 */
comm_sock_no_ipv6("comm_bind_join_udp6", mcast_addr, join_if_index,
my_port, reuse_flag, is_blocking);
return (XORP_BAD_SOCKET);
#endif /* ! HAVE_IPV6 */
}
/**
* Open an IPv4 TCP socket, and connect it to a remote address and port.
*
* @param remote_addr the remote address to connect to.
* @param remote_port the remote port to connect to.
* @param is_blocking if true then the socket will be blocking, otherwise
* non-blocking.
* @param in_progress if the socket is non-blocking and the connect cannot be
* completed immediately, then the referenced value is set to 1, and the
* return value is the new socket. If the non-blocking socket was connected,
* the referenced value is set to 0. If the return value is XORP_BAD_SOCKET
* or if the socket is blocking, then the return value is undefined.
* @return the new socket on success, otherwise XORP_BAD_SOCKET.
*/
xsock_t
comm_connect_tcp4(const struct in_addr *remote_addr,
unsigned short remote_port, int is_blocking,
int *in_progress)
{
xsock_t sock;
if (in_progress != NULL)
*in_progress = 0;
comm_init();
sock = comm_sock_open(AF_INET, SOCK_STREAM, 0, is_blocking);
if (sock == XORP_BAD_SOCKET)
return (XORP_BAD_SOCKET);
if (comm_sock_connect4(sock, remote_addr, remote_port, is_blocking,
in_progress)
!= XORP_OK) {
/*
* If this is a non-blocking socket and the connect couldn't
* complete, then return the socket.
*/
if ((! is_blocking) && (in_progress != NULL) && (*in_progress == 1))
return (sock);
comm_sock_close(sock);
return (XORP_BAD_SOCKET);
}
return (sock);
}
/**
* Open an IPv6 TCP socket, and connect it to a remote address and port.
*
* @param remote_addr the remote address to connect to.
* @param remote_port the remote port to connect to.
* @param is_blocking if true then the socket will be blocking, otherwise
* non-blocking.
* @param in_progress if the socket is non-blocking and the connect cannot be
* completed immediately, then the referenced value is set to 1, and the
* return value is the new socket. If the non-blocking socket was connected,
* the referenced value is set to 0. If the return value is XORP_BAD_SOCKET
* or if the socket is blocking, then the return value is undefined.
* @return the new socket on success, otherwise XORP_BAD_SOCKET.
*/
xsock_t
comm_connect_tcp6(const struct in6_addr *remote_addr,
unsigned short remote_port, int is_blocking,
int *in_progress)
{
#ifdef HAVE_IPV6
xsock_t sock;
if (in_progress != NULL)
*in_progress = 0;
comm_init();
sock = comm_sock_open(AF_INET6, SOCK_STREAM, 0, is_blocking);
if (sock == XORP_BAD_SOCKET)
return (XORP_BAD_SOCKET);
if (comm_sock_connect6(sock, remote_addr, remote_port, is_blocking,
in_progress)
!= XORP_OK) {
/*
* If this is a non-blocking socket and the connect couldn't
* complete, then return the socket.
*/
if ((! is_blocking) && (in_progress != NULL) && (*in_progress == 1))
return (sock);
comm_sock_close(sock);
return (XORP_BAD_SOCKET);
}
return (sock);
#else /* ! HAVE_IPV6 */
if (in_progress != NULL)
*in_progress = 0;
comm_sock_no_ipv6("comm_connect_tcp6", remote_addr, remote_port,
is_blocking, in_progress);
return (XORP_BAD_SOCKET);
#endif /* ! HAVE_IPV6 */
}
/**
* Open an IPv4 UDP socket, and connect it to a remote address and port.
*
* @param remote_addr the remote address to connect to.
* @param remote_port the remote port to connect to.
* @param is_blocking if true then the socket will be blocking, otherwise
* non-blocking.
* @param in_progress if the socket is non-blocking and the connect cannot be
* completed immediately, then the referenced value is set to 1, and the
* return value is the new socket. If the non-blocking socket was connected,
* the referenced value is set to 0. If the return value is XORP_BAD_SOCKET
* or if the socket is blocking, then the return value is undefined.
* @return the new socket on success, otherwise XORP_BAD_SOCKET.
*/
xsock_t
comm_connect_udp4(const struct in_addr *remote_addr,
unsigned short remote_port, int is_blocking,
int *in_progress)
{
xsock_t sock;
if (in_progress != NULL)
*in_progress = 0;
comm_init();
sock = comm_sock_open(AF_INET, SOCK_DGRAM, 0, is_blocking);
if (sock == XORP_BAD_SOCKET)
return (XORP_BAD_SOCKET);
if (comm_sock_connect4(sock, remote_addr, remote_port, is_blocking,
in_progress)
!= XORP_OK) {
/*
* If this is a non-blocking socket and the connect couldn't
* complete, then return the socket.
*/
if ((! is_blocking) && (in_progress != NULL) && (*in_progress == 1))
return (sock);
comm_sock_close(sock);
return (XORP_BAD_SOCKET);
}
return (sock);
}
/**
* Open an IPv6 UDP socket, and connect it to a remote address and port.
*
* @param remote_addr the remote address to connect to.
* @param remote_port the remote port to connect to.
* @param is_blocking if true then the socket will be blocking, otherwise
* non-blocking.
* @param in_progress if the socket is non-blocking and the connect cannot be
* completed immediately, then the referenced value is set to 1, and the
* return value is the new socket. If the non-blocking socket was connected,
* the referenced value is set to 0. If the return value is XORP_BAD_SOCKET
* or if the socket is blocking, then the return value is undefined.
* @return the new socket on success, otherwise XORP_BAD_SOCKET.
*/
xsock_t
comm_connect_udp6(const struct in6_addr *remote_addr,
unsigned short remote_port, int is_blocking,
int *in_progress)
{
#ifdef HAVE_IPV6
xsock_t sock;
if (in_progress != NULL)
*in_progress = 0;
comm_init();
sock = comm_sock_open(AF_INET6, SOCK_DGRAM, 0, is_blocking);
if (sock == XORP_BAD_SOCKET)
return (XORP_BAD_SOCKET);
if (comm_sock_connect6(sock, remote_addr, remote_port, is_blocking,
in_progress)
!= XORP_OK) {
/*
* If this is a non-blocking socket and the connect couldn't
* complete, then return the socket.
*/
if ((! is_blocking) && (in_progress != NULL) && (*in_progress == 1))
return (sock);
comm_sock_close(sock);
return (XORP_BAD_SOCKET);
}
return (sock);
#else /* ! HAVE_IPV6 */
if (in_progress != NULL)
*in_progress = 0;
comm_sock_no_ipv6("comm_connect_udp6", remote_addr, remote_port,
is_blocking, in_progress);
return (XORP_BAD_SOCKET);
#endif /* ! HAVE_IPV6 */
}
/**
* Open an IPv4 UDP socket, bind it to a local address and a port,
* and connect it to a remote address and port.
*
* @param local_addr the local address to bind to.
* If it is NULL, will bind to `any' local address.
* @param local_port the local port to bind to.
* @param remote_addr the remote address to connect to.
* @param remote_port the remote port to connect to.
* @param is_blocking if true then the socket will be blocking, otherwise
* non-blocking.
* @param in_progress if the socket is non-blocking and the connect cannot be
* completed immediately, then the referenced value is set to 1, and the
* return value is the new socket. If the non-blocking socket was connected,
* the referenced value is set to 0. If the return value is XORP_BAD_SOCKET
* or if the socket is blocking, then the return value is undefined.
* @return the new socket on success, otherwise XORP_BAD_SOCKET.
*/
xsock_t
comm_bind_connect_udp4(const struct in_addr *local_addr,
unsigned short local_port,
const struct in_addr *remote_addr,
unsigned short remote_port,
int is_blocking,
int *in_progress)
{
xsock_t sock;
if (in_progress != NULL)
*in_progress = 0;
comm_init();
sock = comm_sock_open(AF_INET, SOCK_DGRAM, 0, is_blocking);
if (sock == XORP_BAD_SOCKET)
return (XORP_BAD_SOCKET);
if (comm_sock_bind4(sock, local_addr, local_port) != XORP_OK) {
comm_sock_close(sock);
return (XORP_BAD_SOCKET);
}
if (comm_sock_connect4(sock, remote_addr, remote_port, is_blocking,
in_progress)
!= XORP_OK) {
/*
* If this is a non-blocking socket and the connect couldn't
* complete, then return the socket.
*/
if ((! is_blocking) && (in_progress != NULL) && (*in_progress == 1))
return (sock);
comm_sock_close(sock);
return (XORP_BAD_SOCKET);
}
return (sock);
}
/**
* Open an IPv6 UDP socket, bind it to a local address and a port,
* and connect it to a remote address and port.
*
* @param local_addr the local address to bind to.
* If it is NULL, will bind to `any' local address.
* @param local_port the local port to bind to.
* @param remote_addr the remote address to connect to.
* @param remote_port the remote port to connect to.
* @param is_blocking if true then the socket will be blocking, otherwise
* non-blocking.
* @param in_progress if the socket is non-blocking and the connect cannot be
* completed immediately, then the referenced value is set to 1, and the
* return value is the new socket. If the non-blocking socket was connected,
* the referenced value is set to 0. If the return value is XORP_BAD_SOCKET
* or if the socket is blocking, then the return value is undefined.
* @return the new socket on success, otherwise XORP_BAD_SOCKET.
*/
xsock_t
comm_bind_connect_udp6(const struct in6_addr *local_addr,
unsigned short local_port,
const struct in6_addr *remote_addr,
unsigned short remote_port,
int is_blocking,
int *in_progress)
{
#ifdef HAVE_IPV6
xsock_t sock;
if (in_progress != NULL)
*in_progress = 0;
comm_init();
sock = comm_sock_open(AF_INET6, SOCK_DGRAM, 0, is_blocking);
if (sock == XORP_BAD_SOCKET)
return (XORP_BAD_SOCKET);
if (comm_sock_bind6(sock, local_addr, local_port) != XORP_OK) {
comm_sock_close(sock);
return (XORP_BAD_SOCKET);
}
if (comm_sock_connect6(sock, remote_addr, remote_port, is_blocking,
in_progress)
!= XORP_OK) {
/*
* If this is a non-blocking socket and the connect couldn't
* complete, then return the socket.
*/
if ((! is_blocking) && (in_progress != NULL) && (*in_progress == 1))
return (sock);
comm_sock_close(sock);
return (XORP_BAD_SOCKET);
}
return (sock);
#else /* ! HAVE_IPV6 */
if (in_progress != NULL)
*in_progress = 0;
comm_sock_no_ipv6("comm_bind_connect_udp6", local_addr, local_port,
remote_addr, remote_port, is_blocking, in_progress);
return (XORP_BAD_SOCKET);
#endif /* ! HAVE_IPV6 */
}
syntax highlighted by Code2HTML, v. 0.9.1