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

📄 nea.c

📁 sip协议栈
💻 C
字号:
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 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 nea.c  Nokia Event Client API agent implementation. * * @author Pekka Pessi <Pekka.Pessi@nokia.com> * * @date Created: Wed Feb 14 18:32:58 2001 ppessi */#include "config.h"#include <stddef.h>#include <stdlib.h>#include <string.h>#include <stdio.h>#include <stdarg.h>#include <assert.h>#include <sofia-sip/su_tagarg.h>#include <sofia-sip/sip.h>#include <sofia-sip/sip_header.h>#include <sofia-sip/sip_util.h>#include <sofia-sip/sip_status.h>#define SU_TIMER_ARG_T       struct nea_s#define NTA_LEG_MAGIC_T      struct nea_s#define NTA_OUTGOING_MAGIC_T struct nea_s#define NEA_TIMER_DELTA 2 /* time to resubscribe without expiration */#define EXPIRES_DEFAULT       3600#include <sofia-sip/su_wait.h>#include "sofia-sip/nea.h"struct nea_s {  su_home_t         nea_home[1];  su_timer_t       *nea_timer;  nta_agent_t      *nea_agent;  nta_leg_t        *nea_leg;  nta_outgoing_t   *nea_oreq;		/**< Outstanding request */  sip_to_t         *nea_to;		/**< The other end of subscription :) */  nea_notify_f      nea_callback;	/**< Notify callback  */  nea_magic_t      *nea_context;	/**< Application context */     sip_contact_t    *nea_contact;	/**< */  sip_expires_t    *nea_expires;	/**< Proposed expiration time */  nea_state_t       nea_state;	        /**< State of our subscription */  sip_time_t        nea_deadline;	/**< When our subscription expires */  tagi_t           *nea_args;  unsigned          nea_dialog : 1;     /**< Dialog has been established */  unsigned          nea_notify_received : 1;  unsigned          nea_terminating : 1;  unsigned          nea_strict_3265 : 1;       /**< Strict mode */};int details = 0;static int process_nea_request(nea_t *nea,			       nta_leg_t *leg,			       nta_incoming_t *ireq, 			       sip_t const *sip);static int handle_notify(nta_leg_magic_t *lmagic, 			 nta_leg_t *leg,			 nta_incoming_t *ireq, 			 sip_t const *sip);static int response_to_subscribe(nea_t *nea,				 nta_outgoing_t *req,				 sip_t const *sip);static int response_to_unsubscribe(nea_t *nea,				   nta_outgoing_t *req,				   sip_t const *sip);static void nea_expires_renew(su_root_magic_t *magic,		       su_timer_t *timer,		       nea_t *nea);/* ---------------------------------------------------------- *//** Create a event watcher object. * */nea_t *nea_create(nta_agent_t *agent,		  su_root_t *root,		  nea_notify_f no_callback,		  nea_magic_t *context,		  tag_type_t tag, tag_value_t value, ...){  nea_t *nea = NULL;  ta_list ta;  int have_from, have_to, have_contact;  sip_expires_t const *expires = NULL;  char const *expires_str = NULL;  sip_method_t method = sip_method_subscribe;  char const *SUBSCRIBE = "SUBSCRIBE";  char const *method_name = SUBSCRIBE;  ta_start(ta, tag, value);  have_to =     tl_find(ta_args(ta), siptag_to) || tl_find(ta_args(ta), siptag_to_str);  have_from =     tl_find(ta_args(ta), siptag_from) || tl_find(ta_args(ta), siptag_from_str);  have_contact =    tl_find(ta_args(ta), siptag_contact) ||     tl_find(ta_args(ta), siptag_contact_str);      if (have_to && (nea = su_home_new(sizeof(nea_t)))) {    su_home_t      *home = nea->nea_home;    sip_contact_t  *m = nta_agent_contact(agent);    sip_from_t     *from;    sip_to_t const *to;    int strict = 0;    nea->nea_agent = agent;    nea->nea_callback = no_callback;    nea->nea_context = context;    if (!have_from)       from = sip_from_create(home, (url_string_t*)m->m_url);    else      from = NULL;    nea->nea_args = tl_tlist(home,			     TAG_IF(!have_contact, SIPTAG_CONTACT(m)),			     ta_tags(ta));    /* Get and remove Expires header from tag list */    tl_gets(nea->nea_args, 	    SIPTAG_EXPIRES_REF(expires),	    SIPTAG_EXPIRES_STR_REF(expires_str),	    SIPTAG_TO_REF(to),	    NEATAG_STRICT_3265_REF(strict),	    NTATAG_METHOD_REF(method_name),	    TAG_END());    nea->nea_strict_3265 = strict;    if (to)      nea->nea_to = sip_to_dup(home, to);    if (expires)      nea->nea_expires = sip_expires_dup(home, expires);    else if (expires_str)      nea->nea_expires = sip_expires_make(home, expires_str);    else      nea->nea_expires = sip_expires_create(home, EXPIRES_DEFAULT);    tl_tremove(nea->nea_args, 	       SIPTAG_EXPIRES(0), 	       SIPTAG_EXPIRES_STR(0),	       TAG_END());    if (method_name != SUBSCRIBE)      method = sip_method_code(method_name);    if (method != sip_method_invalid)      /* Create the timer object */      nea->nea_timer = su_timer_create(su_root_task(root), 0L);    if (nea->nea_timer) {      /* Create leg for NOTIFY requests */      nea->nea_leg = nta_leg_tcreate(nea->nea_agent, 				     process_nea_request, nea,				     TAG_IF(!have_from, SIPTAG_FROM(from)),				     TAG_NEXT(nea->nea_args));      if (nea->nea_leg) {	nta_leg_tag(nea->nea_leg, NULL);	nea->nea_oreq = nta_outgoing_tcreate(nea->nea_leg,					     response_to_subscribe, nea,					     NULL,					     method, method_name,					     NULL,					     SIPTAG_EXPIRES(nea->nea_expires),					     TAG_NEXT(nea->nea_args));      }    }    if (!nea->nea_leg ||	!nea->nea_oreq ||	!nea->nea_timer)       nea_destroy(nea), nea = NULL;  }  ta_end(ta);  return nea;}int nea_update(nea_t *nea, 	       tag_type_t tag,	       tag_value_t value,	       ...){  ta_list ta;  sip_expires_t const *expires = NULL;  sip_payload_t const *pl = NULL;  sip_content_type_t const *ct = NULL;  char const *cts = NULL;  /* char const *expires_str = NULL; */  su_home_t *home = nea->nea_home;  /* XXX - hack, previous request still waiting for response */  if (!nea->nea_leg || nea->nea_oreq)    return -1;      ta_start(ta, tag, value);    tl_gets(ta_args(ta),	  SIPTAG_CONTENT_TYPE_REF(ct),	  SIPTAG_CONTENT_TYPE_STR_REF(cts),	  SIPTAG_PAYLOAD_REF(pl),	  SIPTAG_EXPIRES_REF(expires),	  TAG_NULL());    if (!pl || (!ct && !cts)) {    ta_end(ta);    return -1;  }  tl_tremove(nea->nea_args, 	     SIPTAG_CONTENT_TYPE(0),	     SIPTAG_CONTENT_TYPE_STR(0),	     SIPTAG_PAYLOAD(0),	     SIPTAG_PAYLOAD_STR(0),	     TAG_END());  su_free(home, nea->nea_expires);  if (expires)    nea->nea_expires = sip_expires_dup(home, expires);  else    nea->nea_expires = sip_expires_create(home, EXPIRES_DEFAULT);  /* nta_leg_tag(nea->nea_leg, NULL); */  nea->nea_oreq = nta_outgoing_tcreate(nea->nea_leg,				       response_to_subscribe, nea,				       NULL,				       SIP_METHOD_SUBSCRIBE,				       NULL, 				       SIPTAG_TO(nea->nea_to),				       SIPTAG_PAYLOAD(pl),				       TAG_IF(ct, SIPTAG_CONTENT_TYPE(ct)), 				       TAG_IF(cts, SIPTAG_CONTENT_TYPE_STR(cts)),				       SIPTAG_EXPIRES(nea->nea_expires),				       TAG_NEXT(nea->nea_args));  ta_end(ta);  if (!nea->nea_oreq)     return -1;  return 0;}/** Unsubscribe the agent. */void nea_end(nea_t *nea){  if (nea == NULL)    return;  nea->nea_terminating = 1;  su_timer_destroy(nea->nea_timer), nea->nea_timer = NULL;  if (nea->nea_leg && nea->nea_deadline) {    nea->nea_oreq =      nta_outgoing_tcreate(nea->nea_leg,			   response_to_unsubscribe,			   nea,			   NULL,			   SIP_METHOD_SUBSCRIBE,			   NULL,			   SIPTAG_EXPIRES_STR("0"),			   TAG_NEXT(nea->nea_args));  }}void nea_destroy(nea_t *nea){  if (nea == NULL)    return;  if (nea->nea_oreq)    nta_outgoing_destroy(nea->nea_oreq), nea->nea_oreq = NULL;  if (nea->nea_leg)    nta_leg_destroy(nea->nea_leg), nea->nea_leg = NULL;  if (nea->nea_timer) {    su_timer_reset(nea->nea_timer);    su_timer_destroy(nea->nea_timer), nea->nea_timer = NULL;  }  su_free(NULL, nea);}/* Function called by NTA to handle incoming requests belonging to the leg */int process_nea_request(nea_t *nea, 			nta_leg_t *leg,			nta_incoming_t *ireq, 			sip_t const *sip){  switch (sip->sip_request->rq_method) {  case sip_method_notify:    return handle_notify(nea, leg, ireq, sip);  case sip_method_ack:      return 400;  default:    nta_incoming_treply(ireq, SIP_405_METHOD_NOT_ALLOWED,			SIPTAG_ALLOW_STR("NOTIFY"), TAG_END());    return 405;  }}/* Callback function to handle subscription requests */int response_to_subscribe(nea_t *nea,			  nta_outgoing_t *oreq,			  sip_t const *sip){  int status = sip->sip_status->st_status;  int error = status >= 300;  if (status >= 200 && oreq == nea->nea_oreq)    nea->nea_oreq = NULL;  nea->nea_callback(nea, nea->nea_context, sip);  if (status < 200)    return 0;  nea->nea_oreq = NULL;  if (status < 300) {    sip_time_t now = sip_now();    if (!nea->nea_notify_received) {      nea->nea_deadline = now +	sip_contact_expires(NULL, sip->sip_expires, sip->sip_date, 			    EXPIRES_DEFAULT, now);      if (sip->sip_to->a_tag && !nea->nea_dialog) {	nea->nea_dialog = 1;	nta_leg_rtag(nea->nea_leg, sip->sip_to->a_tag);	nta_leg_client_route(nea->nea_leg, 			     sip->sip_record_route, sip->sip_contact);      }    }  }  else {    nea->nea_deadline = 0;    nea->nea_state = nea_terminated;    if (status == 301 || status == 302 || status == 305) {      sip_contact_t *m;      for (m = sip->sip_contact; m; m = m->m_next) {	if (m->m_url->url_type == url_sip ||	    m->m_url->url_type == url_sips)	  break;      }      if (m) {	url_string_t const *proxy, *url;	if (status == 305)	  url = NULL, proxy = (url_string_t *)m->m_url;	else	  url = (url_string_t *)m->m_url, proxy = NULL;	nea->nea_oreq =	  nta_outgoing_tcreate(nea->nea_leg,			       response_to_subscribe,			       nea,			       proxy,			       SIP_METHOD_SUBSCRIBE,			       url,			       SIPTAG_EXPIRES(nea->nea_expires),			       TAG_NEXT(nea->nea_args));      }    } else if (status == 423 && sip->sip_min_expires) {      unsigned value = sip->sip_min_expires->me_delta;      su_free(nea->nea_home, nea->nea_expires);      nea->nea_expires = sip_expires_format(nea->nea_home, "%u", value);      nea->nea_oreq =	nta_outgoing_tcreate(nea->nea_leg,			     response_to_subscribe,			     nea,			     NULL,			     SIP_METHOD_SUBSCRIBE,			     NULL,			     SIPTAG_EXPIRES(nea->nea_expires),			     TAG_NEXT(nea->nea_args));    }  }  if (status >= 200)    nta_outgoing_destroy(oreq);  if (nea->nea_oreq || !error) {    su_time_t now = su_now();    now.tv_sec = nea->nea_deadline;    su_timer_set_at(nea->nea_timer, 		    nea_expires_renew, 		    nea,		    now);  }  else    nea->nea_callback(nea, nea->nea_context, NULL);      return 0;}int response_to_unsubscribe(nea_t *nea,			    nta_outgoing_t *orq,			    sip_t const *sip){  int status = sip->sip_status->st_status;  nea->nea_callback(nea, nea->nea_context, sip);  if (status >= 200)    nta_outgoing_destroy(orq), nea->nea_oreq = NULL;  if (status >= 300)     nea->nea_callback(nea, nea->nea_context, NULL);  return 0;}/** handle notifications */int handle_notify(nea_t *nea, 		  nta_leg_t *leg,		  nta_incoming_t *irq, 		  sip_t const *sip){  sip_subscription_state_t *ss = sip->sip_subscription_state;  sip_subscription_state_t ss0[1];  char expires[32];  if (nea->nea_strict_3265) {    char const *phrase = NULL;    if (ss == NULL)      phrase = "NOTIFY Has No Subscription-State Header";    else if (sip->sip_event == NULL)       phrase = "Event Header Missing";          if (phrase) {      nta_incoming_treply(irq, 400, phrase, TAG_END());      nta_incoming_destroy(irq);      nta_leg_destroy(nea->nea_leg), nea->nea_leg = NULL;      nea->nea_state = nea_terminated;      nea->nea_callback(nea, nea->nea_context, NULL);      return 0;    }  }  if (ss == NULL) {    /* Do some compatibility stuff here */    unsigned long delta = 3600;    sip_subscription_state_init(ss = ss0);    if (sip->sip_expires)      delta = sip->sip_expires->ex_delta;    if (delta == 0)      ss->ss_substate = "terminated";    else      ss->ss_substate = "active";    if (delta > 0) {      snprintf(expires, sizeof expires, "%lu", delta);      ss->ss_expires = expires;    }  }  if (!nea->nea_dialog) {    nea->nea_dialog = 1;    nta_leg_rtag(nea->nea_leg, sip->sip_from->a_tag);    nta_leg_server_route(nea->nea_leg, 			 sip->sip_record_route, sip->sip_contact);  }  nea->nea_notify_received = 1;  nea->nea_callback(nea, nea->nea_context, sip);  if (strcasecmp(ss->ss_substate, "terminated") == 0) {    nta_leg_destroy(nea->nea_leg), nea->nea_leg = NULL;    nea->nea_state = nea_terminated;    if (str0casecmp(ss->ss_reason, "deactivated") == 0) {      nea->nea_state = nea_embryonic;      nea->nea_deadline = sip_now();    } else if (str0casecmp(ss->ss_reason, "probation") == 0) {      sip_time_t retry = sip_now() + NEA_TIMER_DELTA;      if (ss->ss_retry_after)	retry += strtoul(ss->ss_retry_after, NULL, 10);      else	retry += NEA_TIMER_DELTA;      nea->nea_state = nea_embryonic;      nea->nea_deadline = retry;    } else {      nea->nea_deadline = 0;      nea->nea_callback(nea, nea->nea_context, NULL);      return 200;    }  }  else if (strcasecmp(ss->ss_substate, "pending") == 0)     nea->nea_state = nea_pending;  else if (strcasecmp(ss->ss_substate, "active") == 0)     nea->nea_state = nea_active;  else    nea->nea_state = nea_extended;  if (nea->nea_state != nea_embryonic && ss->ss_expires) {    unsigned retry = strtoul(ss->ss_expires, NULL, 10);    if (retry > 60) retry -= 30; else retry /= 2;    nea->nea_deadline = sip_now() + retry;  }  {    su_time_t now = su_now();    now.tv_sec = nea->nea_deadline;    su_timer_set_at(nea->nea_timer, 		    nea_expires_renew, 		    nea,		    now);  }  return 200;}void nea_expires_renew(su_root_magic_t *magic,		       su_timer_t *timer,		       nea_t *nea){  sip_time_t now = sip_now();  /* re-subscribe if expires soon */  if (nea->nea_state == nea_terminated ||      nea->nea_deadline == 0 ||       nea->nea_deadline > now + NEA_TIMER_DELTA)    return;  if (!nea->nea_notify_received)	/* Hmph. */    return;  nea->nea_notify_received = 0;  nea->nea_oreq =    nta_outgoing_tcreate(nea->nea_leg,			 response_to_subscribe,			 nea,			 NULL,			 SIP_METHOD_SUBSCRIBE,			 NULL,			 SIPTAG_EXPIRES(nea->nea_expires),			 TAG_NEXT(nea->nea_args));      return;}

⌨️ 快捷键说明

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