⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nua_notifier.c

📁 Sofia SIP is an open-source SIP User-Agent library, compliant with the IETF RFC3261 specification.
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2006 Nokia Corporation. * * Contact: Pekka Pessi <pekka.pessi@nokia.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * *//**@CFILE nua_notifier.c * @brief SUBSCRIBE server, NOTIFY client and REFER server * * Simpler event server. See nua_event_server.c for more complex event * server. * * @author Pekka Pessi <Pekka.Pessi@nokia.com> * * @date Created: Wed Mar  8 15:10:08 EET 2006 ppessi */#include "config.h"#include <stddef.h>#include <stdlib.h>#include <string.h>#include <limits.h>#include <assert.h>#include <sofia-sip/string0.h>#include <sofia-sip/sip_protos.h>#include <sofia-sip/sip_extra.h>#include <sofia-sip/sip_status.h>#include <sofia-sip/sip_util.h>#include <sofia-sip/su_uniqueid.h>#include <sofia-sip/su_md5.h>#include <sofia-sip/token64.h>#include "nua_stack.h"/* ---------------------------------------------------------------------- *//* Notifier event usage */struct notifier_usage{  enum nua_substate  nu_substate;	/**< Subscription state */  sip_time_t         nu_expires; 	/**< Expiration time */  sip_time_t         nu_requested;      /**< Requested expiration time */#if SU_HAVE_EXPERIMENTAL  char              *nu_tag;	        /**< @ETag in last NOTIFY */  unsigned           nu_etags:1;	/**< Subscriber supports etags */  unsigned           nu_appl_etags:1;   /**< Application generates etags */  unsigned           nu_no_body:1;      /**< Suppress body */#endif};static char const *nua_notify_usage_name(nua_dialog_usage_t const *du);static int nua_notify_usage_add(nua_handle_t *nh, 				   nua_dialog_state_t *ds,				   nua_dialog_usage_t *du);static void nua_notify_usage_remove(nua_handle_t *nh, 				    nua_dialog_state_t *ds,				    nua_dialog_usage_t *du,				    nua_client_request_t *cr,				    nua_server_request_t *sr);static void nua_notify_usage_refresh(nua_handle_t *nh,				     nua_dialog_state_t *ds,				     nua_dialog_usage_t *du,				     sip_time_t now);static int nua_notify_usage_shutdown(nua_handle_t *nh,				     nua_dialog_state_t *ds,				     nua_dialog_usage_t *du);static nua_usage_class const nua_notify_usage[1] = {  {    sizeof (struct notifier_usage), (sizeof nua_notify_usage),    nua_notify_usage_add,    nua_notify_usage_remove,    nua_notify_usage_name,    nua_base_usage_update_params,    NULL,    nua_notify_usage_refresh,    nua_notify_usage_shutdown,  }};static char const *nua_notify_usage_name(nua_dialog_usage_t const *du){  return "notify";}static int nua_notify_usage_add(nua_handle_t *nh, 			 nua_dialog_state_t *ds,			 nua_dialog_usage_t *du){  ds->ds_has_events++;  ds->ds_has_notifys++;  return 0;}static void nua_notify_usage_remove(nua_handle_t *nh, 			     nua_dialog_state_t *ds,			     nua_dialog_usage_t *du,			     nua_client_request_t *cr,			     nua_server_request_t *sr){  ds->ds_has_events--;	  ds->ds_has_notifys--;	}/* ====================================================================== *//* SUBSCRIBE server *//** @NUA_EVENT nua_i_subscribe * * Incoming @b SUBSCRIBE request. * * @b SUBSCRIBE request is used to query SIP event state or establish a SIP * event subscription. * * @param status status code of response sent automatically by stack * @param phrase response phrase sent automatically by stack * @param nh     operation handle associated with the incoming request * @param hmagic application context associated with the handle *               (NULL when handle is created by the stack) * @param sip    SUBSCRIBE request headers * @param tags   NUTAG_SUBSTATE() * * Initial SUBSCRIBE requests are dropped with <i>489 Bad Event</i> * response, unless the application has explicitly included the @Event in * the list of allowed events with nua_set_params() tag NUTAG_ALLOW_EVENTS() * (or SIPTAG_ALLOW_EVENTS() or SIPTAG_ALLOW_EVENTS_STR()). * * If the event has been allowed the application * can decide whether to accept the SUBSCRIBE request or reject it. The * nua_response() call responding to a SUBSCRIBE request must have * NUTAG_WITH() (or NUTAG_WITH_THIS()/NUTAG_WITH_SAVED()) tag. * * If the application accepts the SUBSCRIBE request, it must immediately * send an initial NOTIFY establishing the dialog. This is because the * response to the SUBSCRIBE request may be lost by an intermediate proxy * because it had forked the SUBSCRIBE request. * * SUBSCRIBE requests modifying (usually refreshing or terminating) an * existing event subscription are accepted by default and a <i>200 OK</i> * response along with a copy of previously sent NOTIFY is sent * automatically to the subscriber. * * By default, only event subscriptions accepted are those created * implicitly by REFER request. See #nua_i_refer how the application must * handle the REFER requests. * * @par Subscription Lifetime and Terminating Subscriptions * * Accepting the SUBSCRIBE request creates a dialog with a <i>notifier * dialog usage</i> on the handle. The dialog usage is active, until the * subscriber terminates the subscription, it times out or the application * terminates the usage with nua_notify() call containing the tag * NUTAG_SUBSTATE(nua_substate_terminated) or @SubscriptionState header with * state "terminated" and/or expiration time 0.  * * When the subscriber terminates the subscription, the application is * notified of an termination by a #nua_i_subscribe event with * NUTAG_SUBSTATE(nua_substate_terminated) tag. When the subscription times * out, nua automatically initiates a NOTIFY transaction. When it is * terminated, the application is sent a #nua_r_notify event with * NUTAG_SUBSTATE(nua_substate_terminated) tag.  * * @sa @RFC3265, nua_notify(), NUTAG_SUBSTATE(), @SubscriptionState, * @Event, nua_subscribe(), #nua_r_subscribe, #nua_i_refer, nua_refer() * * @END_NUA_EVENT */static int nua_subscribe_server_init(nua_server_request_t *sr);static int nua_subscribe_server_preprocess(nua_server_request_t *sr);static int nua_subscribe_server_respond(nua_server_request_t*, tagi_t const *);static int nua_subscribe_server_report(nua_server_request_t*, tagi_t const *);nua_server_methods_t const nua_subscribe_server_methods =   {    SIP_METHOD_SUBSCRIBE,    nua_i_subscribe,		/* Event */    {       1,			/* Create dialog */      0,			/* Initial request */      1,			/* Target refresh request  */      1,			/* Add Contact */    },    nua_subscribe_server_init,    nua_subscribe_server_preprocess,    nua_base_server_params,    nua_subscribe_server_respond,    nua_subscribe_server_report,  };int nua_subscribe_server_init(nua_server_request_t *sr){  nua_handle_t *nh = sr->sr_owner;  nua_dialog_state_t *ds = nh->nh_ds;  sip_allow_events_t const *allow_events = NH_PGET(nh, allow_events);  sip_t const *sip = sr->sr_request.sip;  sip_event_t *o = sip->sip_event;  char const *event = o ? o->o_type : NULL;    if (sr->sr_initial || !nua_dialog_usage_get(ds, nua_notify_usage, o)) {    if (event && str0cmp(event, "refer") == 0)      /* refer event subscription should be initiated with REFER */      return SR_STATUS1(sr, SIP_403_FORBIDDEN);    /* XXX - event is case-sensitive, should use msg_header_find_item() */    if (!event || !msg_header_find_param(allow_events->k_common, event))      return SR_STATUS1(sr, SIP_489_BAD_EVENT);  }  return 0;}int nua_subscribe_server_preprocess(nua_server_request_t *sr){  nua_handle_t *nh = sr->sr_owner;  nua_dialog_state_t *ds = nh->nh_ds;  nua_dialog_usage_t *du;  struct notifier_usage *nu;  sip_t const *sip = sr->sr_request.sip;  sip_event_t *o = sip->sip_event;  char const *event = o ? o->o_type : NULL;  /* Maximum expiration time */  unsigned long expires = sip->sip_expires ? sip->sip_expires->ex_delta : 3600;  sip_time_t now = sip_now();  assert(nh && nh->nh_nua->nua_dhandle != nh);    du = nua_dialog_usage_get(ds, nua_notify_usage, o);  if (du == NULL) {    /* Create a new subscription */    du = nua_dialog_usage_add(nh, ds, nua_notify_usage, o);    if (du == NULL)      return SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);  }  else {    /* Refresh existing subscription */    if (str0cmp(event, "refer") == 0)      expires = NH_PGET(nh, refer_expires);    SR_STATUS1(sr, SIP_200_OK);  }  nu = nua_dialog_usage_private(du);  if (now + expires >= now)    nu->nu_requested = now + expires;  else    nu->nu_requested = SIP_TIME_MAX - 1;#if SU_HAVE_EXPERIMENTAL  nu->nu_etags =     sip_suppress_body_if_match(sip) ||    sip_suppress_notify_if_match(sip) ||    sip_has_feature(sr->sr_request.sip->sip_supported, "etags");#endif  sr->sr_usage = du;  return sr->sr_status <= 100 ? 0 : sr->sr_status;}/** @internal Respond to a SUBSCRIBE request. * */staticint nua_subscribe_server_respond(nua_server_request_t *sr, tagi_t const *tags){  struct notifier_usage *nu = nua_dialog_usage_private(sr->sr_usage);  msg_t *msg = sr->sr_response.msg;  sip_t *sip = sr->sr_response.sip;  if (200 <= sr->sr_status && sr->sr_status < 300) {    sip_expires_t ex[1];     sip_expires_init(ex);    if (nu) {      sip_time_t now = sip_now();      if (nu->nu_requested) {	if (sip->sip_expires) {	  /* Expires in response can only shorten the expiration time */	  if (nu->nu_requested > now + sip->sip_expires->ex_delta) 	    nu->nu_requested = now + sip->sip_expires->ex_delta;	}	else {	  unsigned sub_expires = NH_PGET(sr->sr_owner, sub_expires);	  if (nu->nu_requested > now + sub_expires)	    nu->nu_requested = now + sub_expires;	}	if (nu->nu_requested >= now)	  nu->nu_expires = nu->nu_requested;	else	  nu->nu_expires = now;	if (nu->nu_expires <= now)	  nu->nu_substate = nua_substate_terminated;      }      if (nu->nu_expires > now)	ex->ex_delta = nu->nu_expires - now;    }    else {      /* Always add header Expires: 0 */    }    if (!sip->sip_expires || sip->sip_expires->ex_delta > ex->ex_delta)      sip_add_dup(msg, sip, (sip_header_t *)ex);  }  return nua_base_server_respond(sr, tags);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -