![]() |
Home page |
Mailing list |
Docs
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 }