[asterisk-commits] oej: branch group/pinana-publish-1.4 r296504 - /team/group/pinana-publish-1.4...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Sat Nov 27 08:48:31 CST 2010
Author: oej
Date: Sat Nov 27 08:48:26 2010
New Revision: 296504
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=296504
Log:
Starting to add remote subscriptions
Most of this code is based on the remote MWI subscriptions in trunk,
which is code that needs a bit more love too...
Modified:
team/group/pinana-publish-1.4/channels/chan_sip.c
Modified: team/group/pinana-publish-1.4/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/group/pinana-publish-1.4/channels/chan_sip.c?view=diff&rev=296504&r1=296503&r2=296504
==============================================================================
--- team/group/pinana-publish-1.4/channels/chan_sip.c (original)
+++ team/group/pinana-publish-1.4/channels/chan_sip.c Sat Nov 27 08:48:26 2010
@@ -1106,6 +1106,7 @@
struct sip_peer *relatedpeer; /*!< If this dialog is related to a peer, which one
Used in peerpoke, mwi subscriptions */
struct sip_registry *registry; /*!< If this is a REGISTER dialog, to which registry */
+ struct sip_subscription_pres *pres; /*!< If this is a SUBSCRIBE dialog, to which subscription */
struct ast_rtp *rtp; /*!< RTP Session */
struct ast_rtp *vrtp; /*!< Video RTP session */
struct sip_pkt *packets; /*!< Packets scheduled for re-transmission */
@@ -1859,6 +1860,9 @@
static int transmit_reinvite_with_t38_sdp(struct sip_pvt *p);
static struct ast_udptl *sip_get_udptl_peer(struct ast_channel *chan);
static int sip_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl);
+
+/*------ Remote publish/subscribe support */
+static int sip_pres_notify_update(struct sip_pvt *dialog, struct sip_request *req);
/*! \brief Definition of this channel for PBX channel registration */
static const struct ast_channel_tech sip_tech = {
@@ -9825,6 +9829,12 @@
return 0;
}
+static int sip_devicestate_publish(struct sip_pvt *dialog, struct statechange *sc)
+{
+ /* XXX MARQUIS Just a template for now */
+ return 0;
+}
+
/*! \Publish the state of a device if it matches a publisher and one of its filters */
static void *handle_statechange(struct statechange *sc)
{
@@ -9844,6 +9854,7 @@
ao2_iterator_destroy(&i);
return NULL;
}
+
/*! \brief Consumer of the statechange queue */
static void *device_state_thread(void *data)
@@ -14579,10 +14590,8 @@
else if (sipmethod == SIP_INVITE)
handle_response_invite(p, resp, rest, req, seqno);
else if (sipmethod == SIP_BYE) {
- char *auth, *auth2;
-
- auth = (resp == 407 ? "Proxy-Authenticate" : "WWW-Authenticate");
- auth2 = (resp == 407 ? "Proxy-Authorization" : "Authorization");
+ char *auth = (resp == 407 ? "Proxy-Authenticate" : "WWW-Authenticate");
+ char *auth2 = (resp == 407 ? "Proxy-Authorization" : "Authorization");
if ((p->authtries == MAX_AUTHTRIES) || do_proxy_auth(p, req, auth, auth2, sipmethod, 0)) {
ast_log(LOG_NOTICE, "Failed to authenticate on %s to '%s'\n", msg, get_header(&p->initreq, "From"));
ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
@@ -14941,12 +14950,7 @@
if (option_debug > 1 && sipdebug)
ast_log(LOG_DEBUG, "Got NOTIFY Event: %s\n", event);
- if (strcmp(event, "refer")) {
- /* We don't understand this event. */
- /* Here's room to implement incoming voicemail notifications :-) */
- transmit_response(p, "489 Bad event", req);
- res = -1;
- } else {
+ if (!strcmp(event, "refer")) {
/* Save nesting depth for now, since there might be other events we will
support in the future */
@@ -15047,6 +15051,14 @@
/* Confirm that we received this packet */
transmit_response(p, "200 OK", req);
+ } else if (!strcmp(event, "dialog-info")) {
+ res = sip_pres_notify_update(p, req);
+
+ } else {
+ /* We don't understand this event. */
+ /* Here's room to implement incoming voicemail notifications :-) */
+ transmit_response(p, "489 Bad event", req);
+ res = -1;
};
if (!p->lastinvite)
@@ -19053,6 +19065,293 @@
return peer;
}
+/*! \brief Different types of outbound subscriptions.
+ the Message-waiting subscriptions in Asterisk 1.8 is not very generic in the architecture
+ at this moment and needs to be aligned at some point with the generic code
+*/
+enum sip_subscription_pres_type {
+ SUB_DIALOG_INFO, /* Dialog info */
+ SUB_PIDF, /* SIMPLE presence */
+ SUB_MWI, /* The MWI subscriptions need to move into a more generic subscription format */
+};
+
+#define DEFAULT_PRES_EXPIRY 3600; /* One hour default */
+
+static int pres_expiry = DEFAULT_PRES_EXPIRY;
+
+/*!
+ * \brief Definition of an MWI subscription to another server
+ *
+ * \todo Convert this to astobj2.
+ */
+struct sip_subscription_pres {
+ ASTOBJ_COMPONENTS_FULL(struct sip_subscription_pres,1,1);
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(uri); /*!< Who we are sending the subscription as */
+ AST_STRING_FIELD(domain); /*!< Domain or host we subscribe to */
+ );
+ //enum sip_transport transport; /*!< Transport to use */
+ struct sip_peer *peer; /*!< Peer to use for this subscription */
+ int resub; /*!< Sched ID of resubscription */
+ unsigned int subscribed:1; /*!< Whether we are currently subscribed or not */
+ unsigned int destruction:1; /*!< Whether we are currently being unsubscribed */
+ unsigned int fatalerror:1; /*!< We got a fatal error and can't do anything without a reload */
+ unsigned int shutdown:1; /*!< Are we being destroyed because of a shutdown or not ? */
+ struct sip_pvt *call; /*!< Outbound subscription dialog */
+ struct ast_dnsmgr_entry *dnsmgr; /*!< DNS refresh manager for subscription */
+ //Trunk: struct ast_sockaddr us; /*!< Who the server thinks we are */
+ struct sockaddr_in us; /*!< Who the server thinks we are */
+};
+
+/*! \brief The MWI subscription list */
+static struct ast_subscription_pres_list {
+ ASTOBJ_CONTAINER_COMPONENTS(struct sip_subscription_pres);
+} sip_pres_sublist;
+
+/*! \brief Unsubscribe from presence server
+
+Basically, send resub with Expiry: 0
+*/
+static void sip_pres_unsubscribe(struct sip_subscription_pres *pres)
+{
+ /* XXX OEJ Void nothing nada */
+ return;
+}
+
+/*! \brief Destroy presence subscription object */
+static void sip_subscribe_pres_destroy(struct sip_subscription_pres *pres)
+{
+ if (pres->call) {
+ sip_pres_unsubscribe(pres);
+ /* We need to know if we're doing this because of unload/shutdown of chan_sip or if the hint is just not
+ needed any more. If it's not needed, we can wait for confirmation of unsubscribe for a while. If not,
+ we just forget all about it and ignore the response */
+ if (pres->shutdown) {
+ sip_destroy(pres->call);
+ }
+ }
+
+ AST_SCHED_DEL(sched, pres->resub);
+ ast_string_field_free_memory(pres);
+ //XXX ast_dnsmgr_release(pres->dnsmgr);
+ ast_free(pres);
+}
+
+/*! \brief subscribe to SIP uri */
+static int sip_subscribe_pres(const char *uri, enum sip_subscription_pres_type type)
+{
+ struct sip_subscription_pres *pres;
+ char *domain;
+ char buf[256] = "";
+
+ /* We have a URI, much like in a dialstring. Just try to find where it leads us like a normal call.
+ the URI can point to a peer, a domain or a host. We can basically use the same logic as
+ we do in a dial string.
+ */
+
+ if (ast_strlen_zero(uri)) {
+ return -1;
+ }
+
+ ast_copy_string(buf, uri, sizeof(buf));
+
+ if ((domain = strrchr(uri, '@'))) {
+ *domain++ = '\0';
+ }
+
+ if (ast_strlen_zero(domain) || ast_strlen_zero(uri)) {
+ ast_log(LOG_ERROR, "Format for SIP remote subscription in a hint is sipds:<username>@<domain/peer> \n");
+ return -1;
+ }
+
+ if (!(pres = ast_calloc(1, sizeof(struct sip_subscription_pres)))) {
+ return -1;
+ }
+ if (ast_string_field_init(pres, 256)) {
+ ASTOBJ_UNREF(pres, sip_subscribe_pres_destroy);
+ return 0;
+ }
+
+ ASTOBJ_INIT(pres);
+ ast_string_field_set(pres, uri, uri);
+ ast_string_field_set(pres, domain, domain);
+ pres->resub = -1;
+
+ ASTOBJ_CONTAINER_LINK(&sip_pres_sublist, pres);
+ ASTOBJ_UNREF(pres, sip_subscribe_pres_destroy);
+
+ return 0;
+}
+
+/* Forward decl (no doxygen here) */
+static int __sip_subscribe_pres_do(struct sip_subscription_pres *pres);
+
+/*! \brief Send a subscription or resubscription for presence */
+static int sip_subscribe_pres_do(const void *data)
+{
+ struct sip_subscription_pres *pres = (struct sip_subscription_pres*)data;
+
+ if (!pres) {
+ return -1;
+ }
+
+ pres->resub = -1;
+ __sip_subscribe_pres_do(pres);
+ ASTOBJ_UNREF(pres, sip_subscribe_pres_destroy);
+
+ return 0;
+}
+
+/*! \brief Actually setup an MWI subscription or resubscribe */
+static int __sip_subscribe_pres_do(struct sip_subscription_pres *pres)
+{
+ /* If we have no DNS manager let's do a lookup */
+ if (!pres->dnsmgr) {
+ // Is this needed. If we base this on peers, we don't need it.
+ //ast_dnsmgr_lookup(mwi->hostname, &mwi->us, &mwi->dnsmgr, sip_cfg.srvlookup ? transport : NULL);
+ }
+
+ /* If we already have a subscription up simply send a resubscription */
+ if (pres->call) {
+ transmit_invite(pres->call, SIP_SUBSCRIBE, 0, 0, NULL);
+ return 0;
+ }
+
+ /* Create a dialog that we will use for the subscription */
+ if (!(pres->call = sip_alloc(NULL, NULL, 0, SIP_SUBSCRIBE))) {
+ return -1;
+ }
+
+ //OEJ ???? ref_proxy(pres->call, obproxy_get(pres->call, NULL));
+
+ //if (!ast_sockaddr_port(&pres->us) && pres->portno) {
+ //ast_sockaddr_set_port(&pres->us, pres->portno);
+ //}
+
+ /* Setup the destination of our subscription */
+ if (create_addr(pres->call, pres->domain, &pres->us)) {
+ // XXX ??? dialog_unlink_all(pres->call, TRUE, TRUE);
+ // XXX ??? pres->call = dialog_unref(pres->call, "unref dialog after unlink_all");
+ sip_destroy(pres->call);
+ return 0;
+ }
+
+ pres->call->expiry = pres_expiry; // OEJ is this a global variable???
+
+ //set_socket_transport(&mwi->call->socket, mwi->transport);
+ ast_sip_ouraddrfor(&pres->call->sa.sin_addr, &pres->call->ourip);
+ build_contact(pres->call);
+ build_via(pres->call);
+ build_callid_pvt(pres->call);
+ ast_set_flag(&pres->call->flags[0], SIP_OUTGOING);
+
+ /* Associate the call with us */
+ pres->call->pres = ASTOBJ_REF(pres);
+
+ //??? pres->call->subscribed = MWI_NOTIFICATION;
+
+ /* Actually send the packet */
+ transmit_invite(pres->call, SIP_SUBSCRIBE, 0, 2, NULL);
+
+ return 0;
+}
+
+/* \brief Handle SIP response in SUBSCRIBE transaction */
+static void handle_response_subscribe(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno)
+{
+ //Trunk: if (!p->mwi && !p->pres) {
+ if (!p->pres) {
+ return;
+ }
+
+ switch (resp) {
+ case 200: /* Subscription accepted */
+ if (option_debug > 2) {
+ ast_log(LOG_DEBUG, "Got 200 OK on subscription for presence\n");
+ }
+ //XXX set_pvt_allowed_methods(p, req);
+ if (p->options) {
+ ast_free(p->options);
+ p->options = NULL;
+ }
+ p->pres->subscribed = 1;
+ if ((p->pres->resub = ast_sched_add(sched, pres_expiry * 1000, sip_subscribe_pres_do, ASTOBJ_REF(p->pres))) < 0) {
+ ASTOBJ_UNREF(p->pres, sip_subscribe_pres_destroy);
+ }
+ break;
+ case 401:
+ case 407:
+ ast_string_field_set(p, theirtag, NULL);
+ if (p->authtries > 1 || do_proxy_auth(p, req, (resp == 401 ? "WWW-Authenticate" : "Proxy-Authenticate"),
+ (resp == 401 ? "Authorization" : "Proxy-Authorization"), SIP_SUBSCRIBE, 0)) {
+
+ ast_log(LOG_NOTICE, "Failed to authenticate on SUBSCRIBE to '%s'\n", get_header(&p->initreq, "From"));
+ p->pres->call = NULL;
+ ASTOBJ_UNREF(p->pres, sip_subscribe_pres_destroy);
+ pvt_set_needdestroy(p, "failed to authenticate SUBSCRIBE");
+ }
+ break;
+ case 403:
+ transmit_response_with_date(p, "200 OK", req);
+ ast_log(LOG_WARNING, "Authentication failed while trying to subscribe for presence (URI: %s)\n", p->pres->uri);
+ p->pres->call = NULL;
+ ASTOBJ_UNREF(p->pres, sip_subscribe_pres_destroy);
+ pvt_set_needdestroy(p, "received 403 response");
+ sip_alreadygone(p);
+ break;
+ case 404:
+ ast_log(LOG_ERROR, "Subscription failed for presence. URI doesn't exist. (URI: %s) \n", p->pres->uri);
+ p->pres->call = NULL;
+ p->pres->fatalerror = TRUE;
+ ASTOBJ_UNREF(p->pres, sip_subscribe_pres_destroy);
+ pvt_set_needdestroy(p, "received 404 response");
+ break;
+ case 481:
+ ast_log(LOG_WARNING, "Re-Subscription failed. The remote side said that our dialog did not exist.(URI: %s)\n", p->pres->uri);
+ p->pres->call = NULL;
+ ASTOBJ_UNREF(p->pres, sip_subscribe_pres_destroy);
+ /* In this case we need to start a new subscription, not give up */
+ pvt_set_needdestroy(p, "received 481 response");
+ break;
+ case 500:
+ case 501:
+ ast_log(LOG_ERROR, "Subscription failed. Got error %d on URI %s.\n", resp, p->pres->uri);
+ p->pres->fatalerror = TRUE;
+ p->pres->call = NULL;
+ ASTOBJ_UNREF(p->pres, sip_subscribe_pres_destroy);
+ pvt_set_needdestroy(p, "received 500/501 response");
+ break;
+ }
+}
+
+/*! \brief Parse the incoming NOTIFY update and update the device state provider system for this device */
+static int sip_pres_notify_update(struct sip_pvt *dialog, struct sip_request *req)
+{
+ /* Get the XML message body */
+ /* Find the good stuff in it */
+ /* Notify the device state system if there's a change */
+ /* Live long and prosper */
+ return 0;
+}
+
+/*! \brief Callback for devicestate providers */
+static int sip_remote_devicestate(const char *data)
+{
+ /* Data is the device to get state for, actually the SIP uri */
+ /* 1. Try to find the device in the list of subscriptions */
+ /* 2. If the device exists - get the last known state and return it */
+ /* 3. If the device does not exist in the list - set up a subscription */
+
+ /* When a dialplan is loaded, we get a first call to check state. In that call,
+ we just answer back with a dummy answer. When we get the first notify later on,
+ we'll update automatically with the initial state.
+ */
+
+
+ /* This is just a dummy */
+ return AST_DEVICE_INUSE;
+}
+
static void publisher_destructor_cb(void *data)
{
struct sip_publisher *publisher = data;
@@ -19482,6 +19781,11 @@
default_expiry = atoi(v->value);
if (default_expiry < 1)
default_expiry = DEFAULT_DEFAULT_EXPIRY;
+ } else if (!strcasecmp(v->name, "presexpiry")) {
+ pres_expiry = atoi(v->value);
+ if (pres_expiry < 1) {
+ pres_expiry = DEFAULT_PRES_EXPIRY;
+ }
} else if (!strcasecmp(v->name, "sipdebug")) { /* XXX maybe ast_set2_flags ? */
if (ast_true(v->value))
ast_set_flag(&global_flags[1], SIP_PAGE2_DEBUG_CONFIG);
@@ -20542,6 +20846,9 @@
ast_manager_register2("SIPshowpeer", EVENT_FLAG_SYSTEM, manager_sip_show_peer,
"Show SIP peer (text format)", mandescr_show_peer);
+ /* Register our remote device state provider */
+ ast_devstate_prov_add("sipds", sip_remote_devicestate);
+
sip_poke_all_peers();
sip_send_all_registers();
@@ -20580,6 +20887,9 @@
/* Unregister CLI commands */
ast_cli_unregister_multiple(cli_sip, sizeof(cli_sip) / sizeof(struct ast_cli_entry));
+
+ /* Unregister our remote device state provider */
+ ast_devstate_prov_del("sipds");
/* Disconnect from the RTP subsystem */
ast_rtp_proto_unregister(&sip_rtp);
More information about the asterisk-commits
mailing list