[asterisk-commits] jpdionne: branch group/v6-new r260565 - in /team/group/v6-new: include/asteri...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon May 3 08:35:29 CDT 2010


Author: jpdionne
Date: Mon May  3 08:35:26 2010
New Revision: 260565

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=260565
Log:
Create "IP version-independent" netsock functions and other utility functions

- Forgot to add main/netsock2.c and include/asterisk/netsock2.h in last commit (r260340)


Added:
    team/group/v6-new/include/asterisk/netsock2.h   (with props)
    team/group/v6-new/main/netsock2.c   (with props)

Added: team/group/v6-new/include/asterisk/netsock2.h
URL: http://svnview.digium.com/svn/asterisk/team/group/v6-new/include/asterisk/netsock2.h?view=auto&rev=260565
==============================================================================
--- team/group/v6-new/include/asterisk/netsock2.h (added)
+++ team/group/v6-new/include/asterisk/netsock2.h Mon May  3 08:35:26 2010
@@ -1,0 +1,201 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * Viagénie <asteriskv6 at viagenie.ca>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ * \brief Network socket handling
+ */
+
+#ifndef _ASTERISK_NETSOCK2_H
+#define _ASTERISK_NETSOCK2_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <sys/socket.h>
+
+/**
+ * Socket address structure. The first member is big enough to contain addresses
+ * of any family. The second member contains the length (in bytes) used in the
+ * first member.
+ *
+ * Some BSDs have then length embedded in sockaddr structs. We ignore them.
+ * (This is the right thing to do.)
+ */
+struct ast_sockaddr {
+	struct sockaddr_storage	 ss;
+	socklen_t		 len;
+};
+
+/**
+ * \return 1 if \a addr is null, 0 otherwise.
+ */
+static inline int ast_sockaddr_isnull(const struct ast_sockaddr *addr)
+{
+	return addr->len == 0;
+}
+
+/**
+ * Sets address \a addr to null.
+ */
+static inline void ast_sockaddr_setnull(struct ast_sockaddr *addr)
+{
+	addr->len = 0;
+}
+
+/**
+ * Copy socket address \a src to \a dst.
+ */
+static inline void ast_sockaddr_copy(struct ast_sockaddr *dst,
+		const struct ast_sockaddr *src)
+{
+	memcpy(dst, src, src->len);
+	dst->len = src->len;
+};
+
+/**
+ * Compares two socket addresses. Returns -1 if \a a is lexicographically
+ * smaller than \a b, 0 if they are equal, and 1 otherwise.
+ */
+static inline int ast_sockaddr_cmp(struct ast_sockaddr *a,
+				   struct ast_sockaddr *b)
+{
+	if (a->len < b->len)
+		return -1;
+	else if (a->len > b->len)
+		return 1;
+	return memcmp(&a->ss, &b->ss, a->len);
+}
+
+/**
+ * Convert a socket address to a string. This will be of the form a.b.c.d:xyz
+ * for IPv4 and [a:b:c:...:d]:xyz for IPv6.
+ *
+ * This function is thread-safe. The returned string is on static
+ * thread-specific storage.
+ */
+char *ast_sockaddr_stringify(struct ast_sockaddr *addr);
+
+/**
+ * Parses a string containing an IPv4 or IPv6 address followed by an optional
+ * port (separated by a colon) into a struct ast_sockaddr. The allowed formats
+ * are the following:
+ *
+ * a.b.c.d
+ * a.b.c.d:port
+ * a:b:c:...:d
+ * [a:b:c:...:d]
+ * [a:b:c:...:d]:port
+ *
+ * Host names are NOT allowed.
+ *
+ * \param flags If set to zero, a port MAY be present. If set to
+ * PARSE_PORT_IGNORE, a port MAY be present but will be ignored. If set to
+ * PARSE_PORT_REQUIRE, a port MUST be present. If set to PARSE_PORT_FORBID, a
+ * port MUST NOT be present.
+ *
+ * \return 1 on success, 0 on failure.
+ */
+int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags);
+
+/**
+ * Returns the port number of a socket address, or zero if the address is null.
+ *
+ * \warning Do not use this function unless you really know what you are doing.
+ * And "I want the port number" is not knowing what you are doing.
+ */
+uint16_t ast_sockaddr_port(const struct ast_sockaddr *addr);
+
+/**
+ * Sets the port number of a socket address.
+ *
+ * \warning Do not use this function unless you really know what you are doing.
+ * And "I want the port number" is not knowing what you are doing.
+ */
+void ast_sockaddr_set_port(struct ast_sockaddr *addr, uint16_t port);
+
+/**
+ * Returns the IPv4 address as a 32-bit value in network order.
+ *
+ * \warning You should rarely need this function. Only use if you know what
+ * you're doing.
+ */
+uint32_t ast_sockaddr_ipv4(const struct ast_sockaddr *addr);
+
+/**
+ * Returns 1 if this is an IPv6 address, 0 otherwise. IPv4-mapped IPv6 addresses
+ * return 1.
+ *
+ * \warning You should rarely need this function. Only use if you know what
+ * you're doing.
+ */
+int ast_sockaddr_is_ipv6(const struct ast_sockaddr *addr);
+
+/**
+ * Wrapper around accept(2) that uses struct ast_sockaddr.
+ */
+int ast_accept(int sockfd, struct ast_sockaddr *addr);
+
+/**
+ * Wrapper around bind(2) that uses struct ast_sockaddr.
+ */
+int ast_bind(int sockfd, struct ast_sockaddr *addr);
+
+/**
+ * Wrapper around connect(2) that uses struct ast_sockaddr.
+ */
+int ast_connect(int sockfd, struct ast_sockaddr *addr);
+
+/**
+ * Wrapper around recvfrom(2) that uses struct ast_sockaddr.
+ */
+ssize_t ast_recvfrom(int sockfd, void *buf, size_t len, int flags,
+		     struct ast_sockaddr *src_addr);
+
+/**
+ * Wrapper around sendto(2) that uses ast_sockaddr.
+ */
+ssize_t ast_sendto(int sockfd, const void *buf, size_t len, int flags,
+		   struct ast_sockaddr *dest_addr);
+
+/**
+ * These are backward compatibility functions that may be used by subsystems
+ * that have not yet been converted to IPv6. They will be removed when all
+ * subsystems are IPv6-ready.
+ */
+/*@{*/
+
+/**
+ * Converts a struct ast_sockaddr to a struct sockaddr_in. Returns nonzero on
+ * success, zero otherwise.
+ */
+int ast_sockaddr_to_sin(const struct ast_sockaddr *addr,
+			struct sockaddr_in *sin);
+
+/**
+ * Converts a struct sockaddr_in to a struct ast_sockaddr.
+ */
+struct ast_sockaddr ast_sockaddr_from_sin(struct sockaddr_in sin);
+
+/*@}*/
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif /* _ASTERISK_NETSOCK2_H */

