mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-03-10 03:41:16 +00:00
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@6644 d0543943-73ff-0310-b7d9-9358b9ac24b2
488 lines
14 KiB
C
488 lines
14 KiB
C
/*
|
|
* This file is part of the Sofia-SIP package
|
|
*
|
|
* Copyright (C) 2005,2006,2007 Nokia Corporation.
|
|
*
|
|
* Contact: Pekka Pessi <pekka.pessi@nokia.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public License
|
|
* as published by the Free Software Foundation; either version 2.1 of
|
|
* the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
* 02110-1301 USA
|
|
*
|
|
*/
|
|
|
|
#ifndef SU_H
|
|
/** Defined when <sofia-sip/su.h> has been included. */
|
|
#define SU_H
|
|
/**@ingroup su_socket
|
|
* @file sofia-sip/su.h Socket and network address interface
|
|
*
|
|
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
|
|
*
|
|
* @date Created: Thu Mar 18 19:40:51 1999 pessi
|
|
*/
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Includes */
|
|
|
|
#ifndef SU_CONFIG_H
|
|
#include <sofia-sip/su_config.h>
|
|
#endif
|
|
#ifndef SU_TYPES_H
|
|
#include <sofia-sip/su_types.h>
|
|
#endif
|
|
#ifndef SU_ERRNO_H
|
|
#include <sofia-sip/su_errno.h>
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <limits.h>
|
|
|
|
#if SU_HAVE_BSDSOCK /* Unix-compatible includes */
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <netdb.h>
|
|
#endif
|
|
|
|
#if SU_HAVE_WINSOCK /* Windows includes */
|
|
# include <winsock2.h>
|
|
# include <ws2tcpip.h>
|
|
# if SU_HAVE_IN6
|
|
# if defined(IPPROTO_IPV6) || (_WIN32_WINNT >= 0x0600)
|
|
/* case 1: IPv6 defined in winsock2.h/ws2tcpip.h */
|
|
# else
|
|
/* case 2: try to use "IPv6 Tech Preview" */
|
|
# include <tpipv6.h>
|
|
# endif
|
|
# endif
|
|
#endif
|
|
|
|
SOFIA_BEGIN_DECLS
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Constant definitions */
|
|
|
|
#if SU_HAVE_BSDSOCK || DOCUMENTATION_ONLY
|
|
enum {
|
|
/** Invalid socket descriptor, error from socket() or accept() */
|
|
INVALID_SOCKET = -1,
|
|
#define INVALID_SOCKET ((su_socket_t)INVALID_SOCKET)
|
|
/** Error from other socket calls */
|
|
SOCKET_ERROR = -1,
|
|
#define SOCKET_ERROR SOCKET_ERROR
|
|
/** Return code for a successful call */
|
|
su_success = 0,
|
|
/** Return code for an unsuccessful call */
|
|
su_failure = -1
|
|
};
|
|
#if SYMBIAN && !defined(MSG_NOSIGNAL)
|
|
#define MSG_NOSIGNAL (0)
|
|
#endif
|
|
#elif SU_HAVE_WINSOCK
|
|
enum {
|
|
su_success = 0,
|
|
su_failure = 0xffffffffUL
|
|
};
|
|
|
|
#define MSG_NOSIGNAL (0)
|
|
|
|
#endif
|
|
|
|
/**@HI Maximum size of host name. */
|
|
#define SU_MAXHOST (1025)
|
|
/**@HI Maximum size of service name. */
|
|
#define SU_MAXSERV (25)
|
|
|
|
/**@HI Maximum size of address in text format. */
|
|
#define SU_ADDRSIZE (48)
|
|
/**@HI Maximum size of port number in text format. */
|
|
#define SU_SERVSIZE (16)
|
|
|
|
#define SU_SUCCESS su_success
|
|
#define SU_FAILURE su_failure
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Type definitions */
|
|
|
|
/** Socket descriptor type. */
|
|
#if SU_HAVE_BSDSOCK || DOCUMENTATION_ONLY
|
|
typedef int su_socket_t;
|
|
#elif SU_HAVE_WINSOCK
|
|
typedef SOCKET su_socket_t;
|
|
#endif
|
|
|
|
#if !SU_HAVE_SOCKADDR_STORAGE
|
|
/*
|
|
* RFC 2553: protocol-independent placeholder for socket addresses
|
|
*/
|
|
#define _SS_MAXSIZE 128
|
|
#define _SS_ALIGNSIZE (sizeof(int64_t))
|
|
#define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof(u_char) * 2)
|
|
#define _SS_PAD2SIZE (_SS_MAXSIZE - sizeof(u_char) * 2 - \
|
|
_SS_PAD1SIZE - _SS_ALIGNSIZE)
|
|
|
|
struct sockaddr_storage {
|
|
#if SU_HAVE_SOCKADDR_SA_LEN
|
|
unsigned char ss_len; /* address length */
|
|
unsigned char ss_family; /* address family */
|
|
#else
|
|
unsigned short ss_family; /* address family */
|
|
#endif
|
|
char __ss_pad1[_SS_PAD1SIZE];
|
|
int64_t __ss_align; /* force desired structure storage alignment */
|
|
char __ss_pad2[_SS_PAD2SIZE];
|
|
};
|
|
#endif
|
|
|
|
/** Common socket address structure. */
|
|
union su_sockaddr_u {
|
|
#ifdef DOCUMENTATION_ONLY
|
|
uint8_t su_len; /**< Length of structure */
|
|
uint8_t su_family; /**< Address family. */
|
|
uint16_t su_port; /**< Port number. */
|
|
#else
|
|
short su_dummy; /**< Dummy member to initialize */
|
|
#if SU_HAVE_SOCKADDR_SA_LEN
|
|
#define su_len su_sa.sa_len
|
|
#define su_family su_sa.sa_family
|
|
#else
|
|
#define su_len su_array[0]
|
|
short su_family;
|
|
#endif
|
|
#define su_port su_sin.sin_port
|
|
#endif
|
|
|
|
char su_array[32]; /**< Presented as chars */
|
|
uint16_t su_array16[16]; /**< Presented as 16-bit ints */
|
|
uint32_t su_array32[8]; /**< Presented as 32-bit ints */
|
|
struct sockaddr su_sa; /**< Address in struct sockaddr format */
|
|
struct sockaddr_in su_sin; /**< Address in IPv4 format */
|
|
#if SU_HAVE_IN6
|
|
struct sockaddr_in6 su_sin6; /**< Address in IPv6 format */
|
|
#endif
|
|
#ifdef DOCUMENTATION_ONLY
|
|
uint32_t su_scope_id; /**< Scope ID. */
|
|
#else
|
|
#define su_scope_id su_array32[6]
|
|
#endif
|
|
};
|
|
|
|
typedef union su_sockaddr_u su_sockaddr_t;
|
|
|
|
#if SU_HAVE_BSDSOCK || DOCUMENTATION_ONLY
|
|
/**Type of @a siv_len field in #su_iovec_t.
|
|
*
|
|
* The @a siv_len field in #su_iovec_t has different types in with POSIX
|
|
* (size_t) and WINSOCK2 (u_long). Truncate the iovec element size to
|
|
* #SU_IOVECLEN_MAX, if needed, and cast using #su_ioveclen_t.
|
|
*
|
|
* @sa #su_iovec_t, #SU_IOVECLEN_MAX
|
|
*
|
|
* @since New in @VERSION_1_12_2.
|
|
*/
|
|
typedef size_t su_ioveclen_t;
|
|
|
|
/** I/O vector for scatter-gather I/O.
|
|
*
|
|
* This is the I/O vector element used with su_vsend() and su_vrecv(). It is
|
|
* defined like struct iovec with POSIX sockets:
|
|
* @code
|
|
* struct iovec {
|
|
* void *iov_base; // Pointer to data.
|
|
* size_t iov_len; // Length of data.
|
|
* };
|
|
* @endcode
|
|
*
|
|
* When using WINSOCK sockets it is defined as
|
|
* <a href="http://msdn.microsoft.com/library/en-us/winsock/winsock/wsabuf_2.asp">
|
|
* WSABUF</a>:
|
|
* @code
|
|
* typedef struct __WSABUF {
|
|
* u_long len;
|
|
* char FAR* buf;
|
|
* } WSABUF, *LPWSABUF;
|
|
* @endcode
|
|
*
|
|
* @note Ordering of the fields is reversed on Windows. Do not initialize
|
|
* this structure with static initializer, but assign both fields
|
|
* separately. Note that the type of the siv_len is #su_ioveclen_t which is
|
|
* defined as u_long on Windows and size_t on POSIX.
|
|
*
|
|
* For historical reasons, the structure is known as #msg_iovec_t in @msg
|
|
* module.
|
|
*
|
|
* @sa #su_ioveclen_t, SU_IOVECLEN_MAX, su_vsend(), su_vrecv(),
|
|
* #msg_iovec_t, msg_iovec(), msg_recv_iovec(),
|
|
* @c struct @c iovec defined in <sys/uio.h>, writev(2), readv(2),
|
|
* sendmsg(), recvmsg(),
|
|
* <a href="http://msdn.microsoft.com/library/en-us/winsock/winsock/wsabuf_2.asp">
|
|
* WSABUF of WinSock2</a>
|
|
*/
|
|
typedef struct su_iovec_s {
|
|
void *siv_base; /**< Pointer to buffer. */
|
|
su_ioveclen_t siv_len; /**< Size of buffer. */
|
|
} su_iovec_t;
|
|
|
|
/** Maximum size of buffer in a single su_iovec_t element.
|
|
* @sa #su_ioveclen_t, #su_iovec_t
|
|
*
|
|
* @since New in @VERSION_1_12_2.
|
|
* @HIDE
|
|
*/
|
|
#define SU_IOVECLEN_MAX SIZE_MAX
|
|
#endif
|
|
|
|
#if SU_HAVE_WINSOCK
|
|
typedef u_long su_ioveclen_t;
|
|
|
|
/* This is same as WSABUF */
|
|
typedef struct su_iovec_s {
|
|
su_ioveclen_t siv_len;
|
|
void *siv_base;
|
|
} su_iovec_t;
|
|
|
|
#define SU_IOVECLEN_MAX ULONG_MAX
|
|
#endif
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Socket compatibility functions */
|
|
|
|
SOFIAPUBFUN int su_init(void);
|
|
SOFIAPUBFUN void su_deinit(void);
|
|
|
|
/** Create an endpoint for communication. */
|
|
SOFIAPUBFUN su_socket_t su_socket(int af, int sock, int proto);
|
|
/** Close an socket descriptor. */
|
|
SOFIAPUBFUN int su_close(su_socket_t s);
|
|
/** Control socket. */
|
|
SOFIAPUBFUN int su_ioctl(su_socket_t s, int request, ...);
|
|
|
|
/**Check for in-progress error codes.
|
|
*
|
|
* Checks if the @a errcode indicates that the socket call failed because
|
|
* it would have blocked.
|
|
*
|
|
* Defined as macro with POSIX sockets.
|
|
*
|
|
* @since New in @VERSION_1_12_2.
|
|
*/
|
|
SOFIAPUBFUN int su_is_blocking(int errcode);
|
|
|
|
/** Set/reset blocking option. */
|
|
SOFIAPUBFUN int su_setblocking(su_socket_t s, int blocking);
|
|
/** Set/reset address reusing option. */
|
|
SOFIAPUBFUN int su_setreuseaddr(su_socket_t s, int reuse);
|
|
/** Get the error code associated with the socket. */
|
|
SOFIAPUBFUN int su_soerror(su_socket_t s);
|
|
/** Get the socket type. */
|
|
SOFIAPUBFUN int su_getsocktype(su_socket_t s);
|
|
|
|
/** Get size of message available in socket. */
|
|
SOFIAPUBFUN issize_t su_getmsgsize(su_socket_t s);
|
|
|
|
/** Scatter-gather send. */
|
|
SOFIAPUBFUN
|
|
issize_t su_vsend(su_socket_t, su_iovec_t const iov[], isize_t len, int flags,
|
|
su_sockaddr_t const *su, socklen_t sulen);
|
|
/** Scatter-gather receive. */
|
|
SOFIAPUBFUN
|
|
issize_t su_vrecv(su_socket_t, su_iovec_t iov[], isize_t len, int flags,
|
|
su_sockaddr_t *su, socklen_t *sulen);
|
|
/** Return local IP address */
|
|
SOFIAPUBFUN int su_getlocalip(su_sockaddr_t *sin);
|
|
|
|
#if SU_HAVE_BSDSOCK
|
|
#define su_ioctl ioctl
|
|
/*
|
|
* Note: before 1.12.2, there was su_isblocking() which did not take argument
|
|
* and which was missing from WINSOCK
|
|
*/
|
|
#define su_is_blocking(e) \
|
|
((e) == EINPROGRESS || (e) == EAGAIN || (e) == EWOULDBLOCK)
|
|
#endif
|
|
|
|
#if SU_HAVE_WINSOCK
|
|
SOFIAPUBFUN int su_inet_pton(int af, char const *src, void *dst);
|
|
SOFIAPUBFUN const char *su_inet_ntop(int af, void const *src,
|
|
char *dst, size_t size);
|
|
SOFIAPUBFUN ssize_t
|
|
su_send(su_socket_t s, void *buffer, size_t length, int flags),
|
|
su_sendto(su_socket_t s, void *buffer, size_t length, int flags,
|
|
su_sockaddr_t const *to, socklen_t tolen),
|
|
su_recv(su_socket_t s, void *buffer, size_t length, int flags),
|
|
su_recvfrom(su_socket_t s, void *buffer, size_t length, int flags,
|
|
su_sockaddr_t *from, socklen_t *fromlen);
|
|
|
|
static __inline
|
|
uint16_t su_ntohs(uint16_t s)
|
|
{
|
|
return (uint16_t)(((s & 255) << 8) | ((s & 0xff00) >> 8));
|
|
}
|
|
|
|
static __inline
|
|
uint32_t su_ntohl(uint32_t l)
|
|
{
|
|
return ((l & 0xff) << 24) | ((l & 0xff00) << 8)
|
|
| ((l & 0xff0000) >> 8) | ((l & 0xff000000U) >> 24);
|
|
}
|
|
|
|
#define ntohs su_ntohs
|
|
#define htons su_ntohs
|
|
#define ntohl su_ntohl
|
|
#define htonl su_ntohl
|
|
|
|
#else
|
|
#define su_inet_pton inet_pton
|
|
#define su_inet_ntop inet_ntop
|
|
#define su_send(s,b,l,f) send((s),(b),(l),(f))
|
|
#define su_sendto(s,b,l,f,a,L) sendto((s),(b),(l),(f),(void const*)(a),(L))
|
|
#define su_recv(s,b,l,f) recv((s),(b),(l),(f))
|
|
#define su_recvfrom(s,b,l,f,a,L) recvfrom((s),(b),(l),(f),(void *)(a),(L))
|
|
#endif
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Other compatibility stuff */
|
|
|
|
#if SU_HAVE_WINSOCK
|
|
#define getuid() (0x505)
|
|
#endif
|
|
|
|
#ifndef IPPROTO_SCTP
|
|
#define IPPROTO_SCTP (132)
|
|
#endif
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/* Address manipulation macros */
|
|
|
|
/**@HI Get pointer to address field.
|
|
*
|
|
* The macro SU_ADDR() returns pointer to the address field (sin_data,
|
|
* sin_addr or sin_addr6, depending on the address family).
|
|
*/
|
|
#if SU_HAVE_IN6
|
|
#define SU_ADDR(su) \
|
|
((su)->su_family == AF_INET ? (void *)&(su)->su_sin.sin_addr : \
|
|
((su)->su_family == AF_INET6 ? (void *)&(su)->su_sin6.sin6_addr : \
|
|
(void *)&(su)->su_sa.sa_data))
|
|
#else
|
|
#define SU_ADDR(su) \
|
|
((su)->su_family == AF_INET ? (void *)&(su)->su_sin.sin_addr : \
|
|
(void *)&(su)->su_sa.sa_data)
|
|
#endif
|
|
|
|
/**@HI Get length of address field.
|
|
*
|
|
* The macro SU_ADDRLEN() returns length of the address field (sin_data,
|
|
* sin_addr or sin_addr6, depending on the address family).
|
|
*/
|
|
#if SU_HAVE_IN6
|
|
#define SU_ADDRLEN(su) \
|
|
((su)->su_family == AF_INET \
|
|
? (socklen_t)sizeof((su)->su_sin.sin_addr) : \
|
|
((su)->su_family == AF_INET6 \
|
|
? (socklen_t)sizeof((su)->su_sin6.sin6_addr) \
|
|
: (socklen_t)sizeof((su)->su_sa.sa_data)))
|
|
#else
|
|
#define SU_ADDRLEN(su) \
|
|
((su)->su_family == AF_INET \
|
|
? (socklen_t)sizeof((su)->su_sin.sin_addr) \
|
|
: (socklen_t)sizeof((su)->su_sa.sa_data))
|
|
#endif
|
|
|
|
/**@HI Test if su_sockaddr_t is INADDR_ANY or IN6ADDR_ANY. */
|
|
#if SU_HAVE_IN6
|
|
#define SU_HAS_INADDR_ANY(su) \
|
|
((su)->su_family == AF_INET \
|
|
? ((su)->su_sin.sin_addr.s_addr == INADDR_ANY) \
|
|
: ((su)->su_family == AF_INET6 \
|
|
? (memcmp(&(su)->su_sin6.sin6_addr, su_in6addr_any(), \
|
|
sizeof(*su_in6addr_any())) == 0) : 0))
|
|
#else
|
|
#define SU_HAS_INADDR_ANY(su) \
|
|
((su)->su_family == AF_INET \
|
|
? ((su)->su_sin.sin_addr.s_addr == INADDR_ANY) : 0)
|
|
#endif
|
|
|
|
#define SU_SOCKADDR_INADDR_ANY(su) SU_HAS_INADDR_ANY(su)
|
|
|
|
/**@HI Calculate correct size of su_sockaddr_t structure. */
|
|
#if SU_HAVE_IN6
|
|
#define SU_SOCKADDR_SIZE(su) \
|
|
((socklen_t)((su)->su_family == AF_INET ? sizeof((su)->su_sin) \
|
|
: ((su)->su_family == AF_INET6 ? sizeof((su)->su_sin6) \
|
|
: sizeof(*su))))
|
|
#else
|
|
#define SU_SOCKADDR_SIZE(su) \
|
|
((socklen_t)((su)->su_family == AF_INET ? sizeof((su)->su_sin) \
|
|
: sizeof(*su)))
|
|
#endif
|
|
#define su_sockaddr_size SU_SOCKADDR_SIZE
|
|
|
|
#if SU_HAVE_IN6
|
|
#if SU_HAVE_BSDSOCK
|
|
#define su_in6addr_any() (&in6addr_any)
|
|
#define su_in6addr_loopback() (&in6addr_loopback)
|
|
#define SU_IN6ADDR_ANY_INIT IN6ADDR_ANY_INIT
|
|
#define SU_IN6ADDR_LOOPBACK_INIT IN6ADDR_LOOPBACK_INIT
|
|
#endif
|
|
#if SU_HAVE_WINSOCK || DOCUMENTATION_ONLY
|
|
SOFIAPUBVAR const struct in_addr6 *su_in6addr_any(void);
|
|
SOFIAPUBVAR const struct in_addr6 *su_in6addr_loopback(void);
|
|
#define SU_IN6ADDR_ANY_INIT { 0 }
|
|
#define SU_IN6ADDR_LOOPBACK_INIT { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1 }
|
|
#endif
|
|
#endif /* SU_HAVE_IN6 */
|
|
|
|
#define SU_IN6_IS_ADDR_V4MAPPED(a) \
|
|
(((uint32_t const *) (a))[0] == 0 && \
|
|
((uint32_t const *) (a))[1] == 0 && \
|
|
((uint32_t const *) (a))[2] == htonl(0xffff))
|
|
|
|
#define SU_IN6_IS_ADDR_V4COMPAT(a) \
|
|
(((uint32_t const *)(a))[0] == 0 && \
|
|
((uint32_t const *)(a))[1] == 0 && \
|
|
((uint32_t const *)(a))[2] == 0 && \
|
|
((uint32_t const *)(a))[3] != htonl(1) && \
|
|
((uint32_t const *)(a))[3] != htonl(0))
|
|
|
|
SOFIAPUBFUN int su_cmp_sockaddr(su_sockaddr_t const *a,
|
|
su_sockaddr_t const *b);
|
|
SOFIAPUBFUN int su_match_sockaddr(su_sockaddr_t const *a,
|
|
su_sockaddr_t const *b);
|
|
SOFIAPUBFUN void su_canonize_sockaddr(su_sockaddr_t *su);
|
|
|
|
#if SU_HAVE_IN6
|
|
#define SU_CANONIZE_SOCKADDR(su) \
|
|
((su)->su_family == AF_INET6 ? su_canonize_sockaddr(su) : (void)0)
|
|
#else
|
|
#define SU_CANONIZE_SOCKADDR(su) \
|
|
((void)0)
|
|
#endif
|
|
|
|
SOFIA_END_DECLS
|
|
|
|
#ifndef SU_ADDRINFO_H
|
|
#include <sofia-sip/su_addrinfo.h>
|
|
#endif
|
|
|
|
#endif /* !defined(SU_H) */
|