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

📄 nua_subnotref.c

📁 this is simple sip stack.
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * 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_subnotref.c * @brief SUBSCRIBE, NOTIFY and REFER methods * * @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_status.h>#include <sofia-sip/sip_util.h>#include <sofia-sip/su_uniqueid.h>#define NTA_LEG_MAGIC_T      struct nua_handle_s#define NTA_OUTGOING_MAGIC_T struct nua_handle_s#include "nua_stack.h"/* ---------------------------------------------------------------------- *//* Subcribe event usage */struct event_usage{  enum nua_substate  eu_substate;	/**< Subscription state */  sip_time_t eu_expires;	        /**< Proposed expiration time */};static char const *nua_subscribe_usage_name(nua_dialog_usage_t const *du);static int nua_subscribe_usage_add(nua_handle_t *nh, 				   nua_dialog_state_t *ds,				   nua_dialog_usage_t *du);static void nua_subscribe_usage_remove(nua_handle_t *nh, 				       nua_dialog_state_t *ds,				       nua_dialog_usage_t *du);static nua_usage_class const nua_subscribe_usage[1] = {  {    sizeof (struct event_usage), (sizeof nua_subscribe_usage),    nua_subscribe_usage_add,    nua_subscribe_usage_remove,    nua_subscribe_usage_name,  }};static char const *nua_subscribe_usage_name(nua_dialog_usage_t const *du){  return "subscribe";}static int nua_subscribe_usage_add(nua_handle_t *nh, 			   nua_dialog_state_t *ds,			   nua_dialog_usage_t *du){  ds->ds_has_events++;  ds->ds_has_subscribes++;  return 0;}static void nua_subscribe_usage_remove(nua_handle_t *nh, 			       nua_dialog_state_t *ds,			       nua_dialog_usage_t *du){  ds->ds_has_events--;	  ds->ds_has_subscribes--;	}/* ---------------------------------------------------------------------- *//* Notify event usage */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);static nua_usage_class const nua_notify_usage[1] = {  {    sizeof (struct event_usage), (sizeof nua_notify_usage),    nua_notify_usage_add,    nua_notify_usage_remove,    nua_notify_usage_name,  }};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){  ds->ds_has_events--;	  ds->ds_has_notifys--;	}/* ====================================================================== *//* SUBSCRIBE */static void   refresh_subscribe(nua_handle_t *nh, nua_dialog_usage_t *, sip_time_t now),  terminate_subscription(nua_handle_t *nh, nua_dialog_usage_t *, sip_time_t now);static int process_response_to_subscribe(nua_handle_t *nh,					 nta_outgoing_t *orq,					 sip_t const *sip);intnua_stack_subscribe(nua_t *nua, nua_handle_t *nh, nua_event_t e,		    tagi_t const *tags){  nua_client_request_t *cr = nh->nh_cr;  nua_dialog_usage_t *du = NULL;  struct event_usage *eu;  msg_t *msg;  sip_t *sip;  if (nh->nh_special && nh->nh_special != nua_r_subscribe)    return UA_EVENT3(e, 500, "Invalid handle for SUBSCRIBE", 		     NUTAG_SUBSTATE(nua_substate_terminated));  else if (cr->cr_orq)    return UA_EVENT2(e, 500, "Request already in progress");  /* Initialize allow and auth */  nua_stack_init_handle(nua, nh, nh_has_subscribe, "NOTIFY", TAG_NEXT(tags));  if (nh->nh_has_subscribe)    /* We can re-use existing INVITE handle */    nh->nh_special = nua_r_subscribe;  msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count,		     SIP_METHOD_SUBSCRIBE,		     NUTAG_USE_DIALOG(1),		     NUTAG_ADD_CONTACT(1),		     TAG_NEXT(tags));  sip = sip_object(msg);  if (sip) {    sip_event_t *o = sip->sip_event;    if (e != nua_r_subscribe) {	/* Unsubscribe */      sip_add_make(msg, sip, sip_expires_class, "0");      du = nua_dialog_usage_get(nh->nh_ds, nua_subscribe_usage, o);      if (du == NULL && o == NULL) {	du = nua_dialog_usage_get(nh->nh_ds, nua_subscribe_usage, NONE);	if (du && du->du_event)	  sip_add_dup(msg, sip, (sip_header_t *)du->du_event);      }    }    else      /* We allow here SUBSCRIBE without event */      du = nua_dialog_usage_add(nh, nh->nh_ds, nua_subscribe_usage, o);  }  /* Store supported features (eventlist) */  if (du && sip) {    if (du->du_msg)      msg_destroy(du->du_msg);    du->du_msg = msg_ref_create(cr->cr_msg);  }  if (du)    cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,				      process_response_to_subscribe, nh, NULL,				      msg,				      SIPTAG_END(), TAG_NEXT(tags));  eu = nua_dialog_usage_private(du);  if (!cr->cr_orq) {    int substate = nua_substate_terminated;    if (du == NULL)      ;    else if (du->du_ready)      substate = eu->eu_substate; /* We already  */    else      nua_dialog_usage_remove(nh, nh->nh_ds, du);    msg_destroy(msg);    return UA_EVENT3(e, NUA_INTERNAL_ERROR, 		     NUTAG_SUBSTATE(substate), TAG_END());  }  du->du_pending = NULL;  du->du_terminating = e != nua_r_subscribe; /* Unsubscribe or destroy */  if (du->du_terminating)    eu->eu_expires = 0;  else if (sip->sip_expires)    eu->eu_expires = sip->sip_expires->ex_delta;  else    /* We just use common default value, but the default is actually       package-specific according to the RFC 3265 section 4.4.4:       [Event] packages MUST also define a       default "Expires" value to be used if none is specified. */    eu->eu_expires = 3600;      if (sip->sip_expires && sip->sip_expires->ex_delta == 0)    du->du_terminating = 1;  if (eu->eu_substate == nua_substate_terminated)    eu->eu_substate = nua_substate_embryonic;  cr->cr_usage = du;  return cr->cr_event = e;}static void restart_subscribe(nua_handle_t *nh, tagi_t *tags){  nua_creq_restart(nh, nh->nh_cr, process_response_to_subscribe, tags);}static int process_response_to_subscribe(nua_handle_t *nh,					 nta_outgoing_t *orq,					 sip_t const *sip){  nua_client_request_t *cr = nh->nh_cr;  nua_dialog_usage_t *du = cr->cr_usage;   struct event_usage *eu = nua_dialog_usage_private(du);  int status = sip ? sip->sip_status->st_status : 408;  int gracefully = 0;  int substate = nua_substate_embryonic;  assert(du); assert(du->du_class == nua_subscribe_usage);  if (status < 200)    ;  else if (du == NULL) {    /* NOTIFY already removed du */  }  /* We have not received NOTIFY. */  else if (status < 300) {    int win_messenger_enable = NH_PGET(nh, win_messenger_enable);    sip_time_t delta, now = sip_now();    du->du_ready = 1;    substate = eu->eu_substate;        if (cr->cr_event == nua_r_unsubscribe)      delta = 0;    else      /* If there is no expires header,	 use default value stored in eu_expires */      delta = sip_contact_expires(NULL, sip->sip_expires, sip->sip_date, 				  eu->eu_expires, now);    if (!win_messenger_enable)      nua_dialog_uac_route(nh, nh->nh_ds, sip, 1);    nua_dialog_store_peer_info(nh, nh->nh_ds, sip);    if (delta > 0) {      nua_dialog_usage_set_refresh(du, delta);      du->du_pending = refresh_subscribe;    }    else {      if (win_messenger_enable)	/* Wait 4 minutes for NOTIFY from Messenger */	du->du_refresh = now + 4 * 60;       else	/* Wait 32 seconds for NOTIFY */	du->du_refresh = now + 64 * NTA_SIP_T1 / 1000;      du->du_pending = terminate_subscription;    }  }  else /* if (status >= 300) */ {    int terminated;    if (nua_creq_check_restart(nh, cr, orq, sip, restart_subscribe))      return 0;    cr->cr_usage = NULL; /* We take care of removing/not removing usage */    substate = eu->eu_substate;    if (!sip || !sip->sip_retry_after)      gracefully = 1;    terminated =       sip_response_terminates_dialog(status, sip_method_subscribe, 				     &gracefully);    /* XXX - zap dialog if terminated < 0 ? */    if (terminated || !du->du_ready || du->du_terminating) {      substate = nua_substate_terminated;      nua_dialog_usage_remove(nh, nh->nh_ds, du);    }    else if (gracefully && substate != nua_substate_terminated)       /* Post un-subscribe event */      nua_stack_post_signal(nh, nua_r_unsubscribe, 			    SIPTAG_EVENT(du->du_event), 			    SIPTAG_EXPIRES_STR("0"),			    TAG_END());  }  nua_stack_process_response(nh, cr, orq, sip, 			     TAG_IF(substate >= 0, NUTAG_SUBSTATE(substate)),			     TAG_END());  return 0;}/** Refresh subscription */voidrefresh_subscribe(nua_handle_t *nh, nua_dialog_usage_t *du, sip_time_t now){  nua_t *nua = nh->nh_nua;  nua_client_request_t *cr = nh->nh_cr;  nua_event_t e;  msg_t *msg;  sip_t *sip;  if (cr->cr_msg) {		/* Already doing something  */    /* Delay of 5 .. 15 seconds */    du->du_refresh = sip_now() + su_randint(5, 15);    du->du_pending = refresh_subscribe;    return;  }  if (now > 0)    e = nua_r_subscribe;  else    e = nua_r_destroy, du->du_terminating = 1;  cr->cr_msg = msg_copy(du->du_msg);  {    /* Remove initial route */    sip_t *sip = sip_object(cr->cr_msg);    if (sip->sip_route)      msg_header_remove(cr->cr_msg, (msg_pub_t*)sip, (void *)sip->sip_route);  }  msg = nua_creq_msg(nua, nh, cr, 1,		     SIP_METHOD_SUBSCRIBE,		     NUTAG_USE_DIALOG(1),		     NUTAG_ADD_CONTACT(1),		     TAG_IF(du->du_terminating, 			    SIPTAG_EXPIRES_STR("0")),		     TAG_END());  sip = sip_object(msg);  cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,				    process_response_to_subscribe, nh, NULL,				    msg,				    SIPTAG_END(), TAG_NEXT(NULL));  if (!cr->cr_orq) {    struct event_usage *eu = nua_dialog_usage_private(du);    if (du->du_terminating)      nua_dialog_usage_remove(nh, nh->nh_ds, du);    msg_destroy(msg);    UA_EVENT3(e, NUA_INTERNAL_ERROR, 	      NUTAG_SUBSTATE(eu->eu_substate), TAG_END());    return;  }  cr->cr_usage = du;  cr->cr_event = e;}/** Terminate subscription when we have not received a NOTIFY */static void terminate_subscription(nua_handle_t *nh,		       nua_dialog_usage_t *du,		       sip_time_t now){  sip_event_t const *o = NULL;  char const *id;  if (!du) {    SU_DEBUG_1(("nua(%p): terminate_subscription() without usage to remove\n", 		nh));    return;  }  o = du->du_event;  id = o ? o->o_id : NULL;  SU_DEBUG_3(("nua(%p): terminate_subscription() with event %s%s%s\n",	      nh, o ? o->o_type : "(empty)",	      id ? "; id=" : "", id ? id : ""));  nua_stack_event(nh->nh_nua, nh,  NULL,	   nua_i_notify, 408, "Early Subscription Timeouts without NOTIFY", 	   NUTAG_SUBSTATE(nua_substate_terminated),	   SIPTAG_EVENT(o),	   TAG_END());  nua_dialog_usage_remove(nh, nh->nh_ds, du);}/** @internal Process incoming SUBSCRIBE. */int nua_stack_process_subsribe(nua_t *nua,			       nua_handle_t *nh,			       nta_incoming_t *irq,			       sip_t const *sip){  nua_dialog_state_t *ds;  nua_dialog_usage_t *du = NULL;  struct event_usage *eu;  sip_event_t *o = sip->sip_event;  sip_contact_t const *m = NULL;  int status; char const *phrase;  unsigned long expires, refer_expires;  nua_registration_t *nr;  enter;  if (nh)    du = nua_dialog_usage_get(ds = nh->nh_ds, nua_notify_usage, o);  if (nh == NULL || du == NULL) {    /* Hard-coded support only for refer subscriptions */    if (o && str0cmp(o->o_type, "refer") == 0)      nta_incoming_treply(irq, 			  SET_STATUS(481, "Subscription Does Not Exist"), 			  TAG_END());    else      nta_incoming_treply(irq,			  SET_STATUS1(SIP_489_BAD_EVENT), 			  SIPTAG_ALLOW_EVENTS_STR("refer"),			  SIPTAG_ACCEPT_STR("message/sipfrag"),			  TAG_END());    nua_stack_event(nua, nh, nta_incoming_getrequest(irq),	     nua_i_subscribe, status, phrase, 	     NUTAG_SUBSTATE(nua_substate_terminated),	     TAG_END());    return status;  }  /* Refresh existing subscription */  eu = nua_dialog_usage_private(du);  assert(nh && du && eu);  nua_dialog_store_peer_info(nh, nh->nh_ds, sip);  nua_dialog_uas_route(nh, nh->nh_ds, sip, 1);  refer_expires = NH_PGET(nh, refer_expires);  expires = refer_expires;  if (sip->sip_expires) {    expires = sip->sip_expires->ex_delta;    if (expires > refer_expires)      expires = refer_expires;  }  if (expires == 0) {    eu->eu_substate = nua_substate_terminated;    du->du_refresh = sip_now();  }  else {    du->du_refresh = sip_now() + expires;  }  if (eu->eu_substate == nua_substate_pending)    SET_STATUS1(SIP_202_ACCEPTED);  else

⌨️ 快捷键说明

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