123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704 |
- /*
- * Presence Agent, watcher structure and related functions
- *
- * $Id$
- *
- * 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:
- * [email protected]
- *
- * 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 "paerrno.h"
- #include "../../lib/srdb2/db.h"
- #include "../../dprint.h"
- #include "../../parser/parse_event.h"
- #include "../../mem/shm_mem.h"
- #include "../../trim.h"
- #include "../../ut.h"
- #include "pa_mod.h"
- #include "watcher.h"
- #include "presentity.h"
- #include "auth.h"
- #include "ptime.h"
- str watcher_status_names[] = {
- [WS_PENDING] = STR_STATIC_INIT("pending"),
- [WS_ACTIVE] = STR_STATIC_INIT("active"),
- [WS_REJECTED] = STR_STATIC_INIT("rejected"),
- [WS_TERMINATED] = STR_STATIC_INIT("terminated"),
- [WS_PENDING_TERMINATED] = STR_STATIC_INIT("terminated"),
- STR_NULL
- };
- str watcher_event_names[] = {
- [WE_SUBSCRIBE] = STR_STATIC_INIT("subscribe"),
- [WE_APPROVED] = STR_STATIC_INIT("approved"),
- [WE_DEACTIVATED] = STR_STATIC_INIT("deactivated"),
- [WE_PROBATION] = STR_STATIC_INIT("probation"),
- [WE_REJECTED] = STR_STATIC_INIT("rejected"),
- [WE_TIMEOUT] = STR_STATIC_INIT("timeout"),
- [WE_GIVEUP] = STR_STATIC_INIT("giveup"),
- [WE_NORESOURCE] = STR_STATIC_INIT("noresource"),
- STR_NULL
- };
- const char *event_package2str(int et) /* FIXME: change working with this to enum ?*/
- {
- /* added due to incorrect package handling */
- switch (et) {
- case EVENT_PRESENCE: return "presence";
- case EVENT_PRESENCE_WINFO: return "presence.winfo";
- /*case EVENT_XCAP_CHANGE: return ...; */
- default: return "unknown";
- }
- }
- int str2event_package(const char *epname)
- {
- /* work only with packages supported by PA! */
- if (strcmp(epname, "presence") == 0) return EVENT_PRESENCE;
- if (strcmp(epname, "presence.winfo") == 0) return EVENT_PRESENCE_WINFO;
- return -1; /* unsupported */
- }
- /*int event_package_from_string(str *epname)
- {
- int i;
- for (i = 0; event_package_name[i]; i++) {
- if (strcasecmp(epname->s, event_package_name[i]) == 0) {
- return i;
- }
- }
- return 0;
- }*/
- watcher_status_t watcher_status_from_string(str *wsname)
- {
- int i;
- for (i = 0; watcher_status_names[i].len; i++) {
- if (str_nocase_equals(wsname, &watcher_status_names[i]) == 0) {
- return i;
- }
- }
- return 0;
- }
- static watcher_event_t watcher_event_from_string(str *wename)
- {
- int i;
- for (i = 0; watcher_event_names[i].len; i++) {
- if (str_nocase_equals(wename, &watcher_event_names[i]) == 0) {
- return i;
- }
- }
- return 0;
- }
- /* be sure s!=NULL */
- /* compute a hash value for a string */
- unsigned int compute_hash(unsigned int _h, char* s, int len)
- {
- #define h_inc h+=v^(v>>3);
-
- char* p;
- register unsigned v;
- register unsigned h = _h;
- for(p=s; p<=(s+len-4); p+=4)
- {
- v=(*p<<24)+(p[1]<<16)+(p[2]<<8)+p[3];
- h_inc;
- }
-
- v=0;
- for(;p<(s+len); p++)
- {
- v<<=8;
- v+=*p;
- }
- h_inc;
- return h;
- }
- /*
- * Create a new watcher structure but do not write to database
- */
- int new_watcher_no_wb(str* _uri, time_t _e, int event_package,
- int doc_type, dlg_t* _dlg, str *_dn, str *server_contact,
- str *id, watcher_t** _w)
- {
- watcher_t* watcher;
- int size;
- dbid_t dbid;
- str sid;
- /* Check parameters */
- if (!_uri && !_dlg && !_w) {
- LOG(L_ERR, "new_watcher(): Invalid parameter value\n");
- return -1;
- }
- if (!id) {
- /* generate new database/watcher id (needed for winfo documents!) */
- generate_dbid(dbid);
- sid.s = dbid_strptr(dbid);
- sid.len = dbid_strlen(dbid);
- id = &sid;
- }
-
- /* Allocate memory buffer for watcher_t structure and uri string */
- size = sizeof(watcher_t) + id->len + _uri->len + _dn->len + server_contact->len;
- watcher = (watcher_t*)mem_alloc(size);
- if (!watcher) {
- paerrno = PA_NO_MEMORY;
- ERR("No memory left (%d bytes)\n", size);
- return -1;
- }
- memset(watcher, 0, sizeof(watcher_t));
- /* Copy ID string */
- watcher->id.s = (char*)watcher + sizeof(watcher_t);
- str_cpy(&watcher->id, id);
-
- /* Copy uri string */
- watcher->uri.s = after_str_ptr(&watcher->id);
- str_cpy(&watcher->uri, _uri);
-
- /* Copy display_name string */
- watcher->display_name.s = after_str_ptr(&watcher->uri);
- str_cpy(&watcher->display_name, _dn);
-
- /* Copy server_contact string */
- watcher->server_contact.s = after_str_ptr(&watcher->display_name);
- str_cpy(&watcher->server_contact, server_contact);
- watcher->document_index = 0;
- watcher->event_package = event_package;
- watcher->expires = _e; /* Expires value */
- watcher->preferred_mimetype = doc_type; /* Accepted document type */
- watcher->dialog = _dlg; /* Dialog handle */
- watcher->event = WE_SUBSCRIBE;
- watcher->status = WS_PENDING;
-
- *_w = watcher;
- return 0;
- }
- static int set_watcher_db_data(presentity_t *_p, watcher_t *watcher,
- db_key_t *cols, db_val_t *vals, int *col_cnt,
- str *dialog_str /* destination for dialog string -> must be freed after ! */
- )
- {
- int n_cols = 0;
- char *package = (char*)event_package2str(watcher->event_package);
- str dialog; /* serialized dialog */
- str_clear(dialog_str);
-
- if (dlg_func.dlg2str(watcher->dialog, &dialog) != 0) {
- LOG(L_ERR, "Error while serializing dialog\n");
- return -1;
- }
-
- cols[n_cols] = col_w_uri;
- vals[n_cols].type = DB_STR;
- vals[n_cols].nul = 0;
- vals[n_cols].val.str_val = watcher->uri;
- n_cols++;
- cols[n_cols] = col_package;
- vals[n_cols].type = DB_STR;
- vals[n_cols].nul = 0;
- vals[n_cols].val.str_val.s = package;
- vals[n_cols].val.str_val.len = strlen(package);
- n_cols++;
- cols[n_cols] = col_s_id;
- vals[n_cols].type = DB_STR;
- vals[n_cols].nul = 0;
- vals[n_cols].val.str_val = watcher->id;
- n_cols++;
- cols[n_cols] = col_status;
- vals[n_cols].type = DB_STR;
- vals[n_cols].nul = 0;
- vals[n_cols].val.str_val = watcher_status_names[watcher->status];
- n_cols++;
- cols[n_cols] = col_event;
- vals[n_cols].type = DB_STR;
- vals[n_cols].nul = 0;
- vals[n_cols].val.str_val = watcher_event_names[watcher->event];
- n_cols++;
- cols[n_cols] = col_display_name;
- vals[n_cols].type = DB_STR;
- vals[n_cols].nul = 0;
- vals[n_cols].val.str_val.s = watcher->display_name.s;
- vals[n_cols].val.str_val.len = watcher->display_name.len;
- n_cols++;
-
- cols[n_cols] = col_accepts;
- vals[n_cols].type = DB_INT;
- vals[n_cols].nul = 0;
- vals[n_cols].val.int_val = watcher->preferred_mimetype;
- n_cols++;
- cols[n_cols] = col_expires;
- vals[n_cols].type = DB_DATETIME;
- vals[n_cols].nul = 0;
- vals[n_cols].val.time_val = watcher->expires;
- n_cols++;
- cols[n_cols] = col_dialog;
- vals[n_cols].type = DB_BLOB;
- vals[n_cols].nul = 0;
- vals[n_cols].val.blob_val = dialog;
- n_cols++;
-
- cols[n_cols] = col_server_contact;
- vals[n_cols].type = DB_STR;
- vals[n_cols].nul = 0;
- vals[n_cols].val.str_val = watcher->server_contact;
- n_cols++;
-
- cols[n_cols] = col_pres_id;
- vals[n_cols].type = DB_STR;
- vals[n_cols].nul = 0;
- vals[n_cols].val.str_val = _p->pres_id;
- n_cols++;
- cols[n_cols] = col_doc_index;
- vals[n_cols].type = DB_INT;
- vals[n_cols].nul = 0;
- vals[n_cols].val.int_val = watcher->document_index;
- n_cols++;
-
- *col_cnt = n_cols;
- if (dialog_str) *dialog_str = dialog;
-
- return 0;
- }
- static int db_add_watcher(presentity_t *_p, watcher_t *watcher)
- {
- str_t tmp;
- db_key_t query_cols[20];
- db_val_t query_vals[20];
-
- int n_query_cols = 0;
- if (!use_db) return 0;
-
- str_clear(&tmp);
- if (pa_dbf.use_table(pa_db, watcherinfo_table) < 0) {
- LOG(L_ERR, "db_add_watcher: Error in use_table\n");
- return -1;
- }
-
- if (set_watcher_db_data(_p, watcher,
- query_cols, query_vals, &n_query_cols,
- &tmp) != 0) {
- return -1;
- }
- /* insert new record into database */
- if (pa_dbf.insert(pa_db, query_cols, query_vals, n_query_cols) < 0) {
- LOG(L_ERR, "db_add_watcher: Error while inserting watcher\n");
- str_free_content(&tmp);
- return -1;
- }
- str_free_content(&tmp);
-
- return 0;
- }
- int db_update_watcher(presentity_t *_p, watcher_t *watcher)
- {
- str tmp;
- db_key_t query_cols[20];
- db_val_t query_vals[20];
- int n_query_cols = 0;
-
- db_key_t keys[] = { col_s_id };
- db_op_t ops[] = { OP_EQ };
- db_val_t k_vals[] = { { DB_STR, 0, { .str_val = watcher->id } } };
- if (!use_db) return 0;
- str_clear(&tmp);
-
- if (pa_dbf.use_table(pa_db, watcherinfo_table) < 0) {
- LOG(L_ERR, "db_update_watcher: Error in use_table\n");
- return -1;
- }
-
- if (set_watcher_db_data(_p, watcher,
- query_cols, query_vals, &n_query_cols,
- &tmp) != 0) {
- return -1;
- }
- if (pa_dbf.update(pa_db, keys, ops, k_vals,
- query_cols, query_vals, 1, n_query_cols) < 0) {
- LOG(L_ERR, "Error while updating watcher in DB\n");
- str_free_content(&tmp);
- return -1;
- }
- str_free_content(&tmp);
- return 0;
- }
- static inline int db_remove_watcher(struct presentity *_p, watcher_t *w)
- {
- db_key_t keys[] = { col_s_id };
- db_op_t ops[] = { OP_EQ };
- db_val_t k_vals[] = { { DB_STR, 0, { .str_val = w->id } } };
- if (!use_db) return 0;
-
- if (pa_dbf.use_table(pa_db, watcherinfo_table) < 0) {
- ERR("Error in use_table\n");
- return -1;
- }
- if (pa_dbf.delete(pa_db, keys, ops, k_vals, 1) < 0) {
- ERR("Error while deleting watcher from DB\n");
- return -1;
- }
- return 0;
- }
- /*
- * Read watcherinfo table from database for presentity _p
- */
- int db_read_watcherinfo(presentity_t *_p, db_con_t* db)
- {
- db_key_t query_cols[5];
- db_op_t query_ops[5];
- db_val_t query_vals[5];
- str dialog = STR_NULL;
- dlg_t *dlg = NULL;
- db_key_t result_cols[11];
- db_res_t *res;
- int r = 0;
- int n_query_cols = 1;
- int n_result_cols = 0;
- int w_uri_col, s_id_col, event_package_col, status_col, watcher_event_col,
- display_name_col, accepts_col, expires_col, dialog_col, server_contact_col,
- doc_index_col;
-
- if (!use_db) return 0;
-
- /* LOG(L_ERR, "db_read_watcherinfo starting\n");*/
- query_cols[0] = col_pres_id;
- query_ops[0] = OP_EQ;
- query_vals[0].type = DB_STR;
- query_vals[0].nul = 0;
- query_vals[0].val.str_val = _p->pres_id;
- result_cols[w_uri_col = n_result_cols++] = col_w_uri;
- result_cols[s_id_col = n_result_cols++] = col_s_id;
- result_cols[event_package_col = n_result_cols++] = col_package;
- result_cols[status_col = n_result_cols++] = col_status;
- result_cols[display_name_col = n_result_cols++] = col_display_name;
- result_cols[accepts_col = n_result_cols++] = col_accepts;
- result_cols[expires_col = n_result_cols++] = col_expires;
- result_cols[watcher_event_col = n_result_cols++] = col_event;
- result_cols[dialog_col = n_result_cols++] = col_dialog;
- result_cols[server_contact_col = n_result_cols++] = col_server_contact;
- result_cols[doc_index_col = n_result_cols++] = col_doc_index;
-
- if (pa_dbf.use_table(db, watcherinfo_table) < 0) {
- ERR("Error in use_table\n");
- return -1;
- }
- if (pa_dbf.query (db, query_cols, query_ops, query_vals,
- result_cols, n_query_cols, n_result_cols, 0, &res) < 0) {
- ERR("Error while querying watcherinfo\n");
- return -1;
- }
- if (res && (res->n > 0)) {
- /* fill in tuple structure from database query result */
- int i;
-
- dlg = NULL;
- for (i = 0; i < res->n; i++) {
- db_row_t *row = &res->rows[i];
- db_val_t *row_vals = ROW_VALUES(row);
- str w_uri = STR_NULL;
- str s_id = STR_NULL;
- char *event_package_str = NULL;
- int event_package = EVENT_PRESENCE;
- str watcher_event_str = STR_NULL;
- watcher_event_t watcher_event = WE_SUBSCRIBE;
- int accepts = row_vals[accepts_col].val.int_val;
- time_t expires = row_vals[expires_col].val.time_val;
- int doc_index = row_vals[doc_index_col].val.int_val;
- str status = STR_NULL;
- str display_name = STR_NULL;
- str server_contact = STR_NULL;
- watcher_t *watcher = NULL;
-
- if (!row_vals[w_uri_col].nul) {
- w_uri.s = (char *)row_vals[w_uri_col].val.string_val;
- w_uri.len = strlen(w_uri.s);
- }
- if (!row_vals[s_id_col].nul) {
- s_id.s = (char *)row_vals[s_id_col].val.string_val;
- s_id.len = strlen(s_id.s);
- }
- if (!row_vals[event_package_col].nul) {
- event_package_str = (char *)row_vals[event_package_col].val.string_val;
- event_package = str2event_package(event_package_str);
- }
- if (!row_vals[status_col].nul) {
- status.s = (char *)row_vals[status_col].val.string_val;
- status.len = strlen(status.s);
- }
- if (!row_vals[watcher_event_col].nul) {
- watcher_event_str.s = (char *)row_vals[watcher_event_col].val.string_val;
- watcher_event_str.len = strlen(watcher_event_str.s);
- watcher_event = watcher_event_from_string(&watcher_event_str);
- }
- if (!row_vals[display_name_col].nul) {
- display_name.s = (char *)row_vals[display_name_col].val.string_val;
- display_name.len = strlen(display_name.s);
- }
- if (!row_vals[dialog_col].nul) {
- dialog = row_vals[dialog_col].val.blob_val;
- dlg = (dlg_t*)mem_alloc(sizeof(*dlg));
- if (!dlg) {
- LOG(L_ERR, "db_read_watcher: Can't allocate dialog\n");
- r = -1;
- }
- else
- if (dlg_func.str2dlg(&dialog, dlg) != 0) {
- LOG(L_ERR, "db_read_watcher: Error while deserializing dialog\n");
- r = -1;
- }
- }
- if (!row_vals[server_contact_col].nul) {
- server_contact.s = (char *)row_vals[server_contact_col].val.string_val;
- server_contact.len = strlen(server_contact.s);
- }
- DBG("creating watcher\n");
- if (new_watcher_no_wb(&w_uri, expires,
- event_package, accepts, dlg, &display_name,
- &server_contact, &s_id, &watcher) == 0) {
-
- watcher->status = watcher_status_from_string(&status);
- watcher->event = watcher_event;
- watcher->document_index = doc_index;
- r = append_watcher(_p, watcher, 0);
- if (r < 0) {
- ERR("Error while adding watcher\n");
- free_watcher(watcher);
- }
- }
- else r = -1;
- }
- }
- pa_dbf.free_result(db, res);
- return r;
- }
- /*
- * Release a watcher structure
- */
- void free_watcher(watcher_t* _w)
- {
- tmb.free_dlg(_w->dialog);
- mem_free(_w);
- }
- /*
- * Update a watcher structure
- */
- int update_watcher(struct presentity *p, watcher_t* _w, time_t _e, struct sip_msg *m)
- {
- watcher_status_t old = _w->status; /* old status of subscription */
- tmb.dlg_request_uas(_w->dialog, m, IS_TARGET_REFRESH);
-
- _w->expires = _e;
- _w->flags |= WFLAG_SUBSCRIPTION_CHANGED;
-
- /* actualize watcher's status according to time */
- if (_w->expires <= act_time) {
- /* ERR("Updated watcher to expire: %.*s\n", _w->uri.len, _w->uri.s); */
- _w->expires = 0;
- set_watcher_terminated_status(_w);
- }
-
- if ((old != _w->status) && (_w->event_package == EVENT_PRESENCE)) {
- /* changed only when presence watcher changes status */
- /* FIXME: it could be changed when expires time changes too,
- * but we don't send expiration in watcherinf notify thus
- * it is worthless */
- p->flags |= PFLAG_WATCHERINFO_CHANGED;
- }
-
- if (use_db) return db_update_watcher(p, _w);
- else return 0;
- }
- int is_watcher_terminated(watcher_t *w)
- {
- if (!w) return -1;
-
- if ((w->status == WS_TERMINATED) ||
- (w->status == WS_REJECTED) ||
- (w->status == WS_PENDING_TERMINATED)) return 1;
- return 0;
- }
- int is_watcher_authorized(watcher_t *w)
- {
- if (!w) return 0;
-
- switch (w->status) {
- case WS_PENDING: ;
- case WS_PENDING_TERMINATED: ;
- case WS_REJECTED: return 0;
- case WS_ACTIVE: ;
- case WS_TERMINATED: return 1;
- }
- return 0;
- }
- void set_watcher_terminated_status(watcher_t *w)
- {
- if (!w) return;
-
- switch (w->status) {
- case WS_REJECTED: break;
- case WS_PENDING: ;
- w->status = WS_PENDING_TERMINATED;
- break;
- case WS_PENDING_TERMINATED: break;
- case WS_TERMINATED: break;
- case WS_ACTIVE: ;
- w->status = WS_TERMINATED;
- break;
- }
- }
- int append_watcher(presentity_t *_p, watcher_t *_w, int add_to_db)
- {
- if (add_to_db && use_db) {
- if (db_add_watcher(_p, _w) != 0) {
- ERR("Error while adding watcher\n");
- paerrno = PA_INTERNAL_ERROR;
- return -5;
- }
- }
-
- if (_w->event_package == EVENT_PRESENCE_WINFO) {
- DOUBLE_LINKED_LIST_ADD(_p->first_winfo_watcher,
- _p->last_winfo_watcher, _w);
- }
- else {
- DOUBLE_LINKED_LIST_ADD(_p->first_watcher,
- _p->last_watcher, _w);
-
- /* changed only when presence watcher added */
- _p->flags |= PFLAG_WATCHERINFO_CHANGED;
- DEBUG("setting PFLAG_WATCHERINFO_CHANGED\n");
- }
-
- return 0;
- }
- void remove_watcher(presentity_t* _p, watcher_t *w)
- {
- if (!w) return;
-
- if (use_db) db_remove_watcher(_p, w);
- if (w->event_package == EVENT_PRESENCE_WINFO)
- DOUBLE_LINKED_LIST_REMOVE(_p->first_winfo_watcher,
- _p->last_winfo_watcher, w);
- else {
- DOUBLE_LINKED_LIST_REMOVE(_p->first_watcher,
- _p->last_watcher, w);
- _p->flags |= PFLAG_WATCHERINFO_CHANGED;
- }
- }
- /* returns 0 if equal dialog IDs */
- static int cmp_dlg_ids(dlg_id_t *a, dlg_id_t *b)
- {
- if (!a) {
- if (!b) return -1;
- else return 0;
- }
- if (!b) return 1;
- if (str_case_equals(&a->call_id, &b->call_id) != 0) return 1;
- if (str_case_equals(&a->rem_tag, &b->rem_tag) != 0) return 1; /* case sensitive ? */
- if (str_case_equals(&a->loc_tag, &b->loc_tag) != 0) return 1; /* case sensitive ? */
- return 0;
- }
- /* Find a watcher in the list via dialog identifier */
- int find_watcher_dlg(struct presentity* _p, dlg_id_t *dlg_id, int _et, watcher_t** _w)
- {
- watcher_t* watcher;
- /* first look for watchers */
- if (!dlg_id) return -1;
- if (_et != EVENT_PRESENCE_WINFO)
- watcher = _p->first_watcher;
- else
- watcher = _p->first_winfo_watcher;
-
- while(watcher) {
- if (watcher->dialog) {
- if ((cmp_dlg_ids(&watcher->dialog->id, dlg_id) == 0) &&
- (watcher->event_package == _et)) {
- *_w = watcher;
- return 0;
- }
- }
-
- watcher = watcher->next;
- }
-
- return 1;
- }
|