mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 02:37:10 +00:00 
			
		
		
		
	Merge "res_pjsip: Fix statsd regression."
This commit is contained in:
		
							
								
								
									
										2
									
								
								CHANGES
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								CHANGES
									
									
									
									
									
								
							| @@ -408,8 +408,6 @@ res_pjsip | ||||
|     "contact_deny" - List of Contact header addresses to deny | ||||
|     "contact_permit" - List of Contact header addresses to permit | ||||
|  | ||||
|  * Added new status Updated to AMI event ContactStatus on update registration | ||||
|  | ||||
|  * Added "reg_server" to contacts. | ||||
|    If the Asterisk system name is set in asterisk.conf, it will be stored | ||||
|    into the "reg_server" field in the ps_contacts table to facilitate | ||||
|   | ||||
| @@ -271,7 +271,6 @@ enum ast_sip_contact_status_type { | ||||
| 	UNKNOWN, | ||||
| 	CREATED, | ||||
| 	REMOVED, | ||||
| 	UPDATED, | ||||
| }; | ||||
|  | ||||
| /*! | ||||
| @@ -296,6 +295,8 @@ struct ast_sip_contact_status { | ||||
| 	int64_t rtt; | ||||
| 	/*! Last status for a contact (default - unavailable) */ | ||||
| 	enum ast_sip_contact_status_type last_status; | ||||
| 	/*! TRUE if the contact was refreshed. e.g., re-registered */ | ||||
| 	unsigned int refresh:1; | ||||
| }; | ||||
|  | ||||
| /*! | ||||
|   | ||||
| @@ -105,6 +105,40 @@ static void endpoint_update_state(struct ast_endpoint *endpoint, enum ast_endpoi | ||||
| 	ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "PJSIP/%s", ast_endpoint_get_resource(endpoint)); | ||||
| } | ||||
|  | ||||
| static void endpoint_publish_contact_status(struct ast_endpoint *endpoint, struct ast_sip_contact_status *contact) | ||||
| { | ||||
| 	struct ast_json *blob; | ||||
| 	char rtt[32]; | ||||
|  | ||||
| 	snprintf(rtt, sizeof(rtt), "%" PRId64, contact->rtt); | ||||
| 	blob = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}", | ||||
| 		"contact_status", ast_sip_get_contact_status_label(contact->status), | ||||
| 		"aor", contact->aor, | ||||
| 		"uri", contact->uri, | ||||
| 		"roundtrip_usec", rtt, | ||||
| 		"endpoint_name", ast_endpoint_get_resource(endpoint)); | ||||
| 	if (blob) { | ||||
| 		ast_endpoint_blob_publish(endpoint, ast_endpoint_contact_state_type(), blob); | ||||
| 		ast_json_unref(blob); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /*! \brief Callback function for publishing the status of an endpoint */ | ||||
| static int persistent_endpoint_publish_status(void *obj, void *arg, int flags) | ||||
| { | ||||
| 	struct sip_persistent_endpoint *persistent = obj; | ||||
| 	struct ast_endpoint *endpoint = persistent->endpoint; | ||||
| 	struct ast_sip_contact_status *status = arg; | ||||
|  | ||||
| 	/* If the status' aor isn't one of the endpoint's, we skip */ | ||||
| 	if (!strstr(persistent->aors, status->aor)) { | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	endpoint_publish_contact_status(endpoint, status); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /*! \brief Callback function for changing the state of an endpoint */ | ||||
| static int persistent_endpoint_update_state(void *obj, void *arg, int flags) | ||||
| { | ||||
| @@ -112,30 +146,17 @@ static int persistent_endpoint_update_state(void *obj, void *arg, int flags) | ||||
| 	struct ast_endpoint *endpoint = persistent->endpoint; | ||||
| 	struct ast_sip_contact_status *status = arg; | ||||
| 	struct ao2_container *contacts; | ||||
| 	struct ast_json *blob; | ||||
| 	struct ao2_iterator i; | ||||
| 	struct ast_sip_contact *contact; | ||||
| 	enum ast_endpoint_state state = AST_ENDPOINT_OFFLINE; | ||||
|  | ||||
| 	if (status) { | ||||
| 		char rtt[32]; | ||||
|  | ||||
| 		/* If the status' aor isn't one of the endpoint's, we skip */ | ||||
| 		if (!strstr(persistent->aors, status->aor)) { | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		snprintf(rtt, sizeof(rtt), "%" PRId64, status->rtt); | ||||
| 		blob = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}", | ||||
| 			"contact_status", ast_sip_get_contact_status_label(status->status), | ||||
| 			"aor", status->aor, | ||||
| 			"uri", status->uri, | ||||
| 			"roundtrip_usec", rtt, | ||||
| 			"endpoint_name", ast_endpoint_get_resource(endpoint)); | ||||
| 		ast_endpoint_blob_publish(endpoint, ast_endpoint_contact_state_type(), blob); | ||||
| 		ast_json_unref(blob); | ||||
| 	/* If the status' aor isn't one of the endpoint's, we skip */ | ||||
| 	if (!strstr(persistent->aors, status->aor)) { | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	endpoint_publish_contact_status(endpoint, status); | ||||
|  | ||||
| 	/* Find all the contacts for this endpoint.  If ANY are available, | ||||
| 	 * mark the endpoint as ONLINE. | ||||
| 	 */ | ||||
| @@ -222,6 +243,13 @@ static void persistent_endpoint_contact_status_observer(const void *object) | ||||
| { | ||||
| 	struct ast_sip_contact_status *contact_status = (struct ast_sip_contact_status *)object; | ||||
|  | ||||
| 	if (contact_status->refresh) { | ||||
| 		/* We are only re-publishing the contact status. */ | ||||
| 		ao2_callback(persistent_endpoints, OBJ_NODATA, | ||||
| 			persistent_endpoint_publish_status, contact_status); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	/* If rtt_start is set (this is the outgoing OPTIONS), ignore. */ | ||||
| 	if (contact_status->rtt_start.tv_sec > 0) { | ||||
| 		return; | ||||
|   | ||||
| @@ -43,7 +43,6 @@ static const char *status_map [] = { | ||||
| 	[UNKNOWN] = "Unknown", | ||||
| 	[CREATED] = "Created", | ||||
| 	[REMOVED] = "Removed", | ||||
| 	[UPDATED] = "Updated", | ||||
| }; | ||||
|  | ||||
| static const char *short_status_map [] = { | ||||
| @@ -52,7 +51,6 @@ static const char *short_status_map [] = { | ||||
| 	[UNKNOWN] = "Unknown", | ||||
| 	[CREATED] = "Created", | ||||
| 	[REMOVED] = "Removed", | ||||
| 	[UPDATED] = "Updated", | ||||
| }; | ||||
|  | ||||
| const char *ast_sip_get_contact_status_label(const enum ast_sip_contact_status_type status) | ||||
| @@ -157,7 +155,7 @@ struct ast_sip_contact_status *ast_res_pjsip_find_or_create_contact_status(const | ||||
|  * \brief Update an ast_sip_contact_status's elements. | ||||
|  */ | ||||
| static void update_contact_status(const struct ast_sip_contact *contact, | ||||
| 	enum ast_sip_contact_status_type value) | ||||
| 	enum ast_sip_contact_status_type value, int is_contact_refresh) | ||||
| { | ||||
| 	RAII_VAR(struct ast_sip_contact_status *, status, NULL, ao2_cleanup); | ||||
| 	RAII_VAR(struct ast_sip_contact_status *, update, NULL, ao2_cleanup); | ||||
| @@ -169,6 +167,26 @@ static void update_contact_status(const struct ast_sip_contact *contact, | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if (is_contact_refresh | ||||
| 		&& status->status == CREATED) { | ||||
| 		/* | ||||
| 		 * The contact status hasn't been updated since creation | ||||
| 		 * and we don't want to re-send a created status. | ||||
| 		 */ | ||||
| 		if (contact->qualify_frequency | ||||
| 			|| status->rtt_start.tv_sec > 0) { | ||||
| 			/* Ignore, the status will change soon. */ | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		/* | ||||
| 		 * Convert to a regular contact status update | ||||
| 		 * because the status may never change. | ||||
| 		 */ | ||||
| 		is_contact_refresh = 0; | ||||
| 		value = UNKNOWN; | ||||
| 	} | ||||
|  | ||||
| 	update = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS, | ||||
| 		ast_sorcery_object_get_id(status)); | ||||
| 	if (!update) { | ||||
| @@ -178,22 +196,35 @@ static void update_contact_status(const struct ast_sip_contact *contact, | ||||
| 	} | ||||
|  | ||||
| 	ast_string_field_set(update, uri, contact->uri); | ||||
| 	update->last_status = status->status; | ||||
| 	update->status = value; | ||||
|  | ||||
| 	/* if the contact is available calculate the rtt as | ||||
| 	   the diff between the last start time and "now" */ | ||||
| 	update->rtt = update->status == AVAILABLE && status->rtt_start.tv_sec > 0 ? | ||||
| 		ast_tvdiff_us(ast_tvnow(), status->rtt_start) : 0; | ||||
| 	update->rtt_start = ast_tv(0, 0); | ||||
| 	if (is_contact_refresh) { | ||||
| 		/* Copy everything just to set the refresh flag. */ | ||||
| 		update->status = status->status; | ||||
| 		update->last_status = status->last_status; | ||||
| 		update->rtt = status->rtt; | ||||
| 		update->rtt_start = status->rtt_start; | ||||
| 		update->refresh = 1; | ||||
| 	} else { | ||||
| 		update->last_status = status->status; | ||||
| 		update->status = value; | ||||
|  | ||||
| 	ast_test_suite_event_notify("AOR_CONTACT_QUALIFY_RESULT", | ||||
| 		"Contact: %s\r\n" | ||||
| 		"Status: %s\r\n" | ||||
| 		"RTT: %" PRId64, | ||||
| 		ast_sorcery_object_get_id(update), | ||||
| 		ast_sip_get_contact_status_label(update->status), | ||||
| 		update->rtt); | ||||
| 		/* | ||||
| 		 * if the contact is available calculate the rtt as | ||||
| 		 * the diff between the last start time and "now" | ||||
| 		 */ | ||||
| 		update->rtt = update->status == AVAILABLE && status->rtt_start.tv_sec > 0 | ||||
| 			? ast_tvdiff_us(ast_tvnow(), status->rtt_start) | ||||
| 			: 0; | ||||
| 		update->rtt_start = ast_tv(0, 0); | ||||
|  | ||||
| 		ast_test_suite_event_notify("AOR_CONTACT_QUALIFY_RESULT", | ||||
| 			"Contact: %s\r\n" | ||||
| 			"Status: %s\r\n" | ||||
| 			"RTT: %" PRId64, | ||||
| 			ast_sorcery_object_get_id(update), | ||||
| 			ast_sip_get_contact_status_label(update->status), | ||||
| 			update->rtt); | ||||
| 	} | ||||
|  | ||||
| 	if (ast_sorcery_update(ast_sip_get_sorcery(), update)) { | ||||
| 		ast_log(LOG_ERROR, "Unable to update ast_sip_contact_status for contact %s\n", | ||||
| @@ -306,10 +337,10 @@ static void qualify_contact_cb(void *token, pjsip_event *e) | ||||
| 		/* Fall through */ | ||||
| 	case PJSIP_EVENT_TRANSPORT_ERROR: | ||||
| 	case PJSIP_EVENT_TIMER: | ||||
| 		update_contact_status(contact, UNAVAILABLE); | ||||
| 		update_contact_status(contact, UNAVAILABLE, 0); | ||||
| 		break; | ||||
| 	case PJSIP_EVENT_RX_MSG: | ||||
| 		update_contact_status(contact, AVAILABLE); | ||||
| 		update_contact_status(contact, AVAILABLE, 0); | ||||
| 		break; | ||||
| 	} | ||||
| 	ao2_cleanup(contact); | ||||
| @@ -365,7 +396,7 @@ static int qualify_contact(struct ast_sip_endpoint *endpoint, struct ast_sip_con | ||||
| 		!= PJ_SUCCESS) { | ||||
| 		ast_log(LOG_ERROR, "Unable to send request to qualify contact %s\n", | ||||
| 			contact->uri); | ||||
| 		update_contact_status(contact, UNAVAILABLE); | ||||
| 		update_contact_status(contact, UNAVAILABLE, 0); | ||||
| 		ao2_ref(contact, -1); | ||||
| 		return -1; | ||||
| 	} | ||||
| @@ -525,7 +556,7 @@ static void qualify_and_schedule(struct ast_sip_contact *contact) | ||||
|  | ||||
| 		schedule_qualify(contact, contact->qualify_frequency * 1000); | ||||
| 	} else { | ||||
| 		update_contact_status(contact, UNKNOWN); | ||||
| 		update_contact_status(contact, UNKNOWN, 0); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -544,8 +575,7 @@ static void contact_created(const void *obj) | ||||
|  */ | ||||
| static void contact_updated(const void *obj) | ||||
| { | ||||
| 	update_contact_status((struct ast_sip_contact *) obj, UPDATED); | ||||
| 	qualify_and_schedule((struct ast_sip_contact *) obj); | ||||
| 	update_contact_status(obj, AVAILABLE, 1); | ||||
| } | ||||
|  | ||||
| /*! | ||||
| @@ -574,8 +604,8 @@ static void contact_deleted(const void *obj) | ||||
|  | ||||
| static const struct ast_sorcery_observer contact_observer = { | ||||
| 	.created = contact_created, | ||||
| 	.updated = contact_updated, | ||||
| 	.deleted = contact_deleted, | ||||
| 	.updated = contact_updated | ||||
| }; | ||||
|  | ||||
| static pj_bool_t options_start(void) | ||||
| @@ -1051,7 +1081,7 @@ static void qualify_and_schedule_contact(struct ast_sip_contact *contact) | ||||
| 	if (contact->qualify_frequency) { | ||||
| 		schedule_qualify(contact, initial_interval); | ||||
| 	} else { | ||||
| 		update_contact_status(contact, UNKNOWN); | ||||
| 		update_contact_status(contact, UNKNOWN, 0); | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user