[asterisk-commits] file: trunk r114529 - in /trunk: channels/ configs/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Apr 22 10:54:07 CDT 2008


Author: file
Date: Tue Apr 22 10:54:06 2008
New Revision: 114529

URL: http://svn.digium.com/view/asterisk?view=rev&rev=114529
Log:
Add support for authenticating on a NOTIFY request. This is useful for phones that require it when sending them a special packet to get them to do something (such as reload their configuration).
(closes issue #9896)
Reported by: IgorG
Patches:
      sipnotify-113980-v14.patch uploaded by IgorG (license 20)

Modified:
    trunk/channels/chan_sip.c
    trunk/configs/sip_notify.conf.sample

Modified: trunk/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/trunk/channels/chan_sip.c?view=diff&rev=114529&r1=114528&r2=114529
==============================================================================
--- trunk/channels/chan_sip.c (original)
+++ trunk/channels/chan_sip.c Tue Apr 22 10:54:06 2008
@@ -1278,6 +1278,7 @@
 	struct ast_channel *owner;		/*!< Who owns us (if we have an owner) */
 	struct sip_route *route;		/*!< Head of linked list of routing steps (fm Record-Route) */
 	int route_persistant;			/*!< Is this the "real" route? */
+	struct ast_variable *notify_headers;    /*!< Custom notify type */	
 	struct sip_auth *peerauth;		/*!< Realm authentication */
 	int noncecount;				/*!< Nonce-count */
 	char lastmsg[256];			/*!< Last Message sent/received */
@@ -1832,7 +1833,6 @@
 static int __sip_reliable_xmit(struct sip_pvt *p, int seqno, int resp, struct ast_str *data, int len, int fatal, int sipmethod);
 static int __transmit_response(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable);
 static int retrans_pkt(const void *data);
-static int transmit_sip_request(struct sip_pvt *p, struct sip_request *req);
 static int transmit_response_using_temp(ast_string_field callid, struct sockaddr_in *sin, int useglobal_nat, const int intended_method, const struct sip_request *req, const char *msg);
 static int transmit_response(struct sip_pvt *p, const char *msg, const struct sip_request *req);
 static int transmit_response_reliable(struct sip_pvt *p, const char *msg, const struct sip_request *req);
@@ -1852,6 +1852,7 @@
 static int transmit_refer(struct sip_pvt *p, const char *dest);
 static int transmit_notify_with_mwi(struct sip_pvt *p, int newmsgs, int oldmsgs, char *vmexten);
 static int transmit_notify_with_sipfrag(struct sip_pvt *p, int cseq, char *message, int terminate);
+static int transmit_notify_custom(struct sip_pvt *p, struct ast_variable *vars);
 static int transmit_register(struct sip_registry *r, int sipmethod, const char *auth, const char *authheader);
 static int send_response(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, int seqno);
 static int send_request(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, int seqno);
@@ -1990,7 +1991,7 @@
 static char *sip_do_debug_ip(int fd, char *arg);
 static char *sip_do_debug_peer(int fd, char *arg);
 static char *sip_do_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
-static char *sip_notify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+static char *sip_cli_notify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
 static char *sip_do_history_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
 static char *sip_set_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
 static int sip_dtmfmode(struct ast_channel *chan, void *data);
@@ -2133,6 +2134,7 @@
 
 /*------Response handling functions */
 static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno);
+static void handle_response_notify(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno);
 static void handle_response_refer(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno);
 static int handle_response_register(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno);
 static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno);
@@ -4575,6 +4577,10 @@
 	if (p->options)
 		ast_free(p->options);
 
+	if (p->notify_headers) {
+		ast_variables_destroy(p->notify_headers);
+		p->notify_headers = NULL;
+	}
 	if (p->rtp) {
 		ast_rtp_destroy(p->rtp);
 	}
