[asterisk-commits] file: branch file/rtp_engine r124371 - /team/file/rtp_engine/main/rtp.c
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Jun 20 15:44:56 CDT 2008
Author: file
Date: Fri Jun 20 15:44:56 2008
New Revision: 124371
URL: http://svn.digium.com/view/asterisk?view=rev&rev=124371
Log:
Goodbye STUN.
Modified:
team/file/rtp_engine/main/rtp.c
Modified: team/file/rtp_engine/main/rtp.c
URL: http://svn.digium.com/view/asterisk/team/file/rtp_engine/main/rtp.c?view=diff&rev=124371&r1=124370&r2=124371
==============================================================================
--- team/file/rtp_engine/main/rtp.c (original)
+++ team/file/rtp_engine/main/rtp.c Fri Jun 20 15:44:56 2008
@@ -36,6 +36,7 @@
#include <math.h>
#include "asterisk/rtp.h"
+#include "asterisk/stun.h"
#include "asterisk/pbx.h"
#include "asterisk/frame.h"
#include "asterisk/channel.h"
@@ -74,7 +75,6 @@
static int rtcpdebug; /*!< Are we debugging RTCP? */
static int rtcpstats; /*!< Are we debugging RTCP? */
static int rtcpinterval = RTCP_DEFAULT_INTERVALMS; /*!< Time between rtcp reports in millisecs */
-static int stundebug; /*!< Are we debugging stun? */
static struct sockaddr_in rtpdebugaddr; /*!< Debug packets to/from this host */
static struct sockaddr_in rtcpdebugaddr; /*!< Debug RTCP packets to/from this host */
#ifdef SO_NO_CHECK
@@ -286,422 +286,9 @@
int sendfur;
};
-/*!
- * \brief STUN support code
- *
- * This code provides some support for doing STUN transactions.
- * Eventually it should be moved elsewhere as other protocols
- * than RTP can benefit from it - e.g. SIP.
- * STUN is described in RFC3489 and it is based on the exchange
- * of UDP packets between a client and one or more servers to
- * determine the externally visible address (and port) of the client
- * once it has gone through the NAT boxes that connect it to the
- * outside.
- * The simplest request packet is just the header defined in
- * struct stun_header, and from the response we may just look at
- * one attribute, STUN_MAPPED_ADDRESS, that we find in the response.
- * By doing more transactions with different server addresses we
- * may determine more about the behaviour of the NAT boxes, of
- * course - the details are in the RFC.
- *
- * All STUN packets start with a simple header made of a type,
- * length (excluding the header) and a 16-byte random transaction id.
- * Following the header we may have zero or more attributes, each
- * structured as a type, length and a value (whose format depends
- * on the type, but often contains addresses).
- * Of course all fields are in network format.
- */
-
-typedef struct { unsigned int id[4]; } __attribute__((packed)) stun_trans_id;
-
-struct stun_header {
- unsigned short msgtype;
- unsigned short msglen;
- stun_trans_id id;
- unsigned char ies[0];
-} __attribute__((packed));
-
-struct stun_attr {
- unsigned short attr;
- unsigned short len;
- unsigned char value[0];
-} __attribute__((packed));
-
-/*
- * The format normally used for addresses carried by STUN messages.
- */
-struct stun_addr {
- unsigned char unused;
- unsigned char family;
- unsigned short port;
- unsigned int addr;
-} __attribute__((packed));
-
-#define STUN_IGNORE (0)
-#define STUN_ACCEPT (1)
-
-/*! \brief STUN message types
- * 'BIND' refers to transactions used to determine the externally
- * visible addresses. 'SEC' refers to transactions used to establish
- * a session key for subsequent requests.
- * 'SEC' functionality is not supported here.
- */
-
-#define STUN_BINDREQ 0x0001
-#define STUN_BINDRESP 0x0101
-#define STUN_BINDERR 0x0111
-#define STUN_SECREQ 0x0002
-#define STUN_SECRESP 0x0102
-#define STUN_SECERR 0x0112
-
-/*! \brief Basic attribute types in stun messages.
- * Messages can also contain custom attributes (codes above 0x7fff)
- */
-#define STUN_MAPPED_ADDRESS 0x0001
-#define STUN_RESPONSE_ADDRESS 0x0002
-#define STUN_CHANGE_REQUEST 0x0003
-#define STUN_SOURCE_ADDRESS 0x0004
-#define STUN_CHANGED_ADDRESS 0x0005
-#define STUN_USERNAME 0x0006
-#define STUN_PASSWORD 0x0007
-#define STUN_MESSAGE_INTEGRITY 0x0008
-#define STUN_ERROR_CODE 0x0009
-#define STUN_UNKNOWN_ATTRIBUTES 0x000a
-#define STUN_REFLECTED_FROM 0x000b
-
-/*! \brief helper function to print message names */
-static const char *stun_msg2str(int msg)
-{
- switch (msg) {
- case STUN_BINDREQ:
- return "Binding Request";
- case STUN_BINDRESP:
- return "Binding Response";
- case STUN_BINDERR:
- return "Binding Error Response";
- case STUN_SECREQ:
- return "Shared Secret Request";
- case STUN_SECRESP:
- return "Shared Secret Response";
- case STUN_SECERR:
- return "Shared Secret Error Response";
- }
- return "Non-RFC3489 Message";
-}
-
-/*! \brief helper function to print attribute names */
-static const char *stun_attr2str(int msg)
-{
- switch (msg) {
- case STUN_MAPPED_ADDRESS:
- return "Mapped Address";
- case STUN_RESPONSE_ADDRESS:
- return "Response Address";
- case STUN_CHANGE_REQUEST:
- return "Change Request";
- case STUN_SOURCE_ADDRESS:
- return "Source Address";
- case STUN_CHANGED_ADDRESS:
- return "Changed Address";
- case STUN_USERNAME:
- return "Username";
- case STUN_PASSWORD:
- return "Password";
- case STUN_MESSAGE_INTEGRITY:
- return "Message Integrity";
- case STUN_ERROR_CODE:
- return "Error Code";
- case STUN_UNKNOWN_ATTRIBUTES:
- return "Unknown Attributes";
- case STUN_REFLECTED_FROM:
- return "Reflected From";
- }
- return "Non-RFC3489 Attribute";
-}
-
-/*! \brief here we store credentials extracted from a message */
-struct stun_state {
- const char *username;
- const char *password;
-};
-
-static int stun_process_attr(struct stun_state *state, struct stun_attr *attr)
-{
- if (stundebug)
- ast_verbose("Found STUN Attribute %s (%04x), length %d\n",
- stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len));
- switch (ntohs(attr->attr)) {
- case STUN_USERNAME:
- state->username = (const char *) (attr->value);
- break;
- case STUN_PASSWORD:
- state->password = (const char *) (attr->value);
- break;
- default:
- if (stundebug)
- ast_verbose("Ignoring STUN attribute %s (%04x), length %d\n",
- stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len));
- }
- return 0;
-}
-
-/*! \brief append a string to an STUN message */
-static void append_attr_string(struct stun_attr **attr, int attrval, const char *s, int *len, int *left)
-{
- int size = sizeof(**attr) + strlen(s);
- if (*left > size) {
- (*attr)->attr = htons(attrval);
- (*attr)->len = htons(strlen(s));
- memcpy((*attr)->value, s, strlen(s));
- (*attr) = (struct stun_attr *)((*attr)->value + strlen(s));
- *len += size;
- *left -= size;
- }
-}
-
-/*! \brief append an address to an STUN message */
-static void append_attr_address(struct stun_attr **attr, int attrval, struct sockaddr_in *sin, int *len, int *left)
-{
- int size = sizeof(**attr) + 8;
- struct stun_addr *addr;
- if (*left > size) {
- (*attr)->attr = htons(attrval);
- (*attr)->len = htons(8);
- addr = (struct stun_addr *)((*attr)->value);
- addr->unused = 0;
- addr->family = 0x01;
- addr->port = sin->sin_port;
- addr->addr = sin->sin_addr.s_addr;
- (*attr) = (struct stun_attr *)((*attr)->value + 8);
- *len += size;
- *left -= size;
- }
-}
-
-/*! \brief wrapper to send an STUN message */
-static int stun_send(int s, struct sockaddr_in *dst, struct stun_header *resp)
-{
- return sendto(s, resp, ntohs(resp->msglen) + sizeof(*resp), 0,
- (struct sockaddr *)dst, sizeof(*dst));
-}
-
-/*! \brief helper function to generate a random request id */
-static void stun_req_id(struct stun_header *req)
-{
- int x;
- for (x = 0; x < 4; x++)
- req->id.id[x] = ast_random();
-}
-
size_t ast_rtp_alloc_size(void)
{
return sizeof(struct ast_rtp);
-}
-
-/*! \brief callback type to be invoked on stun responses. */
-typedef int (stun_cb_f)(struct stun_attr *attr, void *arg);
-
-/*! \brief handle an incoming STUN message.
- *
- * Do some basic sanity checks on packet size and content,
- * try to extract a bit of information, and possibly reply.
- * At the moment this only processes BIND requests, and returns
- * the externally visible address of the request.
- * If a callback is specified, invoke it with the attribute.
- */
-static int stun_handle_packet(int s, struct sockaddr_in *src,
- unsigned char *data, size_t len, stun_cb_f *stun_cb, void *arg)
-{
- struct stun_header *hdr = (struct stun_header *)data;
- struct stun_attr *attr;
- struct stun_state st;
- int ret = STUN_IGNORE;
- int x;
-
- /* On entry, 'len' is the length of the udp payload. After the
- * initial checks it becomes the size of unprocessed options,
- * while 'data' is advanced accordingly.
- */
- if (len < sizeof(struct stun_header)) {
- ast_debug(1, "Runt STUN packet (only %d, wanting at least %d)\n", (int) len, (int) sizeof(struct stun_header));
- return -1;
- }
- len -= sizeof(struct stun_header);
- data += sizeof(struct stun_header);
- x = ntohs(hdr->msglen); /* len as advertised in the message */
- if (stundebug)
- ast_verbose("STUN Packet, msg %s (%04x), length: %d\n", stun_msg2str(ntohs(hdr->msgtype)), ntohs(hdr->msgtype), x);
- if (x > len) {
- ast_debug(1, "Scrambled STUN packet length (got %d, expecting %d)\n", x, (int)len);
- } else
- len = x;
- memset(&st, 0, sizeof(st));
- while (len) {
- if (len < sizeof(struct stun_attr)) {
- ast_debug(1, "Runt Attribute (got %d, expecting %d)\n", (int)len, (int) sizeof(struct stun_attr));
- break;
- }
- attr = (struct stun_attr *)data;
- /* compute total attribute length */
- x = ntohs(attr->len) + sizeof(struct stun_attr);
- if (x > len) {
- ast_debug(1, "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n", x, (int)len);
- break;
- }
- if (stun_cb)
- stun_cb(attr, arg);
- if (stun_process_attr(&st, attr)) {
- ast_debug(1, "Failed to handle attribute %s (%04x)\n", stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr));
- break;
- }
- /* Clear attribute id: in case previous entry was a string,
- * this will act as the terminator for the string.
- */
- attr->attr = 0;
- data += x;
- len -= x;
- }
- /* Null terminate any string.
- * XXX NOTE, we write past the size of the buffer passed by the
- * caller, so this is potentially dangerous. The only thing that
- * saves us is that usually we read the incoming message in a
- * much larger buffer in the struct ast_rtp
- */
- *data = '\0';
-
- /* Now prepare to generate a reply, which at the moment is done
- * only for properly formed (len == 0) STUN_BINDREQ messages.
- */
- if (len == 0) {
- unsigned char respdata[1024];
- struct stun_header *resp = (struct stun_header *)respdata;
- int resplen = 0; /* len excluding header */
- int respleft = sizeof(respdata) - sizeof(struct stun_header);
-
- resp->id = hdr->id;
- resp->msgtype = 0;
- resp->msglen = 0;
- attr = (struct stun_attr *)resp->ies;
- switch (ntohs(hdr->msgtype)) {
- case STUN_BINDREQ:
- if (stundebug)
- ast_verbose("STUN Bind Request, username: %s\n",
- st.username ? st.username : "<none>");
- if (st.username)
- append_attr_string(&attr, STUN_USERNAME, st.username, &resplen, &respleft);
- append_attr_address(&attr, STUN_MAPPED_ADDRESS, src, &resplen, &respleft);
- resp->msglen = htons(resplen);
- resp->msgtype = htons(STUN_BINDRESP);
- stun_send(s, src, resp);
- ret = STUN_ACCEPT;
- break;
- default:
- if (stundebug)
- ast_verbose("Dunno what to do with STUN message %04x (%s)\n", ntohs(hdr->msgtype), stun_msg2str(ntohs(hdr->msgtype)));
- }
- }
- return ret;
-}
-
-/*! \brief Extract the STUN_MAPPED_ADDRESS from the stun response.
- * This is used as a callback for stun_handle_response
- * when called from ast_stun_request.
- */
-static int stun_get_mapped(struct stun_attr *attr, void *arg)
-{
- struct stun_addr *addr = (struct stun_addr *)(attr + 1);
- struct sockaddr_in *sa = (struct sockaddr_in *)arg;
-
- if (ntohs(attr->attr) != STUN_MAPPED_ADDRESS || ntohs(attr->len) != 8)
- return 1; /* not us. */
- sa->sin_port = addr->port;
- sa->sin_addr.s_addr = addr->addr;
- return 0;
-}
-
-/*! \brief Generic STUN request
- * Send a generic stun request to the server specified,
- * possibly waiting for a reply and filling the 'reply' field with
- * the externally visible address. Note that in this case the request
- * will be blocking.
- * (Note, the interface may change slightly in the future).
- *
- * \param s the socket used to send the request
- * \param dst the address of the STUN server
- * \param username if non null, add the username in the request
- * \param answer if non null, the function waits for a response and
- * puts here the externally visible address.
- * \return 0 on success, other values on error.
- */
-int ast_stun_request(int s, struct sockaddr_in *dst,
- const char *username, struct sockaddr_in *answer)
-{
- struct stun_header *req;
- unsigned char reqdata[1024];
- int reqlen, reqleft;
- struct stun_attr *attr;
- int res = 0;
- int retry;
-
- req = (struct stun_header *)reqdata;
- stun_req_id(req);
- reqlen = 0;
- reqleft = sizeof(reqdata) - sizeof(struct stun_header);
- req->msgtype = 0;
- req->msglen = 0;
- attr = (struct stun_attr *)req->ies;
- if (username)
- append_attr_string(&attr, STUN_USERNAME, username, &reqlen, &reqleft);
- req->msglen = htons(reqlen);
- req->msgtype = htons(STUN_BINDREQ);
- for (retry = 0; retry < 3; retry++) { /* XXX make retries configurable */
- /* send request, possibly wait for reply */
- unsigned char reply_buf[1024];
- fd_set rfds;
- struct timeval to = { 3, 0 }; /* timeout, make it configurable */
- struct sockaddr_in src;
- socklen_t srclen;
-
- res = stun_send(s, dst, req);
- if (res < 0) {
- ast_log(LOG_WARNING, "ast_stun_request send #%d failed error %d, retry\n",
- retry, res);
- continue;
- }
- if (answer == NULL)
- break;
- FD_ZERO(&rfds);
- FD_SET(s, &rfds);
- res = ast_select(s + 1, &rfds, NULL, NULL, &to);
- if (res <= 0) /* timeout or error */
- continue;
- bzero(&src, sizeof(src));
- srclen = sizeof(src);
- /* XXX pass -1 in the size, because stun_handle_packet might
- * write past the end of the buffer.
- */
- res = recvfrom(s, reply_buf, sizeof(reply_buf) - 1,
- 0, (struct sockaddr *)&src, &srclen);
- if (res < 0) {
- ast_log(LOG_WARNING, "ast_stun_request recvfrom #%d failed error %d, retry\n",
- retry, res);
- continue;
- }
- bzero(answer, sizeof(struct sockaddr_in));
- stun_handle_packet(s, &src, reply_buf, res,
- stun_get_mapped, answer);
- res = 0; /* signal regular exit */
- break;
- }
- return res;
-}
-
-/*! \brief send a STUN BIND request to the given destination.
- * Optionally, add a username if specified.
- */
-void ast_rtp_stun_request(struct ast_rtp *rtp, struct sockaddr_in *suggestion, const char *username)
-{
- ast_stun_request(rtp->s, suggestion, username, NULL);
}
/*! \brief List of current sessions */
@@ -1586,11 +1173,11 @@
version = (seqno & 0xC0000000) >> 30;
if (!version) {
/* If the two high bits are 0, this might be a
- * STUN message, so process it. stun_handle_packet()
- * answers to requests, and it returns STUN_ACCEPT
+ * STUN message, so process it. ast_stun_handle_packet()
+ * answers to requests, and it returns AST_STUN_ACCEPT
* if the request is valid.
*/
- if ((stun_handle_packet(rtp->s, &sin, rtp->rawdata + AST_FRIENDLY_OFFSET, res, NULL, NULL) == STUN_ACCEPT) &&
+ if ((ast_stun_handle_packet(rtp->s, &sin, rtp->rawdata + AST_FRIENDLY_OFFSET, res, NULL, NULL) == AST_STUN_ACCEPT) &&
(!rtp->them.sin_port && !rtp->them.sin_addr.s_addr)) {
memcpy(&rtp->them, &sin, sizeof(rtp->them));
}
@@ -4585,68 +4172,14 @@
return CLI_SUCCESS;
}
-static char *handle_cli_stun_debug_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
- switch (cmd) {
- case CLI_INIT:
- e->command = "stun debug [off]";
- e->usage =
- "Usage: stun debug [off]\n"
- " Enable/Disable STUN (Simple Traversal of UDP through NATs)\n"
- " debugging\n";
- return NULL;
- case CLI_GENERATE:
- return NULL;
- }
-
- if (a->argc < 2 || a->argc > 3)
- return CLI_SHOWUSAGE;
- if (a->argc == 3 && strncasecmp(a->argv[2], "off", 3))
- return CLI_SHOWUSAGE;
-
- stundebug = (a->argc == 3) ? 0 : 1;
- ast_cli(a->fd, "STUN Debugging %s\n", stundebug ? "Enabled" : "Disabled");
- return CLI_SUCCESS;
-}
-
-static char *handle_cli_stun_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
- switch (cmd) {
- case CLI_INIT:
- e->command = "stun set debug {on|off}";
- e->usage =
- "Usage: stun set debug {on|off}\n"
- " Enable/Disable STUN (Simple Traversal of UDP through NATs)\n"
- " debugging\n";
- return NULL;
- case CLI_GENERATE:
- return NULL;
- }
-
- if (a->argc != e->args)
- return CLI_SHOWUSAGE;
-
- if (!strncasecmp(a->argv[e->args-1], "on", 2))
- stundebug = 1;
- else if (!strncasecmp(a->argv[e->args-1], "off", 3))
- stundebug = 0;
- else
- return CLI_SHOWUSAGE;
-
- ast_cli(a->fd, "STUN Debugging %s\n", stundebug ? "Enabled" : "Disabled");
- return CLI_SUCCESS;
-}
-
static struct ast_cli_entry cli_rtp_debug_deprecated = AST_CLI_DEFINE(handle_cli_rtp_debug_deprecated, "Enable/Disable RTP debugging");
static struct ast_cli_entry cli_rtcp_debug_deprecated = AST_CLI_DEFINE(handle_cli_rtcp_debug_deprecated, "Enable/Disable RTCP debugging");
static struct ast_cli_entry cli_rtcp_stats_deprecated = AST_CLI_DEFINE(handle_cli_rtcp_stats_deprecated, "Enable/Disable RTCP stats");
-static struct ast_cli_entry cli_stun_debug_deprecated = AST_CLI_DEFINE(handle_cli_stun_debug_deprecated, "Enable/Disable STUN debugging");
static struct ast_cli_entry cli_rtp[] = {
AST_CLI_DEFINE(handle_cli_rtp_set_debug, "Enable/Disable RTP debugging", .deprecate_cmd = &cli_rtp_debug_deprecated),
AST_CLI_DEFINE(handle_cli_rtcp_set_debug, "Enable/Disable RTCP debugging", .deprecate_cmd = &cli_rtcp_debug_deprecated),
AST_CLI_DEFINE(handle_cli_rtcp_set_stats, "Enable/Disable RTCP stats", .deprecate_cmd = &cli_rtcp_stats_deprecated),
- AST_CLI_DEFINE(handle_cli_stun_set_debug, "Enable/Disable STUN debugging", .deprecate_cmd = &cli_stun_debug_deprecated),
};
static int __ast_rtp_reload(int reload)
More information about the asterisk-commits
mailing list