Propchange: team/group/v6-new/include/asterisk/netsock2.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/group/v6-new/include/asterisk/netsock2.h
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/group/v6-new/include/asterisk/netsock2.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: team/group/v6-new/main/netsock2.c
URL: http://svnview.digium.com/svn/asterisk/team/group/v6-new/main/netsock2.c?view=auto&rev=260565
==============================================================================
--- team/group/v6-new/main/netsock2.c (added)
+++ team/group/v6-new/main/netsock2.c Mon May  3 08:35:26 2010
@@ -1,0 +1,241 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * Viagénie <asteriskv6 at viagenie.ca>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Network socket handling
+ *
+ * \author Viagénie <asteriskv6 at viagenie.ca>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/config.h"
+#include "asterisk/netsock2.h"
+#include "asterisk/utils.h"
+#include "asterisk/threadstorage.h"
+
+AST_THREADSTORAGE(ast_sockaddr_stringify_buf);
+
+char *ast_sockaddr_stringify(struct ast_sockaddr *sa)
+{
+	char host[NI_MAXHOST];
+	char port[NI_MAXSERV];
+	char *str;
+	int e;
+	static const size_t size = sizeof(host) - 1 + sizeof(port) - 1 + 4;
+
+	if(ast_sockaddr_isnull(sa))
+		return "(null)";
+
+	if ((e = getnameinfo((struct sockaddr *)&sa->ss, sa->len,
+			     host, sizeof(host), port, sizeof(port),
+			     NI_NUMERICHOST | NI_NUMERICSERV))) {
+		ast_log(LOG_ERROR, "getnameinfo(): %s\n", gai_strerror(e));
+		return "";
+	}
+
+	if (!(str = ast_threadstorage_get(&ast_sockaddr_stringify_buf, size)))
+		return "";
+
+	snprintf(str, size, sa->ss.ss_family == AF_INET6 ? "[%s]:%s" : "%s:%s",
+		 host, port);
+
+	return str;
+}
+
+int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
+{
+	struct addrinfo		 hints;
+	struct addrinfo		*res;
+	char			*s;
+	char			*host;
+	char			*port;
+	int			 e;
+
+	s = ast_strdupa(str);
+
+	host = NULL;
+	port = NULL;
+	if (*s == '[') {
+		host = ++s;
+		for (; *s && *s != ']'; ++s)
+			;
+		if (*s == ']') {
+			*s++ = '\0';
+			if (*s == ':')
+				port = s + 1;
+		}
+	} else {
+		host = s;
+		for (; *s; ++s) {
+			if (*s == ':')
+				port = port ? NULL : s;
+		}
+		if (port)
+			*port++ = '\0';
+	}
+
+	switch (flags & PARSE_PORT_MASK) {
+	case PARSE_PORT_IGNORE:
+		port = NULL;
+		break;
+	case PARSE_PORT_REQUIRE:
+		if (port == NULL) {
+			ast_log(LOG_WARNING, "missing port in %s\n", str);
+			return 0;
+		}
+		break;
+	case PARSE_PORT_FORBID:
+		if (port != NULL) {
+			ast_log(LOG_WARNING, "port disallowed in %s\n", str);
+			return 0;
+		}
+		break;
+	}
+
+	memset(&hints, 0, sizeof(hints));
+	/* Hint to get only one entry from getaddrinfo */
+	hints.ai_socktype = SOCK_DGRAM;
+
+	hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
+	if ((e = getaddrinfo(host, port, &hints, &res))) {
+		ast_log(LOG_ERROR, "getaddrinfo(): %s\n", gai_strerror(e));
+		return 0;
+	}
+
+	/*
+	 * I don't see how this could be possible since we're not resolving host
+	 * names. But let's be careful...
+	 */
+	if (res->ai_next != NULL)
+		ast_log(LOG_WARNING, "getaddrinfo() returned multiple "
+			"addresses. Ignoring all but the first.\n");
+
+	addr->len = res->ai_addrlen;
+	memcpy(&addr->ss, res->ai_addr, addr->len);
+
+	freeaddrinfo(res);
+
+	return 1;
+}
+
+uint16_t ast_sockaddr_port(const struct ast_sockaddr *addr)
+{
+	if (addr->ss.ss_family == AF_INET &&
+	    addr->len == sizeof(struct sockaddr_in))
+		return ntohs(((struct sockaddr_in *)&addr->ss)->sin_port);
+	else if (addr->ss.ss_family == AF_INET6 &&
+		 addr->len == sizeof(struct sockaddr_in6))
+		return ntohs(((struct sockaddr_in6 *)&addr->ss)->sin6_port);
+	ast_log(LOG_ERROR, "Not an IPv4 nor IPv6 address, cannot get port.\n");
+	return 0;
+}
+
+void ast_sockaddr_set_port(struct ast_sockaddr *addr, uint16_t port)
+{
+	if (addr->ss.ss_family == AF_INET &&
+	    addr->len == sizeof(struct sockaddr_in))
+		((struct sockaddr_in *)&addr->ss)->sin_port = htons(port);
+	else if (addr->ss.ss_family == AF_INET6 &&
+		 addr->len == sizeof(struct sockaddr_in6))
+		((struct sockaddr_in6 *)&addr->ss)->sin6_port = htons(port);
+	else
+		ast_log(LOG_ERROR,
+			"Not an IPv4 nor IPv6 address, cannot set port.\n");
+}
+
+uint32_t ast_sockaddr_ipv4(const struct ast_sockaddr *addr)
+{
+	const struct sockaddr_in *sin = (struct sockaddr_in *)&addr->ss;
+	return ntohl(sin->sin_addr.s_addr);
+}
+
+int ast_sockaddr_is_ipv6(const struct ast_sockaddr *addr)
+{
+	return addr->ss.ss_family == AF_INET6 &&
+	    addr->len == sizeof(struct sockaddr_in6);
+}
+
+int ast_accept(int sockfd, struct ast_sockaddr *addr)
+{
+	addr->len = sizeof(addr->ss);
+	return accept(sockfd, (struct sockaddr *)&addr->ss, &addr->len);
+}
+
+int ast_bind(int sockfd, struct ast_sockaddr *addr)
+{
+	return bind(sockfd, (struct sockaddr *)&addr->ss, addr->len);
+}
+
+int ast_connect(int sockfd, struct ast_sockaddr *addr)
+{
+	return connect(sockfd, (struct sockaddr *)&addr->ss, addr->len);
+}
+
+ssize_t ast_recvfrom(int sockfd, void *buf, size_t len, int flags,
+		     struct ast_sockaddr *src_addr)
+{
+	src_addr->len = sizeof(src_addr->ss);
+	return recvfrom(sockfd, buf, len, flags,
+			(struct sockaddr *)&src_addr->ss, &src_addr->len);
+}
+
+ssize_t ast_sendto(int sockfd, const void *buf, size_t len, int flags,
+		   struct ast_sockaddr *dest_addr)
+{
+	return sendto(sockfd, buf, len, flags,
+		      (struct sockaddr *)&dest_addr->ss, dest_addr->len);
+}
+
+int ast_sockaddr_to_sin(const struct ast_sockaddr *addr,
+			struct sockaddr_in *sin)
+{
+	if (addr->len == 0) {
+		memset(sin, 0, sizeof(*sin));
+		return 1;
+	}
+
+	if (addr->len != sizeof(*sin)) {
+		ast_log(LOG_ERROR, "Bad address cast to IPv4\n");
+		return 0;
+	}
+
+	if (addr->ss.ss_family != AF_INET) {
+		ast_log(LOG_DEBUG, "Address family is not AF_INET\n");
+	}
+
+	memcpy(sin, &addr->ss, sizeof(*sin));
+	return 1;
+}
+
+struct ast_sockaddr ast_sockaddr_from_sin(struct sockaddr_in sin)
+{
+	struct ast_sockaddr addr;
+
+	memcpy(&addr.ss, &sin, sizeof(sin));
+
+	if (addr.ss.ss_family != AF_INET) {
+		ast_log(LOG_DEBUG, "Address family is not AF_INET\n");
+	}
+
+	addr.len = sizeof(sin);
+	return addr;
+}

Propchange: team/group/v6-new/main/netsock2.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/group/v6-new/main/netsock2.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/group/v6-new/main/netsock2.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain




More information about the asterisk-commits mailing list