@@ -9002,6 +9008,7 @@
 static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init)
 {
 	struct sip_request req;
+	struct ast_variable *var;
 	
 	req.method = sipmethod;
 	if (init) {/* Bump branch even on initial requests */
@@ -9050,6 +9057,14 @@
 
 	add_header(&req, "Allow", ALLOWED_METHODS);
 	add_header(&req, "Supported", SUPPORTED_EXTENSIONS);
+
+	if(p->notify_headers) {
+		char buf[512];
+		for (var = p->notify_headers; var; var = var->next) {
+			ast_copy_string(buf, var->value, sizeof(buf));
+			add_header(&req, var->name, ast_unescape_semicolon(buf));
+		}
+	}
 	if (p->options && p->options->addsipheaders && p->owner) {
 		struct ast_channel *chan = p->owner; /* The owner channel */
 		struct varshead *headp;
@@ -9098,7 +9113,9 @@
 		} else if (p->rtp) 
 			add_sdp(&req, p, FALSE);
 	} else {
-		add_header_contentLength(&req, 0);
+		if (!p->notify_headers) {
+			add_header_contentLength(&req, 0);
+		}
 	}
 
 	if (!p->initreq.headers)
@@ -9107,7 +9124,7 @@
 	return send_request(p, &req, init ? XMIT_CRITICAL : XMIT_RELIABLE, p->ocseq);
 }
 
-/*! \brief Used in the SUBSCRIBE notification subsystem */
+/*! \brief Used in the SUBSCRIBE notification subsystem (RFC3265) */
 static int transmit_state_notify(struct sip_pvt *p, int state, int full, int timeout)
 {
 	struct ast_str *tmp = ast_str_alloca(4000);
@@ -9290,7 +9307,7 @@
 	return send_request(p, &req, XMIT_RELIABLE, p->ocseq);
 }
 
-/*! \brief Notify user of messages waiting in voicemail
+/*! \brief Notify user of messages waiting in voicemail (RFC3842)
 \note	- Notification only works for registered peers with mailbox= definitions
 	in sip.conf
 	- We use the SIP Event package message-summary
@@ -9329,15 +9346,7 @@
 	return send_request(p, &req, XMIT_RELIABLE, p->ocseq);
 }
 
-/*! \brief Transmit SIP request unreliably (only used in sip_notify subsystem) */
-static int transmit_sip_request(struct sip_pvt *p, struct sip_request *req)
-{
-	if (!p->initreq.headers) 	/* Initialize first request before sending */
-		initialize_initreq(p, req);
-	return send_request(p, req, XMIT_UNRELIABLE, p->ocseq);
-}
-
-/*! \brief Notify a transferring party of the status of transfer */
+/*! \brief Notify a transferring party of the status of transfer (RFC3515) */
 static int transmit_notify_with_sipfrag(struct sip_pvt *p, int cseq, char *message, int terminate)
 {
 	struct sip_request req;
@@ -9361,6 +9370,32 @@
 	p->lastnoninvite = p->ocseq;
 
 	return send_request(p, &req, XMIT_RELIABLE, p->ocseq);
+}
+
+/*! \brief Notify device with custom headers from sip_notify.conf */
+static int transmit_notify_custom(struct sip_pvt *p, struct ast_variable *vars) {
+	struct sip_request req;
+	struct ast_variable *var, *newvar;
+
+	initreqprep(&req, p, SIP_NOTIFY);
+
+	/* Copy notify vars and add headers */
+	p->notify_headers = newvar = ast_variable_new("Subscription-State", "terminated", "");
+	add_header(&req, newvar->name, newvar->value);
+	for (var = vars; var; var = var->next) {
+		char buf[512];
+		ast_debug(2, "  Adding pair %s=%s\n", var->name, var->value);
+		ast_copy_string(buf, var->value, sizeof(buf));
+		add_header(&req, var->name, ast_unescape_semicolon(buf));
+		newvar->next = ast_variable_new(var->name, var->value, "");
+		newvar = newvar->next;
+	}
+
+	if (!p->initreq.headers) { /* Initialize first request before sending */
+		initialize_initreq(p, &req);
+	}
+
+	return send_request(p, &req, XMIT_UNRELIABLE, p->ocseq);
 }
 
 static const struct _map_x_s regstatestrings[] = {
@@ -14689,7 +14724,7 @@
 }
 
 /*! \brief Cli command to send SIP notify to peer */
