[asterisk-commits] mmichelson: branch mmichelson/subscription_abstraction r416236 - in /team/mmi...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Jun 13 18:07:52 CDT 2014


Author: mmichelson
Date: Fri Jun 13 18:07:48 2014
New Revision: 416236

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=416236
Log:
Commit some progress towards this effort.

Unfortunately, I've simply run out of time for the day
so this is a big garbled mess at the moment. This does
not even come close to compiling right now.

I've made the necessary changes to res_pjsip_pubsub.h, and
I'm working on the pubsub core before I start adjusting
subscription handlers' calls to the API.


Modified:
    team/mmichelson/subscription_abstraction/include/asterisk/res_pjsip_pubsub.h
    team/mmichelson/subscription_abstraction/res/res_pjsip_pubsub.c

Modified: team/mmichelson/subscription_abstraction/include/asterisk/res_pjsip_pubsub.h
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/subscription_abstraction/include/asterisk/res_pjsip_pubsub.h?view=diff&rev=416236&r1=416235&r2=416236
==============================================================================
--- team/mmichelson/subscription_abstraction/include/asterisk/res_pjsip_pubsub.h (original)
+++ team/mmichelson/subscription_abstraction/include/asterisk/res_pjsip_pubsub.h Fri Jun 13 18:07:48 2014
@@ -222,19 +222,20 @@
 };
 
 #define AST_SIP_MAX_ACCEPT 32
