[asterisk-commits] mmichelson: branch group/CCSS r229505 - /team/group/CCSS/channels/chan_sip.c
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed Nov 11 14:17:34 CST 2009
Author: mmichelson
Date: Wed Nov 11 14:17:30 2009
New Revision: 229505
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=229505
Log:
Initial work towards supporting PUBLISH in chan_sip.
For now, I've put structures in place for defining a general
purpose event state compositor, as well as some fundamental
code for handling incoming PUBLISH requests.
The code is intended to work as a base so that if we wish to
support PUBLISH for event types other than call-completion,
it is obvious how it should be done, and it shouldn't be
too difficult to do so either.
Modified:
team/group/CCSS/channels/chan_sip.c
Modified: team/group/CCSS/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/group/CCSS/channels/chan_sip.c?view=diff&rev=229505&r1=229504&r2=229505
==============================================================================
--- team/group/CCSS/channels/chan_sip.c (original)
+++ team/group/CCSS/channels/chan_sip.c Wed Nov 11 14:17:30 2009
@@ -1648,6 +1648,202 @@
enum referstatus status; /*!< REFER status */
};
+/*!
+ * Used to create new entity IDs by ESCs.
+ */
+int esc_eid_counter;
+static const int DEFAULT_PUBLISH_EXPIRES = 3600;
+
+enum sip_publish_type {
+ SIP_PUBLISH_UNKNOWN,
+ SIP_PUBLISH_INITIAL,
+ SIP_PUBLISH_REFRESH,
+ SIP_PUBLISH_MODIFY,
+ SIP_PUBLISH_REMOVE,
+};
+
+/*!
+ * \brief common ESC items for all event types
+ *
+ * The entity_id field serves as a means by which
+ * A specific entry may be found.
+ */
+struct sip_esc_entry {
+ /*!
+ * The name of the party who
+ * sent us the PUBLISH. This will more
+ * than likely correspond to a peer name.
+ *
+ * This field's utility isn't really that
+ * great. It's mainly just a user-recognizable
+ * handle that can be printed in debug messages.
+ */
+ const char *device_name;
+ /*!
+ * The entity ID used when corresponding
+ * with the EPA on the other side. As the
+ * ESC, we generate an entity ID for each
+ * received PUBLISH and store it in this
+ * structure.
+ */
+ char *entity_id;
+ /*!
+ * The ID for the scheduler. We schedule
+ * destruction of a sip_esc_entry when we
+ * receive a PUBLISH. The destruction is
+ * scheduled for the duration received in
+ * the Expires header.
+ */
+ int sched_id;
+ /*!
+ * Each ESC entry will be for a specific
+ * event type. Those entries will need to
+ * carry data which is intrinsic to the
+ * ESC entry but which is specific to
+ * the event package
+ */
+ void *event_specific_data;
+};
+
+enum sip_cc_state {
+ CC_CLOSED,
+ CC_OPEN,
+};
+
+/*!
+ * \brief Data specific to CC ESC entries.
+ *
+ * This structure lives in the event_specific_data
+ * section of a sip_esc_entry for the CC ESC.
+ */
+struct cc_esc_entry {
+ /*!
+ * The current state of the device from which
+ * we have received a PUBLISH.
+ */
+ enum sip_cc_state current_state;
+ /*!
+ * The core_id to which this particular ESC entry
+ * pertains. We can determine this information using
+ * either the Request-URI to which the received PUBLISH
+ * was sent, or by seeing in which dialog the PUBLISH
+ * arrived if sent in the same dialog as the SUBSCRIBE-
+ * NOTIFY
+ */
+ int core_id;
+};
+
+/*!
+ * \brief call-completion event state compositor
+ *
+ * The container is of sip_esc_entries. These can
+ * be looked up by their entity ID.
+ */
+struct ao2_container *cc_esc;
+
+/*!
+ * \brief The Event State Compositors
+ *
+ * An Event State Compositor is an entity which
+ * accepts PUBLISH requests and acts appropriately
+ * based on these requests.
+ *
+ * The actual event_state_compositor structure is simply
+ * an ao2_container of sip_esc_entrys. When an incoming
+ * PUBLISH is received, we can match the appropriate sip_esc_entry
+ * using the entity ID of the incoming PUBLISH.
+ */
+static struct event_state_compositor {
+ const char * name;
+ struct ao2_container **compositor;
+} event_state_compositors [] = {
+ {"call-completion", &cc_esc},
+};
+
+static const int ESC_MAX_BUCKETS = 37;
+
+static void esc_entry_destructor(void *obj)
+{
+ struct sip_esc_entry *esc_entry = obj;
+ if (esc_entry->sched_id > -1) {
+ AST_SCHED_DEL(sched, esc_entry->sched_id);
+ }
+ /* We need to add a switch statement or something
+ * here so that we can call the appropriate event-package
+ * destructor function on the event_specific_data
+ */
+}
+
+static int esc_hash_fn(const void *obj, const int flags)
+{
+ const struct sip_esc_entry *entry = obj;
+ return ast_str_hash(entry->entity_id);
+}
+
+static int esc_cmp_fn(void *obj, void *arg, int flags)
+{
+ struct sip_esc_entry *entry1 = obj;
+ struct sip_esc_entry *entry2 = arg;
+
+ return (!strcmp(entry1->entity_id, entry2->entity_id)) ? (CMP_MATCH | CMP_STOP) : 0;
+}
+
+static struct event_state_compositor *get_esc(const char * const event_package) {
+ int i;
+ for (i = 0; i < ARRAY_LEN(event_state_compositors); i++) {
+ if (!strcasecmp(event_package, event_state_compositors[i].name)) {
+ return &event_state_compositors[i];
+ }
+ }
+ return NULL;
+}
+
+static struct sip_esc_entry *get_esc_entry(const char * entity_id, struct event_state_compositor *esc) {
+ struct sip_esc_entry *entry;
+ struct sip_esc_entry finder = { .entity_id = (char *)entity_id };
+
+ entry = ao2_find(*esc->compositor, &finder, OBJ_POINTER);
+
+ return entry;
+}
+
+static struct sip_esc_entry *create_esc_entry(const char *event)
+{
+ struct sip_esc_entry *esc_entry;
+ struct event_state_compositor *esc = get_esc(event);
+
+ if (!esc) {
+ return NULL;
+ }
+
+ if (!(esc_entry = ao2_alloc(sizeof(*esc_entry), esc_entry_destructor))) {
+ return NULL;
+ }
+
+ ao2_link(*esc->compositor, esc_entry);
+ return esc_entry;
+}
+
+static int initialize_escs(void)
+{
+ int i, res = 0;
+ for (i = 0; i < ARRAY_LEN(event_state_compositors); i++) {
+ if (!((*event_state_compositors[i].compositor) =
+ ao2_container_alloc(ESC_MAX_BUCKETS, esc_hash_fn, esc_cmp_fn))) {
+ res = -1;
+ }
+ }
+ return res;
+}
+
+static void destroy_escs(void)
+{
+ int i;
+ for (i = 0; i < ARRAY_LEN(event_state_compositors); i++) {
+ ao2_ref(event_state_compositors[i].compositor, -1);
+ }
+}
+
/*! \brief Struct to handle custom SIP notify requests. Dynamically allocated when needed */
struct sip_notify {
struct ast_variable *headers;
@@ -22204,6 +22400,121 @@
return 1;
}
+static enum sip_publish_type determine_sip_publish_type(struct sip_request *req, const char * const event, const char * const eid)
+{
+ const char *expires = get_header(req, "Expires");
+ int expires_int;
+ int eid_present = !ast_strlen_zero(eid);
+ int body_present = req->lines > 0;
+
+ if (ast_strlen_zero(expires)) {
+ /* Section 6, item 4, second bullet point of RFC 3903 says to
+ * use a locally-configured default expiration if none is provided
+ * in the request
+ */
+ expires_int = DEFAULT_PUBLISH_EXPIRES;
+ } else if (sscanf(expires, "%30d", &expires_int) != 1) {
+ return SIP_PUBLISH_UNKNOWN;
+ }
+
+ if (expires_int == 0) {
+ return SIP_PUBLISH_REMOVE;
+ } else if (!eid_present && body_present) {
+ return SIP_PUBLISH_INITIAL;
+ } else if (eid_present && !body_present) {
+ return SIP_PUBLISH_REFRESH;
+ } else if (eid_present && body_present) {
+ return SIP_PUBLISH_MODIFY;
+ }
+
+ return SIP_PUBLISH_UNKNOWN;
+}
+
+static int handle_sip_publish_initial(struct sip_pvt *p, struct sip_request *req, struct event_state_compositor *esc)
+{
+ /* XXX STUB */
+ return 0;
+}
+static int handle_sip_publish_refresh(struct sip_pvt *p, struct sip_request *req, struct event_state_compositor *esc, const char * const eid)
+{
+ /* XXX STUB */
+ return 0;
+}
+static int handle_sip_publish_modify(struct sip_pvt *p, struct sip_request *req, struct event_state_compositor *esc, const char * const eid)
+{
+ /* XXX STUB */
+ return 0;
+}
+static int handle_sip_publish_remove(struct sip_pvt *p, struct sip_request *req, struct event_state_compositor *esc, const char * const eid)
+{
+ /* XXX STUB */
+ return 0;
+}
+
+static int handle_request_publish(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, const char *uri)
+{
+ const char *eid = get_header(req, "SIP-If-Match");
+ const char *event = get_header(req, "Event");
+ struct event_state_compositor *esc;
+ enum sip_publish_type publish_type;
+ int res;
+
+ if (ast_strlen_zero(event)) {
+ transmit_response(p, "489 Bad Event", req);
+ return -1;
+ }
+
+ if (!(esc = get_esc(event))) {
+ transmit_response(p, "489 Bad Event", req);
+ return -1;
+ }
+
+ /* Okay, we've taken care of the Bad Event scenarios.
+ * We're going to have a hard line that PUBLISHes must
+ * be authenticated.
+ */
+
+ res = check_user(p, req, SIP_PUBLISH, uri, XMIT_RELIABLE, sin);
+ if (res == AUTH_CHALLENGE_SENT) {
+ return 0;
+ } else if (res < 0) {
+ if (res == AUTH_FAKE_AUTH) {
+ ast_log(LOG_NOTICE, "Sending fake auth rejection for device %s\n", get_header(req, "From"));
+ transmit_fake_auth_response(p, SIP_INVITE, req, XMIT_RELIABLE);
+ } else {
+ ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From"));
+ transmit_response_reliable(p, "403 Forbidden", req);
+ }
+ sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+ ast_string_field_set(p, theirtag, NULL);
+ return 0;
+ }
+
+ publish_type = determine_sip_publish_type(req, event, eid);
+
+ switch (publish_type) {
+ case SIP_PUBLISH_UNKNOWN:
+ transmit_response(p, "400 Bad Request", req);
+ break;
+ case SIP_PUBLISH_INITIAL:
+ handle_sip_publish_initial(p, req, esc);
+ break;
+ case SIP_PUBLISH_REFRESH:
+ handle_sip_publish_refresh(p, req, esc, eid);
+ break;
+ case SIP_PUBLISH_MODIFY:
+ handle_sip_publish_modify(p, req, esc, eid);
+ break;
+ case SIP_PUBLISH_REMOVE:
+ handle_sip_publish_remove(p, req, esc, eid);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static void add_peer_mwi_subs(struct sip_peer *peer)
{
struct sip_mailbox *mailbox;
@@ -22737,7 +23048,7 @@
}
}
- if (!e && (p->method == SIP_INVITE || p->method == SIP_SUBSCRIBE || p->method == SIP_REGISTER || p->method == SIP_NOTIFY)) {
+ if (!e && (p->method == SIP_INVITE || p->method == SIP_SUBSCRIBE || p->method == SIP_REGISTER || p->method == SIP_NOTIFY || p->method == SIP_PUBLISH)) {
transmit_response(p, "400 Bad request", req);
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
return -1;
@@ -22762,6 +23073,9 @@
break;
case SIP_MESSAGE:
res = handle_request_message(p, req);
+ break;
+ case SIP_PUBLISH:
+ res = handle_request_publish(p, req, sin, e);
break;
case SIP_SUBSCRIBE:
res = handle_request_subscribe(p, req, sin, seqno, e);
@@ -26912,6 +27226,7 @@
sip_poke_all_peers();
sip_send_all_registers();
sip_send_all_mwi_subscriptions();
+ initialize_escs();
/* And start the monitor for the first time */
restart_monitor();
@@ -27019,6 +27334,7 @@
clear_realm_authentication(authl);
+ destroy_escs();
if (default_tls_cfg.certfile)
ast_free(default_tls_cfg.certfile);
More information about the asterisk-commits
mailing list