Fri Apr 29 2011 07:59:09

Asterisk developer's documentation


stun.h File Reference

STUN support. More...

#include "asterisk/network.h"
Include dependency graph for stun.h:
This graph shows which files directly or indirectly include this file:

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

Enumerator:
AST_STUN_IGNORE 
AST_STUN_ACCEPT 

Definition at line 37 of file stun.h.


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_attr::len, stun_header::msglen, stun_header::msgtype, stun_attr2str(), STUN_BINDREQ, STUN_BINDRESP, STUN_MAPPED_ADDRESS, stun_msg2str(), stun_process_attr(), stun_send(), STUN_USERNAME, and stun_state::username.

Referenced by ast_rtp_read(), and ast_stun_request().

{
   struct stun_header *hdr = (struct stun_header *)data;
   struct stun_attr *attr;
   struct stun_state st;
   int ret = AST_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 = AST_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;
}
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:
sthe socket used to send the request
dstthe address of the STUN server
usernameif non null, add the username in the request
answerif non null, the function waits for a response and puts here the externally visible address.
Returns:
0 on success, other values on error. The interface it may change in the future.

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

Parameters:
sthe socket used to send the request
dstthe address of the STUN server
usernameif non null, add the username in the request
answerif 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, stun_header::ies, LOG_WARNING, stun_header::msglen, stun_header::msgtype, 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().

{
   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];
      struct pollfd pfds = { .fd = s, .events = POLLIN };
      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;
      res = ast_poll(&pfds, 1, 3000);
      if (res <= 0)  /* timeout or error */
         continue;
      memset(&src, 0, 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;
      }
      memset(answer, 0, sizeof(struct sockaddr_in));
      ast_stun_handle_packet(s, &src, reply_buf, res,
         stun_get_mapped, answer);
      res = 0; /* signal regular exit */
      break;
   }
   return res;
}

Variable Documentation

const int STANDARD_STUN_PORT = 3478 [static]

Definition at line 35 of file stun.h.

Referenced by gtalk_load_config(), and load_config().