-
-struct ast_sip_subscription_handler {
-	/*! The name of the event this handler deals with */
-	const char *event_name;
-	/*! The types of body this handler accepts.
-	 *
-	 * \note This option has no bearing when the handler is used in the
-	 * notifier role. When in a subscriber role, this header is used to
-	 * populate the Accept: header of an outbound SUBSCRIBE request
-	 */
-	const char *accept[AST_SIP_MAX_ACCEPT];
-	/*!
-	 * \brief Default body type defined for the event package this handler handles.
+enum ast_sip_subscription_notify_reason {
+	/*! Initial NOTIFY for subscription */
+	AST_SIP_SUBSCRIPTION_NOTIFY_REASON_STARTED,
+	/*! Subscription has been renewed */
+	AST_SIP_SUBSCRIPTION_NOTIFY_REASON_RENEWED,
+	/*! Subscription is being terminated */
+	AST_SIP_SUBSCRIPTION_NOTIFY_REASON_TERMINATED,
+	/*! Other unspecified reason */
+	AST_SIP_SUBSCRIPTION_NOTIFY_REASON_OTHER
+};
+
+struct ast_sip_notifier {
+	/*!
+	 * \brief Default body type defined for the event package this notifier handles.
 	 *
 	 * Typically, a SUBSCRIBE request will contain one or more Accept headers that tell
 	 * what format they expect the body of NOTIFY requests to use. However, every event
@@ -243,163 +244,95 @@
 	 */
 	const char *default_accept;
 	/*!
+	 * \brief Called when a SUBSCRIBE arrives attempting to establish a new subscription.
+	 *
+	 * The notifier is expected to return the response that should be sent to the
+	 * SUBSCRIBE request.
+	 *
+	 * If a 200-class response is returned, then the notifier's notify_required
+	 * callback will immediately be called into with a reason of
+	 * AST_SIP_SUBSCRIPTION_NOTIFY_REASON_STARTED.
+	 *
+	 * \param endpoint The endpoint from which we received the SUBSCRIBE
+	 * \param resource The name of the resource to which the subscription is being made
+	 * \return The response code to send to the SUBSCRIBE.
+	 */
+	struct ast_sip_subscription *(*new_subscribe)(struct ast_sip_endpoint *endpoint,
+			const char *resource);
+	/*!
+	 * \brief The subscription is in need of a NOTIFY request.
+	 *
+	 * A reason of AST_SIP_SUBSCRIPTION_NOTIFY_REASON_STARTED is given immediately
+	 * after a SUBSCRIBE is accepted. This is a good opportunity for the notifier to
+	 * perform setup duties such as establishing Stasis subscriptions or adding
+	 * datastores to the subscription.
+	 *
+	 * A reason of AST_SIP_SUBSCRIPTION_NOTIFY_REASON_TERMINATED is given when the
+	 * subscriber has terminated the subscription. If there are any duties that the
+	 *
+	 *
+	 * \param sub The subscription to send the NOTIFY on.
+	 * \param reason The reason why the NOTIFY is being sent.
+	 */
+	void (notify_required)(struct ast_sip_subscription *sub, enum ast_sip_subscription_notify_reason reason);
+};
+
+struct ast_sip_subscriber {
+	/*! The types of body this subscriber accepts. */
+	const char *accept[AST_SIP_MAX_ACCEPT];
+	/*!
+	 * \brief A NOTIFY has been received.
+	 *
+	 * The body of the NOTIFY is provided so that it may be parsed and appropriate
+	 * internal state change may be generated.
+	 *
+	 * The state can be used to determine if the subscription has been terminated
+	 * by the far end or if this is just a typical resource state change.
+	 *
+	 * \param sub The subscription on which the NOTIFY arrived
+	 * \param body The body of the NOTIFY
+	 * \param state The subscription state
+	 */
+	void (*state_change)(struct ast_sip_subscription *sub, const char *body, enum pjsip_evsub_state state);
+};
+
+struct ast_sip_subscription_handler {
+	/*! The name of the event this subscriber deals with */
+	const char *event_name;
+	/*!
 	 * \brief Called when a subscription is to be destroyed
-	 *
-	 * This is a subscriber and notifier callback.
 	 *
 	 * The handler is not expected to send any sort of requests or responses
 	 * during this callback. The handler MUST, however, begin the destruction
 	 * process for the subscription during this callback.
 	 */
 	void (*subscription_shutdown)(struct ast_sip_subscription *subscription);
-
-	/*!
-	 * \brief Called when a SUBSCRIBE arrives in order to create a new subscription
-	 *
-	 * This is a notifier callback.
-	 *
-	 * If the notifier wishes to accept the subscription, then it can create
-	 * a new ast_sip_subscription to do so.
-	 *
-	 * If the notifier chooses to create a new subscription, then it must accept
-	 * the incoming subscription using pjsip_evsub_accept() and it must also
-	 * send an initial NOTIFY with the current subscription state.
-	 *
-	 * \param endpoint The endpoint from which we received the SUBSCRIBE
-	 * \param rdata The SUBSCRIBE request
-	 * \retval NULL The SUBSCRIBE has not been accepted
-	 * \retval non-NULL The newly-created subscription
-	 */
-	struct ast_sip_subscription *(*new_subscribe)(struct ast_sip_endpoint *endpoint,
-			pjsip_rx_data *rdata);
-
-	/*!
-	 * \brief Called when an endpoint renews a subscription.
-	 *
-	 * This is a notifier callback.
-	 *
-	 * Because of the way that the PJSIP evsub framework works, it will automatically
-	 * send a response to the SUBSCRIBE. However, the subscription handler must send
-	 * a NOTIFY with the current subscription state when this callback is called.
-	 *
-	 * The response_data that is passed into this callback is used to craft what should
-	 * be in the response to the incoming SUBSCRIBE. It is initialized with a 200 status
-	 * code and all other parameters are empty.
-	 *
-	 * \param sub The subscription that is being renewed
-	 * \param rdata The SUBSCRIBE request in question
-	 * \param[out] response_data Data pertaining to the SIP response that should be
-	 * sent to the SUBSCRIBE
-	 */
-	void (*resubscribe)(struct ast_sip_subscription *sub,
-			pjsip_rx_data *rdata, struct ast_sip_subscription_response_data *response_data);
-
-	/*!
-	 * \brief Called when a subscription times out.
-	 *
-	 * This is a notifier callback
-	 *
-	 * This indicates that the subscription has timed out. The subscription handler is
-	 * expected to send a NOTIFY that terminates the subscription.
-	 *
-	 * \param sub The subscription that has timed out
-	 */
-	void (*subscription_timeout)(struct ast_sip_subscription *sub);
-
-	/*!
-	 * \brief Called when a subscription is terminated via a SUBSCRIBE or NOTIFY request
-	 *
-	 * This is a notifier and subscriber callback.
-	 *
-	 * The PJSIP subscription framework will automatically send the response to the
-	 * request. If a notifier receives this callback, then the subscription handler
-	 * is expected to send a final NOTIFY to terminate the subscription.
-	 *
-	 * \param sub The subscription being terminated
-	 * \param rdata The request that terminated the subscription
-	 */
-	void (*subscription_terminated)(struct ast_sip_subscription *sub, pjsip_rx_data *rdata);
-
-	/*!
-	 * \brief Called when a subscription handler's outbound NOTIFY receives a response
-	 *
-	 * This is a notifier callback.
-	 *
-	 * \param sub The subscription
-	 * \param rdata The NOTIFY response
-	 */
-	void (*notify_response)(struct ast_sip_subscription *sub, pjsip_rx_data *rdata);
-
-	/*!
-	 * \brief Called when a subscription handler receives an inbound NOTIFY
-	 *
-	 * This is a subscriber callback.
-	 *
-	 * Because of the way that the PJSIP evsub framework works, it will automatically
-	 * send a response to the NOTIFY. By default this will be a 200 OK response, but
-	 * this callback can change details of the response by returning response data
-	 * to use.
-	 *
-	 * The response_data that is passed into this callback is used to craft what should
-	 * be in the response to the incoming SUBSCRIBE. It is initialized with a 200 status
-	 * code and all other parameters are empty.
-	 *
-	 * \param sub The subscription
-	 * \param rdata The NOTIFY request
-	 * \param[out] response_data Data pertaining to the SIP response that should be
-	 * sent to the SUBSCRIBE
-	 */
-	void (*notify_request)(struct ast_sip_subscription *sub,
-			pjsip_rx_data *rdata, struct ast_sip_subscription_response_data *response_data);
-
-	/*!
-	 * \brief Called when it is time for a subscriber to resubscribe
-	 *
-	 * This is a subscriber callback.
-	 *
-	 * The subscriber can reresh the subscription using the pjsip_evsub_initiate()
-	 * function.
-	 *
-	 * \param sub The subscription to refresh
-	 * \retval 0 Success
-	 * \retval non-zero Failure
-	 */
-	int (*refresh_subscription)(struct ast_sip_subscription *sub);
-
 	/*!
 	 * \brief Converts the subscriber to AMI
-	 *
-	 * This is a subscriber callback.
 	 *
 	 * \param sub The subscription
 	 * \param buf The string to write AMI data
 	 */
 	void (*to_ami)(struct ast_sip_subscription *sub, struct ast_str **buf);
+	/*! Subscriber callbacks for this handler */
+	struct ast_sip_subscriber *subscriber;
+	/*! Notifier callbacks for this handler */
+	struct ast_sip_subscriber *notifier;
 	AST_LIST_ENTRY(ast_sip_subscription_handler) next;
 };
 
 /*!
  * \brief Create a new ast_sip_subscription structure
  *
- * In most cases the pubsub core will create a general purpose subscription
- * within PJSIP. However, PJSIP provides enhanced support for the following
- * event packages:
- *
- * presence
- * message-summary
- *
- * If either of these events are handled by the subscription handler, then
- * the special-purpose event subscriptions will be created within PJSIP,
- * and it will be expected that your subscription handler make use of the
- * special PJSIP APIs.
- *
- * \param handler The subsription handler for this subscription
- * \param role Whether we are acting as subscriber or notifier for this subscription
- * \param endpoint The endpoint involved in this subscription
- * \param rdata If acting as a notifier, the SUBSCRIBE request that triggered subscription creation
+ * When a subscriber wishes to create a subscription, it may call this function
+ * to allocate resources and to send the initial SUBSCRIBE out.
+ *
+ * \param subscriber The subscriber that is making the request.
+ * \param endpoint The endpoint to whome the SUBSCRIBE will be sent.
+ * \param resource The resource to place in the SUBSCRIBE's Request-URI.
  */
 struct ast_sip_subscription *ast_sip_create_subscription(const struct ast_sip_subscription_handler *handler,
-		enum ast_sip_subscription_role role, struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata);
+		struct ast_sip_endpoint *endpoint, const char *resource);
 
 
 /*!
@@ -426,34 +359,28 @@
 struct ast_taskprocessor *ast_sip_subscription_get_serializer(struct ast_sip_subscription *sub);
 
 /*!
- * \brief Get the underlying PJSIP evsub structure
- *
- * This is useful when wishing to call PJSIP's API calls in order to
- * create SUBSCRIBEs, NOTIFIES, etc. as well as get subscription state
- *
- * This function, as well as all methods called on the pjsip_evsub should
- * be done in a SIP servant thread.
- *
- * \param sub The subscription
- * \retval NULL Failure
- * \retval non-NULL The underlying pjsip_evsub
- */
-pjsip_evsub *ast_sip_subscription_get_evsub(struct ast_sip_subscription *sub);
-
-/*!
- * \brief Get the underlying PJSIP dialog structure
- *
- * Call this function when information needs to be retrieved from the
- * underlying pjsip dialog.
- *
- * This function, as well as all methods called on the pjsip_evsub should
- * be done in a SIP servant thread.
- *
- * \param sub The subscription
- * \retval NULL Failure
- * \retval non-NULL The underlying pjsip_dialog
- */
-pjsip_dialog *ast_sip_subscription_get_dlg(struct ast_sip_subscription *sub);
+ * \brief Notify a SIP subscription of a state change.
+ *
+ * This will create a NOTIFY body to be sent out for the subscribed resource.
+ * On real subscriptions, a NOTIFY request will be generated and sent.
+ * On virtual subscriptions, the NOTIFY is saved on the virtual subscription and the
+ * parent subscription is alerted.
+ *
+ * \param sub The subscription on which a state change is occurring.
+ * \param notify_data Event package-specific data used to create the NOTIFY body.
+ * \retval 0 Success
+ * \retval non-zero Failure
+ */
+int ast_sip_subscription_notify(struct ast_sip_subscription *sub, void *notify_data);
+
+/*! Retrieve the local URI for this subscription */
+void ast_sip_subscription_get_local_uri(struct ast_sip_subscription *sub, char *buf, size_t size);
+ 
+/*! Retrive the remote URI for this subscription */
+void ast_sip_subscription_get_remote_uri(struct ast_sip_subscription *sub, char *buf, size_t size);
+ 
+/*! Terminate an active SIP subscription. */
+void ast_sip_subscription_terminate(struct ast_sip_subscripiton *sub);
 
 /*!
  * \brief Accept a subscription request
@@ -536,17 +463,30 @@
 void ast_sip_subscription_remove_datastore(struct ast_sip_subscription *subscription, const char *name);
 
 /*!
- * \brief Register a subscription handler
- *
- * \retval 0 Handler was registered successfully
- * \retval non-zero Handler was not registered successfully
- */
-int ast_sip_register_subscription_handler(struct ast_sip_subscription_handler *handler);
-
-/*!
- * \brief Unregister a subscription handler
- */
-void ast_sip_unregister_subscription_handler(struct ast_sip_subscription_handler *handler);
+ * \brief Register a notifier
+ *
+ * \retval 0 Notifier was registered successfully
+ * \retval non-zero Notifier was not registered successfully
+ */
+int ast_sip_register_notifier(struct ast_sip_notifier *notifier);
+
+/*!
+ * \brief Unregister a notifier
+ */
+void ast_sip_unregister_notifier(struct ast_sip_notifier *notifier);
+
+/*!
+ * \brief Register a subscriber
+ *
+ * \retval 0 Subscriber was registered successfully
+ * \retval non-zero Subscriber was not registered successfully
+ */
+int ast_sip_register_subscriber(struct ast_sip_subscriber *subscriber);
+
+/*!
+ * \brief Unregister a subscriber
+ */
+void ast_sip_unregister_subscriber(struct ast_sip_subscriber *subscriber);
 
 /*!
  * \brief Pubsub body generator

Modified: team/mmichelson/subscription_abstraction/res/res_pjsip_pubsub.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/subscription_abstraction/res/res_pjsip_pubsub.c?view=diff&rev=416236&r1=416235&r2=416236
==============================================================================
--- team/mmichelson/subscription_abstraction/res/res_pjsip_pubsub.c (original)
+++ team/mmichelson/subscription_abstraction/res/res_pjsip_pubsub.c Fri Jun 13 18:07:48 2014
@@ -249,6 +249,36 @@
 };
 
 /*!
+ * \brief Real subscription details
+ *
+ * A real subscription is one that has a direct link to a
+ * PJSIP subscription and dialog.
+ */
+struct ast_sip_real_subscription {
+	/*! The underlying PJSIP event subscription structure */
+	pjsip_evsub *evsub;
+	/*! The underlying PJSIP dialog */
+	pjsip_dialog *dlg;
+};
+
+/*!
+ * \brief Virtual subscription details
+ *
+ * A virtual subscription is one that does not have a direct
+ * link to a PJSIP subscription. Instead, it is a descendent
+ * of an ast_sip_subscription. Following the ancestry will
+ * eventually lead to a real subscription.
+ */
+struct ast_sip_virtual_subscription {
+	struct ast_sip_subscription *parent;
+};
+
+enum sip_subscription_type {
+	SIP_SUBSCRIPTION_REAL,
+	SIP_SUBSCRIPTION_VIRTUAL,
+};
+
+/*!
  * \brief Structure representing a SIP subscription
  */
 struct ast_sip_subscription {
@@ -262,16 +292,21 @@
 	const struct ast_sip_subscription_handler *handler;
 	/*! The role for this subscription */
 	enum ast_sip_subscription_role role;
-	/*! The underlying PJSIP event subscription structure */
-	pjsip_evsub *evsub;
-	/*! The underlying PJSIP dialog */
-	pjsip_dialog *dlg;
+	/*! Indicator of real or virtual subscription */
+	enum sip_subscription_type type;
+	/*! Real and virtual components of the subscription */
+	union {
+		struct ast_sip_real_subscription *real;
+		struct ast_sip_virtual_subscription *virtual;
+	} pants;
 	/*! Body generaator for NOTIFYs */
 	struct ast_sip_pubsub_body_generator *body_generator;
 	/*! Persistence information */
 	struct subscription_persistence *persistence;
 	/*! Next item in the list */
 	AST_LIST_ENTRY(ast_sip_subscription) next;
+	/*! List of child subscriptions */
+	AST_LIST_HEAD_NOLOCK(,ast_sip_subscription) children;
 };
 
 static const char *sip_subscription_roles_map[] = {
@@ -428,6 +463,8 @@
 	RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
 	struct ast_sip_subscription *sub;
 	struct ast_sip_pubsub_body_generator *generator;
+	int resp;
+	char *resource;
 
 	/* If this subscription has already expired remove it */
 	if (ast_tvdiff_ms(persistence->expires, ast_tvnow()) <= 0) {
@@ -467,7 +504,7 @@
 	expires_header->ivalue = (ast_tvdiff_ms(persistence->expires, ast_tvnow()) / 1000);
 
 	handler = subscription_get_handler_from_rdata(&rdata);
-	if (!handler) {
+	if (!handler || !handler->notifier) {
 		ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
 		return 0;
 	}
@@ -679,7 +716,6 @@
 }
 
 static void pubsub_on_evsub_state(pjsip_evsub *sub, pjsip_event *event);
-static void pubsub_on_tsx_state(pjsip_evsub *sub, pjsip_transaction *tsx, pjsip_event *event);
 static void pubsub_on_rx_refresh(pjsip_evsub *sub, pjsip_rx_data *rdata,
 		int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body);
 static void pubsub_on_rx_notify(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code,
@@ -690,7 +726,6 @@
 
 static pjsip_evsub_user pubsub_cb = {
 	.on_evsub_state = pubsub_on_evsub_state,
-	.on_tsx_state = pubsub_on_tsx_state,
 	.on_rx_refresh = pubsub_on_rx_refresh,
 	.on_rx_notify = pubsub_on_rx_notify,
 	.on_client_refresh = pubsub_on_client_refresh,
@@ -701,12 +736,7 @@
 		struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pjsip_dialog *dlg)
 {
 	pjsip_evsub *evsub;
-	/* PJSIP is kind enough to have some built-in support for certain
-	 * events. We need to use the correct initialization function for the
-	 * built-in events
-	 */
 	if (role == AST_SIP_NOTIFIER) {
-		pjsip_evsub_create_uas(dlg, &pubsub_cb, rdata, 0, &evsub);
 	} else {
 		pj_str_t pj_event;
 		pj_cstr(&pj_event, event);
@@ -715,8 +745,10 @@
 	return evsub;
 }
 
-struct ast_sip_subscription *ast_sip_create_subscription(const struct ast_sip_subscription_handler *handler,
-		enum ast_sip_subscription_role role, struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
+/* XXX TODO There is a lot of repeated code between the two subscription creation functions. */
+
+struct ast_sip_subscription *notifier_create_subscription(const struct ast_sip_subscription_handler *handler,
+		struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
 {
 	struct ast_sip_subscription *sub = ao2_alloc(sizeof(*sub), subscription_destructor);
 	pjsip_dialog *dlg;
@@ -737,26 +769,14 @@
 	}
 	sub->body_generator = ast_sip_mod_data_get(rdata->endpt_info.mod_data,
 			pubsub_module.id, MOD_DATA_BODY_GENERATOR);
-	sub->role = role;
-	if (role == AST_SIP_NOTIFIER) {
-		dlg = ast_sip_create_dialog_uas(endpoint, rdata);
-	} else {
-		RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
-
-		contact = ast_sip_location_retrieve_contact_from_aor_list(endpoint->aors);
-		if (!contact || ast_strlen_zero(contact->uri)) {
-			ast_log(LOG_WARNING, "No contacts configured for endpoint %s. Unable to create SIP subsription\n",
-					ast_sorcery_object_get_id(endpoint));
-			ao2_ref(sub, -1);
-			return NULL;
-		}
-		dlg = ast_sip_create_dialog_uac(endpoint, contact->uri, NULL);
-	}
+	sub->role = AST_SIP_NOTIFIER;
+	dlg = ast_sip_create_dialog_uas(endpoint, rdata);
 	if (!dlg) {
 		ast_log(LOG_WARNING, "Unable to create dialog for SIP subscription\n");
 		ao2_ref(sub, -1);
 		return NULL;
 	}
+
 	persistence = ast_sip_mod_data_get(rdata->endpt_info.mod_data,
 			pubsub_module.id, MOD_DATA_PERSISTENCE);
 	if (persistence) {
@@ -768,7 +788,62 @@
 		dlg->local.cseq = persistence->cseq;
 		dlg->remote.cseq = persistence->cseq;
 	}
-	sub->evsub = allocate_evsub(handler->event_name, role, endpoint, rdata, dlg);
+
+	pjsip_evsub_create_uas(dlg, &pubsub_cb, rdata, 0, &sub->evsub);
+	/* We keep a reference to the dialog until our subscription is destroyed. See
+	 * the subscription_destructor for more details
+	 */
+	pjsip_dlg_inc_session(dlg, &pubsub_module);
+	sub->dlg = dlg;
+	ast_sip_dialog_set_serializer(dlg, sub->serializer);
+	pjsip_evsub_set_mod_data(sub->evsub, pubsub_module.id, sub);
+	sub->endpoint = ao2_bump(endpoint);
+	sub->handler = handler;
+
+	add_subscription(sub);
+	return sub;
+}
+
+struct ast_sip_subscription *ast_sip_create_subscription(const struct ast_sip_subscription_handler *handler,
+		struct ast_sip_endpoint *endpoint, const char *resource)
+{
+	struct ast_sip_subscription *sub = ao2_alloc(sizeof(*sub), subscription_destructor);
+	pjsip_dialog *dlg;
+	struct ast_sip_contact *contact;
+	pj_str_t event;
+
+	if (!sub) {
+		return NULL;
+	}
+	sub->datastores = ao2_container_alloc(DATASTORE_BUCKETS, datastore_hash, datastore_cmp);
+	if (!sub->datastores) {
+		ao2_ref(sub, -1);
+		return NULL;
+	}
+	sub->serializer = ast_sip_create_serializer();
+	if (!sub->serializer) {
+		ao2_ref(sub, -1);
+		return NULL;
+	}
+	sub->role = AST_SIP_SUBSCRIBER;
+	contact = ast_sip_location_retrieve_contact_from_aor_list(endpoint->aors);
+	if (!contact || ast_strlen_zero(contact->uri)) {
+		ast_log(LOG_WARNING, "No contacts configured for endpoint %s. Unable to create SIP subsription\n",
+				ast_sorcery_object_get_id(endpoint));
+		ao2_ref(sub, -1);
+		ao2_cleanup(contact);
+		return NULL;
+	}
+	dlg = ast_sip_create_dialog_uac(endpoint, contact->uri, NULL);
+	ao2_cleanup(contact);
+	if (!dlg) {
+		ast_log(LOG_WARNING, "Unable to create dialog for SIP subscription\n");
+		ao2_ref(sub, -1);
+		return NULL;
+	}
+
+	pj_cstr(&event, handler->event_name);
+	pjsip_evsub_create_uac(dlg, &pubsub_cb, &event, 0, &sub->evsub);
 	/* We keep a reference to the dialog until our subscription is destroyed. See
 	 * the subscription_destructor for more details
 	 */
@@ -781,6 +856,8 @@
 	sub->handler = handler;
 
 	add_subscription(sub);
+
+	/* XXX TODO We need to send our initial subscribe here */
 	return sub;
 }
 
@@ -1019,9 +1096,9 @@
 int ast_sip_register_subscription_handler(struct ast_sip_subscription_handler *handler)
 {
 	pj_str_t event;
-	pj_str_t accept[AST_SIP_MAX_ACCEPT];
+	pj_str_t accept[AST_SIP_MAX_ACCEPT] = { {0, }, };
 	struct ast_sip_subscription_handler *existing;
-	int i;
+	int i = 0;
 
 	if (ast_strlen_zero(handler->event_name)) {
 		ast_log(LOG_ERROR, "No event package specified for subscription handler. Cannot register\n");
@@ -1035,8 +1112,10 @@
 		return -1;
 	}
 
-	for (i = 0; i < AST_SIP_MAX_ACCEPT && !ast_strlen_zero(handler->accept[i]); ++i) {
-		pj_cstr(&accept[i], handler->accept[i]);
+	if (handler->subscriber) {
+		for (i = 0; i < AST_SIP_MAX_ACCEPT && !ast_strlen_zero(handler->subscriber->accept[i]); ++i) {
+			pj_cstr(&accept[i], handler->subscriber->accept[i]);
+		}
 	}
 
 	pj_cstr(&event, handler->event_name);
@@ -1117,6 +1196,9 @@
 	RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
 	struct ast_sip_subscription *sub;
 	struct ast_sip_pubsub_body_generator *generator;
+	char *resource;
+	struct pjsip_sip_uri *request_uri;
+	size_t resource_size;
 
 	endpoint = ast_pjsip_rdata_get_endpoint(rdata);
 	ast_assert(endpoint != NULL);
@@ -1126,6 +1208,11 @@
 		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 603, NULL, NULL, NULL);
 		return PJ_TRUE;
 	}
+
+	request_uri = pjsip_uri_get_uri(rdata->msg_info.msg->line.req.uri);
+	resource_size = pj_strlen(&request_uri->user) + 1;
+	resource = alloca(resource_size);
+	ast_copy_pj_str(resource, &request_uri->user, resource_size);
 
 	expires_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, rdata->msg_info.msg->hdr.next);
 
@@ -1142,7 +1229,7 @@
 			pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 423, NULL, NULL, NULL);
 			return PJ_TRUE;
 		}
-        }
+	}
 
 	handler = subscription_get_handler_from_rdata(rdata);
 	if (!handler) {
@@ -1159,24 +1246,18 @@
 	ast_sip_mod_data_set(rdata->tp_info.pool, rdata->endpt_info.mod_data,
 			pubsub_module.id, MOD_DATA_BODY_GENERATOR, generator);
 
-	sub = handler->new_subscribe(endpoint, rdata);
+	resp = handler->notifier->new_subscribe(endpoint, resource);
+	if (resp < 200 || resp >= 300) {
+		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, resp, NULL, NULL, NULL);
+	}
+	sub = notifier_create_subscription(handler, endpoint, rdata);
 	if (!sub) {
-		pjsip_transaction *trans = pjsip_rdata_get_tsx(rdata);
-
-		if (trans) {
-			pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
-			pjsip_tx_data *tdata;
-
-			if (pjsip_endpt_create_response(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, &tdata) != PJ_SUCCESS) {
-				return PJ_TRUE;
-			}
-			pjsip_dlg_send_response(dlg, trans, tdata);
-		} else {
-			pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
-		}
+		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
 	} else {
 		sub->persistence = subscription_persistence_create(sub);
 		subscription_persistence_update(sub, rdata);
+		pjsip_evsub_accept(sub->evsub, rdata, resp, NULL);
+		handler->notifier->notify_required(sub, AST_SIP_SUBSCRIPTION_NOTIFY_REASON_STARTED);
 	}
 
 	return PJ_TRUE;
