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; }
/** * 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; }
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; }
/*! * \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_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; }
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; }