Wed Apr 6 11:30:11 2011

Asterisk developer's documentation


stun.h File Reference

STUN support. More...

#include "asterisk/network.h"

Go to the source code of this file.

Typedefs

typedef int( stun_cb_f )(struct stun_attr *attr, void *arg)
 callback type to be invoked on stun responses.

Enumerations

enum  ast_stun_result { AST_STUN_IGNORE = 0, AST_STUN_ACCEPT }

Functions

int ast_stun_handle_packet (int s, struct sockaddr_in *src, unsigned char *data, size_t len, stun_cb_f *stun_cb, void *arg)
 handle an incoming STUN message.
int ast_stun_request (int s, struct sockaddr_in *dst, const char *username, struct sockaddr_in *answer)
 Generic STUN request send a generic stun request to the server specified.

Variables

static const int STANDARD_STUN_PORT = 3478


Detailed Description

STUN support.

STUN is defined in RFC 3489.

Definition in file stun.h.


Typedef Documentation

typedef int( stun_cb_f)(struct stun_attr *attr, void *arg)

callback type to be invoked on stun responses.

Definition at line 57 of file stun.h.


Enumeration Type Documentation

enum ast_stun_result

Enumerator:
AST_STUN_IGNORE 
AST_STUN_ACCEPT 

Definition at line 37 of file stun.h.

00037                      {
00038    AST_STUN_IGNORE = 0,
00039    AST_STUN_ACCEPT,
00040 };


Function Documentation

int ast_stun_handle_packet ( int  s,
struct sockaddr_in *  src,
unsigned char *  data,
size_t  len,
stun_cb_f stun_cb,
void *  arg 
)

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.

Definition at line 253 of file stun.c.

References append_attr_address(), append_attr_string(), ast_debug, AST_STUN_ACCEPT, AST_STUN_IGNORE, ast_verbose, stun_attr::attr, stun_header::id, stun_header::ies, stun_header::msglen, stun_header::msgtype, stun_attr2str(), STUN_BINDREQ, STUN_BINDRESP, STUN_MAPPED_ADDRESS, stun_msg2str(), stun_process_attr(), stun_send(), and STUN_USERNAME.

Referenced by ast_rtp_read(), and ast_stun_request().

00254 {
00255    struct stun_header *hdr = (struct stun_header *)data;
00256    struct stun_attr *attr;
00257    struct stun_state st;
00258    int ret = AST_STUN_IGNORE;
00259    int x;
00260 
00261    /* On entry, 'len' is the length of the udp payload. After the
00262     * initial checks it becomes the size of unprocessed options,
00263     * while 'data' is advanced accordingly.
00264     */
00265    if (len < sizeof(struct stun_header)) {
00266       ast_debug(1, "Runt STUN packet (only %d, wanting at least %d)\n", (int) len, (int) sizeof(struct stun_header));
00267       return -1;
00268    }
00269    len -= sizeof(struct stun_header);
00270    data += sizeof(struct stun_header);
00271    x = ntohs(hdr->msglen); /* len as advertised in the message */
00272    if (stundebug)
00273       ast_verbose("STUN Packet, msg %s (%04x), length: %d\n", stun_msg2str(ntohs(hdr->msgtype)), ntohs(hdr->msgtype), x);
00274    if (x > len) {
00275       ast_debug(1, "Scrambled STUN packet length (got %d, expecting %d)\n", x, (int)len);
00276    } else
00277       len = x;
00278    memset(&st, 0, sizeof(st));
00279    while (len) {
00280       if (len < sizeof(struct stun_attr)) {
00281          ast_debug(1, "Runt Attribute (got %d, expecting %d)\n", (int)len, (int) sizeof(struct stun_attr));
00282          break;
00283       }
00284       attr = (struct stun_attr *)data;
00285       /* compute total attribute length */
00286       x = ntohs(attr->len) + sizeof(struct stun_attr);
00287       if (x > len) {
00288          ast_debug(1, "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n", x, (int)len);
00289          break;
00290       }
00291       if (stun_cb)
00292          stun_cb(attr, arg);
00293       if (stun_process_attr(&st, attr)) {
00294          ast_debug(1, "Failed to handle attribute %s (%04x)\n", stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr));
00295          break;
00296       }
00297       /* Clear attribute id: in case previous entry was a string,
00298        * this will act as the terminator for the string.
00299        */
00300       attr->attr = 0;
00301       data += x;
00302       len -= x;
00303    }
00304    /* Null terminate any string.
00305     * XXX NOTE, we write past the size of the buffer passed by the
00306     * caller, so this is potentially dangerous. The only thing that
00307     * saves us is that usually we read the incoming message in a
00308     * much larger buffer in the struct ast_rtp
00309     */
00310    *data = '\0';
00311 
00312    /* Now prepare to generate a reply, which at the moment is done
00313     * only for properly formed (len == 0) STUN_BINDREQ messages.
00314     */
00315    if (len == 0) {
00316       unsigned char respdata[1024];
00317       struct stun_header *resp = (struct stun_header *)respdata;
00318       int resplen = 0;  /* len excluding header */
00319       int respleft = sizeof(respdata) - sizeof(struct stun_header);
00320 
00321       resp->id = hdr->id;
00322       resp->msgtype = 0;
00323       resp->msglen = 0;
00324       attr = (struct stun_attr *)resp->ies;
00325       switch (ntohs(hdr->msgtype)) {
00326       case STUN_BINDREQ:
00327          if (stundebug)
00328             ast_verbose("STUN Bind Request, username: %s\n",
00329                    st.username ? st.username : "<none>");
00330          if (st.username)
00331             append_attr_string(&attr, STUN_USERNAME, st.username, &resplen, &respleft);
00332          append_attr_address(&attr, STUN_MAPPED_ADDRESS, src, &resplen, &respleft);
00333          resp->msglen = htons(resplen);
00334          resp->msgtype = htons(STUN_BINDRESP);
00335          stun_send(s, src, resp);
00336          ret = AST_STUN_ACCEPT;
00337          break;
00338       default:
00339          if (stundebug)
00340             ast_verbose("Dunno what to do with STUN message %04x (%s)\n", ntohs(hdr->msgtype), stun_msg2str(ntohs(hdr->msgtype)));
00341       }
00342    }
00343    return ret;
00344 }

