📄 nea_server.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 * *//**@file nea_server.c * @brief Nokia Event API - event notifier implementation. * * @author Pekka Pessi <Pekka.Pessi@nokia.com> * @author Martti Mela <Martti.Mela@nokia.com> * * @date Created: Wed Feb 14 18:37:04 EET 2001 ppessi */#include "config.h"#include <sofia-sip/sip.h>#include <sofia-sip/sip_header.h>#include <sofia-sip/sip_util.h>#include <sofia-sip/sip_status.h>#include <sofia-sip/su_tagarg.h>#include "nea_debug.h"#define NONE ((void *)- 1)#define SU_ROOT_MAGIC_T struct nea_server_s#define SU_MSG_ARG_T tagi_t#define NTA_AGENT_MAGIC_T struct nea_server_s#define NTA_LEG_MAGIC_T struct nea_sub_s#define NTA_INCOMING_MAGIC_T struct nea_sub_s#define NTA_OUTGOING_MAGIC_T struct nea_sub_s#include <sofia-sip/nea.h>#include <sofia-sip/htable.h>#include <stddef.h>#include <stdlib.h>#include <string.h>#include <stdio.h>#include <stdarg.h>#include <assert.h>#include <limits.h>/** Number of primary views (with different MIME type or content) */#define NEA_VIEW_MAX (8)/** Server object, created for every notifier. */struct nea_server_s { su_home_t nes_home[1]; su_root_t *nes_root; su_timer_t *nes_timer; nta_agent_t *nes_agent; nta_leg_t *nes_leg; nea_sub_t *nes_subscribers; sip_require_t *nes_require; sip_time_t nes_min_expires; sip_time_t nes_expires; sip_time_t nes_max_expires; int nes_max_subs; unsigned nes_throttle; /**< Default throttle */ unsigned nes_min_throttle; /**< Minimum throttle */ unsigned nes_eventlist:1; /**< Eventlist only */ unsigned nes_in_callback : 1; unsigned nes_pending_destroy : 1; unsigned nes_pending_flush : 1; unsigned nes_202_before_notify:1; unsigned nes_in_list; unsigned nes_throttled; /**< Throttled notifications? */ char const *nes_server; sip_contact_t *nes_eventity_uri; sip_allow_events_t *nes_allow_events; sip_allow_t *nes_allow_methods; nea_new_event_f *nes_callback; nea_smagic_t *nes_context; /** Events. * Each subscriber will be added to one of these. */ nea_event_t *nes_events;};/** Supported events and their subscribers */struct nea_event_s { nea_event_t *ev_next; nea_event_t **ev_prev; nea_watcher_f *ev_callback; nea_emagic_t *ev_magic; unsigned ev_throttle; /**< Default throttle */ unsigned ev_min_throttle; /**< Minimum throttle */ unsigned ev_eventlist:1; /**< Eventlist is supported */ unsigned ev_reliable:1; /**< Keep all notifications */ unsigned :0; /** Sequence number of first unsent update */ unsigned ev_throttling; unsigned ev_updated; /**< Sequence number for updates */ sip_require_t *ev_require; /**< Required features */ sip_supported_t *ev_supported; /**< Supported features */ sip_event_t *ev_event; sip_accept_t const *ev_default;/**< Default content type */ sip_accept_t const *ev_accept; /**< Supported content types */ nea_event_view_t *ev_views[NEA_VIEW_MAX + 1];};typedef struct nea_event_queue_s nea_event_queue_t;/** Object representing particular view of event */struct nea_event_view_s{ nea_event_view_t *evv_next; nea_event_view_t *evv_primary; /**< Backpointer to the primary view */ nea_evmagic_t *evv_magic; unsigned evv_throttle; /**< Default throttle */ unsigned evv_min_throttle; /**< Minimum throttle */ unsigned evv_fake:1; /**< This is "fake" (ie. default) view */ unsigned evv_private:1; /**< This is private view */ unsigned evv_reliable:1; /**< Keep all notifications */ unsigned:0; /** Queued notification */ struct nea_event_queue_s { nea_event_queue_t *evq_next; unsigned evq_updated; unsigned evq_version; sip_content_type_t *evq_content_type; sip_payload_t *evq_payload; } evv_head[1];};#define evv_version evv_head->evq_version#define evv_updated evv_head->evq_updated#define evv_content_type evv_head->evq_content_type#define evv_payload evv_head->evq_payload/** Subscription object */struct nea_sub_s { nea_sub_t *s_next; nea_sub_t **s_prev; nta_leg_t *s_leg; nta_incoming_t *s_irq; nta_outgoing_t *s_oreq; nea_server_t *s_nes; sip_contact_t *s_local; /**< Local contact */ sip_from_t *s_from; sip_contact_t *s_remote; /**< Remote contact */ /* sip_accept_t *s_accept; */ sip_event_t *s_id; nea_event_t *s_event; nea_event_view_t *s_view; nea_state_t s_state; char const *s_extended; sip_content_type_t *s_content_type; /** Content-Type of SUBSCRIBE body. */ sip_payload_t *s_payload; /**< Body of SUBSCRIBE. */ unsigned s_processing : 1; unsigned s_rejected : 1; unsigned s_pending_flush : 1; unsigned s_garbage : 1; unsigned s_fake : 1; /**< Do not send real information to user */ unsigned s_eventlist : 1; /**< Subscriber supported eventlist */ sip_time_t s_subscribed; /**< When first SUBSCRIBE was recv */ sip_time_t s_notified; /**< When last notification was sent */ sip_time_t s_expires; /**< Expiration time. */ unsigned s_version; /**< Version number set by application */ unsigned s_latest; /**< External version of latest payload */ unsigned s_updated; /**< Internal version of latest payload */ unsigned s_throttle; /**< Minimum time between notifications */};/* Prototypes */static void nea_server_pending_flush(nea_server_t *nes);static int nea_view_update(nea_server_t *nes, nea_event_t *ev, nea_event_view_t **evvp, int private, int fake, tag_type_t tag, tag_value_t value, ...);static nea_sub_t *nea_sub_create(nea_server_t *nes);static int nea_sub_is_removed(nea_sub_t const *s);static void nea_sub_remove(nea_sub_t *s);static void nea_sub_destroy(nea_sub_t *s);staticint nea_server_callback(nea_sub_t *nes_as_sub, nta_leg_t *leg, nta_incoming_t *irq, sip_t const *sip);static int nea_sub_process_incoming(nea_sub_t *s, nta_leg_t *leg, nta_incoming_t *irq, sip_t const *sip);static int nea_sub_process_subscribe(nea_sub_t *s, nta_leg_t *leg, nta_incoming_t *irq, sip_t const *sip);static int nea_sub_notify(nea_server_t *nes, nea_sub_t *s, sip_time_t now, tag_type_t tag, tag_value_t value, ...);static int response_to_notify(nea_sub_t *s, nta_outgoing_t *oreq, sip_t const *sip);static void nes_event_timer(nea_server_t *nes, su_timer_t *timer, su_timer_arg_t *arg);static int nea_view_queue(nea_server_t *nes, nea_event_view_t *evv, nea_event_queue_t *evq);/** Assign an event view to subscriber. */static inlinevoid nea_sub_assign_view(nea_sub_t *s, nea_event_view_t *evv){ if (s->s_view != evv) /* Make sure we send a notification */ s->s_updated = evv->evv_updated - 1; s->s_view = evv; s->s_throttle = evv->evv_throttle;}static inline void nea_subnode_init(nea_subnode_t *sn, nea_sub_t *s, sip_time_t now){ sn->sn_state = s->s_state; sn->sn_fake = s->s_fake; sn->sn_subscriber = s; sn->sn_event = s->s_event; sn->sn_remote = s->s_from; sn->sn_contact = s->s_remote; sn->sn_content_type = s->s_content_type; sn->sn_payload = s->s_payload; if (s->s_expires != 0 && (int)(s->s_expires - now) > 0) sn->sn_expires = s->s_expires - now; else sn->sn_expires = 0; sn->sn_latest = s->s_latest; sn->sn_throttle = s->s_throttle; sn->sn_eventlist = s->s_eventlist; sn->sn_version = s->s_version; sn->sn_subscribed = now - s->s_subscribed; sn->sn_notified = s->s_notified; sn->sn_view = s->s_view;}/** Create an event server. * * The function nea_server_create() initializes an event server object and * registers it with @b nta. An event server object takes care of all events * for a particular URI (@em eventity). * * @param agent pointer to an @b nta agent object * @param root pointer to an @b root object *燖param url url of the server to be created * @param max_subs maximum number of subscriptions * @param callback authorization function, * or @c NULL if no authorization is required * @param context server context (pointer to application data) * @param tag, value, ... optional list of tag parameters * * @TAGS * The function nea_server_create() takes the following tag values as its * arguments: * <dl> * * <dt>SIPTAG_CONTACT() or SIPTAG_CONTACT_STR() * <dd>The target address of the event server. * * <dt>SIPTAG_ALLOW_EVENTS() * <dd>The initial list of events supported by eventity. This list is * extended whenever a new event is created with nea_event_tcreate(). * * <dt>SIPTAG_SERVER_STR() * <dd>The @b Server header for the event server. * * <dt>NEATAG_MINSUB() * <dd>Minimum duration of a subscription. * * <dt>NEATAG_THROTTLE() * <dd>Default value for event throttle (by default, 5 seconds). * Throttle determines the minimum interval betweeen notifications. Note * that the notification indicating that the subscription has terminated * will be sent regardless of throttle. * * The default throttle value is used if the subscriber does not include * a throttle parameter in @ref sip_event "Event" header of SUBSCRIBE request. * * <dt>NEATAG_MINTHROTTLE() * <dd>Minimum allowed throttle value (by default, 5 seconds). * * <dt>NEATAG_EVENTLIST() * <dd>If true, the subscribers must support eventlists. If SIPTAG_REQUIRE() * is given, it must contain the "eventlist" feature. * * <dt>NEATAG_DIALOG() * <dd>Give an optional NTA destination leg to event server. * * <dt>SIPTAG_REQUIRE()/SIPTAG_REQUIRE_STR() * <dd>The @b Require header for the event server. The subscribers must * indicate support the specified features. * * </dl> * * @return * The function nea_server_create() returns a pointer to an event server * object, or @c NULL upon an error. */nea_server_t *nea_server_create(nta_agent_t *agent, su_root_t *root, url_t const *url, int max_subs, nea_new_event_f *callback, nea_smagic_t *context, tag_type_t tag, tag_value_t value, ...){ nea_server_t *nes = NULL; sip_contact_t const *contact = NULL; sip_allow_events_t const *allow_events = NULL; sip_require_t const *rq = NULL; char const *contact_str = NULL; char const *server_str = NULL; char const *rq_str = NULL; unsigned min_expires = 15 * 60, expires = NEA_DEFAULT_EXPIRES, max_expires = 24 * 60 * 60; nta_leg_t *leg = NONE; unsigned throttle = 5, min_throttle = throttle; int eventlist = 0; { ta_list ta; ta_start(ta, tag, value); tl_gets(ta_args(ta), SIPTAG_CONTACT_REF(contact), SIPTAG_CONTACT_STR_REF(contact_str), SIPTAG_ALLOW_EVENTS_REF(allow_events), SIPTAG_SERVER_STR_REF(server_str), SIPTAG_REQUIRE_REF(rq), SIPTAG_REQUIRE_STR_REF(rq_str), NEATAG_MIN_EXPIRES_REF(min_expires), NEATAG_EXPIRES_REF(expires), NEATAG_MAX_EXPIRES_REF(max_expires), NEATAG_DIALOG_REF(leg), NEATAG_THROTTLE_REF(throttle), NEATAG_MINTHROTTLE_REF(min_throttle), NEATAG_EVENTLIST_REF(eventlist), TAG_NULL()); ta_end(ta); } if (throttle < min_throttle) throttle = min_throttle; if (!url) { SU_DEBUG_5(("nea_server_create(): invalid url\n")); return NULL; } if (min_expires > expires || expires > max_expires) { SU_DEBUG_5(("nea_server_create(): invalid expiration range\n")); return NULL; } nes = su_home_new(sizeof(nea_server_t)); if (nes) { su_home_t *home = nes->nes_home; nes->nes_root = root; nes->nes_agent = agent; nes->nes_max_subs = max_subs; nes->nes_min_expires = min_expires; nes->nes_expires = expires; nes->nes_max_expires = max_expires; nes->nes_throttle = throttle; nes->nes_min_throttle = min_throttle; if (allow_events) nes->nes_allow_events = sip_allow_events_dup(home, allow_events); else nes->nes_allow_events = sip_allow_events_make(home, ""); nes->nes_allow_methods = sip_allow_make(home, "SUBSCRIBE"); nes->nes_server = su_sprintf(home, "%s%snea/" NEA_VERSION_STR " %s", server_str ? server_str : "", server_str ? " " : "", nta_agent_version(agent)); if (contact) nes->nes_eventity_uri = sip_contact_dup(home, contact); else if (contact_str) nes->nes_eventity_uri = sip_contact_make(home, contact_str); else nes->nes_eventity_uri = sip_contact_create(home, (url_string_t *)url, NULL); if (leg != NONE) { nes->nes_leg = leg; if (leg != NULL) nta_leg_bind(leg, nea_server_callback, (nea_sub_t*)nes); } else { nes->nes_leg = nta_leg_tcreate(agent, nea_server_callback, (nea_sub_t*)nes, NTATAG_NO_DIALOG(1),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -