int sca_dialog_create_replaces_header( sca_dialog *dlg, str *replaces_hdr ) { int len; assert( replaces_hdr != NULL ); if ( SCA_STR_EMPTY( &dlg->call_id ) || SCA_STR_EMPTY( &dlg->from_tag ) || SCA_STR_EMPTY( &dlg->to_tag )) { LM_ERR( "sca_dialog_create_replaces_header: dialog %.*s is not a " "confirmed dialog, cannot build Replaces header", STR_FMT( &dlg->id )); return( -1 ); } memset( replaces_hdr, 0, sizeof( str )); /* +2 for semicolons separating tags, +2 for CRLF */ replaces_hdr->s = pkg_malloc( SCA_REPLACES_HDR_PREFIX_LEN + SCA_REPLACES_TO_TAG_LEN + SCA_REPLACES_FROM_TAG_LEN + dlg->id.len + 2 + 2 ); memcpy( replaces_hdr->s, SCA_REPLACES_HDR_PREFIX, SCA_REPLACES_HDR_PREFIX_LEN ); len = SCA_REPLACES_HDR_PREFIX_LEN; memcpy( replaces_hdr->s + len, dlg->call_id.s, dlg->call_id.len ); len += dlg->call_id.len; memcpy( replaces_hdr->s + len, ";", strlen( ";" )); len += strlen( ";" ); memcpy( replaces_hdr->s + len, SCA_REPLACES_TO_TAG, SCA_REPLACES_TO_TAG_LEN ); len += SCA_REPLACES_TO_TAG_LEN; memcpy( replaces_hdr->s + len, dlg->to_tag.s, dlg->to_tag.len ); len += dlg->to_tag.len; memcpy( replaces_hdr->s + len, ";", strlen( ";" )); len += strlen( ";" ); memcpy( replaces_hdr->s + len, SCA_REPLACES_FROM_TAG, SCA_REPLACES_FROM_TAG_LEN ); len += SCA_REPLACES_FROM_TAG_LEN; memcpy( replaces_hdr->s + len, dlg->from_tag.s, dlg->from_tag.len ); len += dlg->from_tag.len; memcpy( replaces_hdr->s + len, CRLF, CRLF_LEN ); len += CRLF_LEN; replaces_hdr->len = len; return( len ); }
int sca_aor_create_from_info( str *aor, uri_type type, str *user, str *domain, str *port ) { str scheme = STR_NULL; int len = 0; assert( aor != NULL ); uri_type_to_str( type, &scheme ); /* +1 for ':', +1 for '@' */ len = scheme.len + 1 + user->len + 1 + domain->len; if ( !SCA_STR_EMPTY( port )) { /* +1 for ':' */ len += 1 + port->len; } aor->s = (char *)pkg_malloc( len ); if ( aor->s == NULL ) { LM_ERR( "sca_aor_create_from_info: pkg_malloc %d bytes failed", len ); return( -1 ); } len = 0; SCA_STR_COPY( aor, &scheme ); len += scheme.len; *(aor->s + len) = ':'; aor->len++; len++; SCA_STR_APPEND( aor, user ); len += user->len; *(aor->s + len) = '@'; aor->len++; len++; SCA_STR_APPEND( aor, domain ); len += domain->len; if ( !SCA_STR_EMPTY( port )) { *(aor->s + len) = ':'; len += 1; SCA_STR_APPEND( aor, port ); len += port->len; } return( aor->len ); }
/* count characters requiring escape as defined by escape_common */ int sca_uri_display_escapes_count( str *display ) { int c = 0; int i; if ( SCA_STR_EMPTY( display )) { return( 0 ); } for ( i = 0; i < display->len; i++ ) { switch ( display->s[ i ] ) { case '\'': case '"': case '\\': case '\0': c++; default: break; } } return( c ); }
int sca_get_msg_from_header( sip_msg_t *msg, struct to_body **from ) { struct to_body *f; assert( msg != NULL ); assert( from != NULL ); if ( SCA_HEADER_EMPTY( msg->from )) { LM_ERR( "Empty From header" ); return( -1 ); } if ( parse_from_header( msg ) < 0 ) { LM_ERR( "Bad From header" ); return( -1 ); } f = get_from( msg ); if ( SCA_STR_EMPTY( &f->tag_value )) { LM_ERR( "Bad From header: no tag parameter" ); return( -1 ); } /* ensure the URI is parsed for future use */ if ( parse_uri( f->uri.s, f->uri.len, GET_FROM_PURI( msg )) < 0 ) { LM_ERR( "Failed to parse From URI %.*s", STR_FMT( &f->uri )); return( -1 ); } *from = f; return( 0 ); }
void * sca_hash_table_index_kv_find( sca_hash_table *ht, int slot_idx, str *key ) { assert( ht != NULL && !SCA_STR_EMPTY( key )); assert( slot_idx >= 0 && slot_idx < ht->size ); return( sca_hash_table_slot_kv_find( &ht->slots[ slot_idx ], key )); }
int sca_dialog_build_from_tags( sca_dialog *dialog, int maxlen, str *call_id, str *from_tag, str *to_tag ) { int len = 0; assert( dialog != NULL && dialog->id.s != NULL ); assert( call_id != NULL ); assert( from_tag != NULL ); len = call_id->len + from_tag->len; if ( !SCA_STR_EMPTY( to_tag )) { len += to_tag->len; } if ( len >= maxlen ) { LM_ERR( "sca_dialog_build_from_tags: tags too long" ); return( -1 ); } memcpy( dialog->id.s, call_id->s, call_id->len ); dialog->call_id.s = dialog->id.s; dialog->call_id.len = call_id->len; memcpy( dialog->id.s + call_id->len, from_tag->s, from_tag->len ); dialog->from_tag.s = dialog->id.s + call_id->len; dialog->from_tag.len = from_tag->len; if ( !SCA_STR_EMPTY( to_tag )) { memcpy( dialog->id.s + call_id->len + from_tag->len, to_tag->s, to_tag->len ); dialog->to_tag.s = dialog->id.s + call_id->len + from_tag->len; dialog->to_tag.len = to_tag->len; } dialog->id.len = len; return( len ); }
static dlg_t *sca_notify_dlg_for_subscription(sca_subscription *sub) { dlg_t *dlg = NULL; dlg = (dlg_t *) pkg_malloc(sizeof(dlg_t)); if (dlg == NULL) { LM_ERR("pkg_malloc dlg_t for %.*s failed: out of memory\n", STR_FMT(&sub->subscriber)); goto error; } memset(dlg, 0, sizeof(dlg_t)); dlg->loc_seq.value = sub->dialog.notify_cseq; dlg->loc_seq.is_set = 1; dlg->id.call_id = sub->dialog.call_id; dlg->id.rem_tag = sub->dialog.from_tag; dlg->id.loc_tag = sub->dialog.to_tag; // RURI dlg->rem_target = sub->subscriber; // To and From URIs are both the SCA AoR in an SCA NOTIFY dlg->loc_uri = sub->target_aor; dlg->rem_uri = sub->target_aor; // restore route if (!SCA_STR_EMPTY(&sub->rr)) { if (parse_rr_body(sub->rr.s, sub->rr.len, &dlg->route_set) < 0) { LM_ERR("sca_notify_dlg_for_subscription: failed to parse " "%.*s subscription's Record-Route info\n", STR_FMT(&sub->subscriber)); goto error; } } // the dialog state in an SCA NOTIFY should always be confirmed, // since we generated the dialog to-tag in our response to the // subscriber's SUBSCRIBE request. dlg->state = DLG_CONFIRMED; return (dlg); error: if (dlg != NULL) { pkg_free(dlg); } return (NULL); }
sca_hash_entry * sca_hash_table_slot_kv_find_entry_unsafe( sca_hash_slot *slot, str *key ) { sca_hash_entry *e = NULL; assert( slot != NULL && !SCA_STR_EMPTY( key )); for ( e = slot->entries; e != NULL; e = e->next ) { if ( e->compare( key, e->value ) == 0 ) { break; } } return( e ); }
int sca_hash_table_kv_insert( sca_hash_table *ht, str *key, void *value, int (*e_compare)(str *, void *), void (*e_description)(void *), void (*e_free)(void *)) { int hash_idx; int rc; assert( ht != NULL && !SCA_STR_EMPTY( key ) && value != NULL ); hash_idx = sca_hash_table_index_for_key( ht, key ); rc = sca_hash_table_index_kv_insert( ht, hash_idx, value, e_compare, e_description, e_free ); return( rc ); }
/* * send a call-info NOTIFY to all subscribers to a given SCA AoR. */ int sca_notify_call_info_subscribers(sca_mod *scam, str *subscription_aor) { sca_hash_slot *slot; sca_hash_entry *e; sca_subscription *sub; str headers = STR_NULL; str hash_key = STR_NULL; char hdrbuf[SCA_HEADERS_MAX_LEN]; char keybuf[512]; char *event_name; int slot_idx; int rc = -1; assert(scam->subscriptions != NULL); assert(!SCA_STR_EMPTY(subscription_aor)); LM_DBG("Notifying ALL subscribers of AOR %.*s due to a SUBSCRIBTION request\n", STR_FMT(subscription_aor)); event_name = sca_event_name_from_type(SCA_EVENT_TYPE_CALL_INFO); if (subscription_aor->len + strlen(event_name) >= sizeof(keybuf)) { LM_ERR("Hash key %.*s + %s is too long\n", STR_FMT(subscription_aor), event_name); return (-1); } hash_key.s = keybuf; SCA_STR_COPY(&hash_key, subscription_aor); SCA_STR_APPEND_CSTR(&hash_key, event_name); slot_idx = sca_hash_table_index_for_key(scam->subscriptions, &hash_key); slot = sca_hash_table_slot_for_index(scam->subscriptions, slot_idx); sca_hash_table_lock_index(scam->subscriptions, slot_idx); for (e = slot->entries; e != NULL; e = e->next) { sub = (sca_subscription *) e->value; if (!SCA_STR_EQ(subscription_aor, &sub->target_aor)) { continue; } if (headers.len == 0) { headers.s = hdrbuf; if (sca_notify_build_headers_from_info(&headers, sizeof(hdrbuf), scam, sub, SCA_CALL_INFO_APPEARANCE_INDEX_ANY) < 0) { LM_ERR("Failed to build NOTIFY headers\n"); goto done; } } // XXX would like this to be wrapped in one location sub->dialog.notify_cseq += 1; if (sca_notify_subscriber_internal(scam, sub, &headers) < 0) { goto done; } } rc = 1; done: sca_hash_table_unlock_index(scam->subscriptions, slot_idx); return (rc); }
int sca_create_canonical_aor_for_ua( sip_msg_t *msg, str *c_aor, int ua_opts ) { struct to_body *tf = NULL; sip_uri_t c_uri; str tf_aor = STR_NULL; str contact_uri = STR_NULL; int rc = -1; assert( msg != NULL ); assert( c_aor != NULL ); memset( c_aor, 0, sizeof( str )); if (( ua_opts & SCA_AOR_TYPE_AUTO )) { if ( msg->first_line.type == SIP_REQUEST ) { ua_opts = SCA_AOR_TYPE_UAC; } else { ua_opts = SCA_AOR_TYPE_UAS; } } if (( ua_opts & SCA_AOR_TYPE_UAC )) { if ( sca_get_msg_from_header( msg, &tf ) < 0 ) { LM_ERR( "sca_create_canonical_aor: failed to get From header" ); goto done; } } else { if ( sca_get_msg_to_header( msg, &tf ) < 0 ) { LM_ERR( "sca_create_canonical_aor: failed to get To header" ); goto done; } } if ( sca_uri_extract_aor( &tf->uri, &tf_aor ) < 0 ) { LM_ERR( "sca_create_canonical_aor: failed to extract AoR from " "URI <%.*s>", STR_FMT( &tf->uri )); goto done; } memset( &c_uri, 0, sizeof( sip_uri_t )); if (( rc = sca_get_msg_contact_uri( msg, &contact_uri )) < 0 ) { LM_ERR( "sca_create_canonical_aor: failed to get contact URI from " "Contact <%.*s>", STR_FMT( &msg->contact->body )); goto done; } if ( rc > 0 ) { if ( parse_uri( contact_uri.s, contact_uri.len, &c_uri ) < 0 ) { LM_ERR( "sca_create_canonical_aor: failed to parse Contact URI " "<%.*s>", STR_FMT( &contact_uri )); rc = -1; goto done; } } if ( SCA_STR_EMPTY( &c_uri.user ) || SCA_STR_EQ( &c_uri.user, &tf->parsed_uri.user )) { /* empty contact header or Contact user matches To/From AoR */ c_aor->s = (char *)pkg_malloc( tf_aor.len ); c_aor->len = tf_aor.len; memcpy( c_aor->s, tf_aor.s, tf_aor.len ); } else { /* Contact user and To/From user mismatch */ if ( sca_aor_create_from_info( c_aor, c_uri.type, &c_uri.user, &tf->parsed_uri.host, &tf->parsed_uri.port ) < 0 ) { LM_ERR( "sca_create_canonical_aor: failed to create AoR from " "Contact <%.*s> and URI <%.*s>", STR_FMT( &contact_uri ), STR_FMT( &tf_aor )); goto done; } } rc = 1; done: return( rc ); }