-static char *sip_notify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+static char *sip_cli_notify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	struct ast_variable *varlist;
 	int i;
@@ -14706,7 +14741,6 @@
 		return complete_sipnotify(a->line, a->word, a->pos, a->n);
 	}
 
-
 	if (a->argc < 4)
 		return CLI_SHOWUSAGE;
 
@@ -14724,8 +14758,6 @@
 
 	for (i = 3; i < a->argc; i++) {
 		struct sip_pvt *p;
-		struct sip_request req;
-		struct ast_variable *var;
 
 		if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY))) {
 			ast_log(LOG_WARNING, "Unable to build sip pvt data for notify (memory/socket error)\n");
@@ -14741,13 +14773,8 @@
 			continue;
 		}
 
-		initreqprep(&req, p, SIP_NOTIFY);
-
-		for (var = varlist; var; var = var->next) {
-			char buf[512];
-			ast_copy_string(buf, var->value, sizeof(buf));
-			add_header(&req, var->name, ast_unescape_semicolon(buf));
-		}
+		/* Notify is outgoing call */
+		ast_set_flag(&p->flags[0], SIP_OUTGOING);
 
 		/* Recalculate our side, and recalculate Call ID */
 		ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip);
@@ -14757,9 +14784,8 @@
 		ao2_t_link(dialogs, p, "Linking in new name");
 		ast_cli(a->fd, "Sending NOTIFY of type '%s' to '%s'\n", a->argv[2], a->argv[i]);
 		dialog_ref(p, "bump the count of p, which transmit_sip_request will decrement.");
-		transmit_sip_request(p, &req);
-		sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
-		dialog_unref(p, "unref pvt at end of for loop in sip_notify");
+		sip_scheddestroy(p, SIP_TRANS_TIMEOUT);
+		transmit_notify_custom(p, varlist);
 	}
 
 	return CLI_SUCCESS;
@@ -15733,6 +15759,51 @@
 		ast_log(LOG_WARNING, "Could not transmit message in dialog %s\n", p->callid);
 }
 
+/* \brief Handle SIP response in NOTIFY transaction
+       We've sent a NOTIFY, now handle responses to it
+  */
+static void handle_response_notify(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno)
+{
+	switch (resp) {
+	case 200:   /* Notify accepted */
+		/* They got the notify, this is the end */
+		if (p->owner) {
+			if (!p->refer) {
+				ast_log(LOG_WARNING, "Notify answer on an owned channel? - %s\n", p->owner->name);
+				ast_queue_hangup(p->owner);
+			} else {
+				ast_debug(4, "Got OK on REFER Notify message\n");
+			}
+		} else {
+			if (p->subscribed == NONE) {
+				ast_debug(4, "Got 200 accepted on NOTIFY\n");
+				p->needdestroy = 1;
+			}
+			if (ast_test_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE)) {
+				/* Ready to send the next state we have on queue */
+				ast_clear_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE);
+				cb_extensionstate((char *)p->context, (char *)p->exten, p->laststate, (void *) p);
+			}
+		}
+		break;
+	case 401:   /* Not www-authorized on SIP method */
+	case 407:   /* Proxy auth */
+		if (!p->notify_headers) {
+			break; /* Only device notify can use NOTIFY auth */
+		}
+		ast_string_field_set(p, theirtag, NULL);
+		if (ast_strlen_zero(p->authname)) {
+			ast_log(LOG_WARNING, "Asked to authenticate NOTIFY to %s:%d but we have no matching peer or realm auth!\n", ast_inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port));
+			p->needdestroy = 1;
+		}
+		if (p->authtries > 1 || do_proxy_auth(p, req, resp, SIP_NOTIFY, 0)) {
+			ast_log(LOG_NOTICE, "Failed to authenticate on NOTYFY to '%s'\n", get_header(&p->initreq, "From"));
+			p->needdestroy = 1;
+		}
+		break;
+	}
+}
+
 /* \brief Handle SIP response in REFER transaction
 	We've sent a REFER, now handle responses to it 
   */
