Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:00:57 2007

Asterisk developer's documentation :: Codename Pineapple


sip3_transmit.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, Digium, Inc.
00005  * and Edvina AB, Sollentuna, Sweden (chan_sip3 changes/additions)
00006  *
00007  * Mark Spencer <markster@digium.com>
00008  *
00009  * See http://www.asterisk.org for more information about
00010  * the Asterisk project. Please do not directly contact
00011  * any of the maintainers of this project for assistance;
00012  * the project provides a web site, mailing lists and IRC
00013  * channels for your use.
00014  *
00015  * This program is free software, distributed under the terms of
00016  * the GNU General Public License Version 2. See the LICENSE file
00017  * at the top of the source tree.
00018  */
00019 
00020 /*!
00021  * \file
00022  * \brief Various SIP message transmit functions
00023  * Version 3 of chan_sip
00024  *
00025  * \author Mark Spencer <markster@digium.com>
00026  * \author Olle E. Johansson <oej@edvina.net> (all the chan_sip3 changes)
00027  *
00028  * See Also:
00029  * \arg \ref AstCREDITS
00030  *
00031  */
00032 
00033 #include "asterisk.h"
00034 
00035 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 53128 $")
00036 
00037 #include <stdio.h>
00038 #include <ctype.h>
00039 #include <string.h>
00040 #include <unistd.h>
00041 #include <sys/socket.h>
00042 #include <sys/ioctl.h>
00043 #include <net/if.h>
00044 #include <errno.h>
00045 #include <stdlib.h>
00046 #include <fcntl.h>
00047 #include <netdb.h>
00048 #include <signal.h>
00049 #include <sys/signal.h>
00050 #include <netinet/in.h>
00051 #include <netinet/in_systm.h>
00052 #include <arpa/inet.h>
00053 #include <netinet/ip.h>
00054 #include <regex.h>
00055 
00056 #include "asterisk/lock.h"
00057 #include "asterisk/channel.h"
00058 #include "asterisk/config.h"
00059 #include "asterisk/logger.h"
00060 #include "asterisk/module.h"
00061 #include "asterisk/pbx.h"
00062 #include "asterisk/options.h"
00063 #include "asterisk/sched.h"
00064 #include "asterisk/io.h"
00065 #include "asterisk/rtp.h"
00066 #include "asterisk/udptl.h"
00067 #include "asterisk/acl.h"
00068 #include "asterisk/manager.h"
00069 #include "asterisk/callerid.h"
00070 #include "asterisk/cli.h"
00071 #include "asterisk/app.h"
00072 #include "asterisk/musiconhold.h"
00073 #include "asterisk/dsp.h"
00074 #include "asterisk/features.h"
00075 #include "asterisk/srv.h"
00076 #include "asterisk/astdb.h"
00077 #include "asterisk/causes.h"
00078 #include "asterisk/utils.h"
00079 #include "asterisk/file.h"
00080 #include "asterisk/astobj.h"
00081 #include "asterisk/dnsmgr.h"
00082 #include "asterisk/devicestate.h"
00083 #include "asterisk/linkedlists.h"
00084 #include "asterisk/stringfields.h"
00085 #include "asterisk/monitor.h"
00086 #include "asterisk/localtime.h"
00087 #include "asterisk/abstract_jb.h"
00088 #include "asterisk/compiler.h"
00089 #include "sip3.h"
00090 #include "sip3funcs.h"
00091 
00092 /*! \brief add XML encoded media control with update 
00093    \note XML: The only way to turn 0 bits of information into a few hundred. (markster) */
00094 static int add_vidupdate(struct sip_request *req)
00095 {
00096    const char *xml_is_a_huge_waste_of_space =
00097       "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n"
00098       " <media_control>\r\n"
00099       "  <vc_primitive>\r\n"
00100       "   <to_encoder>\r\n"
00101       "    <picture_fast_update>\r\n"
00102       "    </picture_fast_update>\r\n"
00103       "   </to_encoder>\r\n"
00104       "  </vc_primitive>\r\n"
00105       " </media_control>\r\n";
00106    add_header(req, "Content-Type", "application/media_control+xml");
00107    add_header_contentLength(req, strlen(xml_is_a_huge_waste_of_space));
00108    add_line(req, xml_is_a_huge_waste_of_space);
00109    return 0;
00110 }
00111 
00112 /*! \brief Base transmit response function */
00113 GNURK int __transmit_response(struct sip_dialog *p, const char *msg, struct sip_request *req, enum xmittype reliable)
00114 {
00115    struct sip_request *resp;
00116    int seqno = 0;
00117    int res;
00118 
00119 
00120    if (reliable && (sscanf(get_header(req, "CSeq"), "%d ", &seqno) != 1)) {
00121       ast_log(LOG_WARNING, "Unable to determine sequence number from '%s'\n", get_header(req, "CSeq"));
00122       return -1;
00123    }
00124 
00125    resp = siprequest_alloc(SIP_MAX_PACKET, &sipnet);
00126    ast_log(LOG_DEBUG, "   :::: Response data size: %d\n", (int) resp->data_size);
00127    resp->seqno = seqno;
00128    respprep(resp, p, msg, req);
00129    add_header_contentLength(resp, 0);
00130    /* If we are cancelling an incoming invite for some reason, add information
00131       about the reason why we are doing this in clear text */
00132    if (p->method == SIP_INVITE && msg[0] != '1' && p->owner && p->owner->hangupcause) {
00133       char buf[10];
00134 
00135       add_header(resp, "X-Asterisk-HangupCause", ast_cause2str(p->owner->hangupcause));
00136       snprintf(buf, sizeof(buf), "%d", p->owner->hangupcause);
00137       add_header(resp, "X-Asterisk-HangupCauseCode", buf);
00138    }
00139    res =  send_response(p, resp, reliable);
00140    if (reliable == XMIT_UNRELIABLE)
00141       siprequest_free(resp);
00142    return res;
00143 }
00144 
00145 /*! \brief Transmit response, no retransmits */
00146 GNURK int transmit_response(struct sip_dialog *p, const char *msg, struct sip_request *req) 
00147 {
00148    return __transmit_response(p, msg, req, XMIT_UNRELIABLE);
00149 }
00150 
00151 
00152 /*! \brief Transmit response, Make sure you get an ACK
00153    This is only used for responses to INVITEs, where we need to make sure we get an ACK
00154 */
00155 GNURK int transmit_response_reliable(struct sip_dialog *p, const char *msg, struct sip_request *req)
00156 {
00157    return __transmit_response(p, msg, req, XMIT_CRITICAL);
00158 }
00159 
00160 /*! \brief Transmit responses with various attachments */
00161 GNURK int transmit_response_with_attachment(enum responseattach attach, struct sip_dialog *p, const char *msg, 
00162       struct sip_request *req, enum xmittype reliable)
00163 {
00164    struct sip_request *resp;
00165    char buf[12];
00166    int res;
00167 
00168    resp = siprequest_alloc(SIP_MAX_PACKET, &sipnet);
00169    respprep(resp, p, msg, req);
00170    if (resp->seqno == 0) {
00171       if (req->seqno) {
00172          ast_log(LOG_DEBUG, " ************ Response seqno still zero!!!!!!!!!\n");
00173          resp->seqno = req->seqno;
00174       } else {
00175          ast_log(LOG_DEBUG, " ************ Request seqno still zero!!!!!!!!! Can't set response seqno\n");
00176       }
00177    }
00178    append_date(resp);
00179    switch (attach) {
00180    case WITH_DATE:
00181       add_header_contentLength(resp, 0);
00182       break;
00183    case WITH_MINEXPIRY:
00184       snprintf(buf, sizeof(buf), "%d", expiry.min_expiry);
00185       add_header(resp, "Min-Expires", buf);
00186       break;
00187    case WITH_ALLOW:
00188       add_header(resp, "Accept", "application/sdp");
00189       add_header_contentLength(resp, 0);
00190       break;
00191    case WITH_SDP:
00192       if (p->rtp) {
00193          if (!p->autoframing && !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
00194             if (option_debug)
00195                ast_log(LOG_DEBUG, "Setting framing from config on incoming call\n");
00196             ast_rtp_codec_setpref(p->rtp, &p->prefs);
00197          }
00198          try_suggested_sip_codec(p);   
00199          add_sdp(resp, p);
00200       } else 
00201          ast_log(LOG_ERROR, "Can't add SDP to response, since we have no RTP session allocated. Call-ID %s\n", p->callid);
00202       break;
00203    case WITH_T38_SDP:
00204       if (p->udptl) {
00205          ast_udptl_offered_from_local(p->udptl, 0);
00206          add_t38_sdp(resp, p);
00207       } else 
00208          ast_log(LOG_ERROR, "Can't add T38 SDP to response, since we have no UDPTL session allocated. Call-ID %s\n", p->callid);
00209       break;
00210    }
00211    res =  send_response(p, resp, reliable);
00212    if (reliable == XMIT_UNRELIABLE)
00213       siprequest_free(resp);
00214    return res;
00215 }
00216 
00217 /*! \brief Transmit response, no retransmits */
00218 GNURK int transmit_response_with_unsupported(struct sip_dialog *p, const char *msg, struct sip_request *req, const char *unsupported) 
00219 {
00220    struct sip_request *resp;
00221    int res;
00222 
00223    resp = siprequest_alloc(SIP_MAX_PACKET, &sipnet);
00224 
00225    respprep(resp, p, msg, req);
00226    append_date(resp);
00227    add_header(resp, "Unsupported", unsupported);
00228    add_header_contentLength(resp, 0);
00229    add_blank(resp);
00230    res = send_response(p, resp, XMIT_UNRELIABLE);
00231    siprequest_free(resp);
00232    return res;
00233 }
00234 
00235 /*! \brief Respond with authorization request */
00236 GNURK int transmit_response_with_auth(struct sip_dialog *p, const char *msg, struct sip_request *req, const char *randdata, enum xmittype reliable, const char *header, int stale)
00237 {
00238    struct sip_request *resp;
00239    char tmp[512];
00240    int seqno = 0;
00241    int res;
00242 
00243 
00244    if (reliable && (sscanf(get_header(req, "CSeq"), "%d ", &seqno) != 1)) {
00245       ast_log(LOG_WARNING, "Unable to determine sequence number from '%s'\n", get_header(req, "CSeq"));
00246       return -1;
00247    }
00248    resp = siprequest_alloc(SIP_MAX_PACKET, &sipnet);
00249 
00250 
00251    /* Stale means that they sent us correct authentication, but 
00252       based it on an old challenge (nonce) */
00253    snprintf(tmp, sizeof(tmp), "Digest algorithm=MD5, realm=\"%s\", nonce=\"%s\"%s", global.realm, randdata, stale ? ", stale=true" : "");
00254    respprep(resp, p, msg, req);
00255    add_header(resp, header, tmp);
00256    add_header_contentLength(resp, 0);
00257    res =  send_response(p, resp, reliable);
00258    if (reliable == XMIT_UNRELIABLE)
00259       siprequest_free(resp);
00260    return res;
00261 }
00262 
00263 /*! \brief Transmit reinvite with SDP
00264 \note    A re-invite is basically a new INVITE with the same CALL-ID and TAG as the
00265    INVITE that opened the SIP dialogue 
00266    We reinvite so that the audio stream (RTP) go directly between
00267    the SIP UAs. SIP Signalling stays with * in the path.
00268    IF type == 1, we send T.38 SDP 
00269 */
00270 GNURK int transmit_reinvite_with_sdp(struct sip_dialog *p, int t38type)
00271 {
00272    struct sip_request *req;
00273 
00274    req = siprequest_alloc(SIP_MAX_PACKET, &sipnet);
00275    reqprep(req, p, ast_test_flag(&p->flags[0], SIP_REINVITE_UPDATE) ?  SIP_UPDATE : SIP_INVITE, 0, 1);
00276    
00277    add_header(req, "Allow", ALLOWED_METHODS);
00278    add_header(req, "Supported", SUPPORTED_EXTENSIONS);
00279    if (sipdebug)
00280       add_header(req, "X-asterisk-Info",(t38type ? "SIP re-invite for T38 fax" : "SIP re-invite (External RTP bridge)"));
00281    if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY))
00282       append_history(p, "ReInv", "%s", (t38type ? "Re-invite sent for T38" : "Re-invite sent for external RTP media"));
00283    if (t38type)
00284       add_t38_sdp(req, p);
00285    else
00286       add_sdp(req, p);
00287 
00288    /* Use this as the basis */
00289    initialize_initreq(p, req);
00290    p->lastinvite = p->ocseq;
00291    return send_request(p, req, XMIT_CRITICAL);
00292 }
00293 
00294 /*! \brief Build REFER/INVITE/OPTIONS message and transmit it */
00295 GNURK int transmit_invite(struct sip_dialog *dialog, int sipmethod, int sdp, int init)
00296 {
00297    struct sip_request *req;
00298    int res;
00299    
00300    req = siprequest_alloc(SIP_MAX_PACKET, &sipnet);
00301    req->method = sipmethod;
00302    if (init)
00303       /* Bump branch even on initial requests */
00304       build_via(dialog, TRUE);
00305 
00306    if (init == 2) /* open a new dialog */
00307       initreqprep(req, dialog, sipmethod);
00308    else
00309       reqprep(req, dialog, sipmethod, 0, TRUE);
00310       
00311    if (dialog->inviteoptions && dialog->inviteoptions->auth)
00312       add_header(req, dialog->inviteoptions->authheader, dialog->inviteoptions->auth);
00313    append_date(req);
00314    if (sipmethod == SIP_REFER && dialog->refer) { /* Call transfer */
00315       char buf[BUFSIZ];
00316       if (!ast_strlen_zero(dialog->refer->refer_to))
00317          add_header(req, "Refer-To", dialog->refer->refer_to);
00318       if (!ast_strlen_zero(dialog->refer->referred_by)) {
00319          sprintf(buf, "%s <%s>", dialog->refer->referred_by_name, dialog->refer->referred_by);
00320          add_header(req, "Referred-By", buf);
00321       }
00322    }
00323 
00324    if (dialog->inviteoptions && !ast_strlen_zero(dialog->inviteoptions->replaces)) {
00325       /* This new INVITE is part of an attended transfer. Make sure that the
00326          other end knows and replace the current call with this new call */
00327       add_header(req, "Replaces", dialog->inviteoptions->replaces);
00328       add_header(req, "Require", "replaces");
00329    }
00330 
00331    add_header(req, "Allow", ALLOWED_METHODS);
00332    add_header(req, "Supported", SUPPORTED_EXTENSIONS);
00333    if (dialog->inviteoptions && dialog->inviteoptions->addsipheaders) {
00334       struct ast_channel *ast;
00335       struct varshead *headp = NULL;
00336       const struct ast_var_t *current;
00337 
00338       ast = dialog->owner; /* The owner channel */
00339       if (ast) {
00340          char *headdup;
00341          headp = &ast->varshead;
00342          if (!headp)
00343             ast_log(LOG_WARNING,"No varshead for the channel...ooops!\n");
00344          else {
00345             AST_LIST_TRAVERSE(headp, current, entries) {  
00346                /* SIPADDHEADER: Add SIP header to outgoing call */
00347                if (!strncasecmp(ast_var_name(current), "SIPADDHEADER", strlen("SIPADDHEADER"))) {
00348                   char *content, *end;
00349                   const char *header = ast_var_value(current);
00350 
00351                   headdup = ast_strdupa(header);
00352                   /* Strip of the starting " (if it's there) */
00353                   if (*headdup == '"')
00354                      headdup++;
00355                   if ((content = strchr(headdup, ':'))) {
00356                      *content++ = '\0';
00357                      content = ast_skip_blanks(content); /* Skip white space */
00358                      /* Strip the ending " (if it's there) */
00359                      end = content + strlen(content) -1; 
00360                      if (*end == '"')
00361                         *end = '\0';
00362                   
00363                      add_header(req, headdup, content);
00364                      if (sipdebug)
00365                         ast_log(LOG_DEBUG, "Adding SIP Header \"%s\" with content :%s: \n", headdup, content);
00366                   }
00367                }
00368             }
00369          }
00370       }
00371    }
00372    if (sdp) {
00373       if (dialog->udptl && dialog->t38.state == T38_LOCAL_DIRECT) {
00374          ast_udptl_offered_from_local(dialog->udptl, 1);
00375          if (option_debug)
00376             ast_log(LOG_DEBUG, "T38 is in state %d on channel %s\n", dialog->t38.state, dialog->owner ? dialog->owner->name : "<none>");
00377          add_t38_sdp(req, dialog);
00378       } else if (dialog->rtp) 
00379          add_sdp(req, dialog);
00380    } else {
00381       add_header_contentLength(req, 0);
00382    }
00383 
00384    if (!dialog->initreq)
00385       initialize_initreq(dialog, req);
00386    dialog->lastinvite = dialog->ocseq;
00387    res = send_request(dialog, req, init ? XMIT_CRITICAL : XMIT_RELIABLE);
00388 
00389    if (!init)
00390       siprequest_free(req);
00391 
00392    return res;
00393 }
00394 
00395 /*! \brief Notify user of messages waiting in voicemail
00396 \note - Notification only works for registered peers with mailbox= definitions
00397    in sip.conf
00398    - We use the SIP Event package message-summary
00399     MIME type defaults to  "application/simple-message-summary";
00400  */
00401 GNURK int transmit_notify_with_mwi(struct sip_dialog *p, int newmsgs, int oldmsgs, char *vmexten)
00402 {
00403    struct sip_request *req;
00404    char tmp[500];
00405    char *t = tmp;
00406    size_t maxbytes = sizeof(tmp);
00407 
00408    req = siprequest_alloc(SIP_MAX_PACKET, &sipnet);
00409    initreqprep(req, p, SIP_NOTIFY);
00410    add_header(req, "Event", "message-summary");
00411    add_header(req, "Content-Type", global.default_notifymime);
00412 
00413    ast_build_string(&t, &maxbytes, "Messages-Waiting: %s\r\n", newmsgs ? "yes" : "no");
00414    ast_build_string(&t, &maxbytes, "Message-Account: sip:%s@%s\r\n",
00415       S_OR(vmexten, global.default_vmexten), S_OR(p->fromdomain, ast_inet_ntoa(p->ourip)));
00416    ast_build_string(&t, &maxbytes, "Voice-Message: %d/%d (0/0)\r\n", newmsgs, oldmsgs);
00417    if (p->subscribed) {
00418       if (p->expiry)
00419          add_header(req, "Subscription-State", "active");
00420       else  /* Expired */
00421          add_header(req, "Subscription-State", "terminated;reason=timeout");
00422    }
00423 
00424    if (t > tmp + sizeof(tmp))
00425       ast_log(LOG_WARNING, "Buffer overflow detected!!  (Please file a bug report)\n");
00426 
00427    add_header_contentLength(req, strlen(tmp));
00428    add_line(req, tmp);
00429 
00430    if (!p->initreq) 
00431       initialize_initreq(p, req);
00432    return send_request(p, req, XMIT_RELIABLE);
00433 }
00434 
00435 /*! \brief Transmit SIP request unreliably (only used in sip_notify subsystem) */
00436 GNURK int transmit_sip_request(struct sip_dialog *p, struct sip_request *req)
00437 {
00438    if (!p->initreq)  /* Initialize first request before sending */
00439       initialize_initreq(p, req);
00440    return send_request(p, req, XMIT_UNRELIABLE);
00441 }
00442 
00443 /*! \brief Transmit text with SIP MESSAGE method */
00444 GNURK int transmit_message_with_text(struct sip_dialog *p, const char *text)
00445 {
00446    struct sip_request *req;
00447    size_t len = SIP_MAX_PACKET;
00448 
00449    /* If we have a very large text message, allocate enough memory for it 
00450       We're guessing that the max size of headers is 500 bytes here.
00451    */
00452    if (strlen(text) > (len - 500))
00453       len += strlen(text);
00454 
00455    req = siprequest_alloc(len, &sipnet);
00456 
00457    reqprep(req, p, SIP_MESSAGE, 0, TRUE);
00458    add_text(req, text);
00459    return send_request(p, req, XMIT_RELIABLE);
00460 }
00461 
00462 /*! \brief Transmit SIP REFER message (initiated by the transfer() dialplan application
00463    \note this is currently broken as we have no way of telling the dialplan
00464    engine whether a transfer succeeds or fails.
00465    \todo Fix the transfer() dialplan function so that a transfer may fail
00466 */
00467 GNURK int transmit_refer(struct sip_dialog *p, const char *dest)
00468 {
00469    struct sip_request *req;
00470    char from[256];
00471    const char *of;
00472    char *c;
00473    char referto[256];
00474    char *ttag, *ftag;
00475    char *theirtag = ast_strdupa(p->theirtag);
00476 
00477    
00478    req = siprequest_alloc(SIP_MAX_PACKET, &sipnet);
00479    req->headers = 0;
00480 
00481    if (option_debug || sipdebug)
00482       ast_log(LOG_DEBUG, "SIP transfer of %s to %s\n", p->callid, dest);
00483 
00484    /* Are we transfering an inbound or outbound call ? */
00485    if (ast_test_flag(&p->flags[0], SIP_OUTGOING))  {
00486       of = get_header(p->initreq, "To");
00487       ttag = theirtag;
00488       ftag = p->tag;
00489    } else {
00490       of = get_header(p->initreq, "From");
00491       ftag = theirtag;
00492       ttag = p->tag;
00493    }
00494 
00495    ast_copy_string(from, of, sizeof(from));
00496    of = get_in_brackets(from);
00497    ast_string_field_set(p, from, of);
00498    if (strncmp(of, "sip:", 4))
00499       ast_log(LOG_NOTICE, "From address missing 'sip:', using it anyway\n");
00500    else
00501       of += 4;
00502    /* Get just the username part */
00503    if ((c = strchr(dest, '@')))
00504       c = NULL;
00505    else if ((c = strchr(of, '@')))
00506       *c++ = '\0';
00507    if (c) 
00508       snprintf(referto, sizeof(referto), "<sip:%s@%s>", dest, c);
00509    else
00510       snprintf(referto, sizeof(referto), "<sip:%s>", dest);
00511 
00512    /* save in case we get 407 challenge */
00513    sip_refer_allocate(p);
00514    ast_copy_string(p->refer->refer_to, referto, sizeof(p->refer->refer_to));
00515    ast_copy_string(p->refer->referred_by, p->our_contact, sizeof(p->refer->referred_by));
00516    p->refer->status = REFER_SENT;   /* Set refer status */
00517 
00518    reqprep(req, p, SIP_REFER, 0, TRUE);
00519    append_maxforwards(req);
00520 
00521    add_header(req, "Refer-To", referto);
00522    add_header(req, "Allow", ALLOWED_METHODS);
00523    add_header(req, "Supported", SUPPORTED_EXTENSIONS);
00524    if (!ast_strlen_zero(p->our_contact))
00525       add_header(req, "Referred-By", p->our_contact);
00526 
00527    return send_request(p, req, XMIT_RELIABLE);
00528    /* We should propably wait for a NOTIFY here until we ack the transfer */
00529    /* Maybe fork a new thread and wait for a STATUS of REFER_200OK on the refer status before returning to app_transfer */
00530 
00531    /*! \todo In theory, we should hang around and wait for a reply, before
00532    returning to the dial plan here. Don't know really how that would
00533    affect the transfer() app or the pbx, but, well, to make this
00534    useful we should have a STATUS code on transfer().
00535    */
00536 }
00537 
00538 
00539 /*! \brief Send SIP INFO dtmf message, see Cisco documentation on cisco.com */
00540 GNURK int transmit_info_with_digit(struct sip_dialog *p, const char digit, unsigned int duration)
00541 {
00542    struct sip_request *req;
00543 
00544    req = siprequest_alloc(SIP_MAX_PACKET, &sipnet);
00545    reqprep(req, p, SIP_INFO, 0, TRUE);
00546    add_digit(req, digit, duration);
00547    return send_request(p, req, XMIT_RELIABLE);
00548 }
00549 
00550 /*! \brief Send SIP INFO with video update request */
00551 GNURK int transmit_info_with_vidupdate(struct sip_dialog *p)
00552 {
00553    struct sip_request *req;
00554    req = siprequest_alloc(SIP_MAX_PACKET, &sipnet);
00555 
00556    reqprep(req, p, SIP_INFO, 0, TRUE);
00557    add_vidupdate(req);
00558    return send_request(p, req, XMIT_RELIABLE);
00559 }
00560 
00561 /*! \brief Transmit generic SIP request */
00562 GNURK int transmit_request(struct sip_dialog *p, int sipmethod, int seqno, enum xmittype reliable, int newbranch)
00563 {
00564    struct sip_request *resp;
00565    int res;
00566 
00567    resp = siprequest_alloc(SIP_MAX_PACKET, &sipnet);
00568 
00569    reqprep(resp, p, sipmethod, seqno, newbranch);
00570    add_header_contentLength(resp, 0);
00571    res = send_request(p, resp, reliable);
00572    if (reliable == XMIT_UNRELIABLE)
00573       siprequest_free(resp);
00574    return res;
00575 }
00576 
00577 /*! \brief Transmit SIP request, auth added */
00578 GNURK int transmit_request_with_auth(struct sip_dialog *dialog, int sipmethod, int seqno, enum xmittype reliable, int newbranch)
00579 {
00580    struct sip_request *resp;
00581    int res;
00582 
00583    resp = siprequest_alloc(SIP_MAX_PACKET, &sipnet);
00584    if (!resp) {
00585       ast_log(LOG_ERROR, "--- Can't allocate SIP request for this transaction! Call ID %s\n", dialog->callid);
00586    }
00587 
00588    reqprep(resp, dialog, sipmethod, seqno, newbranch);
00589    if (!ast_strlen_zero(dialog->realm)) {
00590       char digest[1024];
00591 
00592       memset(digest, 0, sizeof(digest));
00593       if(!build_reply_digest(dialog, sipmethod, digest, sizeof(digest))) {
00594          char *dummy, *response;
00595 
00596          enum sip_auth_type code = dialog->inviteoptions ? dialog->inviteoptions->auth_type : PROXY_AUTH; /* XXX force 407 if unknown */
00597          auth_headers(code, &dummy, &response);
00598          add_header(resp, response, digest);
00599       } else
00600          ast_log(LOG_WARNING, "No authentication available for call %s\n", dialog->callid);
00601    }
00602    /* If we are hanging up and know a cause for that, send it in clear text to make
00603       debugging easier. */
00604    if (sipmethod == SIP_BYE && dialog->owner && dialog->owner->hangupcause)   {
00605       char buf[10];
00606 
00607       add_header(resp, "X-Asterisk-HangupCause", ast_cause2str(dialog->owner->hangupcause));
00608       snprintf(buf, sizeof(buf), "%d", dialog->owner->hangupcause);
00609       add_header(resp, "X-Asterisk-HangupCauseCode", buf);
00610    }
00611 
00612    add_header_contentLength(resp, 0);
00613 
00614    res = send_request(dialog, resp, reliable);
00615    if (reliable == XMIT_UNRELIABLE)
00616       siprequest_free(resp);
00617    return res;
00618 }
00619 
00620 /*! \brief Send a fake 401 Unauthorized response when the administrator
00621   wants to hide the names of local users/peers from fishers
00622  */
00623 GNURK void transmit_fake_auth_response(struct sip_dialog *p, struct sip_request *req, int reliable)
00624 {
00625    ast_string_field_build(p, randdata, "%08lx", ast_random()); /* Create nonce for challenge */
00626    transmit_response_with_auth(p, "401 Unauthorized", req, p->randdata, reliable, "WWW-Authenticate", 0);
00627 }

Asterisk is a trademark for Digium, inc.. | Edvina.net | Asterisk.org | This documentation was generated with Doxygen