[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