/* * $Id$ * * Usrloc module interface * * Copyright (C) 2001-2003 FhG Fokus * * This file is part of ser, a free SIP server. * * ser is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * For a license to use the ser software under conditions * other than those described here, or to purchase support for this * software, please contact iptel.org by e-mail at the following addresses: * info@iptel.org * * ser is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "../../dprint.h" #include "../../ut.h" #include "../../globals.h" #include "dlist.h" #include "utime.h" #include "ul_mod.h" #include "ul_rpc.h" static inline void rpc_find_domain(str* _name, udomain_t** _d) { dlist_t* ptr; ptr = root; while(ptr) { if ((ptr->name.len == _name->len) && !memcmp(ptr->name.s, _name->s, _name->len)) { break; } ptr = ptr->next; } if (ptr) { *_d = ptr->d; } else { *_d = 0; } } 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 const char* rpc_stats_doc[2] = { "Print usrloc statistics", 0 }; static void rpc_stats(rpc_t* rpc, void* c) { dlist_t* ptr; void* handle; ptr = root; while(ptr) { rpc->add(c, "{", &handle); rpc->struct_add(handle, "Sdd", "domain", ptr->d->name, "users", ptr->d->users, "expired", ptr->d->expired); ptr = ptr->next; } } static const char* rpc_delete_uid_doc[2] = { "Delete all registered contacts for address of record.", 0 }; static void rpc_delete_uid(rpc_t* rpc, void* c) { udomain_t* d; str uid, t; if (rpc->scan(c, "SS", &t, &uid) < 2) return; rpc_find_domain(&t, &d); if (d) { lock_udomain(d); if (delete_urecord(d, &uid) < 0) { ERR("Error while deleting user %.*s\n", uid.len, uid.s); unlock_udomain(d); rpc->fault(c, 500, "Error While Deleting Record"); return; } unlock_udomain(d); } else { rpc->fault(c, 400, "Table Not Found"); } } static const char* rpc_delete_contact_doc[2] = { "Delete a contact if it exists.", 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"); } } static const char* rpc_dump_doc[2] = { "Print all registered contacts.", 0 }; static void rpc_dump(rpc_t* rpc, void* c) { rpc->fault(c, 500, "Not Yet Implemented"); } static const char* rpc_dump_file_doc[2] = { "Print all registered contacts into a file.", 0 }; static void rpc_dump_file(rpc_t* rpc, void* c) { str filename; FILE *file; if (rpc->scan(c, "S", &filename) < 1) { return; } DBG("dumping to file '%.*s'.\n", filename.len, ZSW(filename.s)); if (! (file = fopen(filename.s, "w"))) { ERR("failed to open file `%s'.\n", filename.s); rpc->fault(rpc, 500, "failed to open file `%s'.\n", filename.s); return; } print_all_udomains(file); fclose(file); } static const char* rpc_flush_doc[2] = { "Flush cache into database.", 0 }; static void rpc_flush(rpc_t* rpc, void* c) { synchronize_all_udomains(); } static const char* rpc_add_contact_doc[2] = { "Create a new contact.", 0 }; static void rpc_add_contact(rpc_t* rpc, void* c) { udomain_t* d; int expires, flags, sid; double q; qvalue_t qval; str table, uid, contact; if (rpc->scan(c, "SSSdfd", &table, &uid, &contact, &expires, &q, &flags) < 6) return; qval = double2q(q); if (rpc->scan(c, "d", &sid) < 1) sid = -1; rpc_find_domain(&table, &d); if (d) { lock_udomain(d); if (add_contact(d, &uid, &contact, expires, qval, flags, sid) < 0) { unlock_udomain(d); ERR("Error while adding contact ('%.*s','%.*s') in table '%.*s'\n", uid.len, ZSW(uid.s), contact.len, ZSW(contact.s), table.len, ZSW(table.s)); rpc->fault(c, 500, "Error while adding Contact"); return; } unlock_udomain(d); } else { rpc->fault(c, 400, "Table Not Found"); } } /* * Build Contact HF for reply */ static inline int print_contacts(rpc_t* rpc, void* ctx, ucontact_t* _c) { int cnt = 0; void* handle; while(_c) { if (VALID_CONTACT(_c, act_time)) { cnt++; if (rpc->add(ctx, "{", &handle) < 0) return -1; rpc->struct_add(handle, "SfdSS", "contact", &_c->c, "q", q2double(_c->q), "expires", (int)(_c->expires - act_time), "ua", &_c->user_agent, "recv", &_c->received); } _c = _c->next; } return cnt; } static const char* rpc_show_contacts_doc[2] = { "List all registered contacts for address of record", 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"); } } rpc_export_t ul_rpc[] = { {"usrloc.stats", rpc_stats, rpc_stats_doc, RET_ARRAY}, {"usrloc.delete_uid", rpc_delete_uid, rpc_delete_uid_doc, 0}, {"usrloc.delete_contact", rpc_delete_contact, rpc_delete_contact_doc, 0}, {"usrloc.dump", rpc_dump, rpc_dump_doc, 0}, {"usrloc.dump_file", rpc_dump_file, rpc_dump_file_doc, 0}, {"usrloc.flush", rpc_flush, rpc_flush_doc, 0}, {"usrloc.add_contact", rpc_add_contact, rpc_add_contact_doc, 0}, {"usrloc.show_contacts", rpc_show_contacts, rpc_show_contacts_doc, RET_ARRAY}, {0, 0, 0, 0} };