int ast_stun_request ( int  s,
struct sockaddr_in *  dst,
const char *  username,
struct sockaddr_in *  answer 
)

Generic STUN request send a generic stun request to the server specified.

Parameters:
s the socket used to send the request
dst the address of the STUN server
username if non null, add the username in the request
answer if non null, the function waits for a response and puts here the externally visible address.
Returns:
0 on success, other values on error.

Definition at line 376 of file stun.c.

References append_attr_string(), ast_log(), ast_poll, ast_stun_handle_packet(), stun_attr::attr, LOG_WARNING, STUN_BINDREQ, stun_get_mapped(), stun_req_id(), stun_send(), and STUN_USERNAME.

Referenced by ast_rtp_stun_request(), gtalk_update_externip(), and stun_monitor_request().

00378 {
00379    struct stun_header *req;
00380    unsigned char reqdata[1024];
00381    int reqlen, reqleft;
00382    struct stun_attr *attr;
00383    int res = 0;
00384    int retry;
00385 
00386    req = (struct stun_header *)reqdata;
00387    stun_req_id(req);
00388    reqlen = 0;
00389    reqleft = sizeof(reqdata) - sizeof(struct stun_header);
00390    req->msgtype = 0;
00391    req->msglen = 0;
00392    attr = (struct stun_attr *)req->ies;
00393    if (username)
00394       append_attr_string(&attr, STUN_USERNAME, username, &reqlen, &reqleft);
00395    req->msglen = htons(reqlen);
00396    req->msgtype = htons(STUN_BINDREQ);
00397    for (retry = 0; retry < 3; retry++) {  /* XXX make retries configurable */
00398       /* send request, possibly wait for reply */
00399       unsigned char reply_buf[1024];
00400       struct pollfd pfds = { .fd = s, .events = POLLIN };
00401       struct sockaddr_in src;
00402       socklen_t srclen;
00403 
00404       res = stun_send(s, dst, req);
00405       if (res < 0) {
00406          ast_log(LOG_WARNING, "ast_stun_request send #%d failed error %d, retry\n",
00407             retry, res);
00408          continue;
00409       }
00410       if (answer == NULL)
00411          break;
00412       res = ast_poll(&pfds, 1, 3000);
00413       if (res <= 0)  /* timeout or error */
00414          continue;
00415       memset(&src, 0, sizeof(src));
00416       srclen = sizeof(src);
00417       /* XXX pass -1 in the size, because stun_handle_packet might
00418        * write past the end of the buffer.
00419        */
00420       res = recvfrom(s, reply_buf, sizeof(reply_buf) - 1,
00421          0, (struct sockaddr *)&src, &srclen);
00422       if (res < 0) {
00423          ast_log(LOG_WARNING, "ast_stun_request recvfrom #%d failed error %d, retry\n",
00424             retry, res);
00425          continue;
00426       }
00427       memset(answer, 0, sizeof(struct sockaddr_in));
00428       ast_stun_handle_packet(s, &src, reply_buf, res,
00429          stun_get_mapped, answer);
00430       res = 0; /* signal regular exit */
00431       break;
00432    }
00433    return res;
00434 }


Variable Documentation

const int STANDARD_STUN_PORT = 3478 [static]

Definition at line 35 of file stun.h.

Referenced by load_config().


Generated on Wed Apr 6 11:30:11 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7