int register_watcher(str* _f, str* _t, notcb_t _c, void* _data) { udomain_t* d; urecord_t* r; if (find_domain(&dom, &d) > 0) { LOG(L_ERR, "register_watcher(): Domain '%.*s' not found\n", dom.len, ZSW(dom.s)); return -1; } lock_udomain(d); if (get_urecord(d, _t, &r) > 0) { if (insert_urecord(d, _t, &r) < 0) { unlock_udomain(d); LOG(L_ERR, "register_watcher(): Error while creating a new record\n"); return -2; } } if (add_watcher(r, _c, _data) < 0) { LOG(L_ERR, "register_watcher(): Error while adding a watcher\n"); release_urecord(r); unlock_udomain(d); return -3; } unlock_udomain(d); return 0; }
int unregister_watcher(str* _f, str* _t, notcb_t _c, void* _data) { udomain_t* d; urecord_t* r; if (find_domain(&dom, &d) > 0) { LOG(L_ERR, "unregister_watcher(): Domain '%.*s' not found\n", dom.len, ZSW(dom.s)); return -1; } lock_udomain(d); if (get_urecord(d, _t, &r) > 0) { unlock_udomain(d); DBG("unregister_watcher(): Record not found\n"); return 0; } remove_watcher(r, _c, _data); release_urecord(r); unlock_udomain(d); return 0; }
/** * Note: prevents the creation of any duplicate AoR */ static int receive_urecord_insert(bin_packet_t *packet) { str d, aor; urecord_t *r; udomain_t *domain; bin_pop_str(packet, &d); bin_pop_str(packet, &aor); if (find_domain(&d, &domain) != 0) { LM_ERR("domain '%.*s' is not local\n", d.len, d.s); goto out_err; } lock_udomain(domain, &aor); if (get_urecord(domain, &aor, &r) == 0) goto out; if (insert_urecord(domain, &aor, &r, 1) != 0) { unlock_udomain(domain, &aor); goto out_err; } out: unlock_udomain(domain, &aor); return 0; out_err: LM_ERR("failed to replicate event locally. dom: '%.*s', aor: '%.*s'\n", d.len, d.s, aor.len, aor.s); return -1; }
/*! * \brief Delete a urecord from domain * \param _d domain where the record should be deleted * \param _aor address of record * \param _r deleted record * \return 0 on success, -1 if the record could not be deleted */ int delete_urecord(udomain_t* _d, str* _aor, struct urecord* _r) { struct ucontact* c, *t; if (db_mode==DB_ONLY) { if (_r==0) get_static_urecord( _d, _aor, &_r); if (db_delete_urecord(_d, _r)<0) { LM_ERR("DB delete failed\n"); return -1; } free_urecord(_r); return 0; } if (_r==0) { if (get_urecord(_d, _aor, &_r) > 0) { return 0; } } c = _r->contacts; while(c) { t = c; c = c->next; if (delete_ucontact(_r, t) < 0) { LM_ERR("deleting contact failed\n"); return -1; } } release_urecord(_r); return 0; }
static int receive_ucontact_delete(bin_packet_t *packet) { udomain_t *domain; urecord_t *record; ucontact_t *contact; str d, aor, contact_str, callid; int cseq, rc; bin_pop_str(packet, &d); bin_pop_str(packet,&aor); bin_pop_str(packet,&contact_str); bin_pop_str(packet,&callid); bin_pop_int(packet,&cseq); if (find_domain(&d, &domain) != 0) { LM_ERR("domain '%.*s' is not local\n", d.len, d.s); goto error; } lock_udomain(domain, &aor); /* failure in retrieving a urecord may be ok, because packet order in UDP * is not guaranteed, so urecord_delete commands may arrive before * ucontact_delete's */ if (get_urecord(domain, &aor, &record) != 0) { LM_INFO("failed to fetch local urecord - ignoring request " "(ci: '%.*s')\n", callid.len, callid.s); unlock_udomain(domain, &aor); return 0; } /* simply specify a higher cseq and completely avoid any complications */ rc = get_ucontact(record, &contact_str, &callid, cseq + 1, &contact); if (rc != 0 && rc != 2) { LM_ERR("contact '%.*s' not found: (ci: '%.*s')\n", contact_str.len, contact_str.s, callid.len, callid.s); unlock_udomain(domain, &aor); goto error; } if (skip_replicated_db_ops) contact->flags |= FL_MEM; if (delete_ucontact(record, contact, 1) != 0) { LM_ERR("failed to delete ucontact '%.*s' (ci: '%.*s')\n", contact_str.len, contact_str.s, callid.len, callid.s); unlock_udomain(domain, &aor); goto error; } unlock_udomain(domain, &aor); return 0; error: LM_ERR("failed to process replication event. dom: '%.*s', aor: '%.*s'\n", d.len, d.s, aor.len, aor.s); return -1; }
static inline int add_contact(udomain_t* _d, str* _u, str* _c, time_t _e, qvalue_t _q, int _f, int sid) { urecord_t* r; ucontact_t* c = 0; int res; str cid; str ua; str aor = STR_NULL; if (_e == 0 && !(_f & FL_PERMANENT)) { LOG(L_ERR, "rpc_add_contact(): expires == 0 and not persistent contact, giving up\n"); return -1; } get_act_time(); res = get_urecord(_d, _u, &r); if (res < 0) { LOG(L_ERR, "rpc_add_contact(): Error while getting record\n"); return -2; } if (res > 0) { /* Record not found */ if (insert_urecord(_d, _u, &r) < 0) { LOG(L_ERR, "rpc_add_contact(): Error while creating new urecord\n"); return -3; } } else { if (get_ucontact(r, _c, &c) < 0) { LOG(L_ERR, "rpc_add_contact(): Error while obtaining ucontact\n"); return -4; } } cid.s = "RPC-Call-ID"; cid.len = strlen(cid.s); ua.s = "SER-RPC"; ua.len = strlen(ua.s); if (c) { if (update_ucontact(c, &aor, _c, _e + act_time, _q, &cid, 42, _f, FL_NONE, &ua, 0, 0, 0, sid == -1 ? server_id : sid) < 0) { LOG(L_ERR, "rpc_add_contact(): Error while updating contact\n"); release_urecord(r); return -5; } } else { if (insert_ucontact(r, &aor, _c, _e + act_time, _q, &cid, 42, _f, &c, &ua, 0, 0, 0, sid == -1 ? server_id : sid) < 0) { LOG(L_ERR, "rpc_add_contact(): Error while inserting contact\n"); release_urecord(r); return -6; } } release_urecord(r); return 0; }
static inline int add_contact(udomain_t* _d, str* _u, str* _c, time_t _e, qvalue_t _q, int _f) { urecord_t* r; ucontact_t* c = 0; int res; str cid; str ua; if (_e == 0 && !(_f & FL_PERMANENT)) { LOG(L_ERR, "fifo_add_contact(): expires == 0 and not persistent contact, giving up\n"); return -1; } get_act_time(); res = get_urecord(_d, _u, &r); if (res < 0) { LOG(L_ERR, "fifo_add_contact(): Error while getting record\n"); return -2; } if (res > 0) { /* Record not found */ if (insert_urecord(_d, _u, &r) < 0) { LOG(L_ERR, "fifo_add_contact(): Error while creating new urecord\n"); return -3; } } else { if (get_ucontact(r, _c, &c) < 0) { LOG(L_ERR, "fifo_add_contact(): Error while obtaining ucontact\n"); return -4; } } cid.s = FIFO_CALLID; cid.len = FIFO_CALLID_LEN; ua.s = FIFO_UA; ua.len = FIFO_UA_LEN; if (c) { if (update_ucontact(c, _e + act_time, _q, &cid, FIFO_CSEQ, _f, FL_NONE, &ua, 0) < 0) { LOG(L_ERR, "fifo_add_contact(): Error while updating contact\n"); release_urecord(r); return -5; } } else { if (insert_ucontact(r, _c, _e + act_time, _q, &cid, FIFO_CSEQ, _f, &c, &ua, 0) < 0) { LOG(L_ERR, "fifo_add_contact(): Error while inserting contact\n"); release_urecord(r); return -6; } } release_urecord(r); return 0; }
static void rpc_delete_contact(rpc_t* rpc, void* ctx) { udomain_t* d; urecord_t* r; ucontact_t* con; str uid, t, c; int res; if (rpc->scan(ctx, "SSS", &t, &uid, &c) < 3) return; rpc_find_domain(&t, &d); if (d) { lock_udomain(d); res = get_urecord(d, &uid, &r); if (res < 0) { rpc->fault(ctx, 500, "Error While Searching Table"); ERR("Error while looking for uid %.*s in table %.*s\n", uid.len, uid.s, t.len, t.s); unlock_udomain(d); return; } if (res > 0) { rpc->fault(ctx, 404, "AOR Not Found"); unlock_udomain(d); return; } res = get_ucontact(r, &c, &con); if (res < 0) { rpc->fault(ctx, 500, "Error While Searching for Contact"); ERR("Error while looking for contact %.*s\n", c.len, c.s); unlock_udomain(d); return; } if (res > 0) { rpc->fault(ctx, 404, "Contact Not Found"); unlock_udomain(d); return; } if (delete_ucontact(r, con) < 0) { rpc->fault(ctx, 500, "Error While Deleting Contact"); unlock_udomain(d); return; } release_urecord(r); unlock_udomain(d); } else { rpc->fault(ctx, 404, "Table Not Found"); } }
/*! * \brief Delete a contact from an AOR record * \param cmd mi_root containing the parameter * \param param not used * \note expects 3 nodes: the table name, the AOR and contact * \return mi_root with the result or 0 on failure */ struct mi_root* mi_usrloc_rm_contact(struct mi_root *cmd, void *param) { struct mi_node *node; udomain_t *dom; urecord_t *rec; ucontact_t* con; str *aor, *contact; int ret; node = cmd->node.kids; if (node==NULL || node->next==NULL || node->next->next==NULL || node->next->next->next!=NULL) return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); /* look for table */ dom = mi_find_domain( &node->value ); if (dom==NULL) return init_mi_tree( 404, "Table not found", 15); /* process the aor */ aor = &node->next->value; if ( mi_fix_aor(aor)!=0 ) return init_mi_tree( 400, "Domain missing in AOR", 21); lock_udomain( dom, aor); ret = get_urecord( dom, aor, &rec); if (ret == 1) { unlock_udomain( dom, aor); return init_mi_tree( 404, "AOR not found", 13); } contact = &node->next->next->value; set_mi_ul_cid(); ret = get_ucontact( rec, contact, &mi_ul_cid, &mi_ul_path, MI_UL_CSEQ+1, &con); if (ret < 0) { unlock_udomain( dom, aor); return 0; } if (ret > 0) { unlock_udomain( dom, aor); return init_mi_tree( 404, "Contact not found", 17); } if (delete_ucontact(rec, con) < 0) { unlock_udomain( dom, aor); return 0; } release_urecord(rec); unlock_udomain( dom, aor); return init_mi_tree( 200, MI_OK_S, MI_OK_LEN); }
/* * Delete a urecord from domain */ int delete_urecord(udomain_t* _d, str* _uid) { struct ucontact* c, *t; struct urecord* r; if (get_urecord(_d, _uid, &r) > 0) { return 0; } c = r->contacts; while(c) { t = c; c = c->next; if (delete_ucontact(r, t) < 0) { LOG(L_ERR, "delete_urecord(): Error while deleting contact\n"); return -1; } } release_urecord(r); return 0; }
static void rpc_show_contacts(rpc_t* rpc, void* c) { udomain_t* d; urecord_t* r; int res; str t, uid; if (rpc->scan(c, "SS", &t, &uid) < 2) return; rpc_find_domain(&t, &d); if (d) { lock_udomain(d); res = get_urecord(d, &uid, &r); if (res < 0) { rpc->fault(c, 500, "Error While Searching AOR"); ERR("Error while looking for username %.*s in table %.*s\n", uid.len, uid.s, t.len, t.s); unlock_udomain(d); return; } if (res > 0) { rpc->fault(c, 404, "AOR Not Found"); unlock_udomain(d); return; } get_act_time(); if (!print_contacts(rpc, c, r->contacts)) { unlock_udomain(d); rpc->fault(c, 404, "No Registered Contacts Found"); return; } unlock_udomain(d); } else { rpc->fault(c, 400, "Table Not Found"); } }
int read_reg_avps(struct sip_msg *m, char* _domain, char* fp) { urecord_t* r = NULL; struct ucontact *contact = NULL; udomain_t *d; str uid; if (!use_reg_avps()) return 1; d = (udomain_t*)_domain; if (get_str_fparam(&uid, m, (fparam_t*)fp) < 0) { ERR("invalid parameter\n"); return -1; } /* INFO("reading avps for uid=%.*s\n", uid.len, ZSW(uid.s)); */ lock_udomain(d); if (get_urecord(d, &uid, &r) != 0) { unlock_udomain(d); WARN("urecord not found\n"); return -1; } if (get_ucontact(r, &m->new_uri, &contact) != 0) { unlock_udomain(d); WARN("ucontact not found\n"); return -1; } load_reg_avps(contact); unlock_udomain(d); return 1; }
static int ul_rm_contact(FILE* pipe, char* response_file) { char table[MAX_TABLE]; char user[MAX_USER]; char contact[MAX_CONTACT_LEN]; udomain_t* d; urecord_t* r; ucontact_t* con; str aor, t, c; int res; char* at; if (!read_line(table, MAX_TABLE, pipe, &t.len) || t.len ==0) { fifo_reply(response_file, "400 ul_rm_contact: table name expected\n"); LOG(L_ERR, "ERROR: ul_rm_contact: table name expected\n"); return 1; } if (!read_line(user, MAX_USER, pipe, &aor.len) || aor.len==0) { fifo_reply(response_file, "400 ul_rm_contact: user name expected\n"); LOG(L_ERR, "ERROR: ul_rm_contact: user name expected\n"); return 1; } at = memchr(user, '@', aor.len); if (use_domain) { if (!at) { fifo_reply(response_file, "400 ul_rm_contact: user@domain expected\n"); LOG(L_ERR, "ERROR: ul_rm_contact: Domain missing\n"); return 1; } } else { if (at) { aor.len = at - user; } } if (!read_line(contact, MAX_CONTACT_LEN, pipe, &c.len) || c.len == 0) { fifo_reply(response_file, "400 ul_rm_contact: contact expected\n"); LOG(L_ERR, "ERROR: ul_rm_contact: contact expected\n"); return 1; } aor.s = user; strlower(&aor); t.s = table; c.s = contact; fifo_find_domain(&t, &d); LOG(L_INFO, "INFO: deleting user-loc contact (%s,%s,%s)\n", table, user, contact ); if (d) { lock_udomain(d); res = get_urecord(d, &aor, &r); if (res < 0) { fifo_reply(response_file, "500 Error while looking for username %s in table %s\n", user, table); LOG(L_ERR, "ERROR: ul_rm_contact: Error while looking for username %s in table %s\n", user, table); unlock_udomain(d); return 1; } if (res > 0) { fifo_reply(response_file, "404 Username %s in table %s not found\n", user, table); unlock_udomain(d); return 1; } res = get_ucontact(r, &c, &con); if (res < 0) { fifo_reply(response_file, "500 Error while looking for contact %s\n", contact); LOG(L_ERR, "ERROR: ul_rm_contact: Error while looking for contact %s\n", contact); unlock_udomain(d); return 1; } if (res > 0) { fifo_reply(response_file, "404 Contact %s in table %s not found\n", contact, table); unlock_udomain(d); return 1; } if (delete_ucontact(r, con) < 0) { fifo_reply(response_file, "500 ul_rm_contact: Error while deleting contact %s\n", contact); unlock_udomain(d); return 1; } release_urecord(r); unlock_udomain(d); fifo_reply(response_file, "200 Contact (%s, %s) deleted from table %s\n", user, contact, table); return 1; } else { fifo_reply(response_file, "400 table (%s) not found\n", table); return 1; } }
static inline int ul_show_contact(FILE* pipe, char* response_file) { char table[MAX_TABLE]; char user[MAX_USER]; FILE* reply_file; udomain_t* d; urecord_t* r; int res; str t, aor; char* at; if (!read_line(table, MAX_TABLE, pipe, &t.len) || t.len ==0) { fifo_reply(response_file, "400 ul_show_contact: table name expected\n"); LOG(L_ERR, "ERROR: ul_show_contact: table name expected\n"); return 1; } if (!read_line(user, MAX_USER, pipe, &aor.len) || aor.len==0) { fifo_reply(response_file, "400 ul_show_contact: user name expected\n"); LOG(L_ERR, "ERROR: ul_show_contact: user name expected\n"); return 1; } at = memchr(user, '@', aor.len); if (use_domain) { if (!at) { fifo_reply(response_file, "400 ul_show_contact: user@domain expected\n"); LOG(L_ERR, "ERROR: ul_show_contact: Domain missing\n"); return 1; } } else { if (at) { aor.len = at - user; } } aor.s = user; strlower(&aor); t.s = table; fifo_find_domain(&t, &d); if (d) { lock_udomain(d); res = get_urecord(d, &aor, &r); if (res < 0) { fifo_reply(response_file, "500 Error while looking for username %s in table %s\n", user, table); LOG(L_ERR, "ERROR: ul_show_contact: Error while looking for username %s in table %s\n", user, table); unlock_udomain(d); return 1; } if (res > 0) { fifo_reply(response_file, "404 Username %s in table %s not found\n", user, table); unlock_udomain(d); return 1; } get_act_time(); reply_file=open_reply_pipe(response_file); if (reply_file==0) { LOG(L_ERR, "ERROR: ul_show_contact: file not opened\n"); unlock_udomain(d); return 1; } if (!print_contacts(reply_file, r->contacts)) { unlock_udomain(d); fprintf(reply_file, "404 No registered contacts found\n"); fclose(reply_file); return 1; } fclose(reply_file); unlock_udomain(d); return 1; } else { fifo_reply(response_file, "400 table (%s) not found\n", table); return 1; } }
/*! * \brief Dumps the contacts of an AOR * \param cmd mi_root containing the parameter * \param param not used * \note expects 2 nodes: the table name and the AOR * \return mi_root with the result or 0 on failure */ struct mi_root* mi_usrloc_show_contact(struct mi_root *cmd, void *param) { struct mi_root *rpl_tree; struct mi_node *rpl, *node; udomain_t *dom; urecord_t *rec; ucontact_t* con; str *aor; int ret; node = cmd->node.kids; if (node==NULL || node->next==NULL || node->next->next!=NULL) return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); /* look for table */ dom = mi_find_domain( &node->value ); if (dom==NULL) return init_mi_tree( 404, "Table not found", 15); /* process the aor */ aor = &node->next->value; if ( mi_fix_aor(aor)!=0 ) return init_mi_tree( 400, "Domain missing in AOR", 21); lock_udomain( dom, aor); ret = get_urecord( dom, aor, &rec); if (ret == 1) { unlock_udomain( dom, aor); return init_mi_tree( 404, "AOR not found", 13); } get_act_time(); rpl_tree = 0; rpl = 0; for( con=rec->contacts ; con ; con=con->next) { if (VALID_CONTACT( con, act_time)) { if (rpl_tree==0) { rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN); if (rpl_tree==0) goto error; rpl = &rpl_tree->node; } node = addf_mi_node_child( rpl, 0, "Contact", 7, "<%.*s>;q=%s;expires=%d;flags=0x%X;cflags=0x%X;socket=<%.*s>;" "methods=0x%X" "%s%.*s%s" /*received*/ "%s%.*s%s" /*user-agent*/ "%s%.*s%s" /*path*/ "%s%.*s" /*instance*/ ";reg-id=%u", con->c.len, ZSW(con->c.s), q2str(con->q, 0), (int)(con->expires - act_time), con->flags, con->cflags, con->sock?con->sock->sock_str.len:3, con->sock?con->sock->sock_str.s:"NULL", con->methods, con->received.len?";received=<":"",con->received.len, ZSW(con->received.s), con->received.len?">":"", con->user_agent.len?";user_agent=<":"",con->user_agent.len, ZSW(con->user_agent.s), con->user_agent.len?">":"", con->path.len?";path=<":"", con->path.len, ZSW(con->path.s), con->path.len?">":"", con->instance.len?";+sip.instance=":"", con->instance.len, ZSW(con->instance.s), con->reg_id ); if (node==0) goto error; } } unlock_udomain( dom, aor); if (rpl_tree==0) return init_mi_tree( 404 , "AOR has no contacts", 18); return rpl_tree; error: if (rpl_tree) free_mi_tree( rpl_tree ); unlock_udomain( dom, aor); return 0; }
/*! * \brief Add a new contact for an address of record * \param cmd mi_root containing the parameter * \param param not used * \note Expects 7 nodes: table name, AOR, contact, expires, Q, * useless - backward compatible, flags, cflags, methods * \return mi_root with the result */ struct mi_root* mi_usrloc_add(struct mi_root *cmd, void *param) { ucontact_info_t ci; urecord_t* r; ucontact_t* c; struct mi_node *node; udomain_t *dom; str *aor, *contact; unsigned int ui_val; int n; for( n=0,node = cmd->node.kids; n<9 && node ; n++,node=node->next ); if (n!=9 || node!=0) return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); node = cmd->node.kids; /* look for table (param 1) */ dom = mi_find_domain( &node->value ); if (dom==NULL) return init_mi_tree( 404, "Table not found", 15); /* process the aor (param 2) */ node = node->next; aor = &node->value; if ( mi_fix_aor(aor)!=0 ) return init_mi_tree( 400, "Domain missing in AOR", 21); /* contact (param 3) */ node = node->next; contact = &node->value; memset( &ci, 0, sizeof(ucontact_info_t)); /* expire (param 4) */ node = node->next; if (str2int( &node->value, &ui_val) < 0) goto bad_syntax; ci.expires = ui_val; /* q value (param 5) */ node = node->next; if (str2q( &ci.q, node->value.s, node->value.len) < 0) goto bad_syntax; /* unused value (param 6) FIXME */ node = node->next; /* flags value (param 7) */ node = node->next; if (str2int( &node->value, (unsigned int*)&ci.flags) < 0) goto bad_syntax; /* branch flags value (param 8) */ node = node->next; if (str2int( &node->value, (unsigned int*)&ci.cflags) < 0) goto bad_syntax; /* methods value (param 9) */ node = node->next; if (str2int( &node->value, (unsigned int*)&ci.methods) < 0) goto bad_syntax; if(sruid_next(&_ul_sruid)<0) goto error; ci.ruid = _ul_sruid.uid; lock_udomain( dom, aor); n = get_urecord( dom, aor, &r); if ( n==1) { if (insert_urecord( dom, aor, &r) < 0) goto lock_error; c = 0; } else { if (get_ucontact( r, contact, &mi_ul_cid, &mi_ul_path, MI_UL_CSEQ+1, &c) < 0) goto lock_error; } get_act_time(); ci.callid = &mi_ul_cid; ci.user_agent = &mi_ul_ua; ci.cseq = MI_UL_CSEQ; /* 0 expires means permanent contact */ if (ci.expires!=0) ci.expires += act_time; if (c) { if (update_ucontact( r, c, &ci) < 0) goto release_error; } else { if ( insert_ucontact( r, contact, &ci, &c) < 0 ) goto release_error; } release_urecord(r); unlock_udomain( dom, aor); return init_mi_tree( 200, MI_OK_S, MI_OK_LEN); bad_syntax: return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN); release_error: release_urecord(r); lock_error: unlock_udomain( dom, aor); error: return init_mi_tree( 500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN); }
static int receive_ucontact_insert(bin_packet_t *packet) { static ucontact_info_t ci; static str d, aor, host, contact_str, callid, user_agent, path, attr, st, sock; udomain_t *domain; urecord_t *record; ucontact_t *contact; int rc, port, proto; memset(&ci, 0, sizeof ci); bin_pop_str(packet, &d); bin_pop_str(packet, &aor); if (find_domain(&d, &domain) != 0) { LM_ERR("domain '%.*s' is not local\n", d.len, d.s); goto error; } bin_pop_str(packet, &contact_str); bin_pop_str(packet, &st); memcpy(&ci.contact_id, st.s, sizeof ci.contact_id); bin_pop_str(packet, &callid); ci.callid = &callid; bin_pop_str(packet, &user_agent); ci.user_agent = &user_agent; bin_pop_str(packet, &path); ci.path = &path; bin_pop_str(packet, &attr); ci.attr = &attr; bin_pop_str(packet, &ci.received); bin_pop_str(packet, &ci.instance); bin_pop_str(packet, &st); memcpy(&ci.expires, st.s, sizeof ci.expires); bin_pop_str(packet, &st); memcpy(&ci.q, st.s, sizeof ci.q); bin_pop_str(packet, &sock); if (sock.s && sock.s[0]) { if (parse_phostport(sock.s, sock.len, &host.s, &host.len, &port, &proto) != 0) { LM_ERR("bad socket <%.*s>\n", sock.len, sock.s); goto error; } ci.sock = grep_sock_info(&host, (unsigned short) port, (unsigned short) proto); if (!ci.sock) LM_DBG("non-local socket <%.*s>\n", sock.len, sock.s); } else { ci.sock = NULL; } bin_pop_int(packet, &ci.cseq); bin_pop_int(packet, &ci.flags); bin_pop_int(packet, &ci.cflags); bin_pop_int(packet, &ci.methods); bin_pop_str(packet, &st); memcpy(&ci.last_modified, st.s, sizeof ci.last_modified); if (skip_replicated_db_ops) ci.flags |= FL_MEM; lock_udomain(domain, &aor); if (get_urecord(domain, &aor, &record) != 0) { LM_INFO("failed to fetch local urecord - creating new one " "(ci: '%.*s') \n", callid.len, callid.s); if (insert_urecord(domain, &aor, &record, 1) != 0) { LM_ERR("failed to insert new record\n"); unlock_udomain(domain, &aor); goto error; } } rc = get_ucontact(record, &contact_str, &callid, ci.cseq, &contact); switch (rc) { case -2: /* received data is consistent with what we have */ case -1: /* received data is older than what we have */ break; case 0: /* received data is newer than what we have */ if (update_ucontact(record, contact, &ci, 1) != 0) { LM_ERR("failed to update ucontact (ci: '%.*s')\n", callid.len, callid.s); unlock_udomain(domain, &aor); goto error; } break; case 1: if (insert_ucontact(record, &contact_str, &ci, &contact, 1) != 0) { LM_ERR("failed to insert ucontact (ci: '%.*s')\n", callid.len, callid.s); unlock_udomain(domain, &aor); goto error; } break; } unlock_udomain(domain, &aor); return 0; error: LM_ERR("failed to process replication event. dom: '%.*s', aor: '%.*s'\n", d.len, d.s, aor.len, aor.s); return -1; }
static int receive_ucontact_update(bin_packet_t *packet) { static ucontact_info_t ci; static str d, aor, host, contact_str, callid, user_agent, path, attr, st, sock; udomain_t *domain; urecord_t *record; ucontact_t *contact; int port, proto; int rc; memset(&ci, 0, sizeof ci); bin_pop_str(packet, &d); bin_pop_str(packet, &aor); if (find_domain(&d, &domain) != 0) { LM_ERR("domain '%.*s' is not local\n", d.len, d.s); goto error; } bin_pop_str(packet, &contact_str); bin_pop_str(packet, &callid); ci.callid = &callid; bin_pop_str(packet, &user_agent); ci.user_agent = &user_agent; bin_pop_str(packet, &path); ci.path = &path; bin_pop_str(packet, &attr); ci.attr = &attr; bin_pop_str(packet, &ci.received); bin_pop_str(packet, &ci.instance); bin_pop_str(packet, &st); memcpy(&ci.expires, st.s, sizeof ci.expires); bin_pop_str(packet, &st); memcpy(&ci.q, st.s, sizeof ci.q); bin_pop_str(packet, &sock); if (sock.s && sock.s[0]) { if (parse_phostport(sock.s, sock.len, &host.s, &host.len, &port, &proto) != 0) { LM_ERR("bad socket <%.*s>\n", sock.len, sock.s); goto error; } ci.sock = grep_sock_info(&host, (unsigned short) port, (unsigned short) proto); if (!ci.sock) LM_DBG("non-local socket <%.*s>\n", sock.len, sock.s); } else { ci.sock = NULL; } bin_pop_int(packet, &ci.cseq); bin_pop_int(packet, &ci.flags); bin_pop_int(packet, &ci.cflags); bin_pop_int(packet, &ci.methods); bin_pop_str(packet, &st); memcpy(&ci.last_modified, st.s, sizeof ci.last_modified); bin_pop_str(packet, &st); ci.packed_kv_storage = &st; if (skip_replicated_db_ops) ci.flags |= FL_MEM; lock_udomain(domain, &aor); /* failure in retrieving a urecord may be ok, because packet order in UDP * is not guaranteed, so update commands may arrive before inserts */ if (get_urecord(domain, &aor, &record) != 0) { LM_INFO("failed to fetch local urecord - create new record and contact" " (ci: '%.*s')\n", callid.len, callid.s); if (insert_urecord(domain, &aor, &record, 1) != 0) { LM_ERR("failed to insert urecord\n"); unlock_udomain(domain, &aor); goto error; } if (insert_ucontact(record, &contact_str, &ci, &contact, 1) != 0) { LM_ERR("failed (ci: '%.*s')\n", callid.len, callid.s); unlock_udomain(domain, &aor); goto error; } } else { rc = get_ucontact(record, &contact_str, &callid, ci.cseq + 1, &contact); if (rc == 1) { LM_INFO("contact '%.*s' not found, inserting new (ci: '%.*s')\n", contact_str.len, contact_str.s, callid.len, callid.s); if (insert_ucontact(record, &contact_str, &ci, &contact, 1) != 0) { LM_ERR("failed to insert ucontact (ci: '%.*s')\n", callid.len, callid.s); unlock_udomain(domain, &aor); goto error; } } else if (rc == 0) { if (update_ucontact(record, contact, &ci, 1) != 0) { LM_ERR("failed to update ucontact '%.*s' (ci: '%.*s')\n", contact_str.len, contact_str.s, callid.len, callid.s); unlock_udomain(domain, &aor); goto error; } } /* XXX: for -2 and -1, the master should have already handled these errors - so we can skip them - razvanc */ } unlock_udomain(domain, &aor); return 0; error: LM_ERR("failed to process replication event. dom: '%.*s', aor: '%.*s'\n", d.len, d.s, aor.len, aor.s); return -1; }
int preload_udomain(db_con_t* _c, udomain_t* _d) { char b[256]; db_key_t columns[11]; db_res_t* res; db_row_t* row; int i, cseq; unsigned int flags; struct socket_info* sock; str uid, contact, callid, ua, received, instance, aor; str* rec; time_t expires; qvalue_t q; urecord_t* r; ucontact_t* c; columns[0] = uid_col.s; columns[1] = contact_col.s; columns[2] = expires_col.s; columns[3] = q_col.s; columns[4] = callid_col.s; columns[5] = cseq_col.s; columns[6] = flags_col.s; columns[7] = user_agent_col.s; columns[8] = received_col.s; columns[9] = instance_col.s; columns[10] = aor_col.s; memcpy(b, _d->name->s, _d->name->len); b[_d->name->len] = '\0'; if (ul_dbf.use_table(_c, b) < 0) { LOG(L_ERR, "preload_udomain(): Error in use_table\n"); return -1; } if (ul_dbf.query(_c, 0, 0, 0, columns, 0, 11, 0, &res) < 0) { LOG(L_ERR, "preload_udomain(): Error while doing db_query\n"); return -1; } if (RES_ROW_N(res) == 0) { DBG("preload_udomain(): Table is empty\n"); ul_dbf.free_result(_c, res); return 0; } lock_udomain(_d); for(i = 0; i < RES_ROW_N(res); i++) { row = RES_ROWS(res) + i; uid.s = (char*)VAL_STRING(ROW_VALUES(row)); if (uid.s == 0) { LOG(L_CRIT, "preload_udomain: ERROR: bad uid " "record in table %s\n", b); LOG(L_CRIT, "preload_udomain: ERROR: skipping...\n"); continue; } else { uid.len = strlen(uid.s); } contact.s = (char*)VAL_STRING(ROW_VALUES(row) + 1); if (contact.s == 0) { LOG(L_CRIT, "preload_udomain: ERROR: bad contact " "record in table %s\n", b); LOG(L_CRIT, "preload_udomain: ERROR: for username %.*s\n", uid.len, uid.s); LOG(L_CRIT, "preload_udomain: ERROR: skipping...\n"); continue; } else { contact.len = strlen(contact.s); } expires = VAL_TIME (ROW_VALUES(row) + 2); q = double2q(VAL_DOUBLE(ROW_VALUES(row) + 3)); cseq = VAL_INT (ROW_VALUES(row) + 5); callid.s = (char*)VAL_STRING(ROW_VALUES(row) + 4); if (callid.s == 0) { LOG(L_CRIT, "preload_udomain: ERROR: bad callid record in" " table %s\n", b); LOG(L_CRIT, "preload_udomain: ERROR: for username %.*s," " contact %.*s\n", uid.len, uid.s, contact.len, contact.s); LOG(L_CRIT, "preload_udomain: ERROR: skipping...\n"); continue; } else { callid.len = strlen(callid.s); } flags = VAL_BITMAP(ROW_VALUES(row) + 6); ua.s = (char*)VAL_STRING(ROW_VALUES(row) + 7); if (ua.s) { ua.len = strlen(ua.s); } else { ua.len = 0; } if (!VAL_NULL(ROW_VALUES(row) + 8)) { received.s = (char*)VAL_STRING(ROW_VALUES(row) + 8); if (received.s) { received.len = strlen(received.s); rec = &received; sock = find_socket(&received); } else { received.len = 0; rec = 0; sock = 0; } } else { received.s = 0; received.len = 0; rec = 0; sock = 0; } if (!VAL_NULL(ROW_VALUES(row) + 9)) { instance.s = (char*)VAL_STRING(ROW_VALUES(row) + 9); if (instance.s) { instance.len = strlen(instance.s); } else { instance.len = 0; } } else { instance.s = 0; instance.len = 0; } if (!VAL_NULL(ROW_VALUES(row) + 10)) { aor.s = (char*)VAL_STRING(ROW_VALUES(row) + 10); if (aor.s) { aor.len = strlen(aor.s); } else { aor.len = 0; } } else { aor.s = 0; aor.len = 0; } if (get_urecord(_d, &uid, &r) > 0) { if (mem_insert_urecord(_d, &uid, &r) < 0) { LOG(L_ERR, "preload_udomain(): Can't create a record\n"); ul_dbf.free_result(_c, res); unlock_udomain(_d); return -2; } } if (mem_insert_ucontact(r, &aor, &contact, expires, q, &callid, cseq, flags, &c, &ua, rec, sock, &instance) < 0) { LOG(L_ERR, "preload_udomain(): Error while inserting contact\n"); ul_dbf.free_result(_c, res); unlock_udomain(_d); return -3; } db_read_reg_avps(_c, c); /* We have to do this, because insert_ucontact sets state to CS_NEW * and we have the contact in the database already * we also store zombies in database so we have to restore * the correct state */ c->state = CS_SYNC; } ul_dbf.free_result(_c, res); unlock_udomain(_d); return 0; }