int rls_handle_notify(struct sip_msg* msg, char* c1, char* c2) { struct to_body *pto, TO = {0}, *pfrom = NULL; str body= {0, 0}; ua_pres_t dialog; str* res_id= NULL; db_key_t query_cols[8]; db_val_t query_vals[8]; int n_query_cols= 0; str auth_state= {0, 0}; int found= 0; str reason = {0, 0}; int auth_flag; struct hdr_field* hdr= NULL; int expires= -1; str content_type= {0, 0}; int reply_code = 500; str reply_str = pu_500_rpl; LM_DBG("start\n"); /* extract the dialog information and check if an existing dialog*/ if( parse_headers(msg,HDR_EOH_F, 0)==-1 ) { LM_ERR("parsing headers\n"); reply_code = 400; reply_str = pu_400_rpl; goto error; } if((!msg->event ) ||(msg->event->body.len<=0)) { LM_ERR("Missing event header field value\n"); reply_code = 400; reply_str = pu_400_rpl; goto error; } if( msg->to==NULL || msg->to->body.s==NULL) { LM_ERR("cannot parse TO header\n"); reply_code = 400; reply_str = pu_400_rpl; goto error; } if(msg->to->parsed != NULL) { pto = (struct to_body*)msg->to->parsed; LM_DBG("'To' header ALREADY PARSED: <%.*s>\n", pto->uri.len, pto->uri.s ); } else { parse_to(msg->to->body.s,msg->to->body.s + msg->to->body.len + 1, &TO); if(TO.uri.len <= 0) { LM_ERR(" 'To' header NOT parsed\n"); reply_code = 400; reply_str = pu_400_rpl; goto error; } pto = &TO; } memset(&dialog, 0, sizeof(ua_pres_t)); dialog.watcher_uri= &pto->uri; if (pto->tag_value.s==NULL || pto->tag_value.len==0 ) { LM_ERR("to tag value not parsed\n"); reply_code = 400; reply_str = pu_400_rpl; goto error; } dialog.from_tag= pto->tag_value; if( msg->callid==NULL || msg->callid->body.s==NULL) { LM_ERR("cannot parse callid header\n"); reply_code = 400; reply_str = pu_400_rpl; goto error; } dialog.call_id = msg->callid->body; if (!msg->from || !msg->from->body.s) { LM_ERR("cannot find 'from' header!\n"); reply_code = 400; reply_str = pu_400_rpl; goto error; } if (msg->from->parsed == NULL) { LM_DBG("'From' header not parsed\n"); /* parsing from header */ if ( parse_from_header( msg )<0 ) { LM_ERR("cannot parse From header\n"); reply_code = 400; reply_str = pu_400_rpl; goto error; } } pfrom = (struct to_body*)msg->from->parsed; dialog.pres_uri= &pfrom->uri; if( pfrom->tag_value.s ==NULL || pfrom->tag_value.len == 0) { LM_ERR("no from tag value present\n"); reply_code = 400; reply_str = pu_400_rpl; goto error; } dialog.to_tag= pfrom->tag_value; dialog.flag|= RLS_SUBSCRIBE; dialog.event= get_event_flag(&msg->event->body); if(dialog.event< 0) { LM_ERR("unrecognized event package\n"); reply_code = 489; reply_str = pu_489_rpl; goto error; } /* extract the subscription state */ hdr = msg->headers; while (hdr!= NULL) { if(cmp_hdrname_strzn(&hdr->name, "Subscription-State", 18)==0) { found = 1; break; } hdr = hdr->next; } if(found==0 ) { LM_ERR("'Subscription-State' header not found\n"); goto error; } auth_state = hdr->body; /* extract state and reason */ auth_flag= parse_subs_state(auth_state, &reason, &expires); if(auth_flag< 0) { LM_ERR("while parsing 'Subscription-State' header\n"); goto error; } if(pua_get_record_id(&dialog, &res_id)< 0) /* verify if within a stored dialog */ { LM_ERR("occured when trying to get record id\n"); goto error; } if(res_id==0) { LM_DBG("presence dialog record not found\n"); /* if it is a NOTIFY for a terminated SUBSCRIBE dialog in RLS, then * the module might not have the dialog structure anymore * - just send 200ok, it is harmless */ if(auth_flag==TERMINATED_STATE) goto done; LM_INFO("no presence dialog record for non-TERMINATED state uri pres_uri = %.*s watcher_uri = %.*s\n", dialog.pres_uri->len, dialog.pres_uri->s, dialog.watcher_uri->len, dialog.watcher_uri->s); reply_code = 481; reply_str = pu_481_rpl; goto error; } if(msg->content_type== NULL || msg->content_type->body.s== NULL) { LM_DBG("cannot find content type header header\n"); } else content_type= msg->content_type->body; /*constructing the xml body*/ if(get_content_length(msg) == 0 ) { goto done; } else { if(content_type.s== 0) { LM_ERR("content length != 0 and no content type header found\n"); goto error; } body.s=get_body(msg); if (body.s== NULL) { LM_ERR("cannot extract body from msg\n"); goto error; } body.len = get_content_length( msg ); } /* update in rlpres_table where rlsusb_did= res_id and resource_uri= from_uri*/ LM_DBG("body= %.*s\n", body.len, body.s); query_cols[n_query_cols]= &str_rlsubs_did_col; query_vals[n_query_cols].type = DB1_STR; query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.str_val= *res_id; n_query_cols++; query_cols[n_query_cols]= &str_resource_uri_col; query_vals[n_query_cols].type = DB1_STR; query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.str_val= *dialog.pres_uri; n_query_cols++; query_cols[n_query_cols]= &str_updated_col; query_vals[n_query_cols].type = DB1_INT; query_vals[n_query_cols].nul = 0; if (dbmode == RLS_DB_ONLY) query_vals[n_query_cols].val.int_val= core_hash(res_id, NULL, 0) % (waitn_time * rls_notifier_poll_rate * rls_notifier_processes); else query_vals[n_query_cols].val.int_val = UPDATED_TYPE; n_query_cols++; query_cols[n_query_cols]= &str_auth_state_col; query_vals[n_query_cols].type = DB1_INT; query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.int_val= auth_flag; n_query_cols++; query_cols[n_query_cols]= &str_reason_col; query_vals[n_query_cols].type = DB1_STR; query_vals[n_query_cols].nul = 0; if(reason.len > 0) { query_vals[n_query_cols].val.str_val.s= reason.s; query_vals[n_query_cols].val.str_val.len= reason.len; } else { query_vals[n_query_cols].val.str_val.s = ""; query_vals[n_query_cols].val.str_val.len = 0; } n_query_cols++; query_cols[n_query_cols]= &str_content_type_col; query_vals[n_query_cols].type = DB1_STR; query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.str_val= content_type; n_query_cols++; query_cols[n_query_cols]= &str_presence_state_col; query_vals[n_query_cols].type = DB1_STR; query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.str_val= body; n_query_cols++; query_cols[n_query_cols]= &str_expires_col; query_vals[n_query_cols].type = DB1_INT; query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.int_val= expires+ (int)time(NULL); n_query_cols++; if (rlpres_dbf.use_table(rlpres_db, &rlpres_table) < 0) { LM_ERR("in use_table\n"); goto error; } if (dbmode == RLS_DB_ONLY && rlpres_dbf.start_transaction) { if (rlpres_dbf.start_transaction(rlpres_db) < 0) { LM_ERR("in start_transaction\n"); goto error; } } if (rlpres_dbf.replace != NULL) { if(rlpres_dbf.replace(rlpres_db, query_cols, query_vals, n_query_cols, 2, 0)< 0) { LM_ERR("in sql replace\n"); goto error; } LM_DBG("Inserted/replace in database table new record\n"); } else { if(rlpres_dbf.update(rlpres_db, query_cols, 0, query_vals, query_cols+2, query_vals+2, 2, n_query_cols-2)< 0) { LM_ERR("in sql update\n"); goto error; } if (rlpres_dbf.affected_rows(rlpres_db) == 0) { if(rlpres_dbf.insert(rlpres_db, query_cols, query_vals, n_query_cols)< 0) { LM_ERR("in sql insert\n"); goto error; } LM_DBG("Inserted in database table new record\n"); } } if (dbmode == RLS_DB_ONLY && rlpres_dbf.end_transaction) { if (rlpres_dbf.end_transaction(rlpres_db) < 0) { LM_ERR("in end_transaction\n"); goto error; } } LM_DBG("Updated rlpres_table\n"); /* reply 200OK */ done: if(slb.freply(msg, 200, &su_200_rpl) < 0) { LM_ERR("while sending reply\n"); goto error; } if(res_id!=NULL) { pkg_free(res_id->s); pkg_free(res_id); } if (reason.s) pkg_free(reason.s); free_to_params(&TO); return 1; error: if(slb.freply(msg, reply_code, &reply_str) < 0) { LM_ERR("failed sending reply\n"); } if(res_id!=NULL) { pkg_free(res_id->s); pkg_free(res_id); } if (reason.s) pkg_free(reason.s); free_to_params(&TO); if (dbmode == RLS_DB_ONLY && rlpres_dbf.abort_transaction) { if (rlpres_dbf.abort_transaction(rlpres_db) < 0) LM_ERR("in abort_transaction\n"); } return -1; }
int rls_handle_notify(struct sip_msg* msg, char* c1, char* c2) { struct to_body *pto, *pfrom= NULL; str body= {0, 0}; ua_pres_t dialog; str* res_id= NULL; db_key_t query_cols[9], result_cols[1]; db_val_t query_vals[9]; db_res_t* result= NULL; int n_query_cols= 0; str auth_state= {0, 0}; str* reason= NULL; int auth_flag; struct hdr_field* hdr= NULL; int n, expires= -1; str ctype= {0, 0}; int err_ret = -1; LM_DBG("start\n"); /* extract the dialog information and check if an existing dialog*/ if( parse_headers(msg,HDR_EOH_F, 0)==-1 ) { LM_ERR("parsing headers\n"); return -1; } if((!msg->event ) ||(msg->event->body.len<=0)) { LM_ERR("Missing event header field value\n"); return -1; } if( msg->to==NULL || msg->to->body.s==NULL) { LM_ERR("cannot parse TO header\n"); return -1; } pto = get_to(msg); if (pto == NULL || pto->error != PARSE_OK) { LM_ERR("failed to parse TO header\n"); return -1; } memset(&dialog, 0, sizeof(ua_pres_t)); dialog.watcher_uri= &pto->uri; if (pto->tag_value.s==NULL || pto->tag_value.len==0 ) { LM_ERR("to tag value not parsed\n"); goto error; } dialog.from_tag= pto->tag_value; if( msg->callid==NULL || msg->callid->body.s==NULL) { LM_ERR("cannot parse callid header\n"); goto error; } dialog.call_id = msg->callid->body; if (!msg->from || !msg->from->body.s) { LM_ERR("cannot find 'from' header!\n"); goto error; } if (msg->from->parsed == NULL) { LM_DBG("'From' header not parsed\n"); /* parsing from header */ if ( parse_from_header( msg )<0 ) { LM_ERR("cannot parse From header\n"); goto error; } } pfrom = (struct to_body*)msg->from->parsed; dialog.pres_uri= &pfrom->uri; if( pfrom->tag_value.s ==NULL || pfrom->tag_value.len == 0) { LM_ERR("no from tag value present\n"); goto error; } dialog.to_tag= pfrom->tag_value; dialog.flag|= RLS_SUBSCRIBE; dialog.event= get_event_flag(&msg->event->body); if(dialog.event< 0) { LM_ERR("unrecognized event package\n"); goto error; } if(pua_get_record_id(&dialog, &res_id)< 0) // verify if within a stored dialog { LM_ERR("error occured while trying to get dialog record id\n"); goto error; } if(res_id== 0) { LM_DBG("no dialog match found in hash table\n"); err_ret = 2; goto error; } /* extract the subscription state */ hdr = get_header_by_static_name( msg, "Subscription-State"); if( hdr==NULL ) { LM_ERR("'Subscription-State' header not found\n"); goto error; } auth_state = hdr->body; /* extract state and reason */ auth_flag= parse_subs_state(auth_state, &reason, &expires); if(auth_flag< 0) { LM_ERR("while parsing 'Subscription-State' header\n"); goto error; } if(msg->content_type== NULL || msg->content_type->body.s== NULL) { LM_DBG("cannot find content type header\n"); } else ctype= msg->content_type->body; LM_DBG("NOTIFY for [user]= %.*s\n",dialog.pres_uri->len, dialog.pres_uri->s); /*constructing the xml body*/ if(get_content_length(msg) == 0 ) { LM_DBG("null body\n"); goto done; } else { if(ctype.s== 0) { LM_ERR("content length != 0 and no content type header found\n"); goto error; } if ( get_body(msg,&body)!=0 || body.len==0) { LM_ERR("cannot extract body from msg\n"); goto error; } LM_DBG("[body]= %.*s\n", body.len, body.s); } /* update in rlpres_table where rlsusb_did= res_id and resource_uri= from_uri*/ query_cols[n_query_cols]= &str_rlsubs_did_col; query_vals[n_query_cols].type = DB_STR; query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.str_val= *res_id; n_query_cols++; query_cols[n_query_cols]= &str_resource_uri_col; query_vals[n_query_cols].type = DB_STR; query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.str_val= *dialog.pres_uri; n_query_cols++; query_cols[n_query_cols]= &str_updated_col; query_vals[n_query_cols].type = DB_INT; query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.int_val= UPDATED_TYPE; n_query_cols++; query_cols[n_query_cols]= &str_auth_state_col; query_vals[n_query_cols].type = DB_INT; query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.int_val= auth_flag; n_query_cols++; if(reason) { query_cols[n_query_cols]= &str_reason_col; query_vals[n_query_cols].type = DB_STR; query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.str_val= *reason; n_query_cols++; } query_cols[n_query_cols]= &str_content_type_col; query_vals[n_query_cols].type = DB_STR; query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.str_val= ctype; n_query_cols++; query_cols[n_query_cols]= &str_presence_state_col; query_vals[n_query_cols].type = DB_STR; query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.str_val= body; n_query_cols++; query_cols[n_query_cols]= &str_expires_col; query_vals[n_query_cols].type = DB_INT; query_vals[n_query_cols].nul = 0; query_vals[n_query_cols].val.int_val= expires+ (int)time(NULL); n_query_cols++; if (rls_dbf.use_table(rls_db, &rlpres_table) < 0) { LM_ERR("in use_table\n"); goto error; } /* query-> if not present insert // else update */ result_cols[0]= &str_updated_col; if(rls_dbf.query(rls_db, query_cols, 0, query_vals, result_cols, 2, 1, 0, &result)< 0) { LM_ERR("in sql query\n"); if(result) rls_dbf.free_result(rls_db, result); goto error; } if(result== NULL) goto error; n= result->n; rls_dbf.free_result(rls_db, result); if(n<= 0) { if(rls_dbf.insert(rls_db, query_cols, query_vals, n_query_cols)< 0) { LM_ERR("in sql insert\n"); goto error; } } else { if(expires!= 0) { if(rls_dbf.update(rls_db, query_cols, 0, query_vals, query_cols+2, query_vals+2, 2, n_query_cols-2)< 0) { LM_ERR("in sql update\n"); goto error; } } else /* if terminated - delete from rls_presentity table */ { if(rls_dbf.delete(rls_db, query_cols, 0, query_vals, 2)< 0) { LM_ERR("sql delete failed\n"); goto error; } } } done: if( rls_sigb.reply(msg, 200, &su_200_rpl, 0) < 0) { LM_ERR("failed to send SIP reply\n"); goto error; } pkg_free(res_id->s); pkg_free(res_id); return 1; error: if(res_id) { pkg_free(res_id->s); pkg_free(res_id); } return err_ret; }