int parse_config_lines(void) { char *p,*start; int i, k, step; int mdm_nr, net_nr; nr_of_networks = 0; nr_of_modems = 0; step = 1; /* parsing modems configuration string */ if ( (p = modems_config)==0) { LM_ERR("param \"modems\" not found\n"); goto error; } while (*p) { eat_spaces(p); /*get modem's name*/ start = p; while (*p!=' ' && *p!='\t' && *p!='[' && *p!=0) p++; if ( p==start || *p==0 ) goto parse_error; memcpy(modems[nr_of_modems].name, start, p-start); modems[nr_of_modems].name[p-start] = 0; modems[nr_of_modems].smsc[0] = 0; modems[nr_of_modems].device[0] = 0; modems[nr_of_modems].pin[0] = 0; modems[nr_of_modems].mode = MODE_NEW; modems[nr_of_modems].retry = 4; modems[nr_of_modems].looping_interval = 20; modems[nr_of_modems].baudrate = B9600; modems[nr_of_modems].scan = SMS_BODY_SCAN; modems[nr_of_modems].to[0] = 0; memset(modems[nr_of_modems].net_list,0XFF, sizeof(modems[nr_of_modems].net_list) ); /*get modem parameters*/ eat_spaces(p); if (*p!='[') goto parse_error; p++; while (*p!=']') { eat_spaces(p); start = p; while(*p!=' ' && *p!='\t' && *p!=']' && *p!=';' && *p!=0) p++; if ( p==start || *p==0 ) goto parse_error; if (set_modem_arg( &(modems[nr_of_modems]), start, p)==-1) goto error; eat_spaces(p); if (*p==';') { p++; eat_spaces(p); } } if (*p!=']') goto parse_error; p++; /* end of element */ if (modems[nr_of_modems].device[0]==0) { LM_ERR("modem %s has no device associated\n", modems[nr_of_modems].name); goto error; } if (modems[nr_of_modems].smsc[0]==0) { LM_WARN("modem %s has no sms center associated -> using" " the default one from modem\n",modems[nr_of_modems].name); } nr_of_modems++; eat_spaces(p); if (*p==';') { p++; eat_spaces(p); } } if (nr_of_modems==0) { LM_ERR("failed to parse config modems - no modem found!\n"); goto error; } step++; /* parsing networks configuration string */ if ( (p = networks_config)==0) { LM_ERR("param \"networks\" not found\n"); goto error; } while (*p) { eat_spaces(p); /*get network name*/ start = p; while (*p!=' ' && *p!='\t' && *p!='[' && *p!=0) p++; if ( p==start || *p==0 ) goto parse_error; memcpy(networks[nr_of_networks].name, start, p-start); networks[nr_of_networks].name[p-start] = 0; networks[nr_of_networks].max_sms_per_call = 10; /*get network parameters*/ eat_spaces(p); if (*p!='[') goto parse_error; p++; while (*p!=']') { eat_spaces(p); start = p; while(*p!=' ' && *p!='\t' && *p!=']' && *p!=';' && *p!=0) p++; if ( p==start || *p==0 ) goto parse_error; if (set_network_arg( &(networks[nr_of_networks]), start, p)==-1) goto error; eat_spaces(p); if (*p==';') { p++; eat_spaces(p); } } if (*p!=']') goto parse_error; p++; /* end of element */ nr_of_networks++; eat_spaces(p); if (*p==';') p++; eat_spaces(p); } if (nr_of_networks==0) { LM_ERR("no network found!\n"); goto error; } step++; /* parsing links configuration string */ if ( (p = links_config)==0) { LM_ERR("param \"links\" not found\n"); goto error; } while (*p) { eat_spaces(p); /*get modem's device*/ start = p; while (*p!=' ' && *p!='\t' && *p!='[' && *p!=0) p++; if ( p==start || *p==0 ) goto parse_error; /*looks for modem index*/ for(mdm_nr=-1,i=0;i<nr_of_modems && mdm_nr==-1;i++) if (!strncasecmp(modems[i].name,start,p-start)&& modems[i].name[p-start]==0) mdm_nr = i; if (mdm_nr==-1) { LM_ERR("unknown modem %.*s \n,",(int)(p-start), start); goto error; } /*get associated networks list*/ eat_spaces(p); if (*p!='[') goto parse_error; p++; k=0; while (*p!=']') { eat_spaces(p); start = p; while(*p!=' ' && *p!='\t' && *p!=']' && *p!=';' && *p!=0) p++; if ( p==start || *p==0 ) goto parse_error; /* lookup for the network -> get its index */ for(net_nr=-1,i=0;i<nr_of_networks&&net_nr==-1;i++) if (!strncasecmp(networks[i].name,start,p-start) && networks[i].name[p-start]==0) net_nr = i; if (net_nr==-1) { LM_ERR("associated net <%.*s> not found in net list\n", (int)(p-start), start); goto error; } LM_DBG("linking net \"%s\" to modem \"%s\" on pos %d.\n", networks[net_nr].name,modems[mdm_nr].name,k); modems[mdm_nr].net_list[k++]=net_nr; eat_spaces(p); if (*p==';') { p++; eat_spaces(p); } } if (*p!=']') goto parse_error; p++; /* end of element */ eat_spaces(p); if (*p==';') { p++; eat_spaces(p); } } /* resolving default network name - if any*/ if (default_net_str) { for(net_nr=-1,i=0;i<nr_of_networks&&net_nr==-1;i++) if (!strcasecmp(networks[i].name,default_net_str)) net_nr = i; if (net_nr==-1) { LM_ERR("network \"%s\" not found in net list!\n",default_net_str); goto error; } default_net = net_nr; } return 0; parse_error: LM_ERR("SMS %s config: parse error before chr %d [%.*s]\n", (step==1)?"modems":(step==2?"networks":"links"), (int)(p - ((step==1)?modems_config: (step==2?networks_config:links_config))), (*p==0)?4:1,(*p==0)?"NULL":p ); error: return -1; }
int run_reg_tm_cback(void *e_data, void *data, void *r_data) { struct sip_msg *msg; int statuscode = 0; unsigned int exp = 0; reg_record_t *rec = (reg_record_t*)e_data; struct hdr_field *c_ptr, *head_contact; struct uac_credential crd; contact_t *contact; struct authenticate_body *auth = NULL; static struct authenticate_nc_cnonce auth_nc_cnonce; HASHHEX response; str *new_hdr; struct reg_tm_cback_data *tm_cback_data = (struct reg_tm_cback_data*)data; struct cell *t; struct tmcb_params *ps; time_t now; reg_tm_cb_t *cb_param; cb_param = tm_cback_data->cb_param; if (rec!=cb_param->uac) { /* no action on current list elemnt */ return 0; /* continue list traversal */ } t = tm_cback_data->t; ps = tm_cback_data->ps; now = tm_cback_data->now; reg_print_record(rec); if (ps->rpl==FAKED_REPLY) memset(&rec->td.forced_to_su, 0, sizeof(union sockaddr_union)); else if (rec->td.forced_to_su.s.sa_family == AF_UNSPEC) rec->td.forced_to_su = t->uac[0].request.dst.to; statuscode = ps->code; switch(statuscode) { case 200: msg = ps->rpl; if(msg==FAKED_REPLY) { LM_ERR("FAKED_REPLY\n"); goto done; } if (parse_headers(msg, HDR_EOH_F, 0) == -1) { LM_ERR("failed to parse headers\n"); goto done; } if (msg->contact) { c_ptr = msg->contact; while(c_ptr) { if (c_ptr->type == HDR_CONTACT_T) { if (!c_ptr->parsed && (parse_contact(c_ptr)<0)) { LM_ERR("failed to parse Contact body\n"); goto done; } } c_ptr = c_ptr->next; } } else { LM_ERR("No contact header in received 200ok\n"); goto done; } head_contact = msg->contact; contact = ((contact_body_t*)msg->contact->parsed)->contacts; while (contact) { /* Check for binding */ if (contact->uri.len==rec->contact_uri.len && strncmp(contact->uri.s,rec->contact_uri.s,contact->uri.len)==0){ if (contact->expires && contact->expires->body.len) { if (str2int(&contact->expires->body, &exp)<0) { LM_ERR("Unable to extract expires from [%.*s]" " for binding [%.*s]\n", contact->expires->body.len, contact->expires->body.s, contact->uri.len, contact->uri.s); } } break; } /* get the next contact */ if (contact->next == NULL) { contact = NULL; c_ptr = head_contact->next; while(c_ptr) { if (c_ptr->type == HDR_CONTACT_T) { head_contact = c_ptr; contact = ((contact_body_t*)c_ptr->parsed)->contacts; break; } c_ptr = c_ptr->next; } } else { contact = contact->next; } } rec->state = REGISTERED_STATE; if (exp) rec->expires = exp; rec->registration_timeout = now + rec->expires - timer_interval; break; case WWW_AUTH_CODE: case PROXY_AUTH_CODE: msg = ps->rpl; if(msg==FAKED_REPLY) { LM_ERR("FAKED_REPLY\n"); goto done; } if (rec->auth_user.s==NULL || rec->auth_user.len==0 || rec->auth_password.s==NULL || rec->auth_password.len==0) { LM_ERR("Credentials not provisioned\n"); rec->state = WRONG_CREDENTIALS_STATE; rec->registration_timeout = 0; /* action successfuly completed on current list element */ return 1; /* exit list traversal */ } if (statuscode==WWW_AUTH_CODE) { if (0 == parse_www_authenticate_header(msg)) auth = get_www_authenticate(msg); } else if (statuscode==PROXY_AUTH_CODE) { if (0 == parse_proxy_authenticate_header(msg)) auth = get_proxy_authenticate(msg); } if (auth == NULL) { LM_ERR("Unable to extract authentication info\n"); goto done; } LM_DBG("flags=[%d] realm=[%.*s] domain=[%.*s] nonce=[%.*s]" " opaque=[%.*s] qop=[%.*s]\n", auth->flags, auth->realm.len, auth->realm.s, auth->domain.len, auth->domain.s, auth->nonce.len, auth->nonce.s, auth->opaque.len, auth->opaque.s, auth->qop.len, auth->qop.s); switch(rec->state) { case REGISTERING_STATE: break; case AUTHENTICATING_STATE: /* We already sent an authenticated REGISTER and we are still challanged! */ LM_WARN("Wrong credentials for [%.*s]\n", rec->td.rem_uri.len, rec->td.rem_uri.s); rec->state = WRONG_CREDENTIALS_STATE; rec->registration_timeout = 0; /* action successfuly completed on current list element */ return 1; /* exit list traversal */ default: LM_ERR("Unexpected [%d] notification cb in state [%d]\n", statuscode, rec->state); goto done; } /* perform authentication */ if (auth->realm.s && auth->realm.len) { crd.realm.s = auth->realm.s; crd.realm.len = auth->realm.len; } else { LM_ERR("No realm found\n"); goto done; } crd.user.s = rec->auth_user.s; crd.user.len = rec->auth_user.len; crd.passwd.s = rec->auth_password.s; crd.passwd.len = rec->auth_password.len; memset(&auth_nc_cnonce, 0, sizeof(struct authenticate_nc_cnonce)); uac_auth_api._do_uac_auth(®ister_method, &rec->td.rem_target, &crd, auth, &auth_nc_cnonce, response); new_hdr = uac_auth_api._build_authorization_hdr(statuscode, &rec->td.rem_target, &crd, auth, &auth_nc_cnonce, response); if (!new_hdr) { LM_ERR("failed to build authorization hdr\n"); goto done; } if(send_register(cb_param->hash_index, rec, new_hdr)==1) { rec->state = AUTHENTICATING_STATE; } else { rec->state = INTERNAL_ERROR_STATE; } pkg_free(new_hdr->s); new_hdr->s = NULL; new_hdr->len = 0; break; case 423: /* Interval Too Brief */ msg = ps->rpl; if(msg==FAKED_REPLY) { LM_ERR("FAKED_REPLY\n"); goto done; } if (0 == parse_min_expires(msg)) { rec->expires = (unsigned int)(long)msg->min_expires->parsed; if(send_register(cb_param->hash_index, rec, NULL)==1) rec->state = REGISTERING_STATE; else rec->state = INTERNAL_ERROR_STATE; } else { rec->state = REGISTRAR_ERROR_STATE; rec->registration_timeout = now + rec->expires - timer_interval; } break; case 408: /* Interval Too Brief */ rec->state = REGISTER_TIMEOUT_STATE; rec->registration_timeout = now + rec->expires - timer_interval; break; default: if(statuscode<400 && statuscode>=300) { LM_ERR("Redirection not implemented yet\n"); rec->state = INTERNAL_ERROR_STATE; } else { /* we got an error from the server */ rec->state = REGISTRAR_ERROR_STATE; rec->registration_timeout = now + rec->expires - timer_interval; } } /* action successfuly completed on current list element */ return 1; /* exit list traversal */ done: rec->state = INTERNAL_ERROR_STATE; rec->registration_timeout = now + rec->expires; return -1; /* exit list traversal */ }
/* * Send an SQL query to the server */ static int db_oracle_submit_query(const db_con_t* _h, const str* _s) { OCIBind* bind[MAX_BIND_HANDLES]; OCIDate odt[sizeof(bind)/sizeof(bind[0])]; str tmps; sword status; int pass; ora_con_t* con = CON_ORA(_h); query_data_t* pqd = con->pqdata; size_t hc = pqd->_n + pqd->_nw; OCIStmt *stmthp; if (hc >= sizeof(bind)/sizeof(bind[0])) { LM_ERR("too many bound. Rebuild with MAX_BIND_HANDLES >= %u\n", (unsigned)hc); return -1; } if (!pqd->_rs) { /* * This method is at ~25% faster as set OCI_COMMIT_ON_SUCCESS * in StmtExecute */ tmps.len = snprintf(st_buf, sizeof(st_buf), "begin %.*s; commit write batch nowait; end;", _s->len, _s->s); if ((unsigned)tmps.len >= sizeof(st_buf)) return sql_buf_small(); tmps.s = st_buf; _s = &tmps; } pass = 1; if (!con->connected) { status = db_oracle_reconnect(con); if (status != OCI_SUCCESS) { LM_ERR("can't restore connection: %s\n", db_oracle_error(con, status)); return -2; } LM_INFO("connection restored\n"); --pass; } repeat: stmthp = NULL; status = OCIHandleAlloc(con->envhp, (dvoid**)(dvoid*)&stmthp, OCI_HTYPE_STMT, 0, NULL); if (status != OCI_SUCCESS) goto ora_err; status = OCIStmtPrepare(stmthp, con->errhp, (text*)_s->s, _s->len, OCI_NTV_SYNTAX, OCI_DEFAULT); if (status != OCI_SUCCESS) goto ora_err; if (hc) { bmap_t bmap; size_t pos = 1; int i; memset(bind, 0, hc*sizeof(bind[0])); for (i = 0; i < pqd->_n; i++) { if (db_oracle_val2bind(&bmap, &pqd->_v[i], &odt[pos]) < 0) goto bind_err; status = OCIBindByPos(stmthp, &bind[pos], con->errhp, pos, bmap.addr, bmap.size, bmap.type, NULL, NULL, NULL, 0, NULL, OCI_DEFAULT); if (status != OCI_SUCCESS) goto ora_err; ++pos; } for (i = 0; i < pqd->_nw; i++) { if (db_oracle_val2bind(&bmap, &pqd->_w[i], &odt[pos]) < 0) { bind_err: OCIHandleFree(stmthp, OCI_HTYPE_STMT); LM_ERR("can't map values\n"); return -3; } status = OCIBindByPos(stmthp, &bind[pos], con->errhp, pos, bmap.addr, bmap.size, bmap.type, NULL, NULL, NULL, 0, NULL, OCI_DEFAULT); if (status != OCI_SUCCESS) goto ora_err; ++pos; } } // timelimited operation status = begin_timelimit(con, 0); if (status != OCI_SUCCESS) goto ora_err; do status = OCIStmtExecute(con->svchp, stmthp, con->errhp, !pqd->_rs, 0, NULL, NULL, pqd->_rs ? OCI_STMT_SCROLLABLE_READONLY : OCI_DEFAULT); while (wait_timelimit(con, status)); if (done_timelimit(con, status)) goto stop_exec; switch (status) { case OCI_SUCCESS_WITH_INFO: LM_WARN("driver: %s\n", db_oracle_errorinfo(con)); //PASS THRU case OCI_SUCCESS: if (pqd->_rs) *pqd->_rs = stmthp; else OCIHandleFree(stmthp, OCI_HTYPE_STMT); return 0; default: pass = -pass; break; } ora_err: LM_ERR("driver: %s\n", db_oracle_error(con, status)); stop_exec: if (stmthp) OCIHandleFree(stmthp, OCI_HTYPE_STMT); if (pass == -1 && !con->connected) { /* Attemtp to reconnect */ if (db_oracle_reconnect(con) == OCI_SUCCESS) { LM_NOTICE("attempt repeat after reconnect\n"); pass = 0; goto repeat; } LM_ERR("connection loss\n"); } return -4; }
/*! * \brief Create a new dialog from a sip message * * Create a new dialog from a SIP message, register a callback * to keep track of the dialog with help of the tm module. * This function is either called from the request callback, or * from the dlg_manage function in the configuration script. * \see dlg_onreq * \see w_dlg_manage * \param msg SIP message * \param t transaction * \return 0 on success, -1 on failure */ int dlg_new_dialog(struct sip_msg *req, struct cell *t, const int run_initial_cbs) { struct dlg_cell *dlg; str s; str callid; str ftag; str ttag; str req_uri; unsigned int dir; LM_DBG("starting dlg_new_dialog and method is [%.*s]\n", req->first_line.u.request.method.len, req->first_line.u.request.method.s); if (current_dlg_pointer != NULL) return -1; if (req->first_line.u.request.method_value == METHOD_CANCEL) return -1; if (pre_match_parse(req, &callid, &ftag, &ttag, 0) < 0) { LM_WARN("pre-matching failed\n"); return -1; } if (ttag.s != 0 && ttag.len != 0) return -1; if (pv_printf_s(req, ruri_param_model, &req_uri) < 0) { LM_ERR("error - cannot print the r-uri format\n"); return -1; } trim(&req_uri); if (detect_spirals) { if (spiral_detected == 1) return 0; dir = DLG_DIR_NONE; dlg = get_dlg(&callid, &ftag, &ttag, &dir); if (dlg) { LM_DBG("Callid '%.*s' found, must be a spiraled request\n", callid.len, callid.s); spiral_detected = 1; if (run_initial_cbs) run_dlg_callbacks(DLGCB_SPIRALED, dlg, req, NULL, DLG_DIR_DOWNSTREAM, 0); //Add did to rr header for all spiralled requested INVITEs if (req->first_line.u.request.method_value == METHOD_INVITE) { if (add_dlg_rr_param(dlg, req, dlg->h_entry, dlg->h_id) < 0) { LM_ERR("failed to add RR param\n"); } } // get_dlg has incremented the ref count by 1 unref_dlg(dlg, 1); goto finish; } } spiral_detected = 0; LM_DBG("Building new Dialog for call-id %.*s\n", callid.len, callid.s); LM_DBG("SIP Method: %.*s \n", req->first_line.u.request.method.len, req->first_line.u.request.method.s); dlg = build_new_dlg(&callid /*callid*/, &(get_from(req)->uri) /*from uri*/, &ftag/*from_tag*/, &req_uri /*r-uri*/); if (dlg == 0) { LM_ERR("failed to create new dialog\n"); return -1; } /* save caller's tag, cseq, contact and record route*/ if (populate_leg_info(dlg, req, t, DLG_CALLER_LEG, &(get_from(req)->tag_value)) != 0) { LM_ERR("could not add further info to the dialog\n"); lock_destroy(dlg->dlg_out_entries_lock); lock_dealloc(dlg->dlg_out_entries_lock); shm_free(dlg); return -1; } dlg->transaction = t; /* Populate initial varlist: */ dlg->vars = get_local_varlist_pointer(req, 1); link_dlg(dlg, 0); if (run_initial_cbs) run_create_callbacks(dlg, req); //Dialog will *always* use DID cookie so no need for match mode anymore if (add_dlg_rr_param(dlg, req, dlg->h_entry, dlg->h_id) < 0) { LM_ERR("failed to add RR param\n"); goto error; } if (d_tmb.register_tmcb(req, t, TMCB_RESPONSE_READY | TMCB_RESPONSE_FWDED | TMCB_RESPONSE_OUT, dlg_onreply, (void*) dlg, unref_new_dialog) < 0) { LM_ERR("failed to register TMCB\n"); goto error; } // increase reference counter because of registered callback ref_dlg(dlg, 1); dlg->lifetime = get_dlg_timeout(req); s.s = _dlg_ctx.to_route_name; s.len = strlen(s.s); dlg_set_toroute(dlg, &s); dlg->sflags |= _dlg_ctx.flags; if (_dlg_ctx.to_bye != 0) dlg->dflags |= DLG_FLAG_TOBYE; finish: if (t) { // transaction exists ==> keep ref counter large enough to // avoid premature cleanup and ensure proper dialog referencing if (store_dlg_in_tm(req, t, dlg) < 0) { LM_ERR("failed to store dialog in transaction\n"); goto error; } } else { // no transaction exists ==> postpone work until we see the // request being forwarded statefully if (d_tmb.register_tmcb(req, NULL, TMCB_REQUEST_FWDED, store_dlg_in_tm_cb, (void*) dlg, NULL) < 0) { LM_ERR("failed to register callback for storing dialog in transaction\n"); goto error; } } LM_DBG("Setting current dialog\n"); set_current_dialog(req, dlg); _dlg_ctx.dlg = dlg; ref_dlg(dlg, 1); return 0; error: LM_DBG("Error in build_new_dlg"); if (!spiral_detected) unref_dlg(dlg, 1); // undo ref regarding linking return -1; }
/** * get PContact-Structure for message * (search only once per Request) */ pcontact_t * getContactP(struct sip_msg* _m, udomain_t* _d, enum pcontact_reg_states reg_state) { ppublic_t * p; contact_body_t *b = 0; contact_t *ct; pcontact_info_t search_ci; str received_host = {0, 0}; char srcip[50]; struct via_body *vb; unsigned short port, proto; str host; sip_uri_t contact_uri; int mustRetryViaSearch = 0; int mustRetryReceivedSearch = 0; b = cscf_parse_contacts(_m); if (_m->first_line.type == SIP_REPLY && _m->contact && _m->contact->parsed && b->contacts) { mustRetryViaSearch = 1; mustRetryReceivedSearch = 1; LM_DBG("This is a reply - to look for contact we favour the contact header above the via (b2bua)... if no contact we will use last via\n"); ct = b->contacts; host = ct->uri; if (parse_uri(ct->uri.s, ct->uri.len, &contact_uri) != 0) { LM_WARN("Failed to parse contact [%.*s]\n", ct->uri.len, ct->uri.s); return NULL; } host = contact_uri.host; port = contact_uri.port_no ? contact_uri.port_no : 5060; proto = contact_uri.proto; if (proto == 0) { LM_DBG("Contact protocol not specified - using received\n"); proto = _m->rcv.proto; } } else { if (_m->first_line.type == SIP_REPLY) LM_DBG("This is a reply but we are forced to use the via header\n"); else LM_DBG("This is a request - using first via to find contact\n"); vb = cscf_get_ue_via(_m); host = vb->host; port = vb->port ? vb->port : 5060; proto = vb->proto; } LM_DBG("searching for contact with host:port:proto contact [%d://%.*s:%d]\n", proto, host.len, host.s, port); received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof (srcip)); received_host.s = srcip; // if (_m->id != current_msg_id) { current_msg_id = _m->id; c = NULL; //search_ci.reg_state = PCONTACT_REGISTERED; //we can do this because this function is always called expecting a REGISTERED contact search_ci.reg_state = reg_state; search_ci.received_host.s = received_host.s; search_ci.received_host.len = received_host.len; search_ci.received_port = _m->rcv.src_port; search_ci.received_proto = _m->rcv.proto; search_ci.searchflag = SEARCH_RECEIVED; if (is_registered_fallback2ip == 1) { search_ci.searchflag = SEARCH_NORMAL; } search_ci.via_host = host; search_ci.via_port = port; search_ci.via_prot = proto; search_ci.aor.s = 0; search_ci.aor.len = 0; // b = cscf_parse_contacts(_m); tryagain: if (b && b->contacts) { for (ct = b->contacts; ct; ct = ct->next) { search_ci.aor = ct->uri; if (ul.get_pcontact(_d, &search_ci, &c) == 0) { if (checkcontact(_m, c) != 0) { c = NULL; } else { break; } } } } else { LM_WARN("No contact-header found...\n"); } if ((c == NULL) && (is_registered_fallback2ip == 1)) { LM_INFO("Contact not found based on Contact-header, trying IP/Port/Proto\n"); // received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip)); // received_host.s = srcip; search_ci.searchflag = SEARCH_RECEIVED; if (ul.get_pcontact(_d, &search_ci, &c) == 1) { LM_DBG("No entry in usrloc for %.*s:%i (Proto %i) found!\n", received_host.len, received_host.s, _m->rcv.src_port, _m->rcv.proto); } else { if (checkcontact(_m, c) != 0) { c = NULL; } } } if ((c == NULL) && (is_registered_fallback2ip == 2)) { LM_INFO("Contact not found based on IP/Port/Proto, trying Contact-header\n"); search_ci.searchflag = SEARCH_NORMAL; if (ul.get_pcontact(_d, &search_ci, &c) == 1) { } else { if (checkcontact(_m, c) != 0) { c = NULL; } } } asserted_identity = NULL; registration_contact = NULL; if (c) { LM_DBG("Trying to set asserted identity field"); registration_contact = &c->contact_user; p = c->head; while (p) { LM_DBG("Checking through contact users"); if (p->is_default == 1) { LM_DBG("Found default contact user so setting asserted identity"); asserted_identity = &p->public_identity; } p = p->next; } } if (asserted_identity != NULL && asserted_identity->len > 0) { LM_DBG("Have set the asserted_identity param to [%.*s]\n", asserted_identity->len, asserted_identity->s); } else { LM_DBG("Asserted identity not set"); } // LM_DBG("pcontact flag is [%d]\n", c->flags); // if (c && (c->flags & (1<<FLAG_READFROMDB)) != 0) { // LM_DBG("we have a contact that was read fresh from the DB....\n"); // } if (!c && mustRetryViaSearch) { LM_DBG("This is a reply so we will search using the last via once more...\n"); vb = cscf_get_ue_via(_m); search_ci.via_host = vb->host; search_ci.via_port = vb->port ? vb->port : 5060; search_ci.via_prot = vb->proto; mustRetryViaSearch = 0; goto tryagain; } if (!c && mustRetryReceivedSearch) { LM_DBG("This is a reply and we still don't have a match - will try src ip/port of message\n"); search_ci.via_host = received_host; search_ci.via_port = _m->rcv.src_port; search_ci.via_prot = _m->rcv.proto; mustRetryReceivedSearch = 0; goto tryagain; } return c; }
static int is_peer_verified(struct sip_msg* msg, char* foo, char* foo2) { struct tcp_connection *c; SSL *ssl; long ssl_verify; X509 *x509_cert; LM_DBG("started...\n"); if (msg->rcv.proto != PROTO_TLS) { LM_ERR("proto != TLS --> peer can't be verified, return -1\n"); return -1; } LM_DBG("trying to find TCP connection of received message...\n"); /* what if we have multiple connections to the same remote socket? e.g. we can have connection 1: localIP1:localPort1 <--> remoteIP:remotePort connection 2: localIP2:localPort2 <--> remoteIP:remotePort but I think the is very unrealistic */ tcp_conn_get(0, &(msg->rcv.src_ip), msg->rcv.src_port, PROTO_TLS, &c, NULL/*fd*/); if (c==NULL) { LM_ERR("no corresponding TLS/TCP connection found." " This should not happen... return -1\n"); return -1; } LM_DBG("corresponding TLS/TCP connection found. s=%d, fd=%d, id=%d\n", c->s, c->fd, c->id); if (!c->extra_data) { LM_ERR("no extra_data specified in TLS/TCP connection found." " This should not happen... return -1\n"); goto error; } ssl = (SSL *) c->extra_data; ssl_verify = SSL_get_verify_result(ssl); if ( ssl_verify != X509_V_OK ) { LM_WARN("verification of presented certificate failed... return -1\n"); goto error; } /* now, we have only valid peer certificates or peers without certificates. * Thus we have to check for the existence of a peer certificate */ x509_cert = SSL_get_peer_certificate(ssl); if ( x509_cert == NULL ) { LM_WARN("tlsops:is_peer_verified: WARNING: peer did not presented " "a certificate. Thus it could not be verified... return -1\n"); goto error; } X509_free(x509_cert); tcp_conn_release(c, 0); LM_DBG("tlsops:is_peer_verified: peer is successfully verified" "...done\n"); return 1; error: tcp_conn_release(c, 0); return -1; }
static int load_crl(SSL_CTX * ctx, char *crl_directory, int crl_check_all) { #if OPENSSL_VERSION_NUMBER >= 0x10000000L DIR *d; struct dirent *dir; int crl_added = 0; LM_DBG("Loading CRL from directory\n"); /*Get X509 store from SSL context*/ X509_STORE *store = SSL_CTX_get_cert_store(ctx); if(!store) { LM_ERR("Unable to get X509 store from ssl context\n"); return -1; } /*Parse directory*/ d = opendir(crl_directory); if(!d) { LM_ERR("Unable to open crl directory '%s'\n", crl_directory); return -1; } while ((dir = readdir(d)) != NULL) { /*Skip if not regular file*/ if (dir->d_type != DT_REG) continue; /*Create filename*/ char* filename = (char*) pkg_malloc(sizeof(char)*(strlen(crl_directory)+strlen(dir->d_name)+2)); if (!filename) { LM_ERR("Unable to allocate crl filename\n"); closedir(d); return -1; } strcpy(filename,crl_directory); if(filename[strlen(filename)-1] != '/') strcat(filename,"/"); strcat(filename,dir->d_name); /*Get CRL content*/ FILE *fp = fopen(filename,"r"); pkg_free(filename); if(!fp) continue; X509_CRL *crl = PEM_read_X509_CRL(fp, NULL, NULL, NULL); fclose(fp); if(!crl) continue; /*Add CRL to X509 store*/ if (X509_STORE_add_crl(store, crl) == 1) crl_added++; else LM_ERR("Unable to add crl to ssl context\n"); X509_CRL_free(crl); } closedir(d); if (!crl_added) { LM_ERR("No suitable CRL files found in directory %s\n", crl_directory); return -1; } /*Enable CRL checking*/ X509_VERIFY_PARAM *param; param = X509_VERIFY_PARAM_new(); int flags = X509_V_FLAG_CRL_CHECK; if(crl_check_all) flags |= X509_V_FLAG_CRL_CHECK_ALL; X509_VERIFY_PARAM_set_flags(param, flags); SSL_CTX_set1_param(ctx, param); X509_VERIFY_PARAM_free(param); return 0; #else static int already_warned = 0; if (!already_warned) { LM_WARN("CRL not supported in %s\n", OPENSSL_VERSION_TEXT); already_warned = 1; } return 0; #endif }
/*! \brief * Check if the originating REGISTER message was formed correctly * The whole message must be parsed before calling the function * _s indicates whether the contact was star */ int check_contacts(struct sip_msg* _m, int* _s) { struct hdr_field* p; contact_t* c; *_s = 0; /* Message without contacts is OK */ if (_m->contact == 0) return 0; if (((contact_body_t*)_m->contact->parsed)->star == 1) { /* The first Contact HF is star */ /* Expires must be zero */ if (get_expires_hf(_m) != 0) { LM_WARN("expires must be 0 for star contact\n"); rerrno = R_STAR_EXP; return 1; } /* Message must contain no contacts */ if (((contact_body_t*)_m->contact->parsed)->contacts) { LM_WARN("star contact cannot be mixed with other contacts\n"); rerrno = R_STAR_CONT; return 1; } /* Message must contain no other Contact HFs */ p = _m->contact->next; while(p) { if (p->type == HDR_CONTACT_T) { LM_WARN("star contact cannot be mixed with other contacts\n"); rerrno = R_STAR_CONT; return 1; } p = p->next; } *_s = 1; } else { /* The first Contact HF is not star */ p = _m->contact; while(p) { if (p->type == HDR_CONTACT_T) { /* Message must contain no star Contact HF */ if (((contact_body_t*)p->parsed)->star == 1) { LM_WARN("star contact cannot be mixed with other contacts\n"); rerrno = R_STAR_CONT; return 1; } /* check also the length of all contacts */ for(c=((contact_body_t*)p->parsed)->contacts ; c ; c=c->next) { if (c->uri.len > contact_max_size) { LM_WARN("contact uri is too long: [%.*s]\n", c->uri.len, c->uri.s); rerrno = R_CONTACT_LEN; return 1; } if (c->received && c->received->len>RECEIVED_MAX_SIZE) { LM_WARN("received attribute of contact is too long\n"); rerrno = R_CONTACT_LEN; return 1; } } } p = p->next; } } return 0; }
static int append_fixed_vars(struct sip_msg *msg, struct hf_wrapper **list) { static char tid[MD5_LEN]; str *uri; struct sip_uri parsed_uri, oparsed_uri; char *val; int val_len; /* source ip */ if (!append_var(EV_SRCIP, ip_addr2a(&msg->rcv.src_ip), 0, list)) { LM_ERR("append_var SRCIP failed \n"); return 0; } /* request URI */ uri=msg->new_uri.s && msg->new_uri.len ? &msg->new_uri : &msg->first_line.u.request.uri; if (!append_var(EV_RURI, uri->s, uri->len, list )) { LM_ERR("append_var URI failed\n"); return 0; } /* userpart of request URI */ if (parse_uri(uri->s, uri->len, &parsed_uri)<0) { LM_WARN("uri not parsed\n"); } else { if (!append_var(EV_USER, parsed_uri.user.s, parsed_uri.user.len, list)) { LM_ERR("append_var USER failed\n"); goto error; } } /* original URI */ if (!append_var(EV_ORURI, msg->first_line.u.request.uri.s, msg->first_line.u.request.uri.len, list)) { LM_ERR("append_var O-URI failed\n"); goto error; } /* userpart of request URI */ if (parse_uri(msg->first_line.u.request.uri.s, msg->first_line.u.request.uri.len, &oparsed_uri)<0) { LM_WARN("orig URI not parsed\n"); } else { if (!append_var(EV_OUSER, oparsed_uri.user.s, oparsed_uri.user.len, list)) { LM_ERR("ppend_var OUSER failed\n"); goto error; } } /* tid, transaction id == via/branch */ if (!char_msg_val(msg, tid)) { LM_WARN("no tid can be determined\n"); val=0; val_len=0; } else { val=tid;val_len=MD5_LEN; } if (!append_var(EV_TID, val,val_len, list)) { LM_ERR("append_var TID failed\n"); goto error; } /* did, dialogue id == To-tag */ if (!(msg->to && get_to(msg) )) { LM_ERR("no to-tag\n"); val=0; val_len=0; } else { val=get_to(msg)->tag_value.s; val_len=get_to(msg)->tag_value.len; } if (!append_var(EV_DID, val, val_len, list)) { LM_ERR("append_var DID failed\n"); goto error; } return 1; error: return 0; }
int build_publish_call_info_header(b2b_sca_record_t *rec, str *publish_hdr) { unsigned int i; unsigned int size = sizeof(CALL_INFO_HDR); b2b_sca_call_t *call = NULL; char *p; rec->expires = 30; size += callinfo_default_uri.len + callinfo_appindex.len + callinfo_hdr_postfix.len; if (rec == NULL) { /* we need to build an idle Call-Info header */ publish_hdr->s = publish_call_info_hdr_buf; p = &publish_call_info_hdr_buf[sizeof(CALL_INFO_HDR) - 1]; goto default_hdr; } for (i=0; i<MAX_APPEARANCE_INDEX; i++) { if (rec->call[i]) { call = rec->call[i]; if (call->call_state > ALERTING_STATE) rec->expires = 36000; size += call->call_info_uri.len + callinfo_appuri_prefix.len + call->call_info_apperance_uri.len + callinfo_appindex.len + call->appearance_index_str.len + callinfo_appstate.len + app_state[call->call_state].len + 2; } } if (size > PUBLISH_CALL_INFO_HDR_LEN) { LM_WARN("buffer overflow for PUBLISH Call-Info" " header: size [%d]\n", size); p = (char *)pkg_malloc(size); if (p == NULL) { LM_ERR("OOM\n"); return -1; } publish_hdr->s = p; memcpy(p, publish_call_info_hdr_buf, sizeof(CALL_INFO_HDR) - 1); p += sizeof(CALL_INFO_HDR) - 1; } else { publish_hdr->s = publish_call_info_hdr_buf; p = &publish_call_info_hdr_buf[sizeof(CALL_INFO_HDR) - 1]; } for (i=0; i<MAX_APPEARANCE_INDEX; i++) { if (rec->call[i]) { call = rec->call[i]; memcpy(p, call->call_info_uri.s, call->call_info_uri.len); p += call->call_info_uri.len; memcpy(p, callinfo_appuri_prefix.s, callinfo_appuri_prefix.len); p += callinfo_appuri_prefix.len; memcpy(p, call->call_info_apperance_uri.s, call->call_info_apperance_uri.len); p += call->call_info_apperance_uri.len; *p = '\"'; p++; memcpy(p, callinfo_appindex.s, callinfo_appindex.len); p += callinfo_appindex.len; memcpy(p, call->appearance_index_str.s, call->appearance_index_str.len); p += call->appearance_index_str.len; memcpy(p, callinfo_appstate.s, callinfo_appstate.len); p += callinfo_appstate.len; memcpy(p, app_state[call->call_state].s, app_state[call->call_state].len); p += app_state[call->call_state].len; *p = ','; p++; *p = '<'; p++; } } default_hdr: memcpy(p, callinfo_default_uri.s, callinfo_default_uri.len); p += callinfo_default_uri.len; memcpy(p, callinfo_appindex.s, callinfo_appindex.len); p += callinfo_appindex.len; memcpy(p, callinfo_hdr_postfix.s, callinfo_hdr_postfix.len); p += callinfo_hdr_postfix.len; publish_hdr->len = p - publish_hdr->s; LM_DBG("publish_hdr [%d:%d] [%.*s]\n", size, publish_hdr->len, publish_hdr->len, publish_hdr->s); return 0; }
void vqm_free(struct vqm_block* qm, void* p) #endif { struct vqm_frag *f, *next, *prev, *first_big; unsigned char b; #ifdef DBG_QM_MALLOC LM_GEN1(memlog,"params (%p, %p), called from %s: %s(%d)\n", qm, p, file, func, line); if (p>(void *)qm->core_end || p<(void*)qm->init_core){ LM_CRIT("bad pointer %p (out of memory block!) - aborting\n", p); abort(); } #endif if (p==0) { LM_WARN("free(0) called\n"); return; } f=(struct vqm_frag*) ((char*)p-sizeof(struct vqm_frag)); b=f->u.inuse.bucket; #ifdef DBG_QM_MALLOC VQM_DEBUG_FRAG(qm, f); if ( ! FRAG_ISUSED(f) ) { LM_CRIT("freeing already freed pointer, first freed: %s: %s(%d) " "- aborting\n", f->file, f->func, f->line); abort(); } if ( b>MAX_BUCKET ) { LM_CRIT("fragment with too high bucket nr: " "%d, allocated: %s: %s(%d) - aborting\n", b, f->file, f->func, f->line); abort(); } LM_GEN1(memlog,"freeing %d bucket block alloc'ed from %s: %s(%d)\n", f->u.inuse.bucket, f->file, f->func, f->line); f->file=file; f->func=func; f->line=line; qm->usage[ f->u.inuse.bucket ]--; #endif if (IS_BIGBUCKET(qm,b)) { next=FRAG_NEXT(f); if ((char *)next +sizeof( struct vqm_frag) < qm->core_end) { VQM_DEBUG_FRAG(qm, next); if (! FRAG_ISUSED(next)) { /* coalesce with next fragment */ LM_DBG("coalesced with next\n"); vqm_detach_free(qm, next); f->size+=next->size; FRAG_END(f)->size=f->size; } } first_big = qm->next_free[b]; if (first_big && f>first_big) { prev=FRAG_PREV(f); VQM_DEBUG_FRAG(qm, prev); if (!FRAG_ISUSED(prev)) { /* coalesce with prev fragment */ LM_DBG("coalesced with prev\n"); vqm_detach_free(qm, prev ); prev->size+=f->size; f=prev; FRAG_END(f)->size=f->size; } } if ((char *)f==qm->big_chunks) { /* release unused core */ LM_DBG("big chunk released\n"); qm->free_core+=f->size; qm->big_chunks+=f->size; return; } first_big = qm->next_free[b]; /* fix reverse link (used only for BIG_BUCKET */ if (first_big) FRAG_END(first_big)->prv_free=f; FRAG_END(f)->prv_free=0; } else first_big = qm->next_free[b]; f->u.nxt_free = first_big; /* also clobbers magic */ qm->next_free[b] = f; }
void modem_process(struct modem *mdm) { struct sms_msg *sms_messg; struct incame_sms sms; struct network *net; int i,k,len; int counter; int dont_wait; int empty_pipe; int cpms_unsuported; int max_mem=0, used_mem=0; sms_messg = 0; cpms_unsuported = 0; /* let's open/init the modem */ LM_DBG("opening modem\n"); if (openmodem(mdm)==-1) { LM_ERR("failed to open modem %s! %s \n", mdm->name,strerror(errno)); return; } setmodemparams(mdm); initmodem(mdm,check_cds_report); if ( (max_mem=check_memory(mdm,MAX_MEM))==-1 ) { LM_WARN("CPMS command unsuported! using default values (10,10)\n"); used_mem = max_mem = 10; cpms_unsuported = 1; } LM_DBG("modem maximum memory is %d\n",max_mem); set_gettime_function(); while(1) { /* update the local config */ cfg_update(); dont_wait = 0; for (i=0;i<nr_of_networks && mdm->net_list[i]!=-1;i++) { counter = 0; empty_pipe = 0; net = &(networks[mdm->net_list[i]]); /*getting msgs from pipe*/ while( counter<net->max_sms_per_call && !empty_pipe ) { /* let's read a sms from pipe */ len = read(net->pipe_out, &sms_messg, sizeof(sms_messg)); if (len!=sizeof(sms_messg)) { if (len>=0) LM_ERR("truncated message read from pipe!" " -> discarded\n"); else if (errno==EAGAIN) empty_pipe = 1; else LM_ERR("pipe reading failed: %s\n",strerror(errno)); sleep(1); counter++; continue; } (*queued_msgs)--; /* compute and send the sms */ LM_DBG("%s processing sms for net %s:" " \n\tTo:[%.*s]\n\tBody=<%d>[%.*s]\n", mdm->device, net->name, sms_messg->to.len,sms_messg->to.s, sms_messg->text.len,sms_messg->text.len,sms_messg->text.s); send_as_sms( sms_messg , mdm); counter++; /* if I reached the limit -> set not to wait */ if (counter==net->max_sms_per_call) dont_wait = 1; }/*while*/ }/*for*/ /* let's see if we have incoming sms */ if ( !cpms_unsuported ) if ((used_mem = check_memory(mdm,USED_MEM))==-1) { LM_ERR("CPMS command failed! cannot get used mem -> using 10\n"); used_mem = 10; } /* if any, let's get them */ if (used_mem) LM_DBG("%d new SMS on modem\n",used_mem); for(i=1,k=1;k<=used_mem && i<=max_mem;i++) { if (getsms(&sms,mdm,i)!=-1) { k++; LM_DBG("SMS Get from location %d\n",i); /*for test ;-) -> to be remove*/ LM_DBG("SMS RECEIVED:\n\rFrom: %s %s\n\r%.*s %.*s" "\n\r\"%.*s\"\n\r",sms.sender,sms.name, DATE_LEN,sms.date,TIME_LEN,sms.time, sms.userdatalength,sms.ascii); if (!sms.is_statusreport) _send_sms_as_sip(&sms, mdm); else check_sms_report(&sms); } } /* if reports are used, checks for expired records in report queue */ if (sms_report_type!=NO_REPORT) check_timeout_in_report_queue(); /* sleep -> if it's needed */ if (!dont_wait) { sleep(mdm->looping_interval); } }/*while*/ }
int send_sms_as_sip( struct incame_sms *sms ) { str sip_addr; str sip_body; str sip_from; int is_pattern; int k; char *p; /* first we have to parse the body to try to get out the sip destination address; The sms body can to be in the following two formats: 1. The entire or part of the sent header still exists - we will pars it and consider the start of the sip message the first character that doesn't match the header! 2. The sms body is totally different of the send sms -> search for a sip address inside; everything before it is ignored, only the part following the address being send as sip */ sip_addr.len = 0; sip_body.len = 0; p = sms->ascii; /* is our logo (or a part of it) still there? */ if (*p==SMS_HDR_BF_ADDR[0]) { is_pattern = 1; /* try to match SMS_HDR_BF_ADDR */ k=0; while( is_pattern && p<sms->ascii+sms->userdatalength && k<SMS_HDR_BF_ADDR_LEN) if (*(p++)!=SMS_HDR_BF_ADDR[k++]) is_pattern = 0; if (!is_pattern) { /* first header part is broken -> let's give it a chance and parse for the first word delimiter */ while(p<sms->ascii+sms->userdatalength && no_sip_addr_begin(*p)) p++; p++; if (p+9>=sms->ascii+sms->userdatalength) { LM_ERR("unable to find sip_address start in sms body [%s]!\n", sms->ascii); goto error; } } /* lets get the address */ if (p[0]!='s' || p[1]!='i' || p[2]!='p' || p[3]!=':') { LM_ERR("wrong sip address format in sms body [%s]!\n",sms->ascii); goto error; } sip_addr.s = p; /* goes to the end of the address */ while(p<sms->ascii+sms->userdatalength && is_in_sip_addr(*p) ) p++; if (p>=sms->ascii+sms->userdatalength) { LM_ERR("failed to find sip address end in sms body [%s]!\n", sms->ascii); } sip_addr.len = p-sip_addr.s; LM_DBG("sip address found [%.*s]\n", sip_addr.len,sip_addr.s); /* try to match SMS_HDR_AF_ADDR */ k=0; while( is_pattern && p<sms->ascii+sms->userdatalength && k<SMS_HDR_AF_ADDR_LEN) if (*(p++)!=SMS_HDR_AF_ADDR[k++]) is_pattern = 0; } else { /* no trace of the pattern sent along with the orig sms*/ do { if ((p[0]=='s'||p[0]=='S') && (p[1]=='i'||p[1]=='I') && (p[2]=='p'||p[2]=='P') && p[3]==':') { /* we got the address beginning */ sip_addr.s = p; /* goes to the end of the address */ while(p<sms->ascii+sms->userdatalength && is_in_sip_addr(*p) ) p++; if (p==sms->ascii+sms->userdatalength) { LM_ERR("failed to find sip address end in sms body [%s]!\n", sms->ascii); goto error; } sip_addr.len = p-sip_addr.s; } else { /* parse to the next word */ /*LM_DBG("*** Skipping word len=%d\n",sms->userdatalength);*/ while(p<sms->ascii+sms->userdatalength&&no_sip_addr_begin(*p)){ p++; } p++; if (p+9>=sms->ascii+sms->userdatalength) { LM_ERR("unable to find sip address start in sms body [%s]!\n", sms->ascii); goto error; } /*LM_DBG("*** Done\n");*/ } }while (!sip_addr.len); } /* the rest of the sms (if any ;-)) is the body! */ sip_body.s = p; sip_body.len = sms->ascii + sms->userdatalength - p; /* let's trim out all \n an \r from beginning */ while ( sip_body.len && sip_body.s && (sip_body.s[0]=='\n' || sip_body.s[0]=='\r') ) { sip_body.s++; sip_body.len--; } if (sip_body.len==0) { LM_WARN("empty body for sms [%s]", sms->ascii); goto error; } LM_DBG("extracted body is: [%.*s]\n",sip_body.len, sip_body.s); /* finally, let's send it as sip message */ sip_from.s = sms->sender; sip_from.len = strlen(sms->sender); /* patch the body with date and time */ if (sms->userdatalength + CRLF_LEN + 1 /*'('*/ + DATE_LEN + 1 /*','*/ + TIME_LEN + 1 /*')'*/< sizeof(sms->ascii)) { p = sip_body.s + sip_body.len; append_str( p, CRLF, CRLF_LEN); *(p++) = '('; append_str( p, sms->date, DATE_LEN); *(p++) = ','; append_str( p, sms->time, TIME_LEN); *(p++) = ')'; sip_body.len += CRLF_LEN + DATE_LEN + TIME_LEN + 3; } return send_sip_msg_request(&sip_addr, &sip_from, &sip_body); error: return -1; }
/*! \brief * handle io routine, based on the fd_map type * (it will be called from reactor_main_loop ) * params: fm - pointer to a fd hash entry * idx - index in the fd_array (or -1 if not known) * return: -1 on error, or when we are not interested any more on reads * from this fd (e.g.: we are closing it ) * 0 on EAGAIN or when by some other way it is known that no more * io events are queued on the fd (the receive buffer is empty). * Usefull to detect when there are no more io events queued for * sigio_rt, epoll_et, kqueue. * >0 on successfull read from the fd (when there might be more io * queued -- the receive buffer might still be non-empty) */ inline static int handle_io(struct fd_map* fm, int idx,int event_type) { int ret=0; int n; struct tcp_connection* con; int s,rw; long resp; long response[2]; switch(fm->type){ case F_TIMER_JOB: handle_timer_job(); break; case F_SCRIPT_ASYNC: async_resume_f( fm->fd, fm->data); return 0; case F_TCPMAIN: again: ret=n=receive_fd(fm->fd, response, sizeof(response), &s, 0); if (n<0){ if (errno == EWOULDBLOCK || errno == EAGAIN){ ret=0; break; }else if (errno == EINTR) goto again; else{ LM_CRIT("read_fd: %s \n", strerror(errno)); abort(); /* big error*/ } } if (n==0){ LM_WARN("0 bytes read\n"); break; } con = (struct tcp_connection *)response[0]; rw = (int)response[1]; if (con==0){ LM_CRIT("null pointer\n"); break; } if (s==-1) { LM_BUG("read_fd:no fd read\n"); /* FIXME? */ return -1; } if (con==tcp_conn_lst){ LM_CRIT("duplicate" " connection received: %p, id %d, fd %d, refcnt %d" " state %d (n=%d)\n", con, con->id, con->fd, con->refcnt, con->state, n); tcpconn_release(con, CONN_ERROR,0); break; /* try to recover */ } LM_DBG("We have received conn %p with rw %d on fd %d\n",con,rw,s); if (rw & IO_WATCH_READ) { /* 0 attempts so far for this SIP MSG */ con->msg_attempts = 0; /* must be before reactor_add, as the add might catch some * already existing events => might call handle_io and * handle_io might decide to del. the new connection => * must be in the list */ tcpconn_listadd(tcp_conn_lst, con, c_next, c_prev); con->timeout = con->lifetime; if (reactor_add_reader( s, F_TCPCONN, RCT_PRIO_NET, con )<0) { LM_CRIT("failed to add new socket to the fd list\n"); tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev); goto con_error; } /* mark that the connection is currently in our process future writes to this con won't have to acquire FD */ con->proc_id = process_no; /* save FD which is valid in context of this TCP worker */ con->fd=s; } else if (rw & IO_WATCH_WRITE) { LM_DBG("Received con for async write %p ref = %d\n",con,con->refcnt); lock_get(&con->write_lock); resp = protos[con->type].net.write( (void*)con, s ); lock_release(&con->write_lock); if (resp<0) { ret=-1; /* some error occured */ con->state=S_CONN_BAD; tcpconn_release(con, CONN_ERROR,1); break; } else if (resp==1) { tcpconn_release(con, ASYNC_WRITE,1); } else { tcpconn_release(con, CONN_RELEASE,1); } ret = 0; /* we always close the socket received for writing */ close(s); } break; case F_TCPCONN: if (event_type & IO_WATCH_READ) { con=(struct tcp_connection*)fm->data; resp = protos[con->type].net.read( (void*)con, &ret ); if (resp<0) { ret=-1; /* some error occured */ con->state=S_CONN_BAD; reactor_del_all( con->fd, idx, IO_FD_CLOSING ); tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev); con->proc_id = -1; if (con->fd!=-1) { close(con->fd); con->fd = -1; } tcpconn_release(con, CONN_ERROR,0); } else if (con->state==S_CONN_EOF) { reactor_del_all( con->fd, idx, IO_FD_CLOSING ); tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev); con->proc_id = -1; if (con->fd!=-1) { close(con->fd); con->fd = -1; } tcpconn_release(con, CONN_EOF,0); } else { //tcpconn_release(con, CONN_RELEASE); /* keep the connection for now */ break; } } break; case F_NONE: LM_CRIT("empty fd map %p: " "{%d, %d, %p}\n", fm, fm->fd, fm->type, fm->data); goto error; default: LM_CRIT("uknown fd type %d\n", fm->type); goto error; } return ret; con_error: con->state=S_CONN_BAD; tcpconn_release(con, CONN_ERROR,0); return ret; error: return -1; }
/* * Called after val2str to realy binding */ int db_oracle_val2bind(bmap_t* _m, const db_val_t* _v, OCIDate* _o) { if (VAL_NULL(_v)) { _m->addr = NULL; _m->size = 0; _m->type = SQLT_NON; return 0; } switch (VAL_TYPE(_v)) { case DB_INT: _m->addr = (int*)&VAL_INT(_v); _m->size = sizeof(VAL_INT(_v)); _m->type = SQLT_INT; break; case DB_BIGINT: _m->addr = (int*)&VAL_BIGINT(_v); _m->size = sizeof(VAL_BIGINT(_v)); _m->type = SQLT_NUM; break; case DB_BITMAP: _m->addr = (unsigned*)&VAL_BITMAP(_v); _m->size = sizeof(VAL_BITMAP(_v)); _m->type = SQLT_UIN; break; case DB_DOUBLE: _m->addr = (double*)&VAL_DOUBLE(_v); _m->size = sizeof(VAL_DOUBLE(_v)); _m->type = SQLT_FLT; break; case DB_STRING: _m->addr = (char*)VAL_STRING(_v); _m->size = strlen(VAL_STRING(_v))+1; _m->type = SQLT_STR; break; case DB_STR: { unsigned len = VAL_STR(_v).len; char *estr, *pstr = VAL_STR(_v).s; estr = (char*)memchr(pstr, 0, len); if (estr) { LM_WARN("truncate STR len from %u to: '%s'\n", len, pstr); len = (unsigned)(estr - pstr) + 1; } _m->size = len; _m->addr = pstr; _m->type = SQLT_CHR; } break; case DB_DATETIME: { struct tm* tm = localtime(&VAL_TIME(_v)); if (tm->tm_sec == 60) --tm->tm_sec; OCIDateSetDate(_o, (ub2)(tm->tm_year + 1900), (ub1)(tm->tm_mon + 1), (ub1)tm->tm_mday); OCIDateSetTime(_o, (ub1)tm->tm_hour, (ub1)tm->tm_min, (ub1)tm->tm_sec); _m->addr = _o; _m->size = sizeof(*_o); _m->type = SQLT_ODT; } break; case DB_BLOB: _m->addr = VAL_BLOB(_v).s; _m->size = VAL_BLOB(_v).len; _m->type = SQLT_CLOB; break; default: LM_ERR("unknown data type\n"); return -1; } return 0; }
static int b2bl_add_tuple(b2bl_tuple_t* tuple, str* params[]) { b2bl_tuple_t* shm_tuple= NULL; unsigned int hash_index, local_index; str* b2bl_key; b2bl_entity_id_t* entity; int i; b2b_notify_t cback; str* client_id = NULL; unsigned int logic_restored = 0; LM_DBG("Add tuple key [%.*s]\n", tuple->key->len, tuple->key->s); if(b2bl_parse_key(tuple->key, &hash_index, &local_index)< 0) { LM_ERR("Wrong formatted b2b logic key\n"); return -1; } shm_tuple = b2bl_insert_new(NULL, hash_index, tuple->scenario, params, (tuple->sdp.s?&tuple->sdp:NULL), NULL, local_index, &b2bl_key, UPDATEDB_FLAG); if(shm_tuple == NULL) { LM_ERR("Failed to insert new tuple\n"); return -1; } shm_tuple->lifetime = tuple->lifetime; lock_release(&b2bl_htable[hash_index].lock); shm_tuple->scenario_state= tuple->scenario_state; shm_tuple->next_scenario_state= tuple->next_scenario_state; /* add entities */ for(i=0; i< MAX_BRIDGE_ENT; i++) { if(!tuple->bridge_entities[i]->to_uri.len) continue; LM_DBG("Restore logic info for tuple:entity [%.*s][%d]\n", b2bl_key->len, b2bl_key->s, i); if(tuple->bridge_entities[i]->type == B2B_SERVER) cback = b2b_server_notify; else cback = b2b_client_notify; /* restore to the entities from b2b_entities module * the parameter and callback function */ if(b2b_api.restore_logic_info(tuple->bridge_entities[i]->type, &tuple->bridge_entities[i]->key, cback)< 0) LM_WARN("Failed to restore logic info for tuple:entity [%.*s][%d]\n", b2bl_key->len, b2bl_key->s, i); else logic_restored = 1; entity= b2bl_create_new_entity(tuple->bridge_entities[i]->type, &tuple->bridge_entities[i]->key,&tuple->bridge_entities[i]->to_uri, &tuple->bridge_entities[i]->from_uri, 0, &tuple->bridge_entities[i]->scenario_id, 0); if(client_id) pkg_free(client_id); if(entity == NULL) { LM_ERR("Failed to create entity %d\n", i); goto error; } shm_tuple->bridge_entities[i]= entity; /* put the pointer in clients or servers array */ // FIXME: check if the restore logic is ok if(tuple->bridge_entities[i]->type == B2B_SERVER) { if (shm_tuple->servers[0]) shm_tuple->servers[1] = entity; else shm_tuple->servers[0] = entity; } else { if (shm_tuple->clients[0]) shm_tuple->clients[1] = entity; else shm_tuple->clients[0] = entity; } } if(shm_tuple->bridge_entities[1]) shm_tuple->bridge_entities[1]->peer = shm_tuple->bridge_entities[0]; if(shm_tuple->bridge_entities[0]) shm_tuple->bridge_entities[0]->peer = shm_tuple->bridge_entities[1]; /* Mark tuple without entities as expired */ if(logic_restored==0) shm_tuple->lifetime = 1; return 0; error: shm_free(shm_tuple); return -1; }
static int mod_init(void){ str s; int n; LM_INFO("initializing TLS protocol\n"); if (tls_db_enabled != 0 && tls_db_enabled != 1) { tls_db_enabled = 1; } if (tls_db_enabled) { /* create & init lock */ if ((dom_lock = lock_init_rw()) == NULL) { LM_CRIT("failed to init lock\n"); return -1; } init_db_url(tls_db_url, 0 /*cannot be null*/); tls_db_table.len = strlen(tls_db_table.s); if (tls_db_table.len == 0) { LM_ERR("db url not specified\n"); return -1; } id_col.len = strlen(id_col.s); address_col.len = strlen(address_col.s); type_col.len = strlen(type_col.s); method_col.len = strlen(method_col.s); verify_cert_col.len = strlen(verify_cert_col.s); require_cert_col.len = strlen(require_cert_col.s); certificate_col.len = strlen(certificate_col.s); pk_col.len = strlen(pk_col.s); crl_check_col.len = strlen(crl_check_col.s); calist_col.len = strlen(calist_col.s); cadir_col.len = strlen(cadir_col.s); cplist_col.len = strlen(cplist_col.s); dhparams_col.len = strlen(dhparams_col.s); eccurve_col.len = strlen(eccurve_col.s); if (db_bind_mod(&tls_db_url, &dr_dbf)) { LM_CRIT("cannot bind to database module! " "Did you forget to load a database module ?\n"); return -1; } /* init DB connection */ if ((db_hdl = dr_dbf.init(&tls_db_url)) == 0) { LM_CRIT("cannot initialize database connection\n"); return -1; } if (dr_dbf.use_table(db_hdl, &tls_db_table) < 0) { LM_ERR("cannot select table \"%.*s\"\n", tls_db_table.len, tls_db_table.s); return -1; } } if (tls_domain_avp) { s.s = tls_domain_avp; s.len = strlen(s.s); if (parse_avp_spec( &s, &tls_client_domain_avp)) { LM_ERR("cannot parse tls_client_avp"); return -1; } } /* * this has to be called before any function calling CRYPTO_malloc, * CRYPTO_malloc will set allow_customize in openssl to 0 */ if (!CRYPTO_set_mem_functions(os_malloc, os_realloc, os_free)) { LM_ERR("unable to set the memory allocation functions\n"); LM_ERR("NOTE: check if you have openssl 1.0.1e-fips, as this " "version is know to be broken; if so, you need to upgrade or " "downgrade to a differen openssl version !!\n"); return -1; } #if !defined(OPENSSL_NO_COMP) STACK_OF(SSL_COMP)* comp_methods; /* disabling compression */ LM_WARN("disabling compression due ZLIB problems\n"); comp_methods = SSL_COMP_get_compression_methods(); if (comp_methods==0) { LM_INFO("openssl compression already disabled\n"); } else { sk_SSL_COMP_zero(comp_methods); } #endif if (tls_init_multithread() < 0) { LM_ERR("failed to init multi-threading support\n"); return -1; } SSL_library_init(); SSL_load_error_strings(); init_ssl_methods(); n = check_for_krb(); if (n==-1) { LM_ERR("kerberos check failed\n"); return -1; } if ( ( n ^ #ifndef OPENSSL_NO_KRB5 1 #else 0 #endif )!=0 ) { LM_ERR("compiled agaist an openssl with %s" "kerberos, but run with one with %skerberos\n", (n==1)?"":"no ",(n!=1)?"no ":""); return -1; } /* * finish setting up the tls default domains */ tls_default_client_domain.type = TLS_DOMAIN_DEF|TLS_DOMAIN_CLI ; tls_default_client_domain.addr.af = AF_INET; tls_default_server_domain.type = TLS_DOMAIN_DEF|TLS_DOMAIN_SRV; tls_default_server_domain.addr.af = AF_INET; /* * now initialize tls default domains */ if ( (n=init_tls_domains(&tls_default_server_domain)) ) { return n; } if ( (n=init_tls_domains(&tls_default_client_domain)) ) { return n; } /* * now initialize tls virtual domains */ if (tls_db_enabled && load_info(&dr_dbf, db_hdl, &tls_db_table, &tls_server_domains, &tls_client_domains)){ return -1; } if ( (n=init_tls_domains(tls_server_domains)) ) { return n; } if ( (n=init_tls_domains(tls_client_domains)) ) { return n; } /* * we are all set */ return 0; }
int unregister(struct sip_msg* _m, udomain_t* _d, str* _uri, str *_ruid) { str aor = {0, 0}; sip_uri_t *u; urecord_t *r; ucontact_t *c; int res; if (_ruid == NULL) { /* No ruid provided - remove all contacts for aor */ if (extract_aor(_uri, &aor, NULL) < 0) { LM_ERR("failed to extract Address Of Record\n"); return -1; } u = parse_to_uri(_m); if(u==NULL) { LM_ERR("failed to extract Address Of Record\n"); return -1; } if (star(_m, _d, &aor, &u->host) < 0) { LM_ERR("error unregistering user [%.*s]\n", aor.len, aor.s); return -2; } } else { /* ruid provided - remove a specific contact */ if (_uri->len > 0) { if (extract_aor(_uri, &aor, NULL) < 0) { LM_ERR("failed to extract Address Of Record\n"); return -1; } if (ul.get_urecord_by_ruid(_d, ul.get_aorhash(&aor), _ruid, &r, &c) != 0) { LM_WARN("AOR/Contact not found\n"); return -3; } if (ul.delete_ucontact(r, c) != 0) { ul.unlock_udomain(_d, &aor); LM_WARN("could not delete contact\n"); return -2; } ul.unlock_udomain(_d, &aor); } else { res = ul.delete_urecord_by_ruid(_d, _ruid); switch (res) { case -1: LM_ERR("could not delete contact\n"); return -2; case -2: LM_WARN("contact not found\n"); return -3; default: return 1; } } } return 1; }
/* * Setup default SSL_CTX (and SSL * ) behavior: * verification, cipherlist, acceptable versions, ... */ static int init_ssl_ctx_behavior( struct tls_domain *d ) { int verify_mode; #if (OPENSSL_VERSION_NUMBER > 0x10001000L) /* * set dh params */ if (!d->tmp_dh_file) { LM_DBG("no DH params file for tls[%s:%d] defined, " "using default '%s'\n", ip_addr2a(&d->addr), d->port, tls_tmp_dh_file); d->tmp_dh_file = tls_tmp_dh_file; } if (d->tmp_dh_file && set_dh_params(d->ctx, d->tmp_dh_file) < 0) return -1; if (d->tls_ec_curve) { if (set_ec_params(d->ctx, d->tls_ec_curve) < 0) { return -1; } } else { LM_NOTICE("No EC curve defined\n"); } #else if (d->tmp_dh_file || tls_tmp_dh_file) LM_WARN("DH params file discarded as not supported by your openSSL version\n"); if (d->tls_ec_curve) LM_WARN("EC params file discarded as not supported by your openSSL version\n"); #endif if( d->ciphers_list != 0 ) { if( SSL_CTX_set_cipher_list(d->ctx, d->ciphers_list) == 0 ) { LM_ERR("failure to set SSL context " "cipher list '%s'\n", d->ciphers_list); return -1; } else { LM_NOTICE("cipher list set to %s\n", d->ciphers_list); } } else { LM_DBG( "cipher list null ... setting default\n"); } /* Set a bunch of options: * do not accept SSLv2 / SSLv3 * no session resumption * choose cipher according to server's preference's*/ SSL_CTX_set_options(d->ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_CIPHER_SERVER_PREFERENCE); /* Set verification procedure * The verification can be made null with SSL_VERIFY_NONE, or * at least easier with SSL_VERIFY_CLIENT_ONCE instead of * SSL_VERIFY_FAIL_IF_NO_PEER_CERT. * For extra control, instead of 0, we can specify a callback function: * int (*verify_callback)(int, X509_STORE_CTX *) * Also, depth 2 may be not enough in some scenarios ... though no need * to increase it much further */ if (d->type & TLS_DOMAIN_SRV) { /* Server mode: * SSL_VERIFY_NONE * the server will not send a client certificate request to the * client, so the client will not send a certificate. * SSL_VERIFY_PEER * the server sends a client certificate request to the client. * The certificate returned (if any) is checked. If the verification * process fails, the TLS/SSL handshake is immediately terminated * with an alert message containing the reason for the verification * failure. The behaviour can be controlled by the additional * SSL_VERIFY_FAIL_IF_NO_PEER_CERT and SSL_VERIFY_CLIENT_ONCE flags. * SSL_VERIFY_FAIL_IF_NO_PEER_CERT * if the client did not return a certificate, the TLS/SSL handshake * is immediately terminated with a ``handshake failure'' alert. * This flag must be used together with SSL_VERIFY_PEER. * SSL_VERIFY_CLIENT_ONCE * only request a client certificate on the initial TLS/SSL * handshake. Do not ask for a client certificate again in case of * a renegotiation. This flag must be used together with * SSL_VERIFY_PEER. */ if( d->verify_cert ) { verify_mode = SSL_VERIFY_PEER; if( d->require_client_cert ) { LM_WARN("client verification activated. Client " "certificates are mandatory.\n"); verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; } else LM_WARN("client verification activated. Client " "certificates are NOT mandatory.\n"); } else { verify_mode = SSL_VERIFY_NONE; LM_WARN("client verification NOT activated. Weaker security.\n"); } } else { /* Client mode: * SSL_VERIFY_NONE * if not using an anonymous cipher (by default disabled), the * server will send a certificate which will be checked. The result * of the certificate verification process can be checked after the * TLS/SSL handshake using the SSL_get_verify_result(3) function. * The handshake will be continued regardless of the verification * result. * SSL_VERIFY_PEER * the server certificate is verified. If the verification process * fails, the TLS/SSL handshake is immediately terminated with an * alert message containing the reason for the verification failure. * If no server certificate is sent, because an anonymous cipher is * used, SSL_VERIFY_PEER is ignored. * SSL_VERIFY_FAIL_IF_NO_PEER_CERT * ignored * SSL_VERIFY_CLIENT_ONCE * ignored */ if( d->verify_cert ) { verify_mode = SSL_VERIFY_PEER; LM_WARN("server verification activated.\n"); } else { verify_mode = SSL_VERIFY_NONE; LM_WARN("server verification NOT activated. Weaker security.\n"); } } SSL_CTX_set_verify( d->ctx, verify_mode, verify_callback); SSL_CTX_set_verify_depth( d->ctx, VERIFY_DEPTH_S); SSL_CTX_set_session_cache_mode( d->ctx, SSL_SESS_CACHE_SERVER ); SSL_CTX_set_session_id_context( d->ctx, OS_SSL_SESS_ID, OS_SSL_SESS_ID_LEN ); return 0; }
/*! \brief * Message contained some contacts, but record with same address * of record was not found so we have to create a new record * and insert all contacts from the message that have expires * > 0 */ static inline int insert_contacts(struct sip_msg* _m, udomain_t* _d, str* _a, int _use_regid, int novariation) { ucontact_info_t* ci; urecord_t* r = NULL; ucontact_t* c; contact_t* _c; unsigned int flags; int num, expires; int maxc; #ifdef USE_TCP int e_max, tcp_check; struct sip_uri uri; #endif sip_uri_t *u; u = parse_to_uri(_m); if(u==NULL) goto error; flags = mem_only; #ifdef USE_TCP if ( (_m->flags&tcp_persistent_flag) && (_m->rcv.proto==PROTO_TCP||_m->rcv.proto==PROTO_TLS ||_m->rcv.proto==PROTO_WS||_m->rcv.proto==PROTO_WSS)) { e_max = 0; tcp_check = 1; } else { e_max = tcp_check = 0; } #endif _c = get_first_contact(_m); maxc = reg_get_crt_max_contacts(); for( num=0,r=0,ci=0 ; _c ; _c = get_next_contact(_c) ) { /* calculate expires */ calc_contact_expires(_m, _c->expires, &expires, novariation); /* Skip contacts with zero expires */ if (expires == 0) continue; if (maxc > 0 && num >= maxc) { LM_INFO("too many contacts (%d) for AOR <%.*s>\n", num, _a->len, _a->s); rerrno = R_TOO_MANY; goto error; } num++; if (r==0) { if (ul.insert_urecord(_d, _a, &r) < 0) { rerrno = R_UL_NEW_R; LM_ERR("failed to insert new record structure\n"); goto error; } } /* pack the contact_info */ if ( (ci=pack_ci( (ci==0)?_m:0, _c, expires, flags, _use_regid))==0 ) { LM_ERR("failed to extract contact info\n"); goto error; } /* hack to work with buggy clients having many contacts with same * address in one REGISTER - increase CSeq to detect if there was * one already added, then update */ ci->cseq++; if ( r->contacts==0 || ul.get_ucontact_by_instance(r, &_c->uri, ci, &c) != 0) { ci->cseq--; if (ul.insert_ucontact( r, &_c->uri, ci, &c) < 0) { rerrno = R_UL_INS_C; LM_ERR("failed to insert contact\n"); goto error; } } else { ci->cseq--; if (ul.update_ucontact( r, c, ci) < 0) { rerrno = R_UL_UPD_C; LM_ERR("failed to update contact\n"); goto error; } } #ifdef USE_TCP if (tcp_check) { /* parse contact uri to see if transport is TCP */ if (parse_uri( _c->uri.s, _c->uri.len, &uri)<0) { LM_ERR("failed to parse contact <%.*s>\n", _c->uri.len, _c->uri.s); } else if (uri.proto==PROTO_TCP || uri.proto==PROTO_TLS || uri.proto==PROTO_WS || uri.proto==PROTO_WSS) { if (e_max) { LM_WARN("multiple TCP contacts on single REGISTER\n"); if (expires>e_max) e_max = expires; } else { e_max = expires; } } } #endif } if (r) { if (r->contacts) build_contact(_m, r->contacts, &u->host); ul.release_urecord(r); } else { /* No contacts found */ build_contact(_m, NULL, &u->host); } #ifdef USE_TCP if ( tcp_check && e_max>0 ) { e_max -= act_time; /*FIXME: Do we want this in the sr core?*/ /*force_tcp_conn_lifetime( &_m->rcv , e_max + 10 );*/ } #endif return 0; error: if (r) ul.delete_urecord(_d, _a, r); return -1; }
/*! * \brief Function that is registered as RR callback for dialog tracking * * Function that is registered as RR callback for dialog tracking. It * sets the appropriate events after the SIP method and run the state * machine to update the dialog state. It updates then the saved * dialogs and also the statistics. * \param req SIP request * \param route_params record-route parameter * \param param unused */ void dlg_onroute(struct sip_msg* req, str *route_params, void *param) { struct dlg_cell *dlg; str val, callid, ftag, ttag; int h_entry, h_id, new_state, old_state, unref, event, timeout; unsigned int dir; int ret = 0; if (current_dlg_pointer != NULL) return; /* skip initial requests - they may end up here because of the * preloaded route */ if ((!req->to && parse_headers(req, HDR_TO_F, 0) < 0) || !req->to) { LM_ERR("bad request or missing TO hdr :-/\n"); return; } if (get_to(req)->tag_value.len == 0) return; dlg = 0; dir = DLG_DIR_NONE; if (seq_match_mode != SEQ_MATCH_NO_ID) { if (d_rrb.get_route_param(req, &rr_param, &val) != 0) { LM_DBG("Route param '%.*s' not found\n", rr_param.len, rr_param.s); if (seq_match_mode == SEQ_MATCH_STRICT_ID) return; } else { LM_DBG("route param is '%.*s' (len=%d)\n", val.len, val.s, val.len); if (parse_dlg_rr_param(val.s, val.s + val.len, &h_entry, &h_id) < 0) return; dlg = lookup_dlg(h_entry, h_id); if (dlg == 0) { LM_WARN("unable to find dialog for %.*s " "with route param '%.*s' [%u:%u]\n", req->first_line.u.request.method.len, req->first_line.u.request.method.s, val.len, val.s, h_entry, h_id); if (seq_match_mode == SEQ_MATCH_STRICT_ID) return; } else { if (pre_match_parse(req, &callid, &ftag, &ttag, 1) < 0) { // lookup_dlg has incremented the ref count by 1 unref_dlg(dlg, 1); return; } if (match_dialog(dlg, &callid, &ftag, &ttag, &dir) == 0) { LM_WARN("tight matching failed for %.*s with callid='%.*s'/%d, " "ftag='%.*s'/%d, ttag='%.*s'/%d and direction=%d\n", req->first_line.u.request.method.len, req->first_line.u.request.method.s, callid.len, callid.s, callid.len, ftag.len, ftag.s, ftag.len, ttag.len, ttag.s, ttag.len, dir); LM_WARN("dialog identification elements are callid='%.*s'/%d, " "caller tag='%.*s'/%d\n", dlg->callid.len, dlg->callid.s, dlg->callid.len, dlg->from_tag.len, dlg->from_tag.s, dlg->from_tag.len); // lookup_dlg has incremented the ref count by 1 unref_dlg(dlg, 1); // Reset variables in order to do a lookup based on SIP-Elements. dlg = 0; dir = DLG_DIR_NONE; if (seq_match_mode == SEQ_MATCH_STRICT_ID) return; } } } } if (dlg == 0) { if (pre_match_parse(req, &callid, &ftag, &ttag, 1) < 0) return; /* TODO - try to use the RR dir detection to speed up here the * search -bogdan */ dlg = get_dlg(&callid, &ftag, &ttag, &dir); if (!dlg) { LM_DBG("Callid '%.*s' not found\n", req->callid->body.len, req->callid->body.s); return; } } /* set current dialog - re-use ref increment from dlg_get() above */ set_current_dialog(req, dlg); _dlg_ctx.dlg = dlg; if (d_tmb.register_tmcb(req, NULL, TMCB_REQUEST_FWDED, store_dlg_in_tm_cb, (void*) dlg, NULL) < 0) { LM_ERR("failed to store dialog in transaction during dialog creation for later reference\n"); } /* run state machine */ switch (req->first_line.u.request.method_value) { case METHOD_PRACK: event = DLG_EVENT_REQPRACK; break; case METHOD_ACK: event = DLG_EVENT_REQACK; break; case METHOD_BYE: event = DLG_EVENT_REQBYE; break; default: event = DLG_EVENT_REQ; } next_state_dlg(dlg, event, &old_state, &new_state, &unref, 0); LM_DBG("unref after next state is %i\n", unref); CURR_DLG_ID = req->id; CURR_DLG_LIFETIME = (unsigned int) (time(0)) - dlg->start_ts; CURR_DLG_STATUS = new_state; /* run actions for the transition */ if (event == DLG_EVENT_REQBYE && new_state == DLG_STATE_DELETED && old_state != DLG_STATE_DELETED) { LM_DBG("BYE successfully processed\n"); /* remove from timer */ ret = remove_dialog_timer(&dlg->tl); if (ret < 0) { LM_CRIT("unable to unlink the timer on dlg %p [%u:%u] " "with clid '%.*s' and tags '%.*s'\n", dlg, dlg->h_entry, dlg->h_id, dlg->callid.len, dlg->callid.s, dlg->from_tag.len, dlg->from_tag.s); } else if (ret > 0) { LM_WARN("inconsitent dlg timer data on dlg %p [%u:%u] " "with clid '%.*s' and tags '%.*s' \n", dlg, dlg->h_entry, dlg->h_id, dlg->callid.len, dlg->callid.s, dlg->from_tag.len, dlg->from_tag.s); } else { unref++; } /* dialog terminated (BYE) */ dlg_terminated(req, dlg, dir); unref_dlg(dlg, unref); counter_add(dialog_ng_cnts_h.active, -1); counter_inc(dialog_ng_cnts_h.processed); return; } if ((event == DLG_EVENT_REQ || event == DLG_EVENT_REQACK) && (new_state == DLG_STATE_CONFIRMED || new_state==DLG_STATE_EARLY)) { timeout = get_dlg_timeout(req); if (timeout != default_timeout) { dlg->lifetime = timeout; } if (update_dlg_timer(&dlg->tl, dlg->lifetime) == -1) { LM_ERR("failed to update dialog lifetime\n"); } if (update_cseqs(dlg, req, dir, &ttag) != 0) { LM_ERR("cseqs update failed\n"); } else { dlg->dflags |= DLG_FLAG_CHANGED; } if(dlg_db_mode==DB_MODE_REALTIME && (dlg->dflags&DLG_FLAG_CHANGED)) { update_dialog_dbinfo(dlg); } if (old_state != DLG_STATE_CONFIRMED) { LM_DBG("confirming ACK successfully processed\n"); /* confirming ACK request */ run_dlg_callbacks(DLGCB_CONFIRMED, dlg, req, NULL, dir, 0); } else { LM_DBG("sequential request successfully processed\n"); /* within dialog request */ run_dlg_callbacks(DLGCB_REQ_WITHIN, dlg, req, NULL, dir, 0); if ((event != DLG_EVENT_REQACK) && (dlg->cbs.types) & DLGCB_RESPONSE_WITHIN) { /* ref the dialog as registered into the transaction callback. * unref will be done when the callback will be destroyed */ ref_dlg(dlg, 1); /* register callback for the replies of this request */ if (d_tmb.register_tmcb(req, 0, TMCB_RESPONSE_FWDED, (dir == DLG_DIR_UPSTREAM) ? dlg_seq_down_onreply : dlg_seq_up_onreply, (void*) dlg, unreference_dialog) < 0) { LM_ERR("failed to register TMCB (2)\n"); unref_dlg(dlg, 1); } } } } if (new_state == DLG_STATE_CONFIRMED && old_state != DLG_STATE_CONFIRMED) { dlg->dflags |= DLG_FLAG_CHANGED; if(dlg_db_mode == DB_MODE_REALTIME) update_dialog_dbinfo(dlg); } return; }
/*! \brief * Message contained some contacts and appropriate * record was found, so we have to walk through * all contacts and do the following: * 1) If contact in usrloc doesn't exists and * expires > 0, insert new contact * 2) If contact in usrloc exists and expires * > 0, update the contact * 3) If contact in usrloc exists and expires * == 0, delete contact */ static inline int update_contacts(struct sip_msg* _m, urecord_t* _r, int _mode, int _use_regid, int novariation) { ucontact_info_t *ci; ucontact_t *c, *ptr, *ptr0; int expires, ret, updated; unsigned int flags; #ifdef USE_TCP int e_max, tcp_check; struct sip_uri uri; #endif int rc; contact_t* _c; int maxc; /* mem flag */ flags = mem_only; rc = 0; /* pack the contact_info */ if ( (ci=pack_ci( _m, 0, 0, flags, _use_regid))==0 ) { LM_ERR("failed to initial pack contact info\n"); goto error; } if (!_mode) { maxc = reg_get_crt_max_contacts(); if(maxc>0) { _c = get_first_contact(_m); if(test_max_contacts(_m, _r, _c, ci, maxc) != 0) goto error; } } #ifdef USE_TCP if ( (_m->flags&tcp_persistent_flag) && (_m->rcv.proto==PROTO_TCP||_m->rcv.proto==PROTO_TLS||_m->rcv.proto==PROTO_WS||_m->rcv.proto==PROTO_WSS)) { e_max = -1; tcp_check = 1; } else { e_max = tcp_check = 0; } #endif _c = get_first_contact(_m); updated=0; for( ; _c ; _c = get_next_contact(_c) ) { /* calculate expires */ calc_contact_expires(_m, _c->expires, &expires, novariation); /* pack the contact info */ if ( (ci=pack_ci( 0, _c, expires, 0, _use_regid))==0 ) { LM_ERR("failed to pack contact specific info\n"); goto error; } /* search for the contact*/ ret = ul.get_ucontact_by_instance( _r, &_c->uri, ci, &c); if (ret==-1) { LM_ERR("invalid cseq for aor <%.*s>\n",_r->aor.len,_r->aor.s); rerrno = R_INV_CSEQ; goto error; } else if (ret==-2) { if(expires!=0 && _mode) break; continue; } if ( ret > 0 ) { /* Contact not found -> expired? */ if (expires==0) continue; if (ul.insert_ucontact( _r, &_c->uri, ci, &c) < 0) { rerrno = R_UL_INS_C; LM_ERR("failed to insert contact\n"); goto error; } rc = 1; if(_mode) { ptr=_r->contacts; while(ptr) { ptr0 = ptr->next; if(ptr!=c) ul.delete_ucontact(_r, ptr); ptr=ptr0; } updated=1; } } else { /* Contact found */ if (expires == 0) { /* it's expired */ if (mem_only) { c->flags |= FL_MEM; } else { c->flags &= ~FL_MEM; } if (ul.delete_ucontact(_r, c) < 0) { rerrno = R_UL_DEL_C; LM_ERR("failed to delete contact\n"); goto error; } rc = 3; } else { /* do update */ if(_mode) { ptr=_r->contacts; while(ptr) { ptr0 = ptr->next; if(ptr!=c) ul.delete_ucontact(_r, ptr); ptr=ptr0; } updated=1; } /* If call-id has changed then delete all records with this sip.instance * then insert new record */ if (ci->instance.s != NULL && (ci->callid->len != c->callid.len || strncmp(ci->callid->s, c->callid.s, ci->callid->len) != 0)) { ptr = _r->contacts; while (ptr) { ptr0 = ptr->next; if ((ptr != c) && ptr->instance.len == c->instance.len && strncmp(ptr->instance.s, c->instance.s, ptr->instance.len) == 0) { ul.delete_ucontact(_r, ptr); } ptr = ptr0; } updated = 1; } if (ul.update_ucontact(_r, c, ci) < 0) { rerrno = R_UL_UPD_C; LM_ERR("failed to update contact\n"); goto error; } rc = 2; } } #ifdef USE_TCP if (tcp_check) { /* parse contact uri to see if transport is TCP */ if (parse_uri( _c->uri.s, _c->uri.len, &uri)<0) { LM_ERR("failed to parse contact <%.*s>\n", _c->uri.len, _c->uri.s); } else if (uri.proto==PROTO_TCP || uri.proto==PROTO_TLS || uri.proto==PROTO_WS || uri.proto==PROTO_WSS) { if (e_max>0) { LM_WARN("multiple TCP contacts on single REGISTER\n"); } if (expires>e_max) e_max = expires; } } #endif /* have one contact only -- break */ if(updated) break; } #ifdef USE_TCP if ( tcp_check && e_max>-1 ) { if (e_max) e_max -= act_time; /*FIXME: Do we want this in the sr core? */ /*force_tcp_conn_lifetime( &_m->rcv , e_max + 10 );*/ } #endif return rc; error: return -1; }
int dbg_dump_json(struct sip_msg* msg, unsigned int mask, int level) { int i; pv_value_t value; pv_cache_t **_pv_cache = pv_cache_get_table(); pv_cache_t *el = NULL; srjson_doc_t jdoc; srjson_t *jobj = NULL; char *output = NULL; str item_name = STR_NULL; static char iname[128]; int result = -1; if(_pv_cache==NULL) { LM_ERR("cannot access pv_cache\n"); return -1; } memset(_dbg_xavp_dump, 0, sizeof(str*)*DBG_XAVP_DUMP_SIZE); srjson_InitDoc(&jdoc, NULL); if(jdoc.root==NULL) { jdoc.root = srjson_CreateObject(&jdoc); if(jdoc.root==NULL) { LM_ERR("cannot create json root\n"); goto error; } } for(i=0;i<PV_CACHE_SIZE;i++) { el = _pv_cache[i]; while(el) { if(!(el->spec.type==PVT_AVP|| el->spec.type==PVT_SCRIPTVAR|| el->spec.type==PVT_XAVP|| el->spec.type==PVT_OTHER)|| !((el->spec.type==PVT_AVP&&mask&DBG_DP_AVP)|| (el->spec.type==PVT_XAVP&&mask&DBG_DP_XAVP)|| (el->spec.type==PVT_SCRIPTVAR&&mask&DBG_DP_SCRIPTVAR)|| (el->spec.type==PVT_OTHER&&mask&DBG_DP_OTHER))|| (el->spec.trans!=NULL)) { el = el->next; continue; } jobj = NULL; item_name.len = 0; item_name.s = 0; iname[0] = '\0'; if(el->spec.type==PVT_AVP) { if(el->spec.pvp.pvi.type==PV_IDX_ALL|| (el->spec.pvp.pvi.type==PV_IDX_INT&&el->spec.pvp.pvi.u.ival!=0)) { el = el->next; continue; } else { if(_dbg_get_array_avp_vals(msg, &el->spec.pvp, &jdoc, &jobj, &item_name)!=0) { LM_WARN("can't get value[%.*s]\n", el->pvname.len, el->pvname.s); el = el->next; continue; } if(srjson_GetArraySize(&jdoc, jobj)==0 && !(mask&DBG_DP_NULL)) { el = el->next; continue; } snprintf(iname, 128, "$avp(%.*s)", item_name.len, item_name.s); } } else if(el->spec.type==PVT_XAVP) { if(_dbg_xavp_dump_lookup(&el->spec.pvp)!=0) { el = el->next; continue; } if(_dbg_get_obj_xavp_vals(msg, &el->spec.pvp, &jdoc, &jobj, &item_name)!=0) { LM_WARN("can't get value[%.*s]\n", el->pvname.len, el->pvname.s); el = el->next; continue; } if(srjson_GetArraySize(&jdoc, jobj)==0 && !(mask&DBG_DP_NULL)) { el = el->next; continue; } snprintf(iname, 128, "$xavp(%.*s)", item_name.len, item_name.s); } else { if(pv_get_spec_value(msg, &el->spec, &value)!=0) { LM_WARN("can't get value[%.*s]\n", el->pvname.len, el->pvname.s); el = el->next; continue; } if(value.flags&(PV_VAL_NULL|PV_VAL_EMPTY|PV_VAL_NONE)) { if(mask&DBG_DP_NULL) { jobj = srjson_CreateNull(&jdoc); } else { el = el->next; continue; } }else if(value.flags&(PV_VAL_INT)){ jobj = srjson_CreateNumber(&jdoc, value.ri); }else if(value.flags&(PV_VAL_STR)){ jobj = srjson_CreateStr(&jdoc, value.rs.s, value.rs.len); }else { LM_WARN("el->pvname[%.*s] value[%d] unhandled\n", el->pvname.len, el->pvname.s, value.flags); el = el->next; continue; } if(jobj==NULL) { LM_ERR("el->pvname[%.*s] empty json object\n", el->pvname.len, el->pvname.s); goto error; } snprintf(iname, 128, "%.*s", el->pvname.len, el->pvname.s); } if(jobj!=NULL) { srjson_AddItemToObject(&jdoc, jdoc.root, iname, jobj); } el = el->next; } } output = srjson_PrintUnformatted(&jdoc, jdoc.root); if(output==NULL) { LM_ERR("cannot print json doc\n"); goto error; } LOG(level, "%s\n", output); result = 0; error: if(output!=NULL) jdoc.free_fn(output); srjson_DestroyDoc(&jdoc); return result; }
int save(struct sip_msg* _m, udomain_t* _d, int _cflags, str *_uri) { contact_t* c; int st, mode; str aor; int ret; sip_uri_t *u; rr_t *route; struct sip_uri puri; param_hooks_t hooks; param_t *params; contact_t *contact; int use_ob = 1, use_regid = 1; int novariation = 0; u = parse_to_uri(_m); if(u==NULL) goto error; rerrno = R_FINE; ret = 1; if (parse_message(_m) < 0) { goto error; } if (check_contacts(_m, &st) > 0) { goto error; } if (parse_supported(_m) == 0) { if (!(get_supported(_m) & F_OPTION_TAG_OUTBOUND) && reg_outbound_mode == REG_OUTBOUND_REQUIRE) { LM_WARN("Outbound required by server and not supported by UAC\n"); rerrno = R_OB_UNSUP; goto error; } } if (parse_require(_m) == 0) { if ((get_require(_m) & F_OPTION_TAG_OUTBOUND) && reg_outbound_mode == REG_OUTBOUND_NONE) { LM_WARN("Outbound required by UAC and not supported by server\n"); rerrno = R_OB_REQD; goto error; } } if (reg_outbound_mode != REG_OUTBOUND_NONE && _m->contact && _m->contact->parsed && !(parse_headers(_m, HDR_VIA2_F, 0) == -1 || _m->via2 == 0 || _m->via2->error != PARSE_OK)) { /* Outbound supported on server, and more than one Via: - not the first hop */ if (!(parse_headers(_m, HDR_PATH_F, 0) == -1 || _m->path == 0)) { route = (rr_t *)0; if (parse_rr_body(_m->path->body.s, _m->path->body.len, &route) < 0) { LM_ERR("Failed to parse Path: header body\n"); goto error; } if (parse_uri(route->nameaddr.uri.s, route->nameaddr.uri.len, &puri) < 0) { LM_ERR("Failed to parse Path: URI\n"); free_rr(&route); goto error; } if (parse_params(&puri.params, CLASS_URI, &hooks, ¶ms) != 0) { LM_ERR("Failed to parse Path: URI parameters\n"); free_rr(&route); goto error; } /* Not interested in param body - just the hooks */ free_params(params); if (!hooks.uri.ob) { /* No ;ob parameter to top Path: URI - no outbound */ use_ob = 0; } free_rr(&route); } else { /* No Path: header - no outbound */ use_ob = 0; } contact = ((contact_body_t *) _m->contact->parsed)->contacts; if (!contact) { LM_ERR("empty Contact:\n"); goto error; } if ((use_ob == 0) && (reg_regid_mode == REG_REGID_OUTBOUND)) { if ((get_supported(_m) & F_OPTION_TAG_OUTBOUND) && contact->reg_id) { LM_WARN("Outbound used by UAC but not supported by edge proxy\n"); rerrno = R_OB_UNSUP_EDGE; goto error; } else { /* ignore ;reg-id parameter */ use_regid = 0; } } } get_act_time(); c = get_first_contact(_m); if (extract_aor((_uri)?_uri:&get_to(_m)->uri, &aor, NULL) < 0) { LM_ERR("failed to extract Address Of Record\n"); goto error; } mem_only = is_cflag_set(REG_SAVE_MEM_FL)?FL_MEM:FL_NONE; novariation = is_cflag_set(REG_SAVE_NOVARIATION_FL)? 1:0; if (c == 0) { if (st) { if (star(_m, (udomain_t*)_d, &aor, &u->host) < 0) goto error; else ret=3; } else { if (no_contacts(_m, (udomain_t*)_d, &aor, &u->host) < 0) goto error; else ret=4; } } else { mode = is_cflag_set(REG_SAVE_REPL_FL)?1:0; if ((ret=add_contacts(_m, (udomain_t*)_d, &aor, mode, use_regid, novariation)) < 0) goto error; ret = (ret==0)?1:ret; } update_stat(accepted_registrations, 1); /* Only send reply upon request, not upon reply */ if ((is_route_type(REQUEST_ROUTE) || is_route_type(FAILURE_ROUTE)) && !is_cflag_set(REG_SAVE_NORPL_FL) && (reg_send_reply(_m) < 0)) return -1; if (path_enabled && path_mode != PATH_MODE_OFF) { reset_path_vector(_m); } return ret; error: update_stat(rejected_registrations, 1); if (is_route_type(REQUEST_ROUTE) && !is_cflag_set(REG_SAVE_NORPL_FL) ) reg_send_reply(_m); if (R_TOO_MANY == rerrno) return -2; /* for all other */ return 0; }
/** * Check, if a user-agent follows the indicated service-routes */ int check_service_routes(struct sip_msg* _m, udomain_t* _d) { struct sip_uri uri; int i; struct hdr_field *hdr; rr_t *r; // char srcip[20]; // str received_host; struct via_body * vb; unsigned short port; unsigned short proto; /* Contact not found => not following service-routes */ if (c == NULL) return -1; /* Search for the first Route-Header: */ if (find_first_route(_m) < 0) return -1; LM_DBG("Got %i Route-Headers.\n", c->num_service_routes); // received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip)); // received_host.s = srcip; vb = cscf_get_ue_via(_m); port = vb->port?vb->port:5060; proto = vb->proto; /* Lock this record while working with the data: */ ul.lock_udomain(_d, &vb->host, port, proto); pcontact_t * c = getContactP(_m, _d, PCONTACT_REGISTERED); if (!c) { LM_DBG("no contact found in usrloc when checking for service route\n"); goto error; } /* Check the route-set: */ if (_m->route) { hdr = _m->route; LM_DBG("hdr is %p\n", hdr); /* Check, if the first host is ourself: */ r = (rr_t*)hdr->parsed; if (r) { LM_DBG("Route is %.*s\n", r->nameaddr.uri.len, r->nameaddr.uri.s); /* Skip first headers containing myself: */ while (r && (parse_uri(r->nameaddr.uri.s, r->nameaddr.uri.len, &uri) == 0) && check_self(&uri.host,uri.port_no?uri.port_no:SIP_PORT,0)) { LM_DBG("Self\n"); /* Check for more headers and fail, if it was the last one Check, if service-routes are indicated. If yes, request is not following service-routes */ if (find_next_route(_m, &hdr) != 0) r = NULL; else r = (rr_t*)hdr->parsed; if (!r && (c->num_service_routes > 0)) { LM_DBG("Not enough route-headers in Message\n"); goto error; } LM_DBG("hdr is %p\n", hdr); LM_DBG("r is %p\n", r); if (r) LM_DBG("Next Route is %.*s\n", r->nameaddr.uri.len, r->nameaddr.uri.s); } LM_DBG("We have %d service-routes\n", c->num_service_routes); /* Then check the following headers: */ for (i=0; i< c->num_service_routes; i++) { LM_DBG("Route must be: %.*s\n", c->service_routes[i].len, c->service_routes[i].s); /* No more Route-Headers? Not following service-routes */ if (!r) { LM_DBG("No more route headers in message.\n"); goto error; } LM_DBG("Route is: %.*s\n", r->nameaddr.uri.len, r->nameaddr.uri.s); /* Check length: */ if (r->nameaddr.uri.len != c->service_routes[i].len) { LM_DBG("Length does not match.\n"); goto error; } /* Check contents: */ if (strncasecmp(r->nameaddr.uri.s, c->service_routes[i].s, c->service_routes[i].len) != 0) { LM_DBG("String comparison failed.\n"); goto error; } if (find_next_route(_m, &hdr) != 0) r = NULL; else r = (rr_t*)hdr->parsed; } /* Check, if it was the last route-header in the message: */ if (r) { LM_DBG("Too many route headers in message.\n"); goto error; } } else { LM_WARN("Strange: Route-Header is present, but not parsed?!?"); if (c->num_service_routes > 0) goto error; } } else { LM_DBG("No route header in Message.\n"); /* No route-header? Check, if service-routes are indicated. If yes, request is not following service-routes */ if (c->num_service_routes > 0) goto error; } /* Unlock domain */ ul.unlock_udomain(_d, &vb->host, port, proto); return 1; error: /* Unlock domain */ ul.unlock_udomain(_d, &vb->host, port, proto); return -1; }
static int mod_init(void) { int n; load_dlg_f load_dlg; load_tm_f load_tm; bind_usrloc_t bind_usrloc; if (!fix_parameters()) { LM_ERR("unable to set Ro configuration parameters correctly\n"); goto error; } /* bind to the tm module */ if (!(load_tm = (load_tm_f) find_export("load_tm", NO_SCRIPT, 0))) { LM_ERR("Can not import load_tm. This module requires tm module\n"); goto error; } if (load_tm(&tmb) == -1) goto error; if (!(load_dlg = (load_dlg_f) find_export("load_dlg", 0, 0))) { /* bind to dialog module */ LM_ERR("can not import load_dlg. This module requires Kamailio dialog module.\n"); } if (load_dlg(&dlgb) == -1) { goto error; } if (load_cdp_api(&cdpb) != 0) { /* load the CDP API */ LM_ERR("can't load CDP API\n"); goto error; } if (load_dlg_api(&dlgb) != 0) { /* load the dialog API */ LM_ERR("can't load Dialog API\n"); goto error; } cdp_avp = load_cdp_avp(); /* load CDP_AVP API */ if (!cdp_avp) { LM_ERR("can't load CDP_AVP API\n"); goto error; } /* init timer lists*/ if (init_ro_timer(ro_session_ontimeout) != 0) { LM_ERR("cannot init timer list\n"); return -1; } /* initialized the hash table */ for (n = 0; n < (8 * sizeof(n)); n++) { if (ro_session_hash_size == (1 << n)) break; if (ro_session_hash_size < (1 << n)) { LM_WARN("hash_size is not a power of 2 as it should be -> rounding from %d to %d\n", ro_session_hash_size, 1 << (n - 1)); ro_session_hash_size = 1 << (n - 1); } } if (init_ro_session_table(ro_session_hash_size) < 0) { LM_ERR("failed to create ro session hash table\n"); return -1; } /* register global timer */ if (register_timer(ro_timer_routine, 0/*(void*)ro_session_list*/, 1) < 0) { LM_ERR("failed to register timer \n"); return -1; } bind_usrloc = (bind_usrloc_t) find_export("ul_bind_usrloc", 1, 0); if (!bind_usrloc) { LM_ERR("can't bind usrloc\n"); return -1; } if (bind_usrloc(&ul) < 0) { return -1; } /*Register for callback of URECORD being deleted - so we can send a SAR*/ if (ul.register_ulcb == NULL) { LM_ERR("Could not import ul_register_ulcb\n"); return -1; } /* register statistics */ if (register_module_stats(exports.name, charging_stats) != 0) { LM_ERR("failed to register core statistics\n"); return -1; } /*if (register_stat(MOD_NAME, "ccr_responses_time", &ccr_responses_time, 0)) { LM_ERR("failed to register core statistics\n"); return -1; }*/ return 0; error: LM_ERR("Failed to initialise ims_qos module\n"); return RO_RETURN_FALSE; }
int send_subscribe(subs_info_t* subs) { ua_pres_t* presentity= NULL; str met= {"SUBSCRIBE", 9}; str* str_hdr= NULL; int ret= -1; unsigned int hash_code=0; ua_pres_t* hentity= NULL; int expires; int flag; int result; uac_req_t uac_r; db1_res_t *res=NULL; ua_pres_t dbpres; str pres_uri={0,0}, watcher_uri={0,0}, extra_headers={0,0}; dlg_t* td= NULL; memset(&dbpres, 0, sizeof(dbpres)); dbpres.pres_uri = &pres_uri; dbpres.watcher_uri = &watcher_uri; dbpres.extra_headers = &extra_headers; print_subs(subs); flag= subs->source_flag; if(subs->source_flag & XMPP_INITIAL_SUBS) subs->source_flag= XMPP_SUBSCRIBE; if(subs->expires< 0) expires= 3600; else expires= subs->expires; str_hdr= subs_build_hdr(subs->contact, expires, subs->event, subs->extra_headers); if(str_hdr== NULL || str_hdr->s== NULL) { LM_ERR("while building extra headers\n"); return -1; } if (dbmode == PUA_DB_ONLY && pua_dbf.start_transaction) { if (pua_dbf.start_transaction(pua_db, DB_LOCKING_WRITE) < 0) { LM_ERR("in start_transaction\n"); goto error; } } /* generation of hash and getting lock moved from here to further down */ if (dbmode==PUA_DB_ONLY) { presentity = get_dialog_puadb(subs->id, subs->pres_uri, &dbpres, &res); } else { ua_pres_t pres; memset(&pres, 0, sizeof(ua_pres_t)); pres.pres_uri = subs->pres_uri; pres.watcher_uri = subs->watcher_uri; pres.flag = subs->source_flag; pres.id = subs->id; pres.event = subs->event; if (subs->remote_target) pres.remote_contact = *subs->remote_target; hash_code=core_hash(subs->pres_uri, subs->watcher_uri, HASH_SIZE); lock_get(&HashT->p_records[hash_code].lock); presentity= search_htable(&pres, hash_code); } /* if flag == INSERT_TYPE insert no matter what the search result is */ if(subs->flag & INSERT_TYPE) { LM_DBG("A subscription request with insert type\n"); goto insert; } if(presentity== NULL ) { int size; insert: if (subs->expires == 0) { /* Don't create a new dialog when expires == 0 */ if (dbmode != PUA_DB_ONLY) lock_release(&HashT->p_records[hash_code].lock); goto done; } if(subs->flag & UPDATE_TYPE) { LM_DBG("request for a subscription with update type" " and no record found\n"); subs->flag= INSERT_TYPE; } hentity= subscribe_cbparam(subs, REQ_OTHER); if(hentity== NULL) { LM_ERR("while building callback" " param\n"); if (dbmode != PUA_DB_ONLY) lock_release(&HashT->p_records[hash_code].lock); goto error; } hentity->flag= flag; set_uac_req(&uac_r, &met, str_hdr, 0, 0, TMCB_LOCAL_COMPLETED, subs_cback_func, (void*)hentity); result= tmb.t_request_outside (&uac_r, /* Type of the message */ subs->remote_target?subs->remote_target:subs->pres_uri,/* Request-URI*/ subs->pres_uri, /* To */ subs->watcher_uri, /* From */ subs->outbound_proxy /* Outbound_proxy */ ); if(result< 0) { LM_ERR("while sending request with t_request\n"); if (uac_r.dialog != NULL) { uac_r.dialog->rem_target.s = 0; uac_r.dialog->dst_uri.s = 0; tmb.free_dlg(uac_r.dialog); uac_r.dialog = 0; } shm_free(hentity); if (dbmode != PUA_DB_ONLY) lock_release(&HashT->p_records[hash_code].lock); /* Although this is an error must not return -1 as the calling function must continue processing. */ ret = 0; goto error; } /* Now create a temporary hash table entry. This is needed to deal with the race-hazard when NOTIFYs arrive before the 2xx response to the SUBSCRIBE. */ size = sizeof(ua_pres_t)+ 2 * sizeof(str) + ( subs->pres_uri->len + subs->watcher_uri->len + uac_r.dialog->id.loc_tag.len + uac_r.dialog->id.call_id.len + subs->id.len) * sizeof(char); presentity= (ua_pres_t*)shm_malloc(size); if(presentity== NULL) { LM_ERR("no more share memory\n"); if (dbmode != PUA_DB_ONLY) lock_release(&HashT->p_records[hash_code].lock); goto error; } memset(presentity, 0, size); size= sizeof(ua_pres_t); presentity->pres_uri = (str *) ((char *) presentity + size); size += sizeof(str); presentity->pres_uri->s= (char *) presentity + size; memcpy(presentity->pres_uri->s, subs->pres_uri->s, subs->pres_uri->len); presentity->pres_uri->len= subs->pres_uri->len; size+= subs->pres_uri->len; presentity->watcher_uri= (str *) ((char *) presentity + size); size += sizeof(str); presentity->watcher_uri->s= (char *) presentity + size; memcpy(presentity->watcher_uri->s, subs->watcher_uri->s, subs->watcher_uri->len); presentity->watcher_uri->len = subs->watcher_uri->len; size += subs->watcher_uri->len; presentity->call_id.s = (char *) presentity + size; memcpy(presentity->call_id.s, uac_r.dialog->id.call_id.s, uac_r.dialog->id.call_id.len); presentity->call_id.len = uac_r.dialog->id.call_id.len; size += uac_r.dialog->id.call_id.len; presentity->from_tag.s = (char *) presentity + size; memcpy(presentity->from_tag.s, uac_r.dialog->id.loc_tag.s, uac_r.dialog->id.loc_tag.len); presentity->from_tag.len= uac_r.dialog->id.loc_tag.len; size += uac_r.dialog->id.loc_tag.len; presentity->id.s = (char *) presentity+ size; memcpy(presentity->id.s, subs->id.s, subs->id.len); presentity->id.len = subs->id.len; size += subs->id.len; presentity->event = subs->event; presentity->flag = subs->source_flag; presentity->cseq = uac_r.dialog->loc_seq.value; /* Set the temporary record expiry for 2 * 64T1 seconds from now */ presentity->expires= (int)time(NULL) + 64; presentity->desired_expires= presentity->expires; if (dbmode==PUA_DB_ONLY) { insert_dialog_puadb(presentity); shm_free(presentity); } else { insert_htable(presentity, hash_code); lock_release(&HashT->p_records[hash_code].lock); } uac_r.dialog->rem_target.s = 0; uac_r.dialog->dst_uri.s = 0; tmb.free_dlg(uac_r.dialog); uac_r.dialog = 0; } else { if (subs->internal_update_flag == INTERNAL_UPDATE_TRUE) { LM_INFO("attempting to re-SUBSCRIBE on internal (rls_update_subs()) update - skipping\n"); if (dbmode != PUA_DB_ONLY) lock_release(&HashT->p_records[hash_code].lock); goto done; } if (presentity->to_tag.len == 0) { if (subs->expires > 0) LM_WARN("attempting to re-SUBSCRIBE to a temporary (non-established) dialog - skipping\n"); else { LM_WARN("attempting to un-SUBSCRIBE from a temporary (non-established) dialog - skipping and deleting dialog\n"); if (dbmode==PUA_DB_ONLY) delete_dialog_puadb(presentity); else delete_htable(presentity, hash_code); } if (dbmode != PUA_DB_ONLY) lock_release(&HashT->p_records[hash_code].lock); goto done; } td= pua_build_dlg_t(presentity); if(td== NULL) { LM_ERR("while building tm dlg_t structure"); if (dbmode!=PUA_DB_ONLY) lock_release(&HashT->p_records[hash_code].lock); goto error; } hentity= subs_cbparam_indlg(presentity, expires, REQ_OTHER); if(hentity== NULL) { LM_ERR("while building callback param\n"); if (dbmode!=PUA_DB_ONLY) lock_release(&HashT->p_records[hash_code].lock); goto error; } if (dbmode!=PUA_DB_ONLY) lock_release(&HashT->p_records[hash_code].lock); LM_DBG("event parameter: %d\n", hentity->event); set_uac_req(&uac_r, &met, str_hdr, 0, td, TMCB_LOCAL_COMPLETED, subs_cback_func, (void*)hentity); result= tmb.t_request_within(&uac_r); if(result< 0) { shm_free(hentity); hentity= NULL; LM_ERR("while sending request with t_request\n"); goto error; } } done: if (dbmode == PUA_DB_ONLY && pua_dbf.end_transaction) { if (pua_dbf.end_transaction(pua_db) < 0) { LM_ERR("in end_transaction\n"); goto error; } } ret = 0; error: pua_free_tm_dlg(td); pkg_free(str_hdr); free_results_puadb(res); if (dbmode == PUA_DB_ONLY && pua_dbf.abort_transaction) { if (pua_dbf.abort_transaction(pua_db) < 0) LM_ERR("in abort_transaction\n"); } return ret; }
static int w_ro_ccr(struct sip_msg *msg, str* route_name, str* direction, str* charge_type, str* unit_type, int reservation_units, char* _d) { /* PSEUDOCODE/NOTES * 1. What mode are we in - terminating or originating * 2. check request type - IEC - Immediate Event Charging * ECUR - Event Charging with Unit Reservation * SCUR - Session Charging with Unit Reservation * 3. probably only do SCUR in this module for now - can see event based charging in another component instead (AS for SMS for example, etc) * 4. Check a dialog exists for call, if not we fail * 5. make sure we dont already have an Ro Session for this dialog * 6. create new Ro Session * 7. register for DLG callback passing new Ro session as parameter - (if dlg torn down we know which Ro session it is associated with) * * */ int ret = RO_RETURN_TRUE; int dir = 0; str identity = {0, 0}, contact = {0, 0}; struct hdr_field *h=0; cfg_action_t* cfg_action; tm_cell_t *t; unsigned int tindex = 0, tlabel = 0; struct impu_data *impu_data; udomain_t* domain_t = (udomain_t*) _d; char *p; struct dlg_cell* dlg; unsigned int len; struct ro_session *ro_session = 0; int free_contact = 0; LM_DBG("Ro CCR initiated: direction:%.*s, charge_type:%.*s, unit_type:%.*s, reservation_units:%i, route_name:%.*s", direction->len, direction->s, charge_type->len, charge_type->s, unit_type->len, unit_type->s, reservation_units, route_name->len, route_name->s); if (msg->first_line.type != SIP_REQUEST) { LM_ERR("Ro_CCR() called from SIP reply."); return RO_RETURN_ERROR;; } //make sure we can get the dialog! if not, we can't continue dlg = dlgb.get_dlg(msg); if (!dlg) { LM_ERR("Unable to find dialog and cannot do Ro charging without it\n"); return RO_RETURN_ERROR; } dir = get_direction_as_int(direction); if (dir == RO_ORIG_DIRECTION) { //get caller IMPU from asserted identity if ((identity = cscf_get_asserted_identity(msg, 0)).len == 0) { LM_DBG("No P-Asserted-Identity hdr found. Using From hdr for asserted_identity"); identity = dlg->from_uri; } //get caller contact from contact header - if not present then skip this if ((contact = cscf_get_contact(msg)).len == 0) { LM_WARN("Can not get contact from message - will not get callbacks if this IMPU is removed to terminate call"); goto send_ccr; } } else if (dir == RO_TERM_DIRECTION){ //get callee IMPU from called part id - if not present then skip this if ((identity = cscf_get_public_identity_from_called_party_id(msg, &h)).len == 0) { LM_WARN("No P-Called-Identity hdr found - will not get callbacks if this IMPU is removed to terminate call"); goto send_ccr; } //get callee contact from request URI contact = cscf_get_contact_from_requri(msg); free_contact = 1; } else { LM_CRIT("don't know what to do in unknown mode - should we even get here\n"); ret = RO_RETURN_ERROR; goto done; } LM_DBG("IMPU data to pass to usrloc: contact <%.*s> identity <%.*s>\n", contact.len, contact.s, identity.len, identity.s); //create impu_data_parcel len = identity.len + contact.len + sizeof (struct impu_data); impu_data = (struct impu_data*) shm_malloc(len); if (!impu_data) { LM_ERR("Unable to allocate memory for impu_data, trying to send CCR\n"); ret = RO_RETURN_ERROR; goto done; } memset(impu_data, 0, len); p = (char*) (impu_data + 1); impu_data->identity.s = p; impu_data->identity.len = identity.len; memcpy(p, identity.s, identity.len); p += identity.len; impu_data->contact.s = p; impu_data->contact.len = contact.len; memcpy(p, contact.s, contact.len); p += contact.len; impu_data->d = domain_t; if (p != (((char*) impu_data) + len)) { LM_ERR("buffer overflow creating impu data, trying to send CCR\n"); shm_free(impu_data); ret = RO_RETURN_ERROR; goto done; } //reg for callbacks on confirmed and terminated if (dlgb.register_dlgcb(dlg, /* DLGCB_RESPONSE_FWDED */ DLGCB_CONFIRMED, add_dlg_data_to_contact, (void*)impu_data ,NULL ) != 0) { LM_CRIT("cannot register callback for dialog confirmation\n"); ret = RO_RETURN_ERROR; goto done; } if (dlgb.register_dlgcb(dlg, DLGCB_TERMINATED | DLGCB_FAILED | DLGCB_EXPIRED /*| DLGCB_DESTROY */, remove_dlg_data_from_contact, (void*)impu_data, NULL ) != 0) { LM_CRIT("cannot register callback for dialog termination\n"); ret = RO_RETURN_ERROR; goto done; } send_ccr: //check if we need to send_ccr - //we get the ro_session based on dlg->h_id and dlg->h_entry and direction 0 (so get any ro_session) //if it already exists then we go to done if (single_ro_session_per_dialog && (ro_session = lookup_ro_session(dlg->h_entry, &dlg->callid, 0, 0))) { LM_DBG("single_ro_session_per_dialog = 1 and ro_session already exists for this dialog -so we don't need to send another one\n"); unref_ro_session(ro_session,1);//for the lookup ro session ref goto done; } LM_DBG("Looking for route block [%.*s]\n", route_name->len, route_name->s); int ri = route_get(&main_rt, route_name->s); if (ri < 0) { LM_ERR("unable to find route block [%.*s]\n", route_name->len, route_name->s); ret = RO_RETURN_ERROR; goto done; } cfg_action = main_rt.rlist[ri]; if (!cfg_action) { LM_ERR("empty action lists in route block [%.*s]\n", route_name->len, route_name->s); ret = RO_RETURN_ERROR; goto done; } //before we send lets suspend the transaction t = tmb.t_gett(); if (t == NULL || t == T_UNDEFINED) { if (tmb.t_newtran(msg) < 0) { LM_ERR("cannot create the transaction for CCR async\n"); ret = RO_RETURN_ERROR; goto done; } t = tmb.t_gett(); if (t == NULL || t == T_UNDEFINED) { LM_ERR("cannot lookup the transaction\n"); ret = RO_RETURN_ERROR; goto done; } } LM_DBG("Suspending SIP TM transaction\n"); if (tmb.t_suspend(msg, &tindex, &tlabel) < 0) { LM_ERR("failed to suspend the TM processing\n"); ret = RO_RETURN_ERROR; goto done; } ret = Ro_Send_CCR(msg, dlg, dir, charge_type, unit_type, reservation_units, cfg_action, tindex, tlabel); if(ret < 0){ LM_ERR("Failed to send CCR\n"); tmb.t_cancel_suspend(tindex, tlabel); } done: if(free_contact) shm_free(contact.s);// shm_malloc in cscf_get_public_identity_from_requri return ret; }
/** * init module function */ static int mod_init(void) { unsigned int n; LM_INFO("Initializing Http Async module\n"); #ifdef STATISTICS /* register statistics */ if (register_module_stats( exports.name, mod_stats)!=0 ) { LM_ERR("failed to register core statistics\n"); return -1; } #endif /* sanitize hash_size */ if (hash_size < 1){ LM_WARN("hash_size is smaller " "than 1 -> rounding from %d to 1\n", hash_size); hash_size = 1; } /* check that the hash table size is a power of 2 */ for( n=0 ; n<(8*sizeof(n)) ; n++) { if (hash_size==(1<<n)) break; if (n && hash_size<(1<<n)) { LM_WARN("hash_size is not a power " "of 2 as it should be -> rounding from %d to %d (n=%d)\n", hash_size, 1<<(n-1), n); hash_size = 1<<(n-1); break; } } /* check 'workers' param */ if (num_workers < 1) { LM_ERR("the 'workers' parameter must be >= 1\n"); return -1; } tls_verify_host = tls_verify_host?1:0; tls_verify_peer = tls_verify_peer?1:0; /* init http parameters list */ init_query_params(&ah_params); if (strncmp("shm", memory_manager, 3) == 0) { curl_memory_manager = 0; } else if (strncmp("sys", memory_manager, 3) == 0) { curl_memory_manager = 1; } else { LM_ERR("invalid memory_manager parameter: '%s'\n", memory_manager); return -1; } /* init faked sip msg */ if(faked_msg_init()<0) { LM_ERR("failed to init faked sip msg\n"); return -1; } if(load_tm_api( &tmb ) < 0) { LM_INFO("cannot load the TM-functions - async relay disabled\n"); memset(&tmb, 0, sizeof(tm_api_t)); } /* allocate workers array */ workers = shm_malloc(num_workers * sizeof(*workers)); if(workers == NULL) { LM_ERR("error in shm_malloc\n"); return -1; } memset(workers, 0, num_workers * sizeof(*workers)); register_procs(num_workers); /* add child to update local config framework structures */ cfg_register_child(num_workers); return 0; }
int set_modem_arg(struct modem *mdm, char *arg, char *arg_end) { int err, foo; if (*(arg+1)!='=') { LM_ERR("invalid parameter syntax near [=]\n"); goto error; } switch (*arg) { case 'd': /* device */ memcpy(mdm->device,arg+2,arg_end-arg-2); mdm->device[arg_end-arg-2] = 0; break; case 'p': /* pin */ memcpy(mdm->pin,arg+2,arg_end-arg-2); mdm->pin[arg_end-arg-2] = 0; break; case 'm': /* mode */ if (!strncasecmp(arg+2,"OLD",3) && arg_end-arg-2==3) { mdm->mode = MODE_OLD; } else if (!strncasecmp(arg+2,"DIGICOM",7) && arg_end-arg-2==7) { mdm->mode = MODE_DIGICOM; } else if (!strncasecmp(arg+2,"ASCII",5) && arg_end-arg-2==5) { mdm->mode = MODE_ASCII; } else if (!strncasecmp(arg+2,"NEW",3) && arg_end-arg-2==3) { mdm->mode = MODE_NEW; } else { LM_ERR("invalid value \"%.*s\" for param [m]\n", (int)(arg_end-arg-2),arg+2); goto error; } break; case 'c': /* sms center number */ memcpy(mdm->smsc,arg+2,arg_end-arg-2); mdm->smsc[arg_end-arg-2] = 0; break; case 'r': /* retry time */ foo=str2s(arg+2,arg_end-arg-2,&err); if (err) { LM_ERR("failed to convert [r] arg to integer!\n"); goto error; } mdm->retry = foo; break; case 'l': /* looping interval */ foo=str2s(arg+2,arg_end-arg-2,&err); if (err) { LM_ERR("failed to convert [l] arg to integer!\n"); goto error; } mdm->looping_interval = foo; break; case 'b': /* baudrate */ foo=str2s(arg+2,arg_end-arg-2,&err); if (err) { LM_ERR("failed to convert [b] arg to integer!\n"); goto error; } switch (foo) { case 300: foo=B300; break; case 1200: foo=B1200; break; case 2400: foo=B2400; break; case 9600: foo=B9600; break; case 19200: foo=B19200; break; case 38400: foo=B38400; break; case 57600: foo=B57600; break; default: LM_ERR("unsupported value %d for [b] arg!\n",foo); goto error; } mdm->baudrate = foo; break; case 's': /* scan */ foo=str2s(arg+2,arg_end-arg-2,&err); if (err) { LM_WARN("cannot convert [s] arg to integer!, assume default mode s=%d (SCAN)\n", SMS_BODY_SCAN); foo = SMS_BODY_SCAN; } switch (foo) { case SMS_BODY_SCAN: case SMS_BODY_SCAN_NO: case SMS_BODY_SCAN_MIX: break; default: LM_WARN("unsupported value s=%d for [s] arg!, assume default mode s=%d (SCAN)\n", foo,SMS_BODY_SCAN); foo = SMS_BODY_SCAN; } mdm->scan = foo; break; case 't': /* to */ memcpy(mdm->to,arg+2,arg_end-arg-2); mdm->to[arg_end-arg-2] = 0; break; default: LM_ERR("unknown param name [%c]\n",*arg); goto error; } return 1; error: return -1; }