@@ -16082,22 +16153,7 @@
 			} else if (sipmethod == SIP_INVITE) {
 				handle_response_invite(p, resp, rest, req, seqno);
 			} else if (sipmethod == SIP_NOTIFY) {
-				/* They got the notify, this is the end */
-				if (p->owner) {
-					if (!p->refer) {
-						ast_log(LOG_WARNING, "Notify answer on an owned channel? - %s\n", p->owner->name);
-						ast_queue_hangup(p->owner);
-					} else
-						ast_debug(4, "Got OK on REFER Notify message\n");
-				} else {
-					if (p->subscribed == NONE) 
-						p->needdestroy = 1;
-					if (ast_test_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE)) {
-						/* Ready to send the next state we have on queue */
-						ast_clear_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE);
-						cb_extensionstate((char *)p->context, (char *)p->exten, p->laststate, (void *) p);
-					}
-				}
+				handle_response_notify(p, resp, rest, req, seqno);
 			} else if (sipmethod == SIP_REGISTER) 
 				res = handle_response_register(p, resp, rest, req, seqno);
 			else if (sipmethod == SIP_BYE)		/* Ok, we're ready to go */
@@ -16111,6 +16167,8 @@
 		case 407: /* Proxy auth required */
 			if (sipmethod == SIP_INVITE)
 				handle_response_invite(p, resp, rest, req, seqno);
+			else if (sipmethod == SIP_NOTIFY)
+				handle_response_notify(p, resp, rest, req, seqno);
 			else if (sipmethod == SIP_REFER)
 				handle_response_refer(p, resp, rest, req, seqno);
 			else if (p->registry && sipmethod == SIP_REGISTER)
@@ -22407,7 +22465,7 @@
 	AST_CLI_DEFINE(sip_show_registry, "List SIP registration status"),
 	AST_CLI_DEFINE(sip_unregister, "Unregister (force expiration) a SIP peer from the registery\n"),
 	AST_CLI_DEFINE(sip_show_settings, "Show SIP global settings"),
-	AST_CLI_DEFINE(sip_notify, "Send a notify packet to a SIP peer"),
+	AST_CLI_DEFINE(sip_cli_notify, "Send a notify packet to a SIP peer"),
 	AST_CLI_DEFINE(sip_show_channel, "Show detailed SIP channel info"),
 	AST_CLI_DEFINE(sip_show_history, "Show SIP dialog history"),
 	AST_CLI_DEFINE(sip_show_peer, "Show details on specific SIP peer"),

Modified: trunk/configs/sip_notify.conf.sample
URL: http://svn.digium.com/view/asterisk/trunk/configs/sip_notify.conf.sample?view=diff&rev=114529&r1=114528&r2=114529
==============================================================================
--- trunk/configs/sip_notify.conf.sample (original)
+++ trunk/configs/sip_notify.conf.sample Tue Apr 22 10:54:06 2008
@@ -2,9 +2,20 @@
 Event=>check-sync
 Content-Length=>0
 
-; Untested
 [sipura-check-cfg]
 Event=>resync
+Content-Length=>0
+
+[linksys-cold-restart]
+Event=>reboot_now
+Content-Length=>0
+
+[linksys-warm-restart]
+Event=>restart_now
+Content-Length=>0
+
+[sipura-get-report]
+Event=>report
 Content-Length=>0
 
 ; Untested
@@ -16,17 +27,14 @@
 Event=>check-sync
 Content-Length=>0
 
-; Tested
 [snom-check-cfg]
 Event=>check-sync\;reboot=false
 Content-Length=>0
 
-; Tested
 [aastra-check-cfg]
 Event=>check-sync
 Content-Length=>0
 
-; Tested
 [aastra-xml]
 Event=>aastra-xml
 Content-Length=>0




More information about the asterisk-commits mailing list