From 2e6a62f43b622320d69971cfc07a68ab59e29f1b Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Sat, 1 Dec 2007 08:52:57 +0000 Subject: More ticket #415: more IPv6 and some reorganization of the source codes git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1601 74dad513-b988-da41-8d7b-12977e46ad98 --- pjlib/include/pj/addr_resolv.h | 37 +++- pjlib/include/pj/compat/socket.h | 22 ++ pjlib/include/pj/errno.h | 5 + pjlib/include/pj/ip_helper.h | 16 +- pjlib/include/pj/os.h | 7 + pjlib/include/pj/sock.h | 354 ++++++++++++++++++++++-------- pjlib/src/pj/addr_resolv_sock.c | 144 ++++-------- pjlib/src/pj/addr_resolv_symbian.cpp | 217 +++++++++--------- pjlib/src/pj/errno.c | 3 +- pjlib/src/pj/ioqueue_symbian.cpp | 84 +++++-- pjlib/src/pj/ip_helper_generic.c | 38 ++-- pjlib/src/pj/ip_helper_symbian.cpp | 133 +++++++++++ pjlib/src/pj/ip_helper_win32.c | 111 +++++++++- pjlib/src/pj/os_core_symbian.cpp | 36 ++- pjlib/src/pj/os_symbian.h | 79 +++++-- pjlib/src/pj/sock_bsd.c | 121 +--------- pjlib/src/pj/sock_common.c | 412 +++++++++++++++++++++++++++++++++++ pjlib/src/pj/sock_symbian.cpp | 144 +++--------- 18 files changed, 1341 insertions(+), 622 deletions(-) create mode 100644 pjlib/src/pj/ip_helper_symbian.cpp (limited to 'pjlib') diff --git a/pjlib/include/pj/addr_resolv.h b/pjlib/include/pj/addr_resolv.h index b066bc95..cad82730 100644 --- a/pjlib/include/pj/addr_resolv.h +++ b/pjlib/include/pj/addr_resolv.h @@ -85,9 +85,14 @@ typedef struct pj_addrinfo /** * This function fills the structure of type pj_hostent for a given host name. + * For host resolution function that also works with IPv6, please see + * #pj_getaddrinfo(). * - * @param name Host name, or IPv4 or IPv6 address in standard dot notation. - * @param he The pj_hostent structure to be filled. + * @param name Host name, or IPv4 address in standard dot notation. + * @param he The pj_hostent structure to be filled. Note that + * the pointers in this structure points to temporary + * variables which value will be reset upon subsequent + * invocation. * * @return PJ_SUCCESS, or the appropriate error codes. */ @@ -97,24 +102,33 @@ PJ_DECL(pj_status_t) pj_gethostbyname(const pj_str_t *name, pj_hostent *he); /** * Resolve the primary IP address of local host. * - * @param ip_addr On successful resolution, this will be filled up with - * the host IP address, in network byte order. + * @param af The desired address family to query. Valid values + * are pj_AF_INET() or pj_AF_INET6(). + * @param addr On successful resolution, the address family and address + * part of this socket address will be filled up with the host + * IP address, in network byte order. Other parts of the socket + * address are untouched. * * @return PJ_SUCCESS on success, or the appropriate error code. */ -PJ_DECL(pj_status_t) pj_gethostip(pj_in_addr *ip_addr); +PJ_DECL(pj_status_t) pj_gethostip(int af, pj_sockaddr *addr); /** * Get the IP address of the default interface. Default interface is the * interface of the default route. * - * @param ip_addr On successful resolution, this will be filled up with - * the IP address, in network byte order. + * @param af The desired address family to query. Valid values + * are pj_AF_INET() or pj_AF_INET6(). + * @param addr On successful resolution, the address family and address + * part of this socket address will be filled up with the host + * IP address, in network byte order. Other parts of the socket + * address are untouched. * * @return PJ_SUCCESS on success, or the appropriate error code. */ -PJ_DECL(pj_status_t) pj_getdefaultipinterface(pj_in_addr *ip_addr); +PJ_DECL(pj_status_t) pj_getdefaultipinterface(int af, + pj_sockaddr *addr); /** @@ -123,17 +137,20 @@ PJ_DECL(pj_status_t) pj_getdefaultipinterface(pj_in_addr *ip_addr); * to be used in creating a socket with which to address the specified * service. * + * @param af The desired address family to query. Valid values + * are pj_AF_INET(), pj_AF_INET6(), or pj_AF_UNSPEC(). * @param name Descriptive name or an address string, such as host * name. - * @param af The desired address family to query. * @param count On input, it specifies the number of elements in * \a ai array. On output, this will be set with the * number of address informations found for the * specified name. + * @param ai Array of address info to be filled with the information + * about the host. * * @return PJ_SUCCESS on success, or the appropriate error code. */ -PJ_DECL(pj_status_t) pj_getaddrinfo(const pj_str_t *nodename, int af, +PJ_DECL(pj_status_t) pj_getaddrinfo(int af, const pj_str_t *name, unsigned *count, pj_addrinfo ai[]); diff --git a/pjlib/include/pj/compat/socket.h b/pjlib/include/pj/compat/socket.h index f44a623c..989cda5d 100644 --- a/pjlib/include/pj/compat/socket.h +++ b/pjlib/include/pj/compat/socket.h @@ -185,6 +185,28 @@ typedef int socklen_t; #endif +/* Regarding sin_len member of sockaddr_in: + * BSD systems (including MacOS X requires that the sin_len member of + * sockaddr_in be set to sizeof(sockaddr_in), while other systems (Windows + * and Linux included) do not. + * + * To maintain compatibility between systems, PJLIB will automatically + * set this field before invoking native OS socket API, and it will + * always reset the field to zero before returning pj_sockaddr_in to + * application (such as in pj_getsockname() and pj_recvfrom()). + * + * Application MUST always set this field to zero. + * + * This way we can avoid hard to find problem such as when the socket + * address is used as hash table key. + */ +#if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0 +# define PJ_SOCKADDR_SET_LEN(addr,len) (((pj_addr_hdr*)(addr))->sa_zero_len=(len)) +# define PJ_SOCKADDR_RESET_LEN(addr) (((pj_addr_hdr*)(addr))->sa_zero_len=0) +#else +# define PJ_SOCKADDR_SET_LEN(addr,len) +# define PJ_SOCKADDR_RESET_LEN(addr) +#endif #endif /* __PJ_COMPAT_SOCKET_H__ */ diff --git a/pjlib/include/pj/errno.h b/pjlib/include/pj/errno.h index 507bd7b8..b838f069 100644 --- a/pjlib/include/pj/errno.h +++ b/pjlib/include/pj/errno.h @@ -314,6 +314,11 @@ PJ_DECL(pj_status_t) pj_register_strerror(pj_status_t start_code, * IPv6 is not supported */ #define PJ_EIPV6NOTSUP (PJ_ERRNO_START_STATUS + 21)/* 70021 */ +/** + * @hideinitializer + * Unsupported address family + */ +#define PJ_EAFNOTSUP (PJ_ERRNO_START_STATUS + 22)/* 70022 */ /** @} */ /* pj_errnum */ diff --git a/pjlib/include/pj/ip_helper.h b/pjlib/include/pj/ip_helper.h index 9515d978..266a785a 100644 --- a/pjlib/include/pj/ip_helper.h +++ b/pjlib/include/pj/ip_helper.h @@ -53,16 +53,24 @@ typedef union pj_ip_route_entry /** - * Enumerate the local IP interface currently active in the host. + * Enumerate the local IP interfaces currently active in the host. * + * @param af Family of the address to be retrieved. Application + * may specify pj_AF_UNSPEC() to retrieve all addresses, + * or pj_AF_INET() or pj_AF_INET6() to retrieve interfaces + * with specific address family. * @param count On input, specify the number of entries. On output, * it will be filled with the actual number of entries. - * @param ifs Array of IP addresses. + * @param ifs Array of socket addresses, which address part will + * be filled with the interface address. The address + * family part will be initialized with the address + * family of the IP address. * * @return PJ_SUCCESS on success, or the appropriate error code. */ -PJ_DECL(pj_status_t) pj_enum_ip_interface(unsigned *count, - pj_in_addr ifs[]); +PJ_DECL(pj_status_t) pj_enum_ip_interface(int af, + unsigned *count, + pj_sockaddr ifs[]); /** diff --git a/pjlib/include/pj/os.h b/pjlib/include/pj/os.h index f640df21..a5c10df8 100644 --- a/pjlib/include/pj/os.h +++ b/pjlib/include/pj/os.h @@ -334,6 +334,13 @@ typedef struct pj_symbianos_params */ void *rhostresolver; + /** + * Optional RHostResolver for IPv6 instance to be used by PJLIB. + * If this value is NULL, a new RHostResolver instance will be created + * when pj_init() is called. + */ + void *rhostresolver6; + } pj_symbianos_params; /** diff --git a/pjlib/include/pj/sock.h b/pjlib/include/pj/sock.h index d90c91e8..1d3b035c 100644 --- a/pjlib/include/pj/sock.h +++ b/pjlib/include/pj/sock.h @@ -87,18 +87,36 @@ extern const pj_uint16_t PJ_AF_IRDA; * global variables from a DLL. */ -/** Get #PJ_AF_UNSPEC value */ -PJ_DECL(pj_uint16_t) pj_AF_UNSPEC(void); -/** Get #PJ_AF_UNIX value. */ -PJ_DECL(pj_uint16_t) pj_AF_UNIX(void); -/** Get #PJ_AF_INET value. */ -PJ_DECL(pj_uint16_t) pj_AF_INET(void); -/** Get #PJ_AF_INET6 value. */ -PJ_DECL(pj_uint16_t) pj_AF_INET6(void); -/** Get #PJ_AF_PACKET value. */ -PJ_DECL(pj_uint16_t) pj_AF_PACKET(void); -/** Get #PJ_AF_IRDA value. */ -PJ_DECL(pj_uint16_t) pj_AF_IRDA(void); +#if defined(PJ_DLL) + /** Get #PJ_AF_UNSPEC value */ + PJ_DECL(pj_uint16_t) pj_AF_UNSPEC(void); + /** Get #PJ_AF_UNIX value. */ + PJ_DECL(pj_uint16_t) pj_AF_UNIX(void); + /** Get #PJ_AF_INET value. */ + PJ_DECL(pj_uint16_t) pj_AF_INET(void); + /** Get #PJ_AF_INET6 value. */ + PJ_DECL(pj_uint16_t) pj_AF_INET6(void); + /** Get #PJ_AF_PACKET value. */ + PJ_DECL(pj_uint16_t) pj_AF_PACKET(void); + /** Get #PJ_AF_IRDA value. */ + PJ_DECL(pj_uint16_t) pj_AF_IRDA(void); +#else + /* When pjlib is not built as DLL, these accessor functions are + * simply a macro to get their constants + */ + /** Get #PJ_AF_UNSPEC value */ +# define pj_AF_UNSPEC() PJ_AF_UNSPEC + /** Get #PJ_AF_UNIX value. */ +# define pj_AF_UNIX() PJ_AF_UNIX + /** Get #PJ_AF_INET value. */ +# define pj_AF_INET() PJ_AF_INET + /** Get #PJ_AF_INET6 value. */ +# define pj_AF_INET6() PJ_AF_INET6 + /** Get #PJ_AF_PACKET value. */ +# define pj_AF_PACKET() PJ_AF_PACKET + /** Get #PJ_AF_IRDA value. */ +# define pj_AF_IRDA() PJ_AF_IRDA +#endif /** @@ -127,14 +145,25 @@ extern const pj_uint16_t PJ_SOCK_RDM; * because Symbian doesn't allow exporting global variables from a DLL. */ -/** Get #PJ_SOCK_STREAM constant */ -PJ_DECL(int) pj_SOCK_STREAM(void); -/** Get #PJ_SOCK_DGRAM constant */ -PJ_DECL(int) pj_SOCK_DGRAM(void); -/** Get #PJ_SOCK_RAW constant */ -PJ_DECL(int) pj_SOCK_RAW(void); -/** Get #PJ_SOCK_RDM constant */ -PJ_DECL(int) pj_SOCK_RDM(void); +#if defined(PJ_DLL) + /** Get #PJ_SOCK_STREAM constant */ + PJ_DECL(int) pj_SOCK_STREAM(void); + /** Get #PJ_SOCK_DGRAM constant */ + PJ_DECL(int) pj_SOCK_DGRAM(void); + /** Get #PJ_SOCK_RAW constant */ + PJ_DECL(int) pj_SOCK_RAW(void); + /** Get #PJ_SOCK_RDM constant */ + PJ_DECL(int) pj_SOCK_RDM(void); +#else + /** Get #PJ_SOCK_STREAM constant */ +# define pj_SOCK_STREAM() PJ_SOCK_STREAM + /** Get #PJ_SOCK_DGRAM constant */ +# define pj_SOCK_DGRAM() PJ_SOCK_DGRAM + /** Get #PJ_SOCK_RAW constant */ +# define pj_SOCK_RAW() PJ_SOCK_RAW + /** Get #PJ_SOCK_RDM constant */ +# define pj_SOCK_RDM() PJ_SOCK_RDM +#endif /** @@ -158,16 +187,29 @@ extern const pj_uint16_t PJ_SOL_IPV6; * because Symbian doesn't allow exporting global variables from a DLL. */ -/** Get #PJ_SOL_SOCKET constant */ -PJ_DECL(pj_uint16_t) pj_SOL_SOCKET(void); -/** Get #PJ_SOL_IP constant */ -PJ_DECL(pj_uint16_t) pj_SOL_IP(void); -/** Get #PJ_SOL_TCP constant */ -PJ_DECL(pj_uint16_t) pj_SOL_TCP(void); -/** Get #PJ_SOL_UDP constant */ -PJ_DECL(pj_uint16_t) pj_SOL_UDP(void); -/** Get #PJ_SOL_IPV6 constant */ -PJ_DECL(pj_uint16_t) pj_SOL_IPV6(void); +#if defined(PJ_DLL) + /** Get #PJ_SOL_SOCKET constant */ + PJ_DECL(pj_uint16_t) pj_SOL_SOCKET(void); + /** Get #PJ_SOL_IP constant */ + PJ_DECL(pj_uint16_t) pj_SOL_IP(void); + /** Get #PJ_SOL_TCP constant */ + PJ_DECL(pj_uint16_t) pj_SOL_TCP(void); + /** Get #PJ_SOL_UDP constant */ + PJ_DECL(pj_uint16_t) pj_SOL_UDP(void); + /** Get #PJ_SOL_IPV6 constant */ + PJ_DECL(pj_uint16_t) pj_SOL_IPV6(void); +#else + /** Get #PJ_SOL_SOCKET constant */ +# define pj_SOL_SOCKET() PJ_SOL_SOCKET + /** Get #PJ_SOL_IP constant */ +# define pj_SOL_IP() PJ_SOL_IP + /** Get #PJ_SOL_TCP constant */ +# define pj_SOL_TCP() PJ_SOL_TCP + /** Get #PJ_SOL_UDP constant */ +# define pj_SOL_UDP() PJ_SOL_UDP + /** Get #PJ_SOL_IPV6 constant */ +# define pj_SOL_IPV6() PJ_SOL_IPV6 +#endif /* IP_TOS @@ -179,9 +221,6 @@ PJ_DECL(pj_uint16_t) pj_SOL_IPV6(void); /** IP_TOS optname in setsockopt(). @see pj_IP_TOS() */ extern const pj_uint16_t PJ_IP_TOS; -/** Get #PJ_IP_TOS constant */ -PJ_DECL(int) pj_IP_TOS(void); - /* * IP TOS related constats. * @@ -203,17 +242,37 @@ extern const pj_uint16_t PJ_IPTOS_RELIABILITY; extern const pj_uint16_t PJ_IPTOS_MINCOST; -/** Get #PJ_IPTOS_LOWDELAY constant */ -PJ_DECL(int) pj_IPTOS_LOWDELAY(void); +#if defined(PJ_DLL) + /** Get #PJ_IP_TOS constant */ + PJ_DECL(int) pj_IP_TOS(void); -/** Get #PJ_IPTOS_THROUGHPUT constant */ -PJ_DECL(int) pj_IPTOS_THROUGHPUT(void); + /** Get #PJ_IPTOS_LOWDELAY constant */ + PJ_DECL(int) pj_IPTOS_LOWDELAY(void); -/** Get #PJ_IPTOS_RELIABILITY constant */ -PJ_DECL(int) pj_IPTOS_RELIABILITY(void); + /** Get #PJ_IPTOS_THROUGHPUT constant */ + PJ_DECL(int) pj_IPTOS_THROUGHPUT(void); -/** Get #PJ_IPTOS_MINCOST constant */ -PJ_DECL(int) pj_IPTOS_MINCOST(void); + /** Get #PJ_IPTOS_RELIABILITY constant */ + PJ_DECL(int) pj_IPTOS_RELIABILITY(void); + + /** Get #PJ_IPTOS_MINCOST constant */ + PJ_DECL(int) pj_IPTOS_MINCOST(void); +#else + /** Get #PJ_IP_TOS constant */ +# define pj_IP_TOS() PJ_IP_TOS + + /** Get #PJ_IPTOS_LOWDELAY constant */ +# define pj_IPTOS_LOWDELAY() PJ_IP_TOS_LOWDELAY + + /** Get #PJ_IPTOS_THROUGHPUT constant */ +# define pj_IPTOS_THROUGHPUT() PJ_IP_TOS_THROUGHPUT + + /** Get #PJ_IPTOS_RELIABILITY constant */ +# define pj_IPTOS_RELIABILITY() PJ_IP_TOS_RELIABILITY + + /** Get #PJ_IPTOS_MINCOST constant */ +# define pj_IPTOS_MINCOST() PJ_IP_TOS_MINCOST +#endif /** @@ -231,14 +290,25 @@ extern const pj_uint16_t PJ_SO_RCVBUF; extern const pj_uint16_t PJ_SO_SNDBUF; -/** Get #PJ_SO_TYPE constant */ -PJ_DECL(pj_uint16_t) pj_SO_TYPE(void); +#if defined(PJ_DLL) + /** Get #PJ_SO_TYPE constant */ + PJ_DECL(pj_uint16_t) pj_SO_TYPE(void); -/** Get #PJ_SO_RCVBUF constant */ -PJ_DECL(pj_uint16_t) pj_SO_RCVBUF(void); + /** Get #PJ_SO_RCVBUF constant */ + PJ_DECL(pj_uint16_t) pj_SO_RCVBUF(void); -/** Get #PJ_SO_SNDBUF constant */ -PJ_DECL(pj_uint16_t) pj_SO_SNDBUF(void); + /** Get #PJ_SO_SNDBUF constant */ + PJ_DECL(pj_uint16_t) pj_SO_SNDBUF(void); +#else + /** Get #PJ_SO_TYPE constant */ +# define pj_SO_TYPE() PJ_SO_TYPE + + /** Get #PJ_SO_RCVBUF constant */ +# define pj_SO_RCVBUF() PJ_SO_RCVBUF + + /** Get #PJ_SO_SNDBUF constant */ +# define pj_SO_SNDBUF() PJ_SO_SNDBUF +#endif /* @@ -255,14 +325,25 @@ extern const int PJ_MSG_PEEK; extern const int PJ_MSG_DONTROUTE; -/** Get #PJ_MSG_OOB constant */ -PJ_DECL(int) pj_MSG_OOB(void); +#if defined(PJ_DLL) + /** Get #PJ_MSG_OOB constant */ + PJ_DECL(int) pj_MSG_OOB(void); -/** Get #PJ_MSG_PEEK constant */ -PJ_DECL(int) pj_MSG_PEEK(void); + /** Get #PJ_MSG_PEEK constant */ + PJ_DECL(int) pj_MSG_PEEK(void); -/** Get #PJ_MSG_DONTROUTE constant */ -PJ_DECL(int) pj_MSG_DONTROUTE(void); + /** Get #PJ_MSG_DONTROUTE constant */ + PJ_DECL(int) pj_MSG_DONTROUTE(void); +#else + /** Get #PJ_MSG_OOB constant */ +# define pj_MSG_OOB() PJ_MSG_OOB + + /** Get #PJ_MSG_PEEK constant */ +# define pj_MSG_PEEK() PJ_MSG_PEEK + + /** Get #PJ_MSG_DONTROUTE constant */ +# define pj_MSG_DONTROUTE() PJ_MSG_DONTROUTE +#endif /** @@ -306,6 +387,7 @@ typedef enum pj_socket_sd_type */ #define PJ_INVALID_SOCKET (-1) +/* Must undefine s_addr because of pj_in_addr below */ #undef s_addr /** @@ -362,7 +444,12 @@ typedef union pj_in6_addr /* While these are used for proper alignment */ pj_uint32_t u6_addr32[4]; -#if defined(PJ_HAS_INT64) && PJ_HAS_INT64!=0 + + /* Do not use this with Winsock2, as this will align pj_sockaddr_in6 + * to 64-bit boundary and Winsock2 doesn't like it! + */ +#if defined(PJ_HAS_INT64) && PJ_HAS_INT64!=0 && \ + (!defined(PJ_WIN32) || PJ_WIN32==0) pj_int64_t u6_addr64[2]; #endif @@ -555,54 +642,92 @@ PJ_DECL(pj_in_addr) pj_inet_addr(const pj_str_t *cp); PJ_DECL(pj_in_addr) pj_inet_addr2(const char *cp); /** - * Get the transport layer port number of an Internet socket address. - * The port is returned in host byte order. + * Initialize IPv4 socket address based on the address and port info. + * The string address may be in a standard numbers and dots notation or + * may be a hostname. If hostname is specified, then the function will + * resolve the host into the IP address. * - * @param addr The IP socket address. - * @return Port number, in host byte order. + * @see pj_sockaddr_init() + * + * @param addr The IP socket address to be set. + * @param cp The address string, which can be in a standard + * dotted numbers or a hostname to be resolved. + * @param port The port number, in host byte order. + * + * @return Zero on success. */ -PJ_INLINE(pj_uint16_t) pj_sockaddr_in_get_port(const pj_sockaddr_in *addr) -{ - return pj_ntohs(addr->sin_port); -} +PJ_DECL(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr, + const pj_str_t *cp, + pj_uint16_t port); /** - * Set the port number of an Internet socket address. + * Initialize IP socket address based on the address and port info. + * The string address may be in a standard numbers and dots notation or + * may be a hostname. If hostname is specified, then the function will + * resolve the host into the IP address. * - * @param addr The IP socket address. - * @param hostport The port number, in host byte order. + * @see pj_sockaddr_in_init() + * + * @param af Internet address family. + * @param addr The IP socket address to be set. + * @param cp The address string, which can be in a standard + * dotted numbers or a hostname to be resolved. + * @param port The port number, in host byte order. + * + * @return Zero on success. */ -PJ_INLINE(void) pj_sockaddr_in_set_port(pj_sockaddr_in *addr, - pj_uint16_t hostport) -{ - addr->sin_port = pj_htons(hostport); -} +PJ_DECL(pj_status_t) pj_sockaddr_init(int af, + pj_sockaddr *addr, + const pj_str_t *cp, + pj_uint16_t port); /** - * Get the IP address of an Internet socket address. + * Get pointer to the address part of a socket address. + * + * @param addr Socket address. + * + * @return Pointer to address part (sin_addr or sin6_addr, + * depending on address family) + */ +PJ_DECL(void*) pj_sockaddr_get_addr(const pj_sockaddr_t *addr); + +/** + * Check that a socket address contains a non-zero address part. + * + * @param addr Socket address. + * + * @return Non-zero if address is set to non-zero. + */ +PJ_DECL(pj_bool_t) pj_sockaddr_has_addr(const pj_sockaddr_t *addr); + +/** + * Get the address part length of a socket address, based on its address + * family. For PJ_AF_INET, the length will be sizeof(pj_in_addr), and + * for PJ_AF_INET6, the length will be sizeof(pj_in6_addr). + * + * @param addr Socket address. + * + * @return Port number, in host byte order. + */ +PJ_DECL(unsigned) pj_sockaddr_get_addr_len(const pj_sockaddr_t *addr); + +/** + * Get the IP address of an IPv4 socket address. * The address is returned as 32bit value in host byte order. * * @param addr The IP socket address. * @return 32bit address, in host byte order. */ -PJ_INLINE(pj_in_addr) pj_sockaddr_in_get_addr(const pj_sockaddr_in *addr) -{ - pj_in_addr in_addr; - in_addr.s_addr = pj_ntohl(addr->sin_addr.s_addr); - return in_addr; -} +PJ_DECL(pj_in_addr) pj_sockaddr_in_get_addr(const pj_sockaddr_in *addr); /** - * Set the IP address of an Internet socket address. + * Set the IP address of an IPv4 socket address. * * @param addr The IP socket address. * @param hostaddr The host address, in host byte order. */ -PJ_INLINE(void) pj_sockaddr_in_set_addr(pj_sockaddr_in *addr, - pj_uint32_t hostaddr) -{ - addr->sin_addr.s_addr = pj_htonl(hostaddr); -} +PJ_DECL(void) pj_sockaddr_in_set_addr(pj_sockaddr_in *addr, + pj_uint32_t hostaddr); /** * Set the IP address of an IP socket address from string address, @@ -611,32 +736,73 @@ PJ_INLINE(void) pj_sockaddr_in_set_addr(pj_sockaddr_in *addr, * is specified, then the function will resolve the host into the IP * address. * + * @see pj_sockaddr_set_str_addr() + * * @param addr The IP socket address to be set. * @param cp The address string, which can be in a standard * dotted numbers or a hostname to be resolved. * - * @return Zero on success. + * @return PJ_SUCCESS on success. */ PJ_DECL(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr, const pj_str_t *cp); /** - * Set the IP address and port of an IP socket address. - * The string address may be in a standard numbers and dots notation or - * may be a hostname. If hostname is specified, then the function will - * resolve the host into the IP address. + * Set the IP address of an IPv4 or IPv6 socket address from string address, + * with resolving the host if necessary. The string address may be in a + * standard IPv6 or IPv6 address or may be a hostname. If hostname + * is specified, then the function will resolve the host into the IP + * address according to the address family. * + * @param af Address family. * @param addr The IP socket address to be set. * @param cp The address string, which can be in a standard - * dotted numbers or a hostname to be resolved. - * @param port The port number, in host byte order. + * IP numbers (IPv4 or IPv6) or a hostname to be resolved. * - * @return Zero on success. + * @return PJ_SUCCESS on success. */ -PJ_DECL(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr, - const pj_str_t *cp, - pj_uint16_t port); +PJ_DECL(pj_status_t) pj_sockaddr_set_str_addr(int af, + pj_sockaddr *addr, + const pj_str_t *cp); + +/** + * Get the port number of a socket address, in host byte order. + * This function can be used for both IPv4 and IPv6 socket address. + * + * @param addr Socket address. + * + * @return Port number, in host byte order. + */ +PJ_DECL(pj_uint16_t) pj_sockaddr_get_port(const pj_sockaddr_t *addr); + +/** + * Get the transport layer port number of an Internet socket address. + * The port is returned in host byte order. + * + * @param addr The IP socket address. + * @return Port number, in host byte order. + */ +PJ_DECL(pj_uint16_t) pj_sockaddr_in_get_port(const pj_sockaddr_in *addr); + +/** + * Set the port number of an Internet socket address. + * + * @param addr The socket address. + * @param hostport The port number, in host byte order. + */ +PJ_DECL(pj_status_t) pj_sockaddr_set_port(pj_sockaddr *addr, + pj_uint16_t hostport); +/** + * Set the port number of an IPv4 socket address. + * + * @see pj_sockaddr_set_port() + * + * @param addr The IP socket address. + * @param hostport The port number, in host byte order. + */ +PJ_DECL(void) pj_sockaddr_in_set_port(pj_sockaddr_in *addr, + pj_uint16_t hostport); /***************************************************************************** * diff --git a/pjlib/src/pj/addr_resolv_sock.c b/pjlib/src/pj/addr_resolv_sock.c index a4599ef7..aeb61951 100644 --- a/pjlib/src/pj/addr_resolv_sock.c +++ b/pjlib/src/pj/addr_resolv_sock.c @@ -55,96 +55,8 @@ PJ_DEF(pj_status_t) pj_gethostbyname(const pj_str_t *hostname, pj_hostent *phe) return PJ_SUCCESS; } -/* Get the default IP interface */ -PJ_DEF(pj_status_t) pj_getdefaultipinterface(pj_in_addr *addr) -{ - pj_sock_t fd; - pj_str_t cp; - pj_sockaddr_in a; - int len; - pj_status_t status; - - status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &fd); - if (status != PJ_SUCCESS) { - return status; - } - - cp = pj_str("1.1.1.1"); - pj_sockaddr_in_init(&a, &cp, 53); - - status = pj_sock_connect(fd, &a, sizeof(a)); - if (status != PJ_SUCCESS) { - pj_sock_close(fd); - return status; - } - - len = sizeof(a); - status = pj_sock_getsockname(fd, &a, &len); - if (status != PJ_SUCCESS) { - pj_sock_close(fd); - return status; - } - - pj_sock_close(fd); - - *addr = a.sin_addr; - - /* Success */ - return PJ_SUCCESS; -} - - -/* Resolve the IP address of local machine */ -PJ_DEF(pj_status_t) pj_gethostip(pj_in_addr *addr) -{ - const pj_str_t *hostname = pj_gethostname(); - struct pj_hostent he; - pj_status_t status; - - -#ifdef _MSC_VER - /* Get rid of "uninitialized he variable" with MS compilers */ - pj_bzero(&he, sizeof(he)); -#endif - - /* Try with resolving local hostname first */ - status = pj_gethostbyname(hostname, &he); - if (status == PJ_SUCCESS) { - *addr = *(pj_in_addr*)he.h_addr; - } - - - /* If we end up with 127.x.x.x, resolve the IP by getting the default - * interface to connect to some public host. - */ - if (status != PJ_SUCCESS || (pj_ntohl(addr->s_addr) >> 24)==127 || - addr->s_addr == 0) - { - status = pj_getdefaultipinterface(addr); - } - - /* As the last resort, get the first available interface */ - if (status != PJ_SUCCESS) { - pj_in_addr addrs[2]; - unsigned count = PJ_ARRAY_SIZE(addrs); - - status = pj_enum_ip_interface(&count, addrs); - if (status == PJ_SUCCESS) { - if (count != 0) { - *addr = addrs[0]; - } else { - /* Just return 127.0.0.1 */ - addr->s_addr = pj_htonl (0x7f000001); - } - } - } - - return status; -} - - /* Resolve IPv4/IPv6 address */ -PJ_DEF(pj_status_t) pj_getaddrinfo(const pj_str_t *nodename, int af, +PJ_DEF(pj_status_t) pj_getaddrinfo(int af, const pj_str_t *nodename, unsigned *count, pj_addrinfo ai[]) { #if defined(PJ_SOCK_HAS_GETADDRINFO) && PJ_SOCK_HAS_GETADDRINFO!=0 @@ -155,7 +67,8 @@ PJ_DEF(pj_status_t) pj_getaddrinfo(const pj_str_t *nodename, int af, PJ_ASSERT_RETURN(nodename && count && *count && ai, PJ_EINVAL); PJ_ASSERT_RETURN(nodename->ptr && nodename->slen, PJ_EINVAL); - PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EINVAL); + PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6 || + af==PJ_AF_UNSPEC, PJ_EINVAL); /* Copy node name to null terminated string. */ if (nodename->slen >= PJ_MAX_HOSTNAME) @@ -179,13 +92,10 @@ PJ_DEF(pj_status_t) pj_getaddrinfo(const pj_str_t *nodename, int af, if (af!=PJ_AF_UNSPEC && res->ai_family != af) continue; - /* Ignore name that's too long */ - len = pj_ansi_strlen(res->ai_canonname); - if (len >= PJ_MAX_HOSTNAME) - continue; - - /* Store canonical name */ - pj_ansi_strcpy(ai[i].ai_canonname, res->ai_canonname); + /* Store canonical name (possibly truncating the name) */ + pj_ansi_strncpy(ai[i].ai_canonname, res->ai_canonname, + sizeof(ai[i].ai_canonname)); + ai[i].ai_canonname[sizeof(ai[i].ai_canonname)-1] = '\0'; /* Store address */ PJ_ASSERT_ON_FAIL(res->ai_addrlen <= sizeof(pj_sockaddr), continue); @@ -201,15 +111,43 @@ PJ_DEF(pj_status_t) pj_getaddrinfo(const pj_str_t *nodename, int af, return PJ_SUCCESS; #else /* PJ_SOCK_HAS_GETADDRINFO */ - /* IPv6 is not supported */ - PJ_UNUSED_ARG(nodename); - PJ_UNUSED_ARG(af); - PJ_UNUSED_ARG(ai); PJ_ASSERT_RETURN(count, PJ_EINVAL); - *count = 0; - return PJ_EIPV6NOTSUP; + if (af == PJ_AF_INET || af == PJ_AF_UNSPEC) { + pj_hostent he; + unsigned i, max_count; + pj_status_t status; + + status = pj_gethostbyname(nodename, &he); + if (status != PJ_SUCCESS) + return status; + + max_count = *count; + *count = 0; + + pj_bzero(ai, max_count * sizeof(pj_addrinfo)); + + for (i=0; he.h_addr_list[i] && *counth_name = aliases[0]; + he->h_aliases = aliases; + he->h_addrtype = PJ_AF_INET; + he->h_length = 4; + he->h_addr_list = addrlist; + + return PJ_SUCCESS; +} + - RHostResolver &resv = PjSymbianOS::Instance()->GetResolver(); +// Resolve for specific address family +static pj_status_t getaddrinfo_by_af(int af, const pj_str_t *name, + unsigned *count, pj_addrinfo ai[]) +{ + unsigned i; + pj_status_t status; + + PJ_ASSERT_RETURN(name && count && ai, PJ_EINVAL); + + // Get resolver for the specified address family + RHostResolver &resv = PjSymbianOS::Instance()->GetResolver(af); // Convert name to Unicode wchar_t name16[PJ_MAX_HOSTNAME]; @@ -46,126 +82,81 @@ PJ_DEF(pj_status_t) pj_gethostbyname(const pj_str_t *name, pj_hostent *he) resv.GetByName(data, nameEntry, reqStatus); User::WaitForRequest(reqStatus); - if (reqStatus != KErrNone) - return PJ_RETURN_OS_ERROR(reqStatus.Int()); - - // Get the resolved TInetAddr - // This doesn't work, see Martin email on 28/3/2007: - // const TNameRecord &rec = (const TNameRecord&) nameEntry; - // TInetAddr inetAddr(rec.iAddr); - TInetAddr inetAddr(nameEntry().iAddr); - - // - // This where we keep static variables. - // These should be kept in TLS probably, to allow multiple threads - // to call pj_gethostbyname() without interfering each other. - // But again, we don't support threads in Symbian! - // - static char resolved_name[PJ_MAX_HOSTNAME]; - static char *no_aliases[1]; - static pj_in_addr *addr_list[2]; - static pj_sockaddr_in resolved_addr; - - // Convert the official address to ANSI. - pj_unicode_to_ansi((const wchar_t*)nameEntry().iName.Ptr(), nameEntry().iName.Length(), - resolved_name, sizeof(resolved_name)); - - // Convert IP address - - PjSymbianOS::Addr2pj(inetAddr, resolved_addr); - addr_list[0] = &resolved_addr.sin_addr; - - // Return hostent - he->h_name = resolved_name; - he->h_aliases = no_aliases; - he->h_addrtype = pj_AF_INET(); - he->h_length = 4; - he->h_addr_list = (char**) addr_list; - - return PJ_SUCCESS; -} - - -/* Get the default IP interface */ -PJ_DEF(pj_status_t) pj_getdefaultipinterface(pj_in_addr *addr) -{ - pj_sock_t fd; - pj_str_t cp; - pj_sockaddr_in a; - int len; - pj_status_t status; - - status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &fd); - if (status != PJ_SUCCESS) { - return status; - } - - cp = pj_str("1.1.1.1"); - pj_sockaddr_in_init(&a, &cp, 53); - - status = pj_sock_connect(fd, &a, sizeof(a)); - if (status != PJ_SUCCESS) { - pj_sock_close(fd); - return status; - } - - len = sizeof(a); - status = pj_sock_getsockname(fd, &a, &len); - if (status != PJ_SUCCESS) { - pj_sock_close(fd); - return status; + // Iterate each result + i = 0; + while (reqStatus == KErrNone && i < *count) { + + // Get the resolved TInetAddr + TInetAddr inetAddr(nameEntry().iAddr); + int addrlen; + + // Ignore if this is not the same address family + if (inetAddr.Family() != af) { + resv.Next(nameEntry, reqStatus); + User::WaitForRequest(reqStatus); + continue; + } + + // Convert the official address to ANSI. + pj_unicode_to_ansi((const wchar_t*)nameEntry().iName.Ptr(), + nameEntry().iName.Length(), + ai[i].ai_canonname, sizeof(ai[i].ai_canonname)); + + // Convert IP address + addrlen = sizeof(ai[i].ai_addr); + status = PjSymbianOS::Addr2pj(inetAddr, ai[i].ai_addr, &addrlen); + if (status != PJ_SUCCESS) + return status; + + // Next + ++i; + resv.Next(nameEntry, reqStatus); + User::WaitForRequest(reqStatus); } - pj_sock_close(fd); - - *addr = a.sin_addr; - - /* Success */ + *count = i; return PJ_SUCCESS; } - -/* Resolve the IP address of local machine */ -PJ_DEF(pj_status_t) pj_gethostip(pj_in_addr *addr) +/* Resolve IPv4/IPv6 address */ +PJ_DEF(pj_status_t) pj_getaddrinfo(int af, const pj_str_t *nodename, + unsigned *count, pj_addrinfo ai[]) { - const pj_str_t *hostname = pj_gethostname(); - struct pj_hostent he; + unsigned start; pj_status_t status; - - - /* Try with resolving local hostname first */ - status = pj_gethostbyname(hostname, &he); - if (status == PJ_SUCCESS) { - *addr = *(pj_in_addr*)he.h_addr; + + PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6 || af==PJ_AF_UNSPEC, + PJ_EAFNOTSUP); + PJ_ASSERT_RETURN(nodename && count && *count && ai, PJ_EINVAL); + + start = 0; + + if (af==PJ_AF_INET6 || af==PJ_AF_UNSPEC) { + unsigned max = *count; + status = getaddrinfo_by_af(PJ_AF_INET6, nodename, + &max, &ai[start]); + if (status == PJ_SUCCESS) { + (*count) -= max; + start += max; + } } - - - /* If we end up with 127.x.x.x, resolve the IP by getting the default - * interface to connect to some public host. - */ - if (status != PJ_SUCCESS || (pj_ntohl(addr->s_addr) >> 24)==127 || - addr->s_addr == 0) - { - status = pj_getdefaultipinterface(addr); + + if (af==PJ_AF_INET || af==PJ_AF_UNSPEC) { + unsigned max = *count; + status = getaddrinfo_by_af(PJ_AF_INET, nodename, + &max, &ai[start]); + if (status == PJ_SUCCESS) { + (*count) -= max; + start += max; + } } - - /* As the last resort, get the first available interface */ - if (status != PJ_SUCCESS) { - pj_in_addr addrs[2]; - unsigned count = PJ_ARRAY_SIZE(addrs); - - status = pj_enum_ip_interface(&count, addrs); - if (status == PJ_SUCCESS) { - if (count != 0) { - *addr = addrs[0]; - } else { - /* Just return 127.0.0.1 */ - addr->s_addr = pj_htonl(0x7f000001); - } - } + + *count = start; + + if (*count) { + return PJ_SUCCESS; + } else { + return status!=PJ_SUCCESS ? status : PJ_ENOTFOUND; } - - return status; } - diff --git a/pjlib/src/pj/errno.c b/pjlib/src/pj/errno.c index 6de0c922..1b86d4c6 100644 --- a/pjlib/src/pj/errno.c +++ b/pjlib/src/pj/errno.c @@ -71,7 +71,8 @@ static const struct PJ_BUILD_ERR(PJ_ERESOLVE, "gethostbyname() has returned error"), PJ_BUILD_ERR(PJ_ETOOSMALL, "Size is too short"), PJ_BUILD_ERR(PJ_EIGNORED, "Ignored"), - PJ_BUILD_ERR(PJ_EIPV6NOTSUP, "IPv6 is not supported") + PJ_BUILD_ERR(PJ_EIPV6NOTSUP, "IPv6 is not supported"), + PJ_BUILD_ERR(PJ_EAFNOTSUP, "Unsupported address family") }; #endif /* PJ_HAS_ERROR_STRING */ diff --git a/pjlib/src/pj/ioqueue_symbian.cpp b/pjlib/src/pj/ioqueue_symbian.cpp index 90848f5f..d7aa9d6a 100644 --- a/pjlib/src/pj/ioqueue_symbian.cpp +++ b/pjlib/src/pj/ioqueue_symbian.cpp @@ -232,6 +232,10 @@ pj_status_t CIoqueueCallback::StartAccept(pj_ioqueue_op_key_t *op_key, PJ_ASSERT_RETURN(IsActive()==false, PJ_EBUSY); PJ_ASSERT_RETURN(pending_data_.common_.op_key_==NULL, PJ_EBUSY); + // addrlen must be specified if local or remote is specified + PJ_ASSERT_RETURN((!local && !remote) || + (addrlen && *addrlen), PJ_EINVAL); + pending_data_.accept_.op_key_ = op_key; pending_data_.accept_.new_sock_ = new_sock; pending_data_.accept_.local_ = local; @@ -254,13 +258,11 @@ pj_status_t CIoqueueCallback::StartAccept(pj_ioqueue_op_key_t *op_key, // void CIoqueueCallback::HandleReadCompletion() { - if (pending_data_.read_.addr_) { + if (pending_data_.read_.addr_ && pending_data_.read_.addrlen_) { PjSymbianOS::Addr2pj(aAddress_, - *(pj_sockaddr_in*)pending_data_.read_.addr_); + *(pj_sockaddr*)pending_data_.read_.addr_, + pending_data_.read_.addrlen_); pending_data_.read_.addr_ = NULL; - } - if (pending_data_.read_.addrlen_) { - *pending_data_.read_.addrlen_ = sizeof(pj_sockaddr_in); pending_data_.read_.addrlen_ = NULL; } @@ -273,8 +275,10 @@ void CIoqueueCallback::HandleReadCompletion() // CPjSocket *CIoqueueCallback::HandleAcceptCompletion() { - CPjSocket *pjNewSock = new CPjSocket(blank_sock_); - + CPjSocket *pjNewSock = new CPjSocket(get_pj_socket()->GetAf(), + blank_sock_); + int addrlen = 0; + if (pending_data_.accept_.new_sock_) { *pending_data_.accept_.new_sock_ = (pj_sock_t)pjNewSock; pending_data_.accept_.new_sock_ = NULL; @@ -282,26 +286,37 @@ CPjSocket *CIoqueueCallback::HandleAcceptCompletion() if (pending_data_.accept_.local_) { TInetAddr aAddr; - pj_sockaddr_in *ptr_sockaddr; - + pj_sockaddr *ptr_sockaddr; + blank_sock_.LocalName(aAddr); - ptr_sockaddr = (pj_sockaddr_in*)pending_data_.accept_.local_; - PjSymbianOS::Addr2pj(aAddr, *ptr_sockaddr); + ptr_sockaddr = (pj_sockaddr*)pending_data_.accept_.local_; + addrlen = *pending_data_.accept_.addrlen_; + PjSymbianOS::Addr2pj(aAddr, *ptr_sockaddr, &addrlen); pending_data_.accept_.local_ = NULL; } if (pending_data_.accept_.remote_) { TInetAddr aAddr; - pj_sockaddr_in *ptr_sockaddr; + pj_sockaddr *ptr_sockaddr; blank_sock_.RemoteName(aAddr); - ptr_sockaddr = (pj_sockaddr_in*)pending_data_.accept_.remote_; - PjSymbianOS::Addr2pj(aAddr, *ptr_sockaddr); + ptr_sockaddr = (pj_sockaddr*)pending_data_.accept_.remote_; + addrlen = *pending_data_.accept_.addrlen_; + PjSymbianOS::Addr2pj(aAddr, *ptr_sockaddr, &addrlen); pending_data_.accept_.remote_ = NULL; } if (pending_data_.accept_.addrlen_) { - *pending_data_.accept_.addrlen_ = sizeof(pj_sockaddr_in); + if (addrlen == 0) { + if (pjNewSock->GetAf() == PJ_AF_INET) + addrlen = sizeof(pj_sockaddr_in); + else if (pjNewSock->GetAf() == PJ_AF_INET6) + addrlen = sizeof(pj_sockaddr_in6); + else { + pj_assert(!"Unsupported address family"); + } + } + *pending_data_.accept_.addrlen_ = addrlen; pending_data_.accept_.addrlen_ = NULL; } @@ -605,13 +620,18 @@ PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key, const pj_sockaddr_t *addr, int addrlen ) { - PJ_ASSERT_RETURN(addrlen == sizeof(pj_sockaddr_in), PJ_EINVAL); - + pj_status_t status; + RSocket &rSock = key->cbObj->get_pj_socket()->Socket(); TInetAddr inetAddr; - PjSymbianOS::pj2Addr(*(const pj_sockaddr_in*)addr, inetAddr); TRequestStatus reqStatus; + // Convert address + status = PjSymbianOS::pj2Addr(*(const pj_sockaddr*)addr, addrlen, + inetAddr); + if (status != PJ_SUCCESS) + return status; + // We don't support async connect for now. PJ_TODO(IOQUEUE_SUPPORT_ASYNC_CONNECT); @@ -674,9 +694,22 @@ PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_key_t *key, pj_sockaddr_t *addr, int *addrlen) { + CPjSocket *sock = key->cbObj->get_pj_socket(); + + // If address is specified, check that the length match the + // address family + if (addr || addrlen) { + PJ_ASSERT_RETURN(addr && addrlen && *addrlen, PJ_EINVAL); + if (sock->GetAf() == PJ_AF_INET) { + PJ_ASSERT_RETURN(*addrlen >= sizeof(pj_sockaddr_in), PJ_EINVAL); + } else if (sock->GetAf() == PJ_AF_INET6) { + PJ_ASSERT_RETURN(*addrlen >= sizeof(pj_sockaddr_in6), PJ_EINVAL); + } + } + // If socket has reader, delete it. - if (key->cbObj->get_pj_socket()->Reader()) - key->cbObj->get_pj_socket()->DestroyReader(); + if (sock->Reader()) + sock->DestroyReader(); if (key->cbObj->IsActive()) return PJ_EBUSY; @@ -736,20 +769,23 @@ PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key, TPtrC8 aBuffer; TInetAddr inetAddr; TSockXfrLength aLen; + pj_status_t status; PJ_UNUSED_ARG(op_key); // Forcing pending operation is not supported. PJ_ASSERT_RETURN((flags & PJ_IOQUEUE_ALWAYS_ASYNC)==0, PJ_EINVAL); - // Must be pj_sockaddr_in for now. - PJ_ASSERT_RETURN(addrlen == sizeof(pj_sockaddr_in), PJ_EINVAL); - + // Convert address + status = PjSymbianOS::pj2Addr(*(const pj_sockaddr*)addr, addrlen, + inetAddr); + if (status != PJ_SUCCESS) + return status; + // Clear flag flags &= ~PJ_IOQUEUE_ALWAYS_ASYNC; aBuffer.Set((const TUint8*)data, (TInt)*length); - PjSymbianOS::pj2Addr(*(const pj_sockaddr_in*)addr, inetAddr); CPjSocket *pjSock = key->cbObj->get_pj_socket(); pjSock->Socket().SendTo(aBuffer, inetAddr, flags, reqStatus, aLen); diff --git a/pjlib/src/pj/ip_helper_generic.c b/pjlib/src/pj/ip_helper_generic.c index a9284807..8a2ea785 100644 --- a/pjlib/src/pj/ip_helper_generic.c +++ b/pjlib/src/pj/ip_helper_generic.c @@ -23,8 +23,9 @@ #include #include -static pj_status_t dummy_enum_ip_interface(unsigned *p_cnt, - pj_in_addr ifs[]) +static pj_status_t dummy_enum_ip_interface(int af, + unsigned *p_cnt, + pj_sockaddr ifs[]) { pj_status_t status; @@ -33,7 +34,7 @@ static pj_status_t dummy_enum_ip_interface(unsigned *p_cnt, pj_bzero(ifs, sizeof(ifs[0]) * (*p_cnt)); /* Just get one default route */ - status = pj_getdefaultipinterface(&ifs[0]); + status = pj_getdefaultipinterface(af, &ifs[0]); if (status != PJ_SUCCESS) return status; @@ -42,8 +43,9 @@ static pj_status_t dummy_enum_ip_interface(unsigned *p_cnt, } #ifdef SIOCGIFCONF -static pj_status_t sock_enum_ip_interface(unsigned *p_cnt, - pj_in_addr ifs[]) +static pj_status_t sock_enum_ip_interface(int af, + unsigned *p_cnt, + pj_sockaddr ifs[]) { pj_sock_t sock; char buf[512]; @@ -52,7 +54,9 @@ static pj_status_t sock_enum_ip_interface(unsigned *p_cnt, int i, count; pj_status_t status; - status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock); + PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EINVAL); + + status = pj_sock_socket(af, PJ_SOCK_DGRAM, 0, &sock); if (status != PJ_SUCCESS) return status; @@ -78,7 +82,12 @@ static pj_status_t sock_enum_ip_interface(unsigned *p_cnt, *p_cnt = count; for (i=0; iifr_addr)->sin_addr.s_addr; + struct sockaddr *ad = itf->ifr_addr; + + ifs[i].addr.sa_family = ad->sa_family; + pj_memcpy(pj_sockaddr_get_addr(&ifs[i]), + pj_sockaddr_get_addr(ad), + pj_sockaddr_get_addr_len(ad)); } return PJ_SUCCESS; @@ -88,14 +97,15 @@ static pj_status_t sock_enum_ip_interface(unsigned *p_cnt, /* * Enumerate the local IP interface currently active in the host. */ -PJ_DEF(pj_status_t) pj_enum_ip_interface(unsigned *p_cnt, - pj_in_addr ifs[]) +PJ_DEF(pj_status_t) pj_enum_ip_interface(int af, + unsigned *p_cnt, + pj_sockaddr ifs[]) { #ifdef SIOCGIFCONF - if (sock_enum_ip_interface(p_cnt, ifs) == PJ_SUCCESS) + if (sock_enum_ip_interface(af, p_cnt, ifs) == PJ_SUCCESS) return PJ_SUCCESS; #endif - return dummy_enum_ip_interface(p_cnt, ifs); + return dummy_enum_ip_interface(af, p_cnt, ifs); } /* @@ -104,6 +114,7 @@ PJ_DEF(pj_status_t) pj_enum_ip_interface(unsigned *p_cnt, PJ_DEF(pj_status_t) pj_enum_ip_route(unsigned *p_cnt, pj_ip_route_entry routes[]) { + pj_sockaddr itf; pj_status_t status; PJ_ASSERT_RETURN(p_cnt && *p_cnt > 0 && routes, PJ_EINVAL); @@ -111,10 +122,11 @@ PJ_DEF(pj_status_t) pj_enum_ip_route(unsigned *p_cnt, pj_bzero(routes, sizeof(routes[0]) * (*p_cnt)); /* Just get one default route */ - status = pj_getdefaultipinterface(&routes[0].ipv4.if_addr); + status = pj_getdefaultipinterface(PJ_AF_INET, &itf); if (status != PJ_SUCCESS) return status; - + + routes[0].ipv4.if_addr.s_addr = itf.ipv4.sin_addr.s_addr; routes[0].ipv4.dst_addr.s_addr = 0; routes[0].ipv4.mask.s_addr = 0; *p_cnt = 1; diff --git a/pjlib/src/pj/ip_helper_symbian.cpp b/pjlib/src/pj/ip_helper_symbian.cpp new file mode 100644 index 00000000..3cd2ebfd --- /dev/null +++ b/pjlib/src/pj/ip_helper_symbian.cpp @@ -0,0 +1,133 @@ +/* $Id$ */ +/* + * Copyright (C)2003-2007 Benny Prijono + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include + + +#include "os_symbian.h" + +static pj_status_t rsock_enum_interface(int af, + unsigned *p_cnt, + pj_sockaddr ifs[]) +{ + TInt rc; + RSocket rSock; + TPckgBuf info; + unsigned i; + + if (PjSymbianOS::Instance()->Connection()) { + + rc = rSock.Open(PjSymbianOS::Instance()->SocketServ(), + af, PJ_SOCK_DGRAM, KProtocolInetUdp, + *PjSymbianOS::Instance()->Connection()); + } else { + + rc = rSock.Open(PjSymbianOS::Instance()->SocketServ(), + af, PJ_SOCK_DGRAM, KProtocolInetUdp); + + } + + if (rc != KErrNone) + return PJ_RETURN_OS_ERROR(rc); + + rSock.SetOpt(KSoInetEnumInterfaces, KSolInetIfCtrl); + + for (i=0; i<*p_cnt && + rSock.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, + info) == KErrNone; ) + { + TInetAddr &iAddress = info().iAddress; + int namelen; + + if (iAddress.Family() != af) { + continue; + } + + namelen = sizeof(ifs[i]); + if (PjSymbianOS::Addr2pj(iAddress, ifs[i], &namelen) != PJ_SUCCESS) + continue; + + ++i; + } + + rSock.Close(); + + // Done + *p_cnt = i; + + return PJ_SUCCESS; + +on_error: + rSock.Close(); + *p_cnt = 0; + return PJ_RETURN_OS_ERROR(rc); +} + +/* + * Enumerate the local IP interface currently active in the host. + */ +PJ_DEF(pj_status_t) pj_enum_ip_interface(int af, + unsigned *p_cnt, + pj_sockaddr ifs[]) +{ + unsigned start; + pj_status_t status = PJ_SUCCESS; + + start = 0; + + /* Get IPv6 interface first. */ + if (af==PJ_AF_INET6 || af==PJ_AF_UNSPEC) { + unsigned max = *p_cnt; + status = rsock_enum_interface(PJ_AF_INET6, &max, &ifs[start]); + if (status == PJ_SUCCESS) { + (*p_cnt) -= max; + start += max; + } + } + + /* Get IPv4 interface. */ + if (af==PJ_AF_INET || af==PJ_AF_UNSPEC) { + unsigned max = *p_cnt; + status = rsock_enum_interface(PJ_AF_INET, &max, &ifs[start]); + if (status == PJ_SUCCESS) { + (*p_cnt) -= max; + start += max; + } + } + + *p_cnt = start; + + return start ? PJ_SUCCESS : PJ_ENOTFOUND; +} + +/* + * Enumerate the IP routing table for this host. + */ +PJ_DEF(pj_status_t) pj_enum_ip_route(unsigned *p_cnt, + pj_ip_route_entry routes[]) +{ + PJ_ASSERT_RETURN(p_cnt && *p_cnt > 0 && routes, PJ_EINVAL); + *p_cnt = 0; + return PJ_ENOTSUP; +} + diff --git a/pjlib/src/pj/ip_helper_win32.c b/pjlib/src/pj/ip_helper_win32.c index 1a937d72..d5cc9690 100644 --- a/pjlib/src/pj/ip_helper_win32.c +++ b/pjlib/src/pj/ip_helper_win32.c @@ -27,6 +27,12 @@ #if defined(_MSC_VER) && _MSC_VER==1200 && !defined(PJ_WIN32_WINCE) # define PMIB_ICMP_EX void* #endif +#include + +/* If you encounter error "Cannot open include file: 'Iphlpapi.h' here, + * you need to install newer Platform SDK. Presumably you're using + * Microsoft Visual Studio 6? + */ #include #include @@ -41,6 +47,13 @@ typedef DWORD (WINAPI *PFN_GetIpAddrTable)(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder); +#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0 +typedef DWORD (WINAPI *PFN_GetAdapterAddresses)(ULONG Family, + ULONG Flags, + PVOID Reserved, + PIP_ADAPTER_ADDRESSES AdapterAddresses, + PULONG SizePointer); +#endif /* PJ_HAS_IPV6 */ typedef DWORD (WINAPI *PFN_GetIpForwardTable)(PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSize, BOOL bOrder); @@ -48,15 +61,23 @@ typedef DWORD (WINAPI *PFN_GetIfEntry)(PMIB_IFROW pIfRow); static HANDLE s_hDLL; static PFN_GetIpAddrTable s_pfnGetIpAddrTable; +#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0 + static PFN_GetAdapterAddresses s_pfnGetAdapterAddresses; +#endif /* PJ_HAS_IPV6 */ static PFN_GetIpForwardTable s_pfnGetIpForwardTable; static PFN_GetIfEntry s_pfnGetIfEntry; + static void unload_iphlp_module(void) { FreeLibrary(s_hDLL); s_hDLL = NULL; s_pfnGetIpAddrTable = NULL; s_pfnGetIpForwardTable = NULL; + s_pfnGetIfEntry = NULL; +#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0 + s_pfnGetAdapterAddresses = NULL; +#endif } static FARPROC GetIpHlpApiProc(pj_char_t *lpProcName) @@ -90,6 +111,26 @@ static DWORD MyGetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable, return ERROR_NOT_SUPPORTED; } +#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0 +static DWORD MyGetAdapterAddresses(ULONG Family, + ULONG Flags, + PVOID Reserved, + PIP_ADAPTER_ADDRESSES AdapterAddresses, + PULONG SizePointer) +{ + if(NULL == s_pfnGetAdapterAddresses) { + s_pfnGetAdapterAddresses = (PFN_GetAdapterAddresses) + GetIpHlpApiProc(PJ_T("GetAdapterAddresses")); + } + + if(NULL != s_pfnGetAdapterAddresses) { + return s_pfnGetAdapterAddresses(Family, Flags, Reserved, + AdapterAddresses, SizePointer); + } + + return ERROR_NOT_SUPPORTED; +} +#endif /* PJ_HAS_IPV6 */ #if PJ_IP_HELPER_IGNORE_LOOPBACK_IF static DWORD MyGetIfEntry(MIB_IFROW *pIfRow) @@ -124,11 +165,11 @@ static DWORD MyGetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable, return ERROR_NOT_SUPPORTED; } -/* - * Enumerate the local IP interface currently active in the host. +/* Enumerate local IP interface using GetIpAddrTable() + * for IPv4 addresses only. */ -PJ_DEF(pj_status_t) pj_enum_ip_interface(unsigned *p_cnt, - pj_in_addr ifs[]) +static pj_status_t enum_ipv4_interface(unsigned *p_cnt, + pj_sockaddr ifs[]) { /* Provide enough buffer or otherwise it will fail with * error 22 ("Not Enough Buffer") error. @@ -159,7 +200,7 @@ PJ_DEF(pj_status_t) pj_enum_ip_interface(unsigned *p_cnt, for (i=0; itable[i].dwAddr == 0) continue; @@ -174,14 +215,72 @@ PJ_DEF(pj_status_t) pj_enum_ip_interface(unsigned *p_cnt, continue; #endif - ifs[*p_cnt].s_addr = pTab->table[i].dwAddr; + ifs[*p_cnt].ipv4.sin_family = PJ_AF_INET; + ifs[*p_cnt].ipv4.sin_addr.s_addr = pTab->table[i].dwAddr; (*p_cnt)++; } return PJ_SUCCESS; +} + + +/* Enumerate local IP interface using GetAdapterAddresses(), + * which works for both IPv4 and IPv6. + */ +#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0 +static pj_status_t enum_ipv4_ipv6_interface(int af, + unsigned *p_cnt, + pj_sockaddr ifs[]) +{ + pj_uint8_t buffer[1024]; + IP_ADAPTER_ADDRESSES *adapter = (IP_ADAPTER_ADDRESSES*)buffer; + ULONG size = sizeof(buffer); + unsigned i; + DWORD rc; + + rc = MyGetAdapterAddresses(af, 0, NULL, adapter, &size); + if (rc != ERROR_SUCCESS) + return PJ_RETURN_OS_ERROR(rc); + + for (i=0; i<*p_cnt && adapter; ++i, adapter = adapter->Next) { + SOCKET_ADDRESS *pAddr = &adapter->FirstUnicastAddress->Address; + ifs[i].addr.sa_family = pAddr->lpSockaddr->sa_family; + pj_memcpy(&ifs[i], pAddr->lpSockaddr, pAddr->iSockaddrLength); + } + return PJ_SUCCESS; } +#endif + +/* + * Enumerate the local IP interface currently active in the host. + */ +PJ_DEF(pj_status_t) pj_enum_ip_interface(int af, + unsigned *p_cnt, + pj_sockaddr ifs[]) +{ + pj_status_t status = -1; + + PJ_ASSERT_RETURN(p_cnt && ifs, PJ_EINVAL); + PJ_ASSERT_RETURN(af==PJ_AF_UNSPEC || af==PJ_AF_INET || af==PJ_AF_INET6, + PJ_EAFNOTSUP); + +#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0 + status = enum_ipv4_ipv6_interface(af, p_cnt, ifs); + if (status != PJ_SUCCESS && (af==PJ_AF_INET || af==PJ_AF_UNSPEC)) + status = enum_ipv4_interface(p_cnt, ifs); + return status; +#else + if (af==PJ_AF_INET6) + return PJ_EIPV6NOTSUP; + else if (af != PJ_AF_INET && af != PJ_AF_UNSPEC) + return PJ_EAFNOTSUP; + + status = enum_ipv4_interface(p_cnt, ifs); + return status; +#endif +} /* * Enumerate the IP routing table for this host. diff --git a/pjlib/src/pj/os_core_symbian.cpp b/pjlib/src/pj/os_core_symbian.cpp index f656cb68..c193fb5b 100644 --- a/pjlib/src/pj/os_core_symbian.cpp +++ b/pjlib/src/pj/os_core_symbian.cpp @@ -154,7 +154,8 @@ TInt CPjTimeoutTimer::RunError(TInt aError) PjSymbianOS::PjSymbianOS() : isSocketServInitialized_(false), isResolverInitialized_(false), console_(NULL), selectTimeoutTimer_(NULL), - appSocketServ_(NULL), appConnection_(NULL), appHostResolver_(NULL) + appSocketServ_(NULL), appConnection_(NULL), appHostResolver_(NULL), + appHostResolver6_(NULL) { } @@ -164,6 +165,7 @@ void PjSymbianOS::SetParameters(pj_symbianos_params *params) appSocketServ_ = (RSocketServ*) params->rsocketserv; appConnection_ = (RConnection*) params->rconnection; appHostResolver_ = (RHostResolver*) params->rhostresolver; + appHostResolver6_ = (RHostResolver*) params->rhostresolver6; } // Get PjSymbianOS instance @@ -199,16 +201,29 @@ TInt PjSymbianOS::Initialize() isSocketServInitialized_ = true; } - if (!isResolverInitialized_ && appHostResolver_ == NULL) { - if (Connection()) - err = hostResolver_.Open(SocketServ(), KAfInet, KSockStream, - *Connection()); - else - err = hostResolver_.Open(SocketServ(), KAfInet, KSockStream); + if (!isResolverInitialized_) { + if (appHostResolver_ == NULL) { + if (Connection()) + err = hostResolver_.Open(SocketServ(), KAfInet, KSockStream, + *Connection()); + else + err = hostResolver_.Open(SocketServ(), KAfInet, KSockStream); + + if (err != KErrNone) + goto on_error; + } + + if (appHostResolver6_ == NULL) { + if (Connection()) + err = hostResolver6_.Open(SocketServ(), KAfInet6, KSockStream, + *Connection()); + else + err = hostResolver6_.Open(SocketServ(), KAfInet6, KSockStream); + + if (err != KErrNone) + goto on_error; + } - if (err != KErrNone) - goto on_error; - isResolverInitialized_ = true; } @@ -224,6 +239,7 @@ void PjSymbianOS::Shutdown() { if (isResolverInitialized_) { hostResolver_.Close(); + hostResolver6_.Close(); isResolverInitialized_ = false; } diff --git a/pjlib/src/pj/os_symbian.h b/pjlib/src/pj/os_symbian.h index 2b14ecd6..f564075f 100644 --- a/pjlib/src/pj/os_symbian.h +++ b/pjlib/src/pj/os_symbian.h @@ -19,6 +19,8 @@ #ifndef __OS_SYMBIAN_H__ #define __OS_SYMBIAN_H__ +#include +#include #include #include #include @@ -51,14 +53,20 @@ public: }; // Construct CPjSocket - CPjSocket(RSocket &sock) - : sock_(sock), connected_(false), sockReader_(NULL) + CPjSocket(int af, RSocket &sock) + : af_(af), sock_(sock), connected_(false), sockReader_(NULL) { } // Destroy CPjSocket ~CPjSocket(); + // Get address family + int GetAf() const + { + return af_; + } + // Get the internal RSocket RSocket& Socket() { @@ -91,6 +99,7 @@ public: void DestroyReader(); private: + int af_; RSocket sock_; // Must not be reference, or otherwise // it may point to local variable! bool connected_; @@ -228,23 +237,57 @@ public: } // Convert TInetAddr to pj_sockaddr_in - static inline void Addr2pj(const TInetAddr & sym_addr, - pj_sockaddr_in &pj_addr) + static inline pj_status_t Addr2pj(const TInetAddr & sym_addr, + pj_sockaddr &pj_addr, + int *addr_len) { - pj_bzero(&pj_addr, sizeof(pj_sockaddr_in)); - pj_addr.sin_family = pj_AF_INET(); - pj_addr.sin_addr.s_addr = pj_htonl(sym_addr.Address()); - pj_addr.sin_port = pj_htons((pj_uint16_t) sym_addr.Port()); + pj_bzero(&pj_addr, sizeof(pj_sockaddr)); + pj_addr.addr.sa_family = (pj_uint16_t)sym_addr.Family(); + if (pj_addr.addr.sa_family == PJ_AF_INET) { + PJ_ASSERT_RETURN(*addr_len >= sizeof(pj_sockaddr_in), PJ_ETOOSMALL); + pj_addr.ipv4.sin_addr.s_addr = pj_htonl(sym_addr.Address()); + pj_addr.ipv4.sin_port = pj_htons((pj_uint16_t) sym_addr.Port()); + *addr_len = sizeof(pj_sockaddr_in); + } else if (pj_addr.addr.sa_family == PJ_AF_INET6) { + PJ_ASSERT_RETURN(*addr_len >= sizeof(pj_sockaddr_in6), PJ_ETOOSMALL); + const TIp6Addr & ip6 = sym_addr.Ip6Address(); + pj_memcpy(&pj_addr.ipv6.sin6_addr, ip6.u.iAddr8, 16); + pj_addr.ipv6.sin6_port = pj_htons((pj_uint16_t) sym_addr.Port()); + pj_addr.ipv6.sin6_scope_id = pj_htonl(sym_addr.Scope()); + pj_addr.ipv6.sin6_flowinfo = pj_htonl(sym_addr.FlowLabel()); + *addr_len = sizeof(pj_sockaddr_in6); + } else { + pj_assert(!"Unsupported address family"); + return PJ_EAFNOTSUP; + } + + return PJ_SUCCESS; } // Convert pj_sockaddr_in to TInetAddr - static inline void pj2Addr(const pj_sockaddr_in &pj_addr, - TInetAddr & sym_addr) + static inline pj_status_t pj2Addr(const pj_sockaddr &pj_addr, + int addrlen, + TInetAddr & sym_addr) { - sym_addr.Init(KAfInet); - sym_addr.SetAddress((TUint32)pj_ntohl(pj_addr.sin_addr.s_addr)); - sym_addr.SetPort(pj_ntohs(pj_addr.sin_port)); + if (pj_addr.addr.sa_family == PJ_AF_INET) { + PJ_ASSERT_RETURN(addrlen >= sizeof(pj_sockaddr_in), PJ_EINVAL); + sym_addr.Init(KAfInet); + sym_addr.SetAddress((TUint32)pj_ntohl(pj_addr.ipv4.sin_addr.s_addr)); + sym_addr.SetPort(pj_ntohs(pj_addr.ipv4.sin_port)); + } else if (pj_addr.addr.sa_family == PJ_AF_INET6) { + TIp6Addr ip6; + + PJ_ASSERT_RETURN(addrlen >= sizeof(pj_sockaddr_in6), PJ_EINVAL); + pj_memcpy(ip6.u.iAddr8, &pj_addr.ipv6.sin6_addr, 16); + sym_addr.Init(KAfInet6); + sym_addr.SetAddress(ip6); + sym_addr.SetScope(pj_ntohl(pj_addr.ipv6.sin6_scope_id)); + sym_addr.SetFlowLabel(pj_ntohl(pj_addr.ipv6.sin6_flowinfo)); + } else { + pj_assert(!"Unsupported address family"); + } + return PJ_SUCCESS; } @@ -253,9 +296,13 @@ public: // // Get RHostResolver instance - RHostResolver & GetResolver() + RHostResolver & GetResolver(int af) { - return appHostResolver_ ? *appHostResolver_ : hostResolver_; + if (af==PJ_AF_INET6) { + return appHostResolver6_ ? *appHostResolver6_ : hostResolver6_; + } else { + return appHostResolver_ ? *appHostResolver_ : hostResolver_; + } } @@ -303,6 +350,7 @@ private: bool isResolverInitialized_; RHostResolver hostResolver_; + RHostResolver hostResolver6_; CConsoleBase* console_; @@ -312,6 +360,7 @@ private: RSocketServ *appSocketServ_; RConnection *appConnection_; RHostResolver *appHostResolver_; + RHostResolver *appHostResolver6_; private: PjSymbianOS(); diff --git a/pjlib/src/pj/sock_bsd.c b/pjlib/src/pj/sock_bsd.c index 156ded85..761c03bc 100644 --- a/pjlib/src/pj/sock_bsd.c +++ b/pjlib/src/pj/sock_bsd.c @@ -123,15 +123,6 @@ const int PJ_MSG_PEEK = MSG_PEEK; const int PJ_MSG_DONTROUTE = MSG_DONTROUTE; -#if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0 -# define SET_LEN(addr,len) (((pj_sockaddr_in*)(addr))->sin_zero_len=(len)) -# define RESET_LEN(addr) (((pj_sockaddr_in*)(addr))->sin_zero_len=0) -#else -# define SET_LEN(addr,len) -# define RESET_LEN(addr) -#endif - - /* * Convert 16-bit value from network byte order to host byte order. */ @@ -221,7 +212,7 @@ PJ_DEF(pj_status_t) pj_inet_pton(int af, const pj_str_t *src, void *dst) { char tempaddr[PJ_INET6_ADDRSTRLEN]; - PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EINVAL); + PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EAFNOTSUP); PJ_ASSERT_RETURN(src && src->slen && dst, PJ_EINVAL); /* Initialize output with PJ_IN_ADDR_NONE for IPv4 (to be @@ -310,7 +301,7 @@ PJ_DEF(pj_status_t) pj_inet_ntop(int af, const void *src, *dst = '\0'; - PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EINVAL); + PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EAFNOTSUP); #if defined(PJ_SOCK_HAS_INET_NTOP) && PJ_SOCK_HAS_INET_NTOP != 0 /* @@ -353,7 +344,7 @@ PJ_DEF(pj_status_t) pj_inet_ntop(int af, const void *src, addr_str_len = PJ_INET6_ADDRSTRLEN; } else { pj_assert(!"Unsupported address family"); - return PJ_EINVAL; + return PJ_EAFNOTSUP; } #if PJ_NATIVE_STRING_IS_UNICODE @@ -387,87 +378,6 @@ PJ_DEF(pj_status_t) pj_inet_ntop(int af, const void *src, #endif } -/* - * Convert address string with numbers and dots to binary IP address. - */ -PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp) -{ - pj_in_addr addr; - - pj_inet_aton(cp, &addr); - return addr; -} - -/* - * Convert address string with numbers and dots to binary IP address. - */ -PJ_DEF(pj_in_addr) pj_inet_addr2(const char *cp) -{ - pj_str_t str = pj_str((char*)cp); - return pj_inet_addr(&str); -} - -/* - * Set the IP address of an IP socket address from string address, - * with resolving the host if necessary. The string address may be in a - * standard numbers and dots notation or may be a hostname. If hostname - * is specified, then the function will resolve the host into the IP - * address. - */ -PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr, - const pj_str_t *str_addr) -{ - PJ_CHECK_STACK(); - - PJ_ASSERT_RETURN(!str_addr || str_addr->slen < PJ_MAX_HOSTNAME, - (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL)); - - RESET_LEN(addr); - addr->sin_family = AF_INET; - pj_bzero(addr->sin_zero, sizeof(addr->sin_zero)); - - if (str_addr && str_addr->slen) { - addr->sin_addr = pj_inet_addr(str_addr); - if (addr->sin_addr.s_addr == PJ_INADDR_NONE) { - pj_hostent he; - pj_status_t rc; - - rc = pj_gethostbyname(str_addr, &he); - if (rc == 0) { - addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr; - } else { - addr->sin_addr.s_addr = PJ_INADDR_NONE; - return rc; - } - } - - } else { - addr->sin_addr.s_addr = 0; - } - - return PJ_SUCCESS; -} - -/* - * Set the IP address and port of an IP socket address. - * The string address may be in a standard numbers and dots notation or - * may be a hostname. If hostname is specified, then the function will - * resolve the host into the IP address. - */ -PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr, - const pj_str_t *str_addr, - pj_uint16_t port) -{ - PJ_ASSERT_RETURN(addr, (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL)); - - RESET_LEN(addr); - addr->sin_family = PJ_AF_INET; - pj_bzero(addr->sin_zero, sizeof(addr->sin_zero)); - pj_sockaddr_in_set_port(addr, port); - return pj_sockaddr_in_set_str_addr(addr, str_addr); -} - - /* * Get hostname. */ @@ -490,19 +400,6 @@ PJ_DEF(const pj_str_t*) pj_gethostname(void) return &hostname; } -/* - * Get first IP address associated with the hostname. - */ -PJ_DEF(pj_in_addr) pj_gethostaddr(void) -{ - pj_sockaddr_in addr; - const pj_str_t *hostname = pj_gethostname(); - - pj_sockaddr_in_set_str_addr(&addr, hostname); - return addr.sin_addr; -} - - #if defined(PJ_WIN32) /* * Create new socket/endpoint for communication and returns a descriptor. @@ -582,7 +479,7 @@ PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sock, PJ_CHECK_STACK(); - SET_LEN(&addr, sizeof(pj_sockaddr_in)); + PJ_SOCKADDR_SET_LEN(&addr, sizeof(pj_sockaddr_in)); addr.sin_family = PJ_AF_INET; pj_bzero(addr.sin_zero, sizeof(addr.sin_zero)); addr.sin_addr.s_addr = pj_htonl(addr32); @@ -624,7 +521,7 @@ PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sock, if (getpeername(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0) return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); else { - RESET_LEN(addr); + PJ_SOCKADDR_RESET_LEN(addr); return PJ_SUCCESS; } } @@ -640,7 +537,7 @@ PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock, if (getsockname(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0) return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); else { - RESET_LEN(addr); + PJ_SOCKADDR_RESET_LEN(addr); return PJ_SUCCESS; } } @@ -726,7 +623,7 @@ PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock, if (*len < 0) return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); else { - RESET_LEN(from); + PJ_SOCKADDR_RESET_LEN(from); return PJ_SUCCESS; } } @@ -820,7 +717,7 @@ PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd, #if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0 if (addr) { - SET_LEN(addr, *addrlen); + PJ_SOCKADDR_SET_LEN(addr, *addrlen); } #endif @@ -831,7 +728,7 @@ PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd, #if defined(PJ_SOCKADDR_HAS_LEN) && PJ_SOCKADDR_HAS_LEN!=0 if (addr) { - RESET_LEN(addr); + PJ_SOCKADDR_RESET_LEN(addr); } #endif diff --git a/pjlib/src/pj/sock_common.c b/pjlib/src/pj/sock_common.c index 5b629fc2..06aa9411 100644 --- a/pjlib/src/pj/sock_common.c +++ b/pjlib/src/pj/sock_common.c @@ -17,6 +17,416 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include +#include +#include +#include +#include +#include +#include +#include + + +/* + * Convert address string with numbers and dots to binary IP address. + */ +PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp) +{ + pj_in_addr addr; + + pj_inet_aton(cp, &addr); + return addr; +} + +/* + * Convert address string with numbers and dots to binary IP address. + */ +PJ_DEF(pj_in_addr) pj_inet_addr2(const char *cp) +{ + pj_str_t str = pj_str((char*)cp); + return pj_inet_addr(&str); +} + +/* + * Set the IP address of an IP socket address from string address, + * with resolving the host if necessary. The string address may be in a + * standard numbers and dots notation or may be a hostname. If hostname + * is specified, then the function will resolve the host into the IP + * address. + */ +PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr, + const pj_str_t *str_addr) +{ + PJ_CHECK_STACK(); + + PJ_ASSERT_RETURN(!str_addr || str_addr->slen < PJ_MAX_HOSTNAME, + (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL)); + + PJ_SOCKADDR_RESET_LEN(addr); + addr->sin_family = AF_INET; + pj_bzero(addr->sin_zero, sizeof(addr->sin_zero)); + + if (str_addr && str_addr->slen) { + addr->sin_addr = pj_inet_addr(str_addr); + if (addr->sin_addr.s_addr == PJ_INADDR_NONE) { + pj_hostent he; + pj_status_t rc; + + rc = pj_gethostbyname(str_addr, &he); + if (rc == 0) { + addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr; + } else { + addr->sin_addr.s_addr = PJ_INADDR_NONE; + return rc; + } + } + + } else { + addr->sin_addr.s_addr = 0; + } + + return PJ_SUCCESS; +} + +/* Set address from a name */ +PJ_DEF(pj_status_t) pj_sockaddr_set_str_addr(int af, + pj_sockaddr *addr, + const pj_str_t *str_addr) +{ + pj_status_t status; + + if (af == PJ_AF_INET) { + return pj_sockaddr_in_set_str_addr(&addr->ipv4, str_addr); + } + + PJ_ASSERT_RETURN(af==PJ_AF_INET6, PJ_EAFNOTSUP); + + /* IPv6 specific */ + + addr->ipv6.sin6_family = PJ_AF_INET6; + PJ_SOCKADDR_RESET_LEN(addr); + + if (str_addr && str_addr->slen) { + status = pj_inet_pton(PJ_AF_INET6, str_addr, &addr->ipv6.sin6_addr); + if (status != PJ_SUCCESS) { + pj_addrinfo ai; + unsigned count = 1; + + status = pj_getaddrinfo(PJ_AF_INET6, str_addr, &count, &ai); + if (status==PJ_SUCCESS) { + pj_memcpy(&addr->ipv6.sin6_addr, &ai.ai_addr.ipv6.sin6_addr, + sizeof(pj_sockaddr_in6)); + } + } + } else { + status = PJ_SUCCESS; + } + + return status; +} + +/* + * Set the IP address and port of an IP socket address. + * The string address may be in a standard numbers and dots notation or + * may be a hostname. If hostname is specified, then the function will + * resolve the host into the IP address. + */ +PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr, + const pj_str_t *str_addr, + pj_uint16_t port) +{ + PJ_ASSERT_RETURN(addr, (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL)); + + PJ_SOCKADDR_RESET_LEN(addr); + addr->sin_family = PJ_AF_INET; + pj_bzero(addr->sin_zero, sizeof(addr->sin_zero)); + pj_sockaddr_in_set_port(addr, port); + return pj_sockaddr_in_set_str_addr(addr, str_addr); +} + +/* + * Initialize IP socket address based on the address and port info. + */ +PJ_DEF(pj_status_t) pj_sockaddr_init(int af, + pj_sockaddr *addr, + const pj_str_t *cp, + pj_uint16_t port) +{ + pj_status_t status; + + if (af == PJ_AF_INET) { + return pj_sockaddr_in_init(&addr->ipv4, cp, port); + } + + /* IPv6 specific */ + PJ_ASSERT_RETURN(af==PJ_AF_INET6, PJ_EAFNOTSUP); + + pj_bzero(addr, sizeof(pj_sockaddr_in6)); + addr->addr.sa_family = PJ_AF_INET6; + + status = pj_sockaddr_set_str_addr(af, addr, cp); + if (status != PJ_SUCCESS) + return status; + + addr->ipv6.sin6_port = pj_htons(port); + return PJ_SUCCESS; +} + +/* + * Get first IP address associated with the hostname. + */ +PJ_DEF(pj_in_addr) pj_gethostaddr(void) +{ + pj_sockaddr_in addr; + const pj_str_t *hostname = pj_gethostname(); + + pj_sockaddr_in_set_str_addr(&addr, hostname); + return addr.sin_addr; +} + +/* + * Get port number of a pj_sockaddr_in + */ +PJ_DEF(pj_uint16_t) pj_sockaddr_in_get_port(const pj_sockaddr_in *addr) +{ + return pj_ntohs(addr->sin_port); +} + +/* + * Get the address part + */ +PJ_DEF(void*) pj_sockaddr_get_addr(const pj_sockaddr_t *addr) +{ + const pj_sockaddr *a = (const pj_sockaddr*)addr; + + PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET || + a->addr.sa_family == PJ_AF_INET6, NULL); + + if (a->addr.sa_family == PJ_AF_INET6) + return (void*) &a->ipv6.sin6_addr; + else + return (void*) &a->ipv4.sin_addr; +} + +/* + * Check if sockaddr contains a non-zero address + */ +PJ_DEF(pj_bool_t) pj_sockaddr_has_addr(const pj_sockaddr_t *addr) +{ + const pj_sockaddr *a = (const pj_sockaddr*)addr; + + PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET || + a->addr.sa_family == PJ_AF_INET6, PJ_EAFNOTSUP); + + if (a->addr.sa_family == PJ_AF_INET6) { + pj_uint8_t zero[24]; + pj_bzero(zero, sizeof(zero)); + return pj_memcmp(a->ipv6.sin6_addr.s6_addr, zero, + sizeof(pj_in6_addr)) != 0; + } else + return a->ipv4.sin_addr.s_addr != PJ_INADDR_ANY; +} + +/* + * Get port number + */ +PJ_DEF(pj_uint16_t) pj_sockaddr_get_port(const pj_sockaddr_t *addr) +{ + const pj_sockaddr *a = (const pj_sockaddr*) addr; + + PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET || + a->addr.sa_family == PJ_AF_INET6, (pj_uint16_t)0xFFFF); + + return pj_ntohs((pj_uint16_t)(a->addr.sa_family == PJ_AF_INET6 ? + a->ipv6.sin6_port : a->ipv4.sin_port)); +} + +/* + * Get the length of the address part. + */ +PJ_DEF(unsigned) pj_sockaddr_get_addr_len(const pj_sockaddr_t *addr) +{ + const pj_sockaddr *a = (const pj_sockaddr*) addr; + PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET || + a->addr.sa_family == PJ_AF_INET6, PJ_EAFNOTSUP); + return a->addr.sa_family == PJ_AF_INET6 ? + sizeof(pj_in6_addr) : sizeof(pj_in_addr); +} + +/* + * Set port number of pj_sockaddr_in + */ +PJ_DEF(void) pj_sockaddr_in_set_port(pj_sockaddr_in *addr, + pj_uint16_t hostport) +{ + addr->sin_port = pj_htons(hostport); +} + +/* + * Set port number of pj_sockaddr + */ +PJ_DEF(pj_status_t) pj_sockaddr_set_port(pj_sockaddr *addr, + pj_uint16_t hostport) +{ + int af = addr->addr.sa_family; + + PJ_ASSERT_ON_FAIL(af == PJ_AF_INET || af == PJ_AF_INET6, + PJ_EINVAL); + + if (af == PJ_AF_INET6) + addr->ipv6.sin6_port = pj_htons(hostport); + else + addr->ipv4.sin_port = pj_htons(hostport); + + return PJ_SUCCESS; +} + +/* + * Get IPv4 address + */ +PJ_DEF(pj_in_addr) pj_sockaddr_in_get_addr(const pj_sockaddr_in *addr) +{ + pj_in_addr in_addr; + in_addr.s_addr = pj_ntohl(addr->sin_addr.s_addr); + return in_addr; +} + +/* + * Set IPv4 address + */ +PJ_DEF(void) pj_sockaddr_in_set_addr(pj_sockaddr_in *addr, + pj_uint32_t hostaddr) +{ + addr->sin_addr.s_addr = pj_htonl(hostaddr); +} + +/* Resolve the IP address of local machine */ +PJ_DEF(pj_status_t) pj_gethostip(int af, pj_sockaddr *addr) +{ + unsigned count; + pj_addrinfo ai; + pj_status_t status; + + +#ifdef _MSC_VER + /* Get rid of "uninitialized he variable" with MS compilers */ + pj_bzero(&ai, sizeof(ai)); +#endif + + addr->addr.sa_family = (pj_uint16_t)af; + PJ_SOCKADDR_RESET_LEN(addr); + + /* Try with resolving local hostname first */ + count = 1; + status = pj_getaddrinfo(af, pj_gethostname(), &count, &ai); + if (status == PJ_SUCCESS) { + pj_memcpy(pj_sockaddr_get_addr(addr), + pj_sockaddr_get_addr(&ai.ai_addr), + pj_sockaddr_get_addr_len(&ai.ai_addr)); + } + + + /* If we end up with 127.x.x.x, resolve the IP by getting the default + * interface to connect to some public host. + */ + if (status != PJ_SUCCESS || !pj_sockaddr_has_addr(addr) || + (af==PJ_AF_INET && (pj_ntohl(addr->ipv4.sin_addr.s_addr) >> 24)==127)) + { + status = pj_getdefaultipinterface(af, addr); + } + + /* If failed, get the first available interface */ + if (status != PJ_SUCCESS) { + pj_sockaddr itf[1]; + unsigned count = PJ_ARRAY_SIZE(itf); + + status = pj_enum_ip_interface(af, &count, itf); + if (status == PJ_SUCCESS) { + itf[0].addr.sa_family = (pj_uint16_t)af; + pj_memcpy(pj_sockaddr_get_addr(addr), + pj_sockaddr_get_addr(&itf[0]), + pj_sockaddr_get_addr_len(&itf[0])); + } + } + + /* If else fails, returns loopback interface as the last resort */ + if (status != PJ_SUCCESS) { + if (af==PJ_AF_INET) { + addr->ipv4.sin_addr.s_addr = pj_htonl (0x7f000001); + } else { + pj_in6_addr *s6_addr; + + s6_addr = (pj_in6_addr*) pj_sockaddr_get_addr(addr); + pj_bzero(s6_addr, sizeof(pj_in6_addr)); + s6_addr->s6_addr[15] = 1; + } + status = PJ_SUCCESS; + } + + return status; +} + +/* Get the default IP interface */ +PJ_DEF(pj_status_t) pj_getdefaultipinterface(int af, pj_sockaddr *addr) +{ + pj_sock_t fd; + pj_str_t cp; + pj_sockaddr a; + int len; + pj_uint8_t zero[64]; + pj_status_t status; + + addr->addr.sa_family = (pj_uint16_t)af; + + status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &fd); + if (status != PJ_SUCCESS) { + return status; + } + + if (af == PJ_AF_INET) { + cp = pj_str("1.1.1.1"); + } else { + cp = pj_str("1::1"); + } + status = pj_sockaddr_init(af, &a, &cp, 53); + if (status != PJ_SUCCESS) { + pj_sock_close(fd); + return status; + } + + status = pj_sock_connect(fd, &a, sizeof(a)); + if (status != PJ_SUCCESS) { + pj_sock_close(fd); + return status; + } + + len = sizeof(a); + status = pj_sock_getsockname(fd, &a, &len); + if (status != PJ_SUCCESS) { + pj_sock_close(fd); + return status; + } + + pj_sock_close(fd); + + /* Check that the address returned is not zero */ + pj_bzero(zero, sizeof(zero)); + if (pj_memcmp(pj_sockaddr_get_addr(&a), zero, + pj_sockaddr_get_addr_len(&a))==0) + { + return PJ_ENOTFOUND; + } + + pj_memcpy(pj_sockaddr_get_addr(addr), + pj_sockaddr_get_addr(&a), + pj_sockaddr_get_addr_len(&a)); + + /* Success */ + return PJ_SUCCESS; +} + + +/* Only need to implement these in DLL build */ +#if defined(PJ_DLL) PJ_DEF(pj_uint16_t) pj_AF_UNSPEC(void) { @@ -148,3 +558,5 @@ PJ_DEF(int) pj_MSG_DONTROUTE(void) return PJ_MSG_DONTROUTE; } +#endif /* PJ_DLL */ + diff --git a/pjlib/src/pj/sock_symbian.cpp b/pjlib/src/pj/sock_symbian.cpp index 67eea1a0..90044a35 100644 --- a/pjlib/src/pj/sock_symbian.cpp +++ b/pjlib/src/pj/sock_symbian.cpp @@ -441,85 +441,6 @@ PJ_DEF(pj_status_t) pj_inet_ntop(int af, const void *src, } -/* - * Convert address string with numbers and dots to binary IP address. - */ -PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp) -{ - pj_in_addr addr; - - pj_inet_aton(cp, &addr); - return addr; -} - -/* - * Convert address string with numbers and dots to binary IP address. - */ -PJ_DEF(pj_in_addr) pj_inet_addr2(const char *cp) -{ - pj_str_t str = pj_str((char*)cp); - return pj_inet_addr(&str); -} - -/* - * Set the IP address of an IP socket address from string address, - * with resolving the host if necessary. The string address may be in a - * standard numbers and dots notation or may be a hostname. If hostname - * is specified, then the function will resolve the host into the IP - * address. - */ -PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr, - const pj_str_t *str_addr) -{ - PJ_CHECK_STACK(); - - PJ_ASSERT_RETURN(!str_addr || str_addr->slen < PJ_MAX_HOSTNAME, - (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL)); - - addr->sin_family = PJ_AF_INET; - pj_memset(addr->sin_zero, 0, sizeof(addr->sin_zero)); - - if (str_addr && str_addr->slen) { - addr->sin_addr = pj_inet_addr(str_addr); - if (addr->sin_addr.s_addr == PJ_INADDR_NONE) { - pj_hostent he; - pj_status_t rc; - - rc = pj_gethostbyname(str_addr, &he); - if (rc == 0) { - addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr; - } else { - addr->sin_addr.s_addr = PJ_INADDR_NONE; - return rc; - } - } - - } else { - addr->sin_addr.s_addr = 0; - } - - return PJ_SUCCESS; -} - -/* - * Set the IP address and port of an IP socket address. - * The string address may be in a standard numbers and dots notation or - * may be a hostname. If hostname is specified, then the function will - * resolve the host into the IP address. - */ -PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr, - const pj_str_t *str_addr, - pj_uint16_t port) -{ - PJ_ASSERT_RETURN(addr, (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL)); - - addr->sin_family = PJ_AF_INET; - pj_memset(addr->sin_zero, 0, sizeof(addr->sin_zero)); - pj_sockaddr_in_set_port(addr, port); - return pj_sockaddr_in_set_str_addr(addr, str_addr); -} - - /* * Get hostname. */ @@ -531,7 +452,7 @@ PJ_DEF(const pj_str_t*) pj_gethostname(void) PJ_CHECK_STACK(); if (hostname.ptr == NULL) { - RHostResolver & resv = PjSymbianOS::Instance()->GetResolver(); + RHostResolver &resv = PjSymbianOS::Instance()->GetResolver(PJ_AF_INET); TRequestStatus reqStatus; THostName tmpName; @@ -545,19 +466,6 @@ PJ_DEF(const pj_str_t*) pj_gethostname(void) return &hostname; } -/* - * Get first IP address associated with the hostname. - */ -PJ_DEF(pj_in_addr) pj_gethostaddr(void) -{ - pj_sockaddr_in addr; - const pj_str_t *hostname = pj_gethostname(); - - pj_sockaddr_in_set_str_addr(&addr, hostname); - return addr.sin_addr; -} - - /* * Create new socket/endpoint for communication and returns a descriptor. */ @@ -596,7 +504,7 @@ PJ_DEF(pj_status_t) pj_sock_socket(int af, /* Wrap Symbian RSocket into PJLIB's CPjSocket, and return to caller */ - CPjSocket *pjSock = new CPjSocket(rSock); + CPjSocket *pjSock = new CPjSocket(af, rSock); *p_sock = (pj_sock_t)pjSock; return PJ_SUCCESS; @@ -610,16 +518,19 @@ PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sock, const pj_sockaddr_t *addr, int len) { + pj_status_t status; TInt rc; PJ_CHECK_STACK(); PJ_ASSERT_RETURN(sock != 0, PJ_EINVAL); - PJ_ASSERT_RETURN(addr && len == sizeof(pj_sockaddr_in), PJ_EINVAL); + PJ_ASSERT_RETURN(addr && len >= sizeof(pj_sockaddr_in), PJ_EINVAL); - // Convert PJLIB's pj_sockaddr_in into Symbian's TInetAddr + // Convert PJLIB's pj_sockaddr into Symbian's TInetAddr TInetAddr inetAddr; - PjSymbianOS::pj2Addr(*(pj_sockaddr_in*)addr, inetAddr); + status = PjSymbianOS::pj2Addr(*(pj_sockaddr*)addr, len, inetAddr); + if (status != PJ_SUCCESS) + return status; // Get the RSocket instance RSocket &rSock = ((CPjSocket*)sock)->Socket(); @@ -689,10 +600,7 @@ PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sock, TInetAddr inetAddr; rSock.RemoteName(inetAddr); - PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr_in*)addr); - *namelen = sizeof(pj_sockaddr_in); - - return PJ_SUCCESS; + return PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr*)addr, namelen); } /* @@ -713,10 +621,7 @@ PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock, TInetAddr inetAddr; rSock.LocalName(inetAddr); - PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr_in*)addr); - *namelen = sizeof(pj_sockaddr_in); - - return PJ_SUCCESS; + return PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr*)addr, namelen); } /* @@ -761,6 +666,8 @@ PJ_DEF(pj_status_t) pj_sock_sendto(pj_sock_t sock, const pj_sockaddr_t *to, int tolen) { + pj_status_t status; + PJ_CHECK_STACK(); PJ_ASSERT_RETURN(sock && buf && len, PJ_EINVAL); @@ -768,12 +675,12 @@ PJ_DEF(pj_status_t) pj_sock_sendto(pj_sock_t sock, RSocket &rSock = pjSock->Socket(); // Only supports AF_INET for now - PJ_ASSERT_RETURN(tolen==sizeof(pj_sockaddr_in) && - ((pj_sockaddr*)to)->addr.sa_family == PJ_AF_INET, - PJ_EINVAL); + PJ_ASSERT_RETURN(tolen >= sizeof(pj_sockaddr_in), PJ_EINVAL); TInetAddr inetAddr; - PjSymbianOS::pj2Addr(*(pj_sockaddr_in*)to, inetAddr); + status = PjSymbianOS::pj2Addr(*(pj_sockaddr*)to, tolen, inetAddr); + if (status != PJ_SUCCESS) + return status; TPtrC8 data((const TUint8*)buf, (TInt)*len); TRequestStatus reqStatus; @@ -876,10 +783,11 @@ PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock, *len = data.Length(); if (from && fromlen) { - PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr_in*)from); - *fromlen = sizeof(pj_sockaddr_in); + return PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr*)from, + fromlen); + } else { + return PJ_SUCCESS; } - return PJ_SUCCESS; } } @@ -894,9 +802,7 @@ PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock, if (reqStatus == KErrNone) { //*len = (TInt)recvLen.Length(); *len = data.Length(); - *fromlen = sizeof(pj_sockaddr_in); - PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr_in*)from); - return PJ_SUCCESS; + return PjSymbianOS::Addr2pj(inetAddr, *(pj_sockaddr*)from, fromlen); } else { *len = -1; *fromlen = -1; @@ -947,6 +853,8 @@ PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock, const pj_sockaddr_t *addr, int namelen) { + pj_status_t status; + PJ_CHECK_STACK(); PJ_ASSERT_RETURN(sock && addr && namelen, PJ_EINVAL); @@ -959,7 +867,9 @@ PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock, TInetAddr inetAddr; TRequestStatus reqStatus; - PjSymbianOS::pj2Addr(*(pj_sockaddr_in*)addr, inetAddr); + status = PjSymbianOS::pj2Addr(*(pj_sockaddr*)addr, namelen, inetAddr); + if (status != PJ_SUCCESS) + return status; rSock.Connect(inetAddr, reqStatus); User::WaitForRequest(reqStatus); @@ -1059,7 +969,7 @@ PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd, } // Create PJ socket - CPjSocket *newPjSock = new CPjSocket(newSock); + CPjSocket *newPjSock = new CPjSocket(pjSock->GetAf(), newSock); newPjSock->SetConnected(true); *newsock = (pj_sock_t) newPjSock; -- cgit v1.2.3