int rls_handle_subscribe(struct sip_msg* msg, char* s1, char* s2) { struct to_body *pto, *pfrom = NULL; subs_t subs; pres_ev_t* event= NULL; str* contact= NULL; xmlDocPtr doc= NULL; xmlNodePtr service_node= NULL; unsigned int hash_code= 0; event_t* parsed_event; param_t* ev_param= NULL; int init_req; int reply_code; str reply_str; /*** filter: 'For me or for presence server?' */ reply_code = 400; reply_str = pu_400_rpl; memset(&subs, 0, sizeof(subs_t)); if ( parse_headers(msg,HDR_EOH_F, 0)==-1 ) { LM_ERR("parsing headers\n"); goto error; } /* check for Support: eventlist header */ if(!msg->supported) { LM_DBG("no supported header found\n"); return to_presence_code; } if(parse_supported(msg) < 0) { LM_ERR("failed to parse supported headers\n"); reply_code = 500; reply_str = pu_500_rpl; goto error; } if(!(get_supported(msg) & F_SUPPORTED_EVENTLIST)) { LM_DBG("No 'Support: eventlist' header found\n"); return to_presence_code; } /* inspecting the Event header field */ if(msg->event && msg->event->body.len > 0) { if (!msg->event->parsed && (parse_event(msg->event) < 0)) { LM_ERR("cannot parse Event header\n"); reply_code = 500; reply_str = pu_500_rpl; goto error; } if(! ( ((event_t*)msg->event->parsed)->parsed & rls_events) ) { return to_presence_code; } } else { goto bad_event; } /* search event in the list */ parsed_event= (event_t*)msg->event->parsed; event= pres_search_event(parsed_event); if(event== NULL) { goto bad_event; } subs.event= event; /* extract the id if any*/ ev_param= parsed_event->params; while(ev_param) { if(ev_param->name.len== 2 && strncasecmp(ev_param->name.s, "id", 2)== 0) { subs.event_id= ev_param->body; break; } ev_param= ev_param->next; } pto = get_to(msg); if (pto == NULL || pto->error != PARSE_OK) { LM_ERR("parsing 'To' header failed\n"); goto error; } if(parse_from_uri(msg)<0) { LM_ERR("failed to parse From header\n"); goto error; } pfrom = (struct to_body*)msg->from->parsed; if(pfrom->tag_value.s ==NULL || pfrom->tag_value.len == 0) { LM_ERR("no from tag value present\n"); goto error; } /* verify if the presentity URI is a resource list */ if(pto->tag_value.s== NULL || pto->tag_value.len==0) /* if an initial Subscribe */ { struct sip_uri fu = ((struct to_body*)msg->from->parsed)->parsed_uri; if( parse_sip_msg_uri(msg)< 0) { LM_ERR("parsing Request URI failed\n"); goto error; } /*verify if Request URI represents a list by asking xcap server*/ if(uandd_to_uri(msg->parsed_uri.user, msg->parsed_uri.host, &subs.pres_uri)< 0) { LM_ERR("while constructing uri from user and domain\n"); reply_code = 500; reply_str = pu_500_rpl; goto error; } if( get_resource_list(&subs.pres_uri, fu.user, fu.host, &service_node, &doc) < 0) { LM_ERR("failed to get resource list document\n"); reply_code = 500; reply_str = pu_500_rpl; goto error; } if(doc== NULL|| service_node==NULL) { LM_DBG("list not found - search for uri = %.*s\n",subs.pres_uri.len, subs.pres_uri.s); pkg_free(subs.pres_uri.s); return to_presence_code; } } else /* if request inside a dialog */ { if( msg->callid==NULL || msg->callid->body.s==NULL) { LM_ERR("cannot parse callid header\n"); goto error; } /* search if a stored dialog */ hash_code= core_hash(&msg->callid->body, &pto->tag_value, hash_size); lock_get(&rls_table[hash_code].lock); if(pres_search_shtable(rls_table,msg->callid->body, pto->tag_value, pfrom->tag_value, hash_code)== NULL) { lock_release(&rls_table[hash_code].lock); /* reply with Call/Transaction Does Not Exist */ LM_DBG("No dialog match found\n"); return to_presence_code; } lock_release(&rls_table[hash_code].lock); } /* extract dialog information from message headers */ if(pres_extract_sdialog_info(&subs, msg, rls_max_expires, &init_req, server_address)< 0) { LM_ERR("bad Subscribe request\n"); goto error; } reply_code = 500; reply_str = pu_500_rpl; if(init_req) /* if an initial subscribe */ { /** reply with 200 OK*/ if(reply_200(msg, &subs.local_contact, subs.expires, &subs.to_tag)< 0) goto error_free; hash_code= core_hash(&subs.callid, &subs.to_tag, hash_size); subs.local_cseq= 0; if(subs.expires!= 0) { subs.version= 1; if(pres_insert_shtable(rls_table, hash_code, &subs)< 0) { LM_ERR("while adding new subscription\n"); goto error_free; } } } else { if(update_rlsubs(&subs, hash_code, &reply_code, &reply_str) < 0) { LM_ERR("while updating resource list subscription\n"); goto error; } if(get_resource_list(&subs.pres_uri, subs.from_user, subs.from_domain, &service_node, &doc)< 0) { LM_ERR("when getting resource list\n"); goto error; } if(doc== NULL || service_node== NULL) { LM_DBG("list not found( in-dialog request)- search for uri = %.*s\n", subs.pres_uri.len, subs.pres_uri.s); reply_code = 404; reply_str = pu_404_rpl; goto error; } /** reply with 200 OK*/ if(reply_200(msg, &subs.local_contact, subs.expires, 0)< 0) goto error_free; } /*** send Subscribe requests for all in the list */ /* call sending Notify with full state */ if(send_full_notify(&subs, service_node, subs.version, &subs.pres_uri,hash_code)< 0) { LM_ERR("while sending full state Notify\n"); goto error_free; } if(resource_subscriptions(&subs, service_node)< 0) { LM_ERR("while sending Subscribe requests to resources in a list\n"); goto error_free; } if(contact) { if(contact->s) pkg_free(contact->s); pkg_free(contact); } pkg_free(subs.pres_uri.s); if(subs.record_route.s) pkg_free(subs.record_route.s); xmlFreeDoc(doc); return 1; bad_event: if(reply_489(msg)< 0) LM_ERR("failed to send 489 reply\n"); goto error_free; error: if (rls_sigb.reply(msg, reply_code, &reply_str, 0) == -1) { LM_ERR("failed to send 400 reply\n"); return -1; } error_free: if(contact) { if(contact->s) pkg_free(contact->s); pkg_free(contact); } if(subs.pres_uri.s) pkg_free(subs.pres_uri.s); if(subs.record_route.s) pkg_free(subs.record_route.s); if(doc) xmlFreeDoc(doc); return -1; }
int rls_handle_subscribe(struct sip_msg* msg, str watcher_user, str watcher_domain) { subs_t subs; pres_ev_t* event = NULL; int err_ret = -1; int ret = to_presence_code; str* contact = NULL; xmlDocPtr doc = NULL; xmlNodePtr service_node = NULL; unsigned int hash_code=0; int to_tag_gen = 0; event_t* parsed_event; param_t* ev_param = NULL; str reason; int rt; str rlsubs_did = {0, 0}; memset(&subs, 0, sizeof(subs_t)); /** sanity checks - parse all headers */ if (parse_headers(msg, HDR_EOH_F, 0)<-1) { LM_ERR("failed parsing all headers\n"); if (slb.freply(msg, 400, &pu_400_rpl) < 0) { LM_ERR("while sending 400 reply\n"); return -1; } return 0; } /* check for To and From headesr */ if(parse_to_uri(msg)<0 || parse_from_uri(msg)<0) { LM_ERR("failed to find To or From headers\n"); if (slb.freply(msg, 400, &pu_400_rpl) < 0) { LM_ERR("while sending 400 reply\n"); return -1; } return 0; } if(get_from(msg)->tag_value.s ==NULL || get_from(msg)->tag_value.len==0) { LM_ERR("no from tag value present\n"); return -1; } if(msg->callid==NULL || msg->callid->body.s==NULL) { LM_ERR("cannot find callid header\n"); return -1; } if(parse_sip_msg_uri(msg)<0) { LM_ERR("failed parsing Request URI\n"); return -1; } /* check for header 'Support: eventlist' */ if(msg->supported==NULL) { LM_DBG("supported header not found - not for rls\n"); goto forpresence; } if(parse_supported(msg)<0) { LM_ERR("failed to parse supported headers\n"); return -1; } if(!(get_supported(msg) & F_SUPPORTED_EVENTLIST)) { LM_DBG("No support for 'eventlist' - not for rls\n"); goto forpresence; } /* inspecting the Event header field */ if(msg->event && msg->event->body.len > 0) { if (!msg->event->parsed && (parse_event(msg->event) < 0)) { LM_ERR("cannot parse Event header\n"); goto error; } if(! ( ((event_t*)msg->event->parsed)->type & rls_events) ) { goto forpresence; } } else { goto bad_event; } /* search event in the list */ parsed_event = (event_t*)msg->event->parsed; event = pres_search_event(parsed_event); if(event==NULL) { goto bad_event; } subs.event= event; /* extract the id if any*/ ev_param= parsed_event->params.list; while(ev_param) { if(ev_param->name.len==2 && strncmp(ev_param->name.s, "id", 2)==0) { subs.event_id = ev_param->body; break; } ev_param= ev_param->next; } /* extract dialog information from message headers */ if(pres_extract_sdialog_info(&subs, msg, rls_max_expires, &to_tag_gen, rls_server_address, watcher_user, watcher_domain)<0) { LM_ERR("bad subscribe request\n"); goto error; } hash_code = core_hash(&subs.callid, &subs.to_tag, hash_size); if (CONSTR_RLSUBS_DID(&subs, &rlsubs_did) < 0) { LM_ERR("cannot build rls subs did\n"); goto error; } subs.updated = core_hash(&rlsubs_did, NULL, 0) % (waitn_time * rls_notifier_poll_rate * rls_notifier_processes); if(get_to(msg)->tag_value.s==NULL || get_to(msg)->tag_value.len==0) { /* initial Subscribe */ /*verify if Request URI represents a list by asking xcap server*/ if(uandd_to_uri(msg->parsed_uri.user, msg->parsed_uri.host, &subs.pres_uri)<0) { LM_ERR("while constructing uri from user and domain\n"); goto error; } if(rls_get_service_list(&subs.pres_uri, &subs.watcher_user, &subs.watcher_domain, &service_node, &doc)<0) { LM_ERR("while attepmting to get a resource list\n"); goto error; } if(doc==NULL) { /* if not for RLS, pass it to presence serivce */ LM_DBG("list not found - searched for uri <%.*s>\n", subs.pres_uri.len, subs.pres_uri.s); goto forpresence; } /* if correct reply with 200 OK */ if(reply_200(msg, &subs.local_contact, subs.expires)<0) goto error; subs.local_cseq = 0; if(subs.expires != 0) { subs.version = 1; if (dbmode==RLS_DB_ONLY) { rt=insert_rlsdb( &subs ); } else { rt=pres_insert_shtable(rls_table, hash_code, &subs); } if (rt<0) { LM_ERR("while adding new subscription\n"); goto error; } } } else { /* search if a stored dialog */ if ( dbmode == RLS_DB_ONLY ) { if (rls_dbf.start_transaction) { if (rls_dbf.start_transaction(rls_db, DB_LOCKING_WRITE) < 0) { LM_ERR("in start_transaction\n"); goto error; } } rt = get_dialog_subscribe_rlsdb(&subs); if (rt <= 0) { LM_DBG("subscription dialog not found for <%.*s@%.*s>\n", subs.watcher_user.len, subs.watcher_user.s, subs.watcher_domain.len, subs.watcher_domain.s); if (rls_dbf.end_transaction) { if (rls_dbf.end_transaction(rls_db) < 0) { LM_ERR("in end_transaction\n"); goto error; } } goto forpresence; } else if(rt>=400) { reason = (rt==400)?pu_400_rpl:stale_cseq_rpl; if (slb.freply(msg, 400, &reason) < 0) { LM_ERR("while sending reply\n"); goto error; } if (rls_dbf.end_transaction) { if (rls_dbf.end_transaction(rls_db) < 0) { LM_ERR("in end_transaction\n"); goto error; } } ret = 0; goto stop; } /* if correct reply with 200 OK */ if(reply_200(msg, &subs.local_contact, subs.expires)<0) goto error; if (update_dialog_subscribe_rlsdb(&subs) < 0) { LM_ERR("while updating resource list subscription\n"); goto error; } if (rls_dbf.end_transaction) { if (rls_dbf.end_transaction(rls_db) < 0) { LM_ERR("in end_transaction\n"); goto error; } } } else { lock_get(&rls_table[hash_code].lock); if(pres_search_shtable(rls_table, subs.callid, subs.to_tag, subs.from_tag, hash_code)==NULL) { lock_release(&rls_table[hash_code].lock); LM_DBG("subscription dialog not found for <%.*s@%.*s>\n", subs.watcher_user.len, subs.watcher_user.s, subs.watcher_domain.len, subs.watcher_domain.s); goto forpresence; } lock_release(&rls_table[hash_code].lock); /* if correct reply with 200 OK */ if(reply_200(msg, &subs.local_contact, subs.expires)<0) goto error; rt = update_rlsubs(&subs, hash_code); if(rt<0) { LM_ERR("while updating resource list subscription\n"); goto error; } if(rt>=400) { reason = (rt==400)?pu_400_rpl:stale_cseq_rpl; if (slb.freply(msg, 400, &reason) < 0) { LM_ERR("while sending reply\n"); goto error; } ret = 0; goto stop; } } if(rls_get_service_list(&subs.pres_uri, &subs.watcher_user, &subs.watcher_domain, &service_node, &doc)<0) { LM_ERR("failed getting resource list\n"); goto error; } if(doc==NULL) { /* warning: no document returned?!?! */ LM_WARN("no document returned for uri <%.*s>\n", subs.pres_uri.len, subs.pres_uri.s); goto done; } } if (dbmode != RLS_DB_ONLY) { /* sending notify with full state */ if(send_full_notify(&subs, service_node, &subs.pres_uri, hash_code)<0) { LM_ERR("failed sending full state notify\n"); goto error; } } /* send subscribe requests for all in the list */ if(resource_subscriptions(&subs, service_node)< 0) { LM_ERR("failed sending subscribe requests to resources in list\n"); goto error; } if (dbmode !=RLS_DB_ONLY) remove_expired_rlsubs(&subs, hash_code); done: ret = 1; stop: forpresence: if(contact!=NULL) { if(contact->s!=NULL) pkg_free(contact->s); pkg_free(contact); } if(subs.pres_uri.s!=NULL) pkg_free(subs.pres_uri.s); if(subs.record_route.s!=NULL) pkg_free(subs.record_route.s); if(doc!=NULL) xmlFreeDoc(doc); if (rlsubs_did.s != NULL) pkg_free(rlsubs_did.s); return ret; bad_event: err_ret = 0; if(reply_489(msg)<0) { LM_ERR("failed sending 489 reply\n"); err_ret = -1; } error: LM_ERR("occured in rls_handle_subscribe\n"); if(contact!=NULL) { if(contact->s!=NULL) pkg_free(contact->s); pkg_free(contact); } if(subs.pres_uri.s!=NULL) pkg_free(subs.pres_uri.s); if(subs.record_route.s!=NULL) pkg_free(subs.record_route.s); if(doc!=NULL) xmlFreeDoc(doc); if (rlsubs_did.s != NULL) pkg_free(rlsubs_did.s); if (rls_dbf.abort_transaction) { if (rls_dbf.abort_transaction(rls_db) < 0) LM_ERR("in abort_transaction\n"); } return err_ret; }