@@ -1590,20 +1671,6 @@
 	pjsip_evsub_set_mod_data(evsub, pubsub_module.id, NULL);
 }
 
-static void pubsub_on_tsx_state(pjsip_evsub *evsub, pjsip_transaction *tsx, pjsip_event *event)
-{
-	struct ast_sip_subscription *sub = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
-
-	if (!sub) {
-		return;
-	}
-
-	if (sub->handler->notify_response && tsx->role == PJSIP_ROLE_UAC &&
-	    event->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
-		sub->handler->notify_response(sub, event->body.tsx_state.src.rdata);
-	}
-}
-
 static void set_parameters_from_response_data(pj_pool_t *pool, int *p_st_code,
 		pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body,
 		struct ast_sip_subscription_response_data *response_data)
@@ -1657,27 +1724,18 @@
 		int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
 {
 	struct ast_sip_subscription *sub = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
-	struct ast_sip_subscription_response_data response_data = {
-		.status_code = 200,
-	};
+	enum ast_sip_subscription_notify_reason reason;
 
 	if (!sub) {
 		return;
 	}
 
 	if (pjsip_evsub_get_state(sub->evsub) == PJSIP_EVSUB_STATE_TERMINATED) {
-		sub->handler->subscription_terminated(sub, rdata);
-		return;
-	}
-
-	sub->handler->resubscribe(sub, rdata, &response_data);
-
-	if (!response_data_changed(&response_data)) {
-		return;
-	}
-
-	set_parameters_from_response_data(rdata->tp_info.pool, p_st_code, p_st_text,
-			res_hdr, p_body, &response_data);
+		reason = AST_SIP_SUBSCRIPTION_NOTIFY_REASON_TERMINATED;
+	} else {
+		reason = AST_SIP_SUBSCRIPTION_NOTIFY_REASON_RENEWED;
+	}
+	sub->handler->notify_required(sub, reason);
 }
 
 static void pubsub_on_rx_notify(pjsip_evsub *evsub, pjsip_rx_data *rdata, int *p_st_code,




More information about the asterisk-commits mailing list