summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pjlib/include/pj/addr_resolv.h37
-rw-r--r--pjlib/include/pj/compat/socket.h22
-rw-r--r--pjlib/include/pj/errno.h5
-rw-r--r--pjlib/include/pj/ip_helper.h16
-rw-r--r--pjlib/include/pj/os.h7
-rw-r--r--pjlib/include/pj/sock.h354
-rw-r--r--pjlib/src/pj/addr_resolv_sock.c144
-rw-r--r--pjlib/src/pj/addr_resolv_symbian.cpp217
-rw-r--r--pjlib/src/pj/errno.c3
-rw-r--r--pjlib/src/pj/ioqueue_symbian.cpp84
-rw-r--r--pjlib/src/pj/ip_helper_generic.c38
-rw-r--r--pjlib/src/pj/ip_helper_symbian.cpp133
-rw-r--r--pjlib/src/pj/ip_helper_win32.c111
-rw-r--r--pjlib/src/pj/os_core_symbian.cpp36
-rw-r--r--pjlib/src/pj/os_symbian.h79
-rw-r--r--pjlib/src/pj/sock_bsd.c121
-rw-r--r--pjlib/src/pj/sock_common.c412
-rw-r--r--pjlib/src/pj/sock_symbian.cpp144
18 files changed, 1341 insertions, 622 deletions
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] && *count<max_count; ++i) {
+ pj_ansi_strncpy(ai[*count].ai_canonname, he.h_name,
+ sizeof(ai[*count].ai_canonname));
+ ai[*count].ai_canonname[sizeof(ai[*count].ai_canonname)-1] = '\0';
+
+ ai[*count].ai_addr.ipv4.sin_family = PJ_AF_INET;
+ pj_memcpy(&ai[*count].ai_addr.ipv4.sin_addr,
+ he.h_addr_list[i], he.h_length);
+
+ (*count)++;
+ }
+
+ return PJ_SUCCESS;
+
+ } else {
+ /* IPv6 is not supported */
+ *count = 0;
+
+ return PJ_EIPV6NOTSUP;
+ }
#endif /* PJ_SOCK_HAS_GETADDRINFO */
}
diff --git a/pjlib/src/pj/addr_resolv_symbian.cpp b/pjlib/src/pj/addr_resolv_symbian.cpp
index 496c1f8b..d2bc6366 100644
--- a/pjlib/src/pj/addr_resolv_symbian.cpp
+++ b/pjlib/src/pj/addr_resolv_symbian.cpp
@@ -27,12 +27,48 @@
#include "os_symbian.h"
+
// PJLIB API: resolve hostname
PJ_DEF(pj_status_t) pj_gethostbyname(const pj_str_t *name, pj_hostent *he)
{
- PJ_ASSERT_RETURN(name && he, PJ_EINVAL);
+ static pj_addrinfo ai;
+ static char *aliases[2];
+ static char *addrlist[2];
+ unsigned count = 1;
+ pj_status_t status;
+
+ status = pj_getaddrinfo(PJ_AF_INET, name, &count, &ai);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ aliases[0] = ai.ai_canonname;
+ aliases[1] = NULL;
+
+ addrlist[0] = (char*) &ai.ai_addr.ipv4.sin_addr;
+ addrlist[1] = NULL;
+
+ pj_bzero(he, sizeof(*he));
+ he->h_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 <pj/string.h>
#include <pj/compat/socket.h>
-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; i<count; ++i) {
struct ifreq *itf = &ifr[i];
- ifs[i].s_addr = ((struct sockaddr_in *)&itf->ifr_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 <benny@prijono.org>
+ *
+ * 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 <pj/ip_helper.h>
+#include <pj/addr_resolv.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+#include <pj/string.h>
+#include <pj/compat/socket.h>
+
+
+#include "os_symbian.h"
+
+static pj_status_t rsock_enum_interface(int af,
+ unsigned *p_cnt,
+ pj_sockaddr ifs[])
+{
+ TInt rc;
+ RSocket rSock;
+ TPckgBuf<TSoInetInterfaceInfo> 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 <winsock2.h>
+
+/* 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 <Iphlpapi.h>
#include <pj/ip_helper.h>
@@ -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; i<count; ++i) {
MIB_IFROW ifRow;
- /* Some Windows returns 0.0.0.0! */
+ /* Ignore 0.0.0.0 address (interface is down?) */
if (pTab->table[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 <pj/assert.h>
+#include <pj/errno.h>
#include <pj/sock.h>
#include <pj/os.h>
#include <pj/string.h>
@@ -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
@@ -388,87 +379,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));
-
- 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.
*/
PJ_DEF(const pj_str_t*) pj_gethostname(void)
@@ -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 <pj/sock.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+#include <pj/ip_helper.h>
+#include <pj/os.h>
+#include <pj/addr_resolv.h>
+#include <pj/string.h>
+#include <pj/compat/socket.h>
+
+
+/*
+ * 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
@@ -442,85 +442,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.
*/
PJ_DEF(const pj_str_t*) pj_gethostname(void)
@@ -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;
@@ -546,19 +467,6 @@ PJ_DEF(const pj_str_t*) pj_gethostname(void)
}
/*
- * 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.
*/
PJ_DEF(pj_status_t) pj_sock_socket(int af,
@@ -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;