map_t store_deserialize(const str *input) { map_t map; cJSON *json_map, *obj; str key; int_str_t value; map = map_create(AVLMAP_SHARED); if (!map) { LM_ERR("oom\n"); return NULL; } cJSON_InitHooks(&shm_hooks); json_map = cJSON_Parse(input->s); if (!json_map) { LM_ERR("bad JSON input or oom\n"); goto out; } if (json_map->type != cJSON_Object) { LM_BUG("non-cJSON_Object kv_store col type (%d)", json_map->type); goto out; } for (obj = json_map->child; obj; obj = obj->next) { init_str(&key, obj->string); switch (obj->type) { case cJSON_String: value.is_str = 1; init_str(&value.s, obj->valuestring); break; case cJSON_Number: value.is_str = 0; value.i = obj->valueint; break; default: LM_BUG("unknown obj type (%d)", obj->type); continue; } if (!kv_put(map, &key, &value)) LM_ERR("oom, map will be incomplete\n"); } out: cJSON_Delete(json_map); cJSON_InitHooks(NULL); return map; }
int match_node(const node_info_t *a, const node_info_t *b, enum cl_node_match_op match_op) { switch (match_op) { case NODE_CMP_ANY: break; case NODE_CMP_EQ_SIP_ADDR: lock_get(a->lock); if (!a->sip_addr.s || !b->sip_addr.s || str_strcmp(&a->sip_addr, &b->sip_addr)) { lock_release(a->lock); return 0; } lock_release(a->lock); break; case NODE_CMP_NEQ_SIP_ADDR: lock_get(a->lock); if (!a->sip_addr.s || !b->sip_addr.s || !str_strcmp(&a->sip_addr, &b->sip_addr)) { lock_release(a->lock); return 0; } lock_release(a->lock); break; default: LM_BUG("unknown match_op: %d\n", match_op); return 0; } LM_DBG("matched node %d\n", b->node_id); return 1; }
/* * * pack as hep; version depends on hep_version * @in1 source sockkadr * @in2 dest sockkadr * @in3 protocolo * @in4 SIP payload * @in5 SIP payload length * @out1 packed buffer * @out2 packed buffer length * it's your job to free the buffers */ int pack_hep(union sockaddr_union* from_su, union sockaddr_union* to_su, int proto, char *payload, int plen, char **retbuf, int *retlen) { switch (hep_version) { case 1: case 2: if (pack_hepv2(from_su, to_su, proto, payload, plen, retbuf, retlen) < 0) { LM_ERR("failed to pack using hep protocol version 3\n"); return -1; } break; case 3: if (pack_hepv3(from_su, to_su, proto, payload, plen, retbuf, retlen) < 0) { LM_ERR("failed to pack using hep protocol version 3\n"); return -1; } break; default: /* version check is being done at startup */ LM_BUG("invalid hep protocol version [%d]!" "Probably memory corruption\n", hep_version); return -1; } return 0; }
/* * Convert TLS method string to integer */ int tls_parse_method(str* method) { cfg_option_t* opt; if (!method) { LM_BUG("Invalid parameter value\n"); return -1; } opt = cfg_lookup_token(methods, method); if (!opt) return -1; #if OPENSSL_VERSION_NUMBER < 0x1000100fL if(opt->val == TLS_USE_TLSv1_1 || opt->val == TLS_USE_TLSv1_1_PLUS) { LM_ERR("tls v1.1 not supported by this libssl version: %ld\n", (long)OPENSSL_VERSION_NUMBER); return -1; } #endif #if OPENSSL_VERSION_NUMBER < 0x1000105fL if(opt->val == TLS_USE_TLSv1_2 || opt->val == TLS_USE_TLSv1_2_PLUS) { LM_ERR("tls v1.2 not supported by this libssl version: %ld\n", (long)OPENSSL_VERSION_NUMBER); return -1; } #endif return opt->val; }
static int db_sqlite_bind_values(sqlite3_stmt* stmt, const db_val_t* v, const int n) { int i, ret; if (n>0 && v) { for (i=0; i<n; i++) { if (VAL_NULL(v+i)) { ret=sqlite3_bind_null(stmt, i+1); goto check_ret; } switch(VAL_TYPE(v+i)) { /* every param has '+1' index because in sqlite the leftmost * parameter has index '1' */ case DB_INT: ret=sqlite3_bind_int(stmt, i+1, VAL_INT(v+i)); break; case DB_BIGINT: ret=sqlite3_bind_int64(stmt, i+1, VAL_BIGINT(v+i)); break; case DB_DOUBLE: ret=sqlite3_bind_double(stmt, i+1, VAL_DOUBLE(v+i)); break; case DB_STRING: ret=sqlite3_bind_text(stmt, i+1, VAL_STRING(v+i), strlen(VAL_STRING(v+i)), SQLITE_STATIC); break; case DB_STR: ret=sqlite3_bind_text(stmt, i+1, VAL_STR(v+i).s, VAL_STR(v+i).len, SQLITE_STATIC); break; case DB_DATETIME: ret=sqlite3_bind_int64(stmt, i+1, (long int)VAL_TIME(v+i)); break; case DB_BLOB: ret=sqlite3_bind_blob(stmt, i+1, (void*)VAL_BLOB(v+i).s, VAL_BLOB(v+i).len, SQLITE_STATIC); break; case DB_BITMAP: ret=sqlite3_bind_int(stmt, i+1, (int)VAL_BITMAP(v+i)); break; default: LM_BUG("invalid db type\n"); return 1; } check_ret: if (ret != SQLITE_OK) { return ret; } } } return SQLITE_OK; }
/* Register pre- or post-script callbacks. * Returns -1 on error, 0 on success */ int register_script_cb( cb_function f, unsigned int flags, void *param ) { struct script_cb **cb_array; int i; /* type checkings */ if ( (flags&((1<<SCRIPT_CB_NUM)-1))==0 ) { LM_BUG("callback flag not specified\n"); return -1; } if ( (flags&(~(PRE_SCRIPT_CB|POST_SCRIPT_CB))) >= 1<<SCRIPT_CB_NUM ) { LM_BUG("unsupported callback flags: %u\n", flags); return -1; } if ( (flags&(PRE_SCRIPT_CB|POST_SCRIPT_CB))==0 || (flags&PRE_SCRIPT_CB && flags&POST_SCRIPT_CB) ) { LM_BUG("callback POST or PRE type must be exactly one\n"); return -1; } if (flags&PRE_SCRIPT_CB) cb_array = pre_script_cb; else cb_array = post_script_cb; /* Add the callback to the lists. * (as many times as many flags are set) */ for (i=0; i<SCRIPT_CB_NUM; i++) { if ((flags&(1<<i)) == 0) continue; if (add_callback(&cb_array[i], f, param) < 0) goto add_error; } return 0; add_error: LM_ERR("failed to add callback\n"); return -1; }
static mi_response_t *cluster_send_mi(const mi_params_t *params, struct mi_handler *async_hdl) { int cluster_id, node_id; int rc; str cmd_name; mi_item_t *cmd_params_arr = NULL; int no_params = 0; if (get_mi_int_param(params, "cluster_id", &cluster_id) < 0) return init_mi_param_error(); if (cluster_id < 1) return init_mi_error(400, MI_SSTR("Bad value for 'cluster_id'")); if (get_mi_int_param(params, "destination", &node_id) < 0) return init_mi_param_error(); if (node_id < 1) return init_mi_error(400, MI_SSTR("Bad value for 'destination'")); if (node_id == current_id) return init_mi_error(400, MI_SSTR("Local node specified as destination")); if (get_mi_string_param(params, "cmd_name", &cmd_name.s, &cmd_name.len) < 0) return init_mi_param_error(); rc = try_get_mi_array_param(params, "cmd_params", &cmd_params_arr, &no_params); if (rc < 0) { cmd_params_arr = NULL; if (rc == -2) return init_mi_param_error(); } rc = send_mi_cmd(cluster_id, node_id, cmd_name, cmd_params_arr, no_params); switch (rc) { case CLUSTERER_SEND_SUCCES: LM_DBG("MI command <%.*s> sent\n", cmd_name.len, cmd_name.s); return init_mi_result_ok(); case CLUSTERER_CURR_DISABLED: LM_INFO("Local node disabled, MI command <%.*s> not sent\n", cmd_name.len, cmd_name.s); return init_mi_result_string(MI_SSTR("Local node disabled")); case CLUSTERER_DEST_DOWN: LM_ERR("Destination down, MI command <%.*s> not sent\n", cmd_name.len, cmd_name.s); return init_mi_error(400, MI_SSTR("Destination down")); case CLUSTERER_SEND_ERR: LM_ERR("Error sending MI command <%.*s>+\n", cmd_name.len, cmd_name.s); return init_mi_error(400, MI_SSTR("Send error")); default: LM_BUG("Bad send error code\n"); return init_mi_error(400, MI_SSTR("Internal error")); } }
int db_postgres_async_resume(db_con_t *_h, int fd, db_res_t **_r, void *_priv) { struct pool_con *con = (struct pool_con *)_priv; PGresult *res = NULL; #ifdef EXTRA_DEBUG if (!db_match_async_con(fd, _h)) { LM_BUG("no conn match for fd %d", fd); abort(); } #endif db_switch_to_async(_h, con); if( PQconsumeInput(CON_CONNECTION(_h)) == 0) { LM_ERR("Unable to consume input\n"); db_switch_to_sync(_h); db_store_async_con(_h, con); return -1; } if(PQisBusy(CON_CONNECTION(_h))) { async_status = ASYNC_CONTINUE; db_switch_to_sync(_h); return 1; } while (1) { if ((res = PQgetResult(CON_CONNECTION(_h)))) { CON_RESULT(_h) = res; } else { break; } } if (_r) { if (db_postgres_store_result(_h, _r) != 0) { LM_ERR("failed to store result\n"); db_switch_to_sync(_h); db_store_async_con(_h, con); return -2; } } db_switch_to_sync(_h); db_store_async_con(_h, con); return 0; }
static int avpops_init(void) { LM_INFO("initializing...\n"); if (db_table.s) db_table.len = strlen(db_table.s); uuid_col.len = strlen(uuid_col.s); attribute_col.len = strlen(attribute_col.s); value_col.len = strlen(value_col.s); type_col.len = strlen(type_col.s); username_col.len = strlen(username_col.s); domain_col.len = strlen(domain_col.s); default_db_url = get_default_db_url(); if (default_db_url==NULL) { if (db_default_url==NULL) { LM_ERR("no DB URL provision into the module!\n"); return -1; } /* if nothing explicitly set as DB URL, add automatically * the default DB URL */ if (add_db_url(STR_PARAM, db_default_url)!=0) { LM_ERR("failed to use the default DB URL!\n"); return -1; } default_db_url = get_default_db_url(); if (default_db_url==NULL) { LM_BUG("Really ?!\n"); return -1; } } /* bind to the DB module */ if (avpops_db_bind()<0) goto error; init_store_avps(db_columns); printbuf = (char*)pkg_malloc((buf_size+1)*sizeof(char)); if(printbuf==NULL) { LM_ERR("no pkg memory left\n"); return -1; } return 0; error: return -1; }
/* Execute post-script callbacks of a given type. * Always returns 1, success. */ int exec_post_script_cb( struct sip_msg *msg, enum script_cb_type type) { struct script_cb *cb; unsigned int flags; if (type > SCRIPT_CB_NUM) { LM_BUG("unknown callback type %d\n", type); return 1; } flags = POST_SCRIPT_CB | (1<<(type-1)); for (cb=post_script_cb[type-1]; cb ; cb=cb->next){ cb->cbf(msg, flags, cb->param); } return 1; }
/* * setter function for $acc_extra */ int pv_set_acc_extra(struct sip_msg *msg, pv_param_t *param, int op, pv_value_t *val) { int tag_idx; acc_ctx_t* ctx=try_fetch_ctx(); if (param == NULL || val == NULL) { LM_ERR("bad params!\n"); return -1; } if (ctx == NULL) { /* if we don't have a context then create it */ if (init_acc_ctx(&ctx) < 0) { LM_ERR("failed to create accounting context!\n"); return -1; } ACC_PUT_CTX(ctx); } tag_idx = param->pvn.u.isname.name.n; /* sanity checks for the tag; it should be valid since * we found it in the parse name function */ if (tag_idx < 0 || tag_idx >= extra_tgs_len) { LM_BUG("invalid tag value! probably a memory corruption issue!\n"); return -1; } /* go through all extras and fetch first value you find * all the extras with the same tag will have the same * value */ accX_lock(&ctx->lock); if (set_value_shm(val, &ctx->extra_values[tag_idx]) < 0) { LM_ERR("failed to set extra <%.*s> value!\n", extra_tags[tag_idx].len, extra_tags[tag_idx].s); accX_unlock(&ctx->lock); return -1; } accX_unlock(&ctx->lock); return 0; }
/* Execute pre-script callbacks of a given type. * Returns 0 on error, 1 on success */ int exec_pre_script_cb( struct sip_msg *msg, enum script_cb_type type) { struct script_cb *cb; unsigned int flags; if (type > SCRIPT_CB_NUM) { LM_BUG("unknown callback type %d\n", type); return 0; } flags = PRE_SCRIPT_CB | (1<<(type-1)); for (cb=pre_script_cb[type-1]; cb ; cb=cb->next ) { /* stop on error */ if (cb->cbf(msg, flags, cb->param)==0) return 0; } return 1; }
/* * Wrapper around SSL_write, returns number of bytes written on success, * * -1 on error, 0 when it would block */ static int tls_write(struct tcp_connection *c, int fd, const void *buf, size_t len, short *poll_events) { int ret, err; /* * runs within write lock, no need to lock here */ SSL *ssl; ssl = (SSL *) c->extra_data; ret = SSL_write(ssl, buf, len); if (ret > 0) { LM_DBG("write was successful (%d bytes)\n", ret); return ret; } else { err = SSL_get_error(ssl, ret); switch (err) { case SSL_ERROR_ZERO_RETURN: LM_DBG("connection closed cleanly\n"); c->state = S_CONN_EOF; return -1; case SSL_ERROR_WANT_READ: if (poll_events) *poll_events = POLLIN; return 0; case SSL_ERROR_WANT_WRITE: if (poll_events) *poll_events = POLLOUT; return 0; default: LM_ERR("TLS connection to %s:%d write failed\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port); LM_ERR("TLS write error:\n"); c->state = S_CONN_BAD; tls_print_errstack(); return -1; } } LM_BUG("bug\n"); return -1; }
/* * Wrapper around SSL_read * * returns number of bytes read, 0 on eof and transits into S_CONN_EOF, -1 * on error */ static int _tls_read(struct tcp_connection *c, void *buf, size_t len) { int ret, err; SSL *ssl; ssl = c->extra_data; ret = SSL_read(ssl, buf, len); if (ret > 0) { LM_DBG("%d bytes read\n", ret); return ret; } else { err = SSL_get_error(ssl, ret); switch (err) { case SSL_ERROR_ZERO_RETURN: LM_DBG("TLS connection to %s:%d closed cleanly\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port); /* * mark end of file */ c->state = S_CONN_EOF; return 0; case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: return 0; case SSL_ERROR_SYSCALL: LM_ERR("SYSCALL error -> (%d) <%s>\n",errno,strerror(errno)); default: LM_ERR("TLS connection to %s:%d read failed\n", ip_addr2a(&c->rcv.src_ip), c->rcv.src_port); LM_ERR("TLS read error: %d\n",err); c->state = S_CONN_BAD; tls_print_errstack(); return -1; } } LM_BUG("bug\n"); return -1; }
static struct usr_avp *pack_evi_params_as_avp_list(evi_params_t *params) { struct usr_avp *avp, *head=NULL; evi_param_t *e_param; int_str val; int avp_id; /* take all the EVI parameters and convert them into AVPs */ for( e_param=params->first ; e_param ; e_param=e_param->next ) { /* get an AVP name matching the param name */ if (parse_avp_spec( &e_param->name, &avp_id)<0) { LM_ERR("cannot get AVP ID for name <%.*s>, skipping..\n", e_param->name.len, e_param->name.s); continue; } /* create a new AVP */ if (e_param->flags&EVI_STR_VAL) { val.s = e_param->val.s; avp = new_avp( AVP_VAL_STR, avp_id, val); } else if (e_param->flags&EVI_INT_VAL) { val.n = e_param->val.n; avp = new_avp( 0, avp_id, val); } else { LM_BUG("EVI param no STR, nor INT, ignoring...\n"); continue; } if (avp==NULL) { LM_ERR("cannot get create new AVP name <%.*s>, skipping..\n", e_param->name.len, e_param->name.s); continue; } /* link the AVP */ avp->next = head; head = avp; } return head; }
/* * getter function for $acc_extra */ int pv_get_acc_extra(struct sip_msg *msg, pv_param_t *param, pv_value_t *val) { int tag_idx; acc_ctx_t* ctx=try_fetch_ctx(); if (param == NULL || val == NULL) { LM_ERR("bad input params!\n"); return -1; } if (ctx == NULL) { /* if we don't have a context then create it */ if (init_acc_ctx(&ctx) < 0) { LM_ERR("failed to create accounting context!\n"); return -1; } ACC_PUT_CTX(ctx); } tag_idx = param->pvn.u.isname.name.n; /* sanity checks for the tag; it should be valid since * we found it in the parse name function */ if (tag_idx < 0 || tag_idx >= extra_tgs_len) { LM_BUG("invalid tag value! probably a memory corruption issue!\n"); return -1; } accX_lock(&ctx->lock); if (ctx->extra_values[tag_idx].value.s == NULL) { val->flags = PV_VAL_NULL; } else { val->rs = ctx->extra_values[tag_idx].value; val->flags = PV_VAL_STR; } accX_unlock(&ctx->lock); return 0; }
void wrap_tm_func(struct cell* t, int type, struct tmcb_params* p) { char* buf = t->uac[p->code].request.buffer.s; int olen = t->uac[p->code].request.buffer.len; void* args; switch (type) { case COMPRESS_CB: if ((args = GET_GLOBAL_CTX(compress_ctx_pos)) == NULL) break; if (mc_compress_cb(&buf, args, TM_CB, &olen) < 0) { LM_ERR("compression failed\n"); return; } pkg_free(args); SET_GLOBAL_CTX(compress_ctx_pos, NULL); break; case COMPACT_CB: /* if not registered yet we take from global context */ if ((args = GET_GLOBAL_CTX(compact_ctx_pos)) == NULL) break; if (mc_compact_cb(&buf, args, TM_CB, &olen) < 0) { LM_ERR("compaction failed\n"); return; } pkg_free(args); SET_GLOBAL_CTX(compact_ctx_pos, NULL); break; default: LM_BUG("!!! invalid CB type arg!\n"); return; } t->uac[p->code].request.buffer.s = buf; t->uac[p->code].request.buffer.len = olen; }
void remove_part_struct(struct pm_part_struct *part_struct) { struct pm_part_struct *before, *el; if (!part_structs) LM_BUG("no part structs; what are you asking for?\n"); before = el = part_structs; while (el) { if (part_struct == el) { if (el->next) before->next = el->next; pkg_free(el); } if (before != el) before = before->next; el = el->next; } }
static int fixup_wpvar(void **param) { int ret; pv_spec_t *spec; ret = fixup_pvar(param); if (ret != 0) { LM_ERR("cannot parse pvar\n"); return -1; } spec = *(pv_spec_t **)param; if (!spec) { LM_BUG("cannot find spec"); return -1; } if (!spec->setf) { LM_ERR("pvar not writable\n"); return -1; } return 0; }
int add_listener(struct socket_id *sock, enum si_flags flags) { /* * XXX: using the new version, the protocol _MUST_ be specified * otherwise UDP will be assumed */ enum sip_protos proto = sock->proto; /* validate the protocol */ if (proto < PROTO_FIRST || proto >= PROTO_LAST) { LM_BUG("invalid protocol number %d\n", proto); return -1; } /* convert to socket_info */ if (new_sock2list(sock->name, sock->port, sock->proto, sock->adv_name, sock->adv_port, sock->children, flags, &protos[proto].listeners) < 0) { LM_ERR("cannot add socket to the list\n"); return -1; } return 0; }
static inline unsigned short uri2port(const struct sip_uri *puri) { if (puri->port.s) { return puri->port_no; } else switch (puri->type) { case SIP_URI_T: case TEL_URI_T: if (puri->transport_val.len == sizeof("TLS") - 1) { unsigned trans; trans = puri->transport_val.s[0] | 0x20; trans <<= 8; trans |= puri->transport_val.s[1] | 0x20; trans <<= 8; trans |= puri->transport_val.s[2] | 0x20; if (trans == 0x746C73) /* t l s */ return SIPS_PORT; } return SIP_PORT; case SIPS_URI_T: case TELS_URI_T: return SIPS_PORT; default: LM_BUG("unexpected URI type %d.\n", puri->type); } return 0; }
static struct tcp_connection* ws_connect(struct socket_info* send_sock, union sockaddr_union* to, int *fd) { struct tcp_connection *c; if ((c=ws_sync_connect(send_sock, to))==0) { LM_ERR("connect failed\n"); return NULL; } /* the state of the connection should be NONE, otherwise something is * wrong */ if (WS_TYPE(c) != WS_NONE) { LM_BUG("invalid type for connection %d\n", WS_TYPE(c)); goto error; } WS_TYPE(c) = WS_CLIENT; if (ws_client_handshake(c) < 0) { LM_ERR("cannot complete WebSocket handshake\n"); goto error; } *fd = c->fd; /* clear the fd, just in case */ c->fd = -1; /* handshake done - send the socket to main */ if (tcp_conn_send(c) < 0) { LM_ERR("cannot send socket to main\n"); goto error; } return c; error: tcp_conn_destroy(c); return NULL; }
/** * Evaluates the routing elements in locally originated request or reply to * locally originated request. * If original INVITE was in-dialog (had to-tag), it uses the * routes present there (b/c the 2xx for it does not have a RR set, normally). * Otherwise, use the reply (b/c the INVITE does not have yet the complete * route set). * * @return: negative for failure; out params: * - list: route set; * - ruri: RURI to be used in ACK; * - nexthop: where to first send the ACK. * * NOTE: assumes rpl's parsed to EOF! * */ static int eval_uac_routing(sip_msg_t *rpl, const struct retr_buf *inv_rb, str* contact, struct rte **list, str *ruri, str *next_hop) { sip_msg_t orig_inv, *sipmsg; /* reparse original INVITE */ rte_t *t, *prev_t, *rtset = NULL; int is_req; struct sip_uri puri; static size_t chklen; /* parse the retr. buffer */ memset(&orig_inv, 0, sizeof(struct sip_msg)); orig_inv.buf = inv_rb->buffer; orig_inv.len = inv_rb->buffer_len; LM_DBG("reparsing retransmission buffer of original INVITE:\n%.*s\n", (int)orig_inv.len, orig_inv.buf); if (parse_msg(orig_inv.buf, orig_inv.len, &orig_inv) != 0) { LM_ERR("failed to parse retr buffer (weird!): \n%.*s\n", (int)orig_inv.len, orig_inv.buf); return -1; } /* check if we need to look at request or reply */ if ((parse_headers(&orig_inv, HDR_TO_F, 0) < 0) || (! orig_inv.to)) { /* the bug is at message assembly */ LM_BUG("failed to parse INVITE retr. buffer and/or extract 'To' HF:" "\n%.*s\n", (int)orig_inv.len, orig_inv.buf); goto error; } if (((struct to_body *)orig_inv.to->parsed)->tag_value.len) { LM_DBG("building ACK for in-dialog INVITE (using RS in orig. INV.)\n"); if (parse_headers(&orig_inv, HDR_EOH_F, 0) < 0) { LM_BUG("failed to parse INVITE retr. buffer to EOH:" "\n%.*s\n", (int)orig_inv.len, orig_inv.buf); goto error; } sipmsg = &orig_inv; is_req = 1; } else { LM_DBG("building ACK for out-of-dialog INVITE (using RS in RR set).\n"); sipmsg = rpl; is_req = 0; } /* extract the route set */ if (get_uac_rs(sipmsg, is_req, &rtset) < 0) { LM_ERR("failed to extract route set.\n"); goto error; } if (! rtset) { /* No routes */ *ruri = *contact; *next_hop = *contact; } else if (! is_req) { /* out of dialog req. */ if (parse_uri(rtset->ptr->nameaddr.uri.s, rtset->ptr->nameaddr.uri.len, &puri) < 0) { LM_ERR("failed to parse first route in set.\n"); goto error; } if (puri.lr.s) { /* Next hop is loose router */ *ruri = *contact; *next_hop = rtset->ptr->nameaddr.uri; } else { /* Next hop is strict router */ *ruri = rtset->ptr->nameaddr.uri; *next_hop = *ruri; /* consume first route, b/c it will be put in RURI */ t = rtset; rtset = rtset->next; pkg_free(t); } } else { unsigned long route_flags = inv_rb->flags; LM_DBG("UAC rb flags: 0x%x.\n", (unsigned int)route_flags); eval_flags: switch (route_flags & (F_RB_NH_LOOSE|F_RB_NH_STRICT)) { case 0: LM_WARN("calculate_hooks() not called when built the local UAC of " "in-dialog request, or called with empty route set.\n"); /* try to figure out what kind of hop is the next one * (strict/loose) by reading the original invite */ if ((route_flags = nhop_type(&orig_inv, rtset, &inv_rb->dst, contact))) { LM_DBG("original request's next hop type evaluated to: 0x%x.\n", (unsigned int)route_flags); goto eval_flags; } else { LM_ERR("failed to establish what kind of router the next " "hop is.\n"); goto error; } break; case F_RB_NH_LOOSE: *ruri = *contact; *next_hop = rtset->ptr->nameaddr.uri; break; case F_RB_NH_STRICT: /* find ptr to last route body that contains the (possibly) old * remote target */ for (t = rtset, prev_t = NULL; t->next; prev_t = t, t = t->next) ; if ((t->ptr->len == contact->len) && (memcmp(t->ptr->nameaddr.name.s, contact->s, contact->len) == 0)){ /* the remote target didn't update -> keep the whole route set, * including the last entry */ /* do nothing */ } else { /* trash last entry and replace with new remote target */ free_rte_list(t); /* compact the rr_t struct along with rte. this way, free'ing * it can be done along with rte chunk, independent of Route * header parser's allocator (using pkg/shm) */ chklen = sizeof(struct rte) + sizeof(rr_t); if (! (t = pkg_malloc(chklen))) { ERR("out of pkg memory (%d required)\n", (int)chklen); /* last element was freed, unlink it */ if(prev_t == NULL) { /* there is only one elem in route set: the remote target */ rtset = NULL; } else { prev_t->next = NULL; } goto error; } /* this way, .free_rr is also set to 0 (!!!) */ memset(t, 0, chklen); ((rr_t *)&t[1])->nameaddr.name = *contact; ((rr_t *)&t[1])->len = contact->len; /* chain the new route elem in set */ if (prev_t == NULL) /* there is only one elem in route set: the remote target */ rtset = t; else prev_t->next = t; } *ruri = *GET_RURI(&orig_inv); /* reuse original RURI */ *next_hop = *ruri; break; default: /* probably a mem corruption */ LM_BUG("next hop of original request marked as both loose" " and strict router (buffer: %.*s).\n", inv_rb->buffer_len, inv_rb->buffer); #ifdef EXTRA_DEBUG abort(); #else goto error; #endif } } *list = rtset; free_sip_msg(&orig_inv); /* all went well */ return 0; error: free_sip_msg(&orig_inv); if (rtset) free_rte_list(rtset); return -1; }
/* Build a local request based on a previous request; main * customers of this function are local ACK and local CANCEL */ char *build_local(struct cell *Trans,unsigned int branch, unsigned int *len, char *method, int method_len, str *to #ifdef CANCEL_REASON_SUPPORT , struct cancel_reason* reason #endif /* CANCEL_REASON_SUPPORT */ ) { char *cancel_buf, *p, *via; unsigned int via_len; struct hdr_field *hdr; char branch_buf[MAX_BRANCH_PARAM_LEN]; int branch_len; str branch_str; str via_id; struct hostport hp; #ifdef CANCEL_REASON_SUPPORT int reason_len, code_len; struct hdr_field *reas1, *reas_last; #endif /* CANCEL_REASON_SUPPORT */ /* init */ via_id.s=0; via_id.len=0; /* method, separators, version: "CANCEL sip:[email protected] SIP/2.0" */ *len=SIP_VERSION_LEN + method_len + 2 /* spaces */ + CRLF_LEN; *len+=Trans->uac[branch].uri.len; /*via*/ if (!t_calc_branch(Trans, branch, branch_buf, &branch_len )) goto error; branch_str.s=branch_buf; branch_str.len=branch_len; set_hostport(&hp, (is_local(Trans))?0:(Trans->uas.request)); #ifdef USE_TCP if (!is_local(Trans) && ((Trans->uas.request->rcv.proto==PROTO_TCP) #ifdef USE_TLS || (Trans->uas.request->rcv.proto==PROTO_TLS) #endif /* USE_TLS */ )){ if ((via_id.s=id_builder(Trans->uas.request, (unsigned int*)&via_id.len))==0){ LM_ERR("id builder failed\n"); /* try to continue without id */ } } #endif /* USE_TCP */ via=via_builder(&via_len, NULL, &Trans->uac[branch].request.dst, &branch_str, via_id.s?&via_id:0 , &hp ); /* via_id.s not needed anylonger => free it */ if (via_id.s) { pkg_free(via_id.s); via_id.s=0; via_id.len=0; } if (!via) { LM_ERR("no via header got from builder\n"); goto error; } *len+= via_len; /*headers*/ *len+=Trans->from.len+Trans->callid.len+to->len+ +Trans->cseq_n.len+1+method_len+CRLF_LEN+MAXFWD_HEADER_LEN; /* copy'n'paste Route headers */ if (!is_local(Trans)) { for ( hdr=Trans->uas.request->headers ; hdr ; hdr=hdr->next ) if (hdr->type==HDR_ROUTE_T) *len+=hdr->len; } /* User Agent */ if (server_signature) { *len += user_agent_hdr.len + CRLF_LEN; } /* Content Length, EoM */ *len+=CONTENT_LENGTH_LEN+1 + CRLF_LEN; #ifdef CANCEL_REASON_SUPPORT reason_len = 0; reas1 = 0; reas_last = 0; /* compute reason size (if no reason or disabled => reason_len == 0)*/ if (reason && reason->cause != CANCEL_REAS_UNKNOWN){ if (likely(reason->cause > 0 && cfg_get(tm, tm_cfg, local_cancel_reason))){ /* Reason: SIP;cause=<reason->cause>[;text=<reason->u.text.s>] */ reason_len = REASON_PREFIX_LEN + USHORT2SBUF_MAX_LEN + (reason->u.text.s? REASON_TEXT_LEN + 1 + reason->u.text.len + 1 : 0) + CRLF_LEN; } else if (likely(reason->cause == CANCEL_REAS_PACKED_HDRS && !(Trans->flags & T_NO_E2E_CANCEL_REASON))) { reason_len = reason->u.packed_hdrs.len; } else if (reason->cause == CANCEL_REAS_RCVD_CANCEL && reason->u.e2e_cancel && !(Trans->flags & T_NO_E2E_CANCEL_REASON)) { /* parse the entire cancel, to get all the Reason headers */ if(parse_headers(reason->u.e2e_cancel, HDR_EOH_F, 0)<0) { LM_WARN("failed to parse headers\n"); } for(hdr=get_hdr(reason->u.e2e_cancel, HDR_REASON_T), reas1=hdr; hdr; hdr=next_sibling_hdr(hdr)) { /* hdr->len includes CRLF */ reason_len += hdr->len; reas_last=hdr; } } else if (unlikely(reason->cause < CANCEL_REAS_MIN)) LM_BUG("unhandled reason cause %d\n", reason->cause); } *len+= reason_len; #endif /* CANCEL_REASON_SUPPORT */ *len+= CRLF_LEN; /* end of msg. */ cancel_buf=shm_malloc( *len+1 ); if (!cancel_buf) { LM_ERR("cannot allocate memory\n"); goto error01; } p = cancel_buf; append_str( p, method, method_len ); append_str( p, " ", 1 ); append_str( p, Trans->uac[branch].uri.s, Trans->uac[branch].uri.len); append_str( p, " " SIP_VERSION CRLF, 1+SIP_VERSION_LEN+CRLF_LEN ); /* insert our via */ append_str(p,via,via_len); /*other headers*/ append_str( p, Trans->from.s, Trans->from.len ); append_str( p, Trans->callid.s, Trans->callid.len ); append_str( p, to->s, to->len ); append_str( p, Trans->cseq_n.s, Trans->cseq_n.len ); append_str( p, " ", 1 ); append_str( p, method, method_len ); append_str( p, CRLF, CRLF_LEN ); append_str( p, MAXFWD_HEADER, MAXFWD_HEADER_LEN ); if (!is_local(Trans)) { for ( hdr=Trans->uas.request->headers ; hdr ; hdr=hdr->next ) if(hdr->type==HDR_ROUTE_T) { append_str(p, hdr->name.s, hdr->len ); } } /* User Agent header */ if (server_signature) { append_str(p, user_agent_hdr.s, user_agent_hdr.len ); append_str(p, CRLF, CRLF_LEN ); } /* Content Length */ append_str(p, CONTENT_LENGTH "0" CRLF, CONTENT_LENGTH_LEN + 1 + CRLF_LEN); #ifdef CANCEL_REASON_SUPPORT /* add reason if needed */ if (reason_len) { if (likely(reason->cause > 0)) { append_str(p, REASON_PREFIX, REASON_PREFIX_LEN); code_len=ushort2sbuf(reason->cause, p, *len-(int)(p-cancel_buf)); if (unlikely(code_len==0)) LM_BUG("not enough space to write reason code"); p+=code_len; if (reason->u.text.s){ append_str(p, REASON_TEXT, REASON_TEXT_LEN); *p='"'; p++; append_str(p, reason->u.text.s, reason->u.text.len); *p='"'; p++; } append_str(p, CRLF, CRLF_LEN); } else if (likely(reason->cause == CANCEL_REAS_PACKED_HDRS)) { append_str(p, reason->u.packed_hdrs.s, reason->u.packed_hdrs.len); } else if (reason->cause == CANCEL_REAS_RCVD_CANCEL) { for(hdr=reas1; hdr; hdr=next_sibling_hdr(hdr)) { /* hdr->len includes CRLF */ append_str(p, hdr->name.s, hdr->len); if (likely(hdr==reas_last)) break; } } } #endif /* CANCEL_REASON_SUPPORT */ append_str(p, CRLF, CRLF_LEN); /* msg. end */ *p=0; pkg_free(via); return cancel_buf; error01: pkg_free(via); error: return NULL; }
/* Re-parsing version of build_local() function: * it builds a local CANCEL or ACK (for non-200 response) request based on * the previous INVITE which was sent out. * * Can not be used to build other type of requests! */ char *build_local_reparse(struct cell *Trans,unsigned int branch, unsigned int *len, char *method, int method_len, str *to #ifdef CANCEL_REASON_SUPPORT , struct cancel_reason *reason #endif /* CANCEL_REASON_SUPPORT */ ) { char *invite_buf, *invite_buf_end; char *cancel_buf; char *s, *s1, *d; /* source and destination buffers */ short invite_len; enum _hdr_types_t hf_type; int first_via, to_len; int cancel_buf_len; #ifdef CANCEL_REASON_SUPPORT int reason_len, code_len; struct hdr_field *reas1, *reas_last, *hdr; #endif /* CANCEL_REASON_SUPPORT */ int hadded = 0; sr_cfgenv_t *cenv = NULL; invite_buf = Trans->uac[branch].request.buffer; invite_len = Trans->uac[branch].request.buffer_len; if (!invite_buf || !invite_len) { LM_ERR("INVITE is missing\n"); goto error; } if ((*invite_buf != 'I') && (*invite_buf != 'i')) { LM_ERR("trying to build with local reparse" " for a non-INVITE request?\n"); goto error; } #ifdef CANCEL_REASON_SUPPORT reason_len = 0; reas1 = 0; reas_last = 0; /* compute reason size (if no reason or disabled => reason_len == 0)*/ if (reason && reason->cause != CANCEL_REAS_UNKNOWN){ if (likely(reason->cause > 0 && cfg_get(tm, tm_cfg, local_cancel_reason))){ /* Reason: SIP;cause=<reason->cause>[;text=<reason->u.text.s>] */ reason_len = REASON_PREFIX_LEN + USHORT2SBUF_MAX_LEN + (reason->u.text.s? REASON_TEXT_LEN + 1 + reason->u.text.len + 1 : 0) + CRLF_LEN; } else if (likely(reason->cause == CANCEL_REAS_PACKED_HDRS && !(Trans->flags & T_NO_E2E_CANCEL_REASON))) { reason_len = reason->u.packed_hdrs.len; } else if (reason->cause == CANCEL_REAS_RCVD_CANCEL && reason->u.e2e_cancel && !(Trans->flags & T_NO_E2E_CANCEL_REASON)) { /* parse the entire cancel, to get all the Reason headers */ if(parse_headers(reason->u.e2e_cancel, HDR_EOH_F, 0)<0) { LM_WARN("failed to parse headers\n"); } for(hdr=get_hdr(reason->u.e2e_cancel, HDR_REASON_T), reas1=hdr; hdr; hdr=next_sibling_hdr(hdr)) { /* hdr->len includes CRLF */ reason_len += hdr->len; reas_last=hdr; } } else if (unlikely(reason->cause < CANCEL_REAS_MIN)) LM_BUG("unhandled reason cause %d\n", reason->cause); } #endif /* CANCEL_REASON_SUPPORT */ invite_buf_end = invite_buf + invite_len; s = invite_buf; /* Allocate memory for the new message. The new request will be smaller than the INVITE, so the same size is enough. I just extend it with the length of new To HF to be sure. Ugly, but we avoid lots of checks and memory allocations this way */ to_len = to ? to->len : 0; #ifdef CANCEL_REASON_SUPPORT cancel_buf_len = invite_len + to_len + reason_len; #else cancel_buf_len = invite_len + to_len; #endif /* CANCEL_REASON_SUPPORT */ cancel_buf = shm_malloc(sizeof(char)*cancel_buf_len); if (!cancel_buf) { LM_ERR("cannot allocate shared memory\n"); goto error; } d = cancel_buf; /* method name + space */ append_str(d, method, method_len); *d = ' '; d++; /* skip "INVITE " and copy the rest of the line including CRLF */ s += 7; s1 = s; s = eat_line(s, invite_buf_end - s); append_str(d, s1, s - s1); cenv = sr_cfgenv_get(); /* check every header field name, we must exclude and modify some of the headers */ first_via = 1; while (s < invite_buf_end) { s1 = s; if ((*s == '\n') || (*s == '\r')) { /* end of SIP msg */ hf_type = HDR_EOH_T; } else { /* parse HF name */ s = lw_get_hf_name(s, invite_buf_end, &hf_type); } switch(hf_type) { case HDR_CSEQ_T: /* find the method name and replace it */ while ((s < invite_buf_end) && ((*s == ':') || (*s == ' ') || (*s == '\t') || ((*s >= '0') && (*s <= '9'))) ) s++; append_str(d, s1, s - s1); append_str(d, method, method_len); append_str(d, CRLF, CRLF_LEN); s = lw_next_line(s, invite_buf_end); break; case HDR_VIA_T: s = lw_next_line(s, invite_buf_end); if (first_via) { /* copy hf */ append_str(d, s1, s - s1); first_via = 0; } /* else skip this line, we need olny the first via */ break; case HDR_TO_T: if (to_len == 0) { /* there is no To tag required, just copy paste * the header */ s = lw_next_line(s, invite_buf_end); append_str(d, s1, s - s1); } else { /* use the given To HF instead of the original one */ append_str(d, to->s, to->len); /* move the pointer to the next line */ s = lw_next_line(s, invite_buf_end); } break; case HDR_FROM_T: case HDR_CALLID_T: case HDR_ROUTE_T: case HDR_MAXFORWARDS_T: /* copy hf */ s = lw_next_line(s, invite_buf_end); append_str(d, s1, s - s1); break; case HDR_REQUIRE_T: case HDR_PROXYREQUIRE_T: /* skip this line */ s = lw_next_line(s, invite_buf_end); break; case HDR_CONTENTLENGTH_T: /* copy hf name with 0 value */ append_str(d, s1, s - s1); append_str(d, ": 0" CRLF, 3 + CRLF_LEN); /* move the pointer to the next line */ s = lw_next_line(s, invite_buf_end); break; case HDR_EOH_T: /* end of SIP message found */ #ifdef CANCEL_REASON_SUPPORT /* add reason if needed */ if (reason_len) { /* if reason_len !=0, no need for any reason enabled * checks */ if (likely(reason->cause > 0)) { append_str(d, REASON_PREFIX, REASON_PREFIX_LEN); code_len=ushort2sbuf(reason->cause, d, cancel_buf_len-(int)(d-cancel_buf)); if (unlikely(code_len==0)) LM_BUG("not enough space to write reason code"); d+=code_len; if (reason->u.text.s){ append_str(d, REASON_TEXT, REASON_TEXT_LEN); *d='"'; d++; append_str(d, reason->u.text.s, reason->u.text.len); *d='"'; d++; } append_str(d, CRLF, CRLF_LEN); } else if (likely(reason->cause == CANCEL_REAS_PACKED_HDRS)) { append_str(d, reason->u.packed_hdrs.s, reason->u.packed_hdrs.len); } else if (reason->cause == CANCEL_REAS_RCVD_CANCEL) { for(hdr=reas1; hdr; hdr=next_sibling_hdr(hdr)) { /* hdr->len includes CRLF */ append_str(d, hdr->name.s, hdr->len); if (likely(hdr==reas_last)) break; } } } #endif /* CANCEL_REASON_SUPPORT */ /* final (end-of-headers) CRLF */ append_str(d, CRLF, CRLF_LEN); *len = d - cancel_buf; /* LOG(L_DBG, "DBG: build_local: %.*s\n", *len, cancel_buf); */ return cancel_buf; default: s = lw_next_line(s, invite_buf_end); hadded = 0; /* uac auth headers */ if(Trans->uas.request && (Trans->uas.request->msg_flags & FL_UAC_AUTH)) { if(s1 + cenv->uac_cseq_auth.len + 2 < invite_buf_end) { if(s1[cenv->uac_cseq_auth.len]==':' && strncmp(s1, cenv->uac_cseq_auth.s, cenv->uac_cseq_auth.len)==0) { hadded = 1; append_str(d, s1, s - s1); } else if(s1[cenv->uac_cseq_refresh.len]==':' && strncmp(s1, cenv->uac_cseq_refresh.s, cenv->uac_cseq_refresh.len)==0) { hadded = 1; append_str(d, s1, s - s1); } } } if(likely(hadded==0)) { if (cfg_get(tm, tm_cfg, ac_extra_hdrs).len && (s1 + cfg_get(tm, tm_cfg, ac_extra_hdrs).len < invite_buf_end) && (strncasecmp(s1, cfg_get(tm, tm_cfg, ac_extra_hdrs).s, cfg_get(tm, tm_cfg, ac_extra_hdrs).len) == 0)) { append_str(d, s1, s - s1); } } break; } } /* HDR_EOH_T was not found in the buffer, the message is corrupt */ LM_ERR("HDR_EOH_T was not found\n"); shm_free(cancel_buf); error: LM_ERR("cannot build %.*s request\n", method_len, method); return NULL; }
static int avpops_init(void) { int i; LM_INFO("initializing...\n"); if (db_table.s) db_table.len = strlen(db_table.s); uuid_col.len = strlen(uuid_col.s); attribute_col.len = strlen(attribute_col.s); value_col.len = strlen(value_col.s); type_col.len = strlen(type_col.s); username_col.len = strlen(username_col.s); domain_col.len = strlen(domain_col.s); /* search if any avp_db_* function is used */ for (i=0; cmds[i].name != NULL; i++) { if (strncasecmp(cmds[i].name, AVPDB, sizeof(AVPDB)-1) == 0 && (is_script_func_used(cmds[i].name, cmds[i].param_no))) { need_db=1; } } for (i=0; acmds[i].name != NULL; i++) { if (strncasecmp(acmds[i].name, AVPDB, sizeof(AVPDB)-1) == 0 && (is_script_async_func_used(acmds[i].name, acmds[i].param_no))) { need_db=1; } } if (need_db) { default_db_url = get_default_db_url(); if (default_db_url==NULL) { if (db_default_url==NULL) { LM_ERR("no DB URL provision into the module!\n"); return -1; } /* if nothing explicitly set as DB URL, add automatically * the default DB URL */ if (add_db_url(STR_PARAM, db_default_url)!=0) { LM_ERR("failed to use the default DB URL!\n"); return -1; } default_db_url = get_default_db_url(); if (default_db_url==NULL) { LM_BUG("Really ?!\n"); return -1; } } /* bind to the DB module */ if (avpops_db_bind()<0) goto error; init_store_avps(db_columns); } printbuf = (char*)pkg_malloc((buf_size+1)*sizeof(char)); if(printbuf==NULL) { LM_ERR("no pkg memory left\n"); return -1; } return 0; error: return -1; }
int solve_module_dependencies(struct sr_module *modules) { struct sr_module_dep *md, *it; struct sr_module *this, *mod; enum module_type mod_type; enum dep_type dep_type; int dep_solved; /* * now that we've loaded all shared libraries, * we can attempt to solve each dependency */ for (it = unsolved_deps.next; it; ) { md = it; it = it->next; LM_DBG("solving dependency %s -> %s %.*s\n", md->mod->exports->name, mod_type_to_string(md->mod_type), md->dep.len, md->dep.s); dep_type = md->type; /* * for generic dependencies (e.g. dialog depends on MOD_TYPE_SQLDB), * first load all modules of given type */ if (!md->dep.s) { this = md->mod; mod_type = md->mod_type; for (dep_solved = 0, mod = modules; mod; mod = mod->next) { if (mod != this && mod->exports->type == mod_type) { if (!md) { md = pkg_malloc(sizeof *md); if (!md) { LM_ERR("no more pkg\n"); return -1; } memset(md, 0, sizeof *md); } /* * re-purpose this structure by linking it into a module's * list of dependencies (will be used at init time) * * md->mod used to point to (highlighted with []): * [sr_module A] ---> "mod_name" * * now, the dependency is solved. md->mod will point to: * sr_module A ---> [sr_module B] */ md->mod = mod; md->next = this->sr_deps; this->sr_deps = md; md = NULL; dep_solved++; } } } else { for (dep_solved = 0, mod = modules; mod; mod = mod->next) { if (strcmp(mod->exports->name, md->dep.s) == 0) { /* quick sanity check */ if (mod->exports->type != md->mod_type) LM_BUG("[%.*s %d] -> [%s %d]\n", md->dep.len, md->dep.s, md->mod_type, mod->exports->name, mod->exports->type); /* same re-purposing technique as above */ md->next = md->mod->sr_deps; md->mod->sr_deps = md; md->mod = mod; dep_solved++; break; } } } /* treat unmet dependencies using the intended behaviour */ if (!dep_solved) { switch (dep_type) { case DEP_SILENT: LM_DBG("module %s depends on %s%s%s%.*s%s%s, but %s loaded!\n", md->mod->exports->name, md->dep.len == 0 ? ((md->mod_type == MOD_TYPE_SQLDB || md->mod_type == MOD_TYPE_AAA) ? "an " : md->mod_type == MOD_TYPE_CACHEDB ? "a " : "") : "", mod_type_to_string(md->mod_type), md->dep.len == 0 ? "" : " ", md->dep.len, md->dep.s, md->script_param ? " due to modparam " : "", md->script_param ? md->script_param : "", md->dep.len == 0 ? "none was" : "it was not"); break; case DEP_WARN: case DEP_ABORT: LM_WARN("module %s depends on %s%s%s%.*s%s%s, but %s loaded!\n", md->mod->exports->name, md->dep.len == 0 ? ((md->mod_type == MOD_TYPE_SQLDB || md->mod_type == MOD_TYPE_AAA) ? "an " : md->mod_type == MOD_TYPE_CACHEDB ? "a " : "") : "", mod_type_to_string(md->mod_type), md->dep.len == 0 ? "" : " ", md->dep.len, md->dep.s, md->script_param ? " due to modparam " : "", md->script_param ? md->script_param : "", md->dep.len == 0 ? "none was" : "it was not"); break; } pkg_free(md); if (dep_type == DEP_ABORT) return -1; } } return 0; }
enum async_ret_code resume_async_http_req(int fd, struct sip_msg *msg, void *_param) { CURLcode rc; CURLMcode mrc; rest_async_param *param = (rest_async_param *)_param; int running, max_fd; long http_rc; fd_set rset, wset, eset; pv_value_t val; mrc = curl_multi_perform(multi_handle, &running); if (mrc != CURLM_OK) { LM_ERR("curl_multi_perform: %s\n", curl_multi_strerror(mrc)); return -1; } LM_DBG("running handles: %d\n", running); if (running == running_handles) { async_status = ASYNC_CONTINUE; return 1; } if (running > running_handles) { LM_BUG("incremented handles!!"); /* default async status is DONE */ return -1; } running_handles = running; FD_ZERO(&rset); mrc = curl_multi_fdset(multi_handle, &rset, &wset, &eset, &max_fd); if (mrc != CURLM_OK) { LM_ERR("curl_multi_fdset: %s\n", curl_multi_strerror(mrc)); /* default async status is DONE */ return -1; } if (max_fd == -1) { if (running_handles != 0) { LM_BUG("running_handles == %d", running_handles); abort(); /* default async status is DONE */ return -1; } if (FD_ISSET(fd, &rset)) { LM_BUG("fd %d is still in rset!", fd); abort(); /* default async status is DONE */ return -1; } } else if (FD_ISSET(fd, &rset)) { LM_DBG("fd %d still transfering...\n", fd); async_status = ASYNC_CONTINUE; return 1; } if (del_transfer(fd) != 0) { LM_BUG("failed to delete fd %d", fd); abort(); /* default async status is DONE */ return -1; } mrc = curl_multi_remove_handle(multi_handle, param->handle); if (mrc != CURLM_OK) { LM_ERR("curl_multi_remove_handle: %s\n", curl_multi_strerror(mrc)); /* default async status is DONE */ return -1; } val.flags = PV_VAL_STR; val.rs = param->body; if (pv_set_value(msg, param->body_pv, 0, &val) != 0) LM_ERR("failed to set output body pv\n"); if (param->ctype_pv) { val.rs = param->ctype; if (pv_set_value(msg, param->ctype_pv, 0, &val) != 0) LM_ERR("failed to set output ctype pv\n"); } if (param->code_pv) { rc = curl_easy_getinfo(param->handle, CURLINFO_RESPONSE_CODE, &http_rc); if (rc != CURLE_OK) { LM_ERR("curl_easy_getinfo: %s\n", curl_easy_strerror(rc)); http_rc = 0; } LM_DBG("Last response code: %ld\n", http_rc); val.flags = PV_VAL_INT|PV_TYPE_INT; val.ri = (int)http_rc; if (pv_set_value(msg, param->code_pv, 0, &val) != 0) LM_ERR("failed to set output code pv\n"); } pkg_free(param->body.s); if (param->ctype_pv && param->ctype.s) pkg_free(param->ctype.s); curl_easy_cleanup(param->handle); pkg_free(param); /* default async status is DONE */ return 1; }
enum async_ret_code resume_async_http_req(int fd, struct sip_msg *msg, void *_param) { CURLcode rc; CURLMcode mrc; rest_async_param *param = (rest_async_param *)_param; int running = 0, max_fd; long http_rc; fd_set rset, wset, eset; pv_value_t val; int ret = 1, retr; CURLM *multi_handle; multi_handle = param->multi_list->multi_handle; retr = 0; do { mrc = curl_multi_perform(multi_handle, &running); if (mrc != CURLM_CALL_MULTI_PERFORM) break; LM_DBG("retry last perform...\n"); usleep(_async_resume_retr_itv); retr += _async_resume_retr_itv; } while (retr < _async_resume_retr_timeout); if (mrc != CURLM_OK) { LM_ERR("curl_multi_perform: %s\n", curl_multi_strerror(mrc)); return -1; } LM_DBG("running handles: %d\n", running); if (running == 1) { LM_DBG("transfer in progress...\n"); async_status = ASYNC_CONTINUE; return 1; } if (running != 0) { LM_BUG("non-zero running handles!! (%d)", running); abort(); } FD_ZERO(&rset); mrc = curl_multi_fdset(multi_handle, &rset, &wset, &eset, &max_fd); if (mrc != CURLM_OK) { LM_ERR("curl_multi_fdset: %s\n", curl_multi_strerror(mrc)); ret = -1; goto out; } if (max_fd == -1) { if (FD_ISSET(fd, &rset)) { LM_BUG("fd %d is still in rset!", fd); abort(); } } else if (FD_ISSET(fd, &rset)) { LM_DBG("fd %d still transferring...\n", fd); async_status = ASYNC_CONTINUE; return 1; } curl_slist_free_all(param->header_list); if (del_transfer(fd) != 0) { LM_BUG("failed to delete fd %d", fd); abort(); } mrc = curl_multi_remove_handle(multi_handle, param->handle); if (mrc != CURLM_OK) { LM_ERR("curl_multi_remove_handle: %s\n", curl_multi_strerror(mrc)); /* default async status is ASYNC_DONE */ return -1; } put_multi(param->multi_list); val.flags = PV_VAL_STR; val.rs = param->body; if (pv_set_value(msg, param->body_pv, 0, &val) != 0) LM_ERR("failed to set output body pv\n"); if (param->ctype_pv) { val.rs = param->ctype; if (pv_set_value(msg, param->ctype_pv, 0, &val) != 0) LM_ERR("failed to set output ctype pv\n"); } if (param->code_pv) { rc = curl_easy_getinfo(param->handle, CURLINFO_RESPONSE_CODE, &http_rc); if (rc != CURLE_OK) { LM_ERR("curl_easy_getinfo: %s\n", curl_easy_strerror(rc)); http_rc = 0; } LM_DBG("Last response code: %ld\n", http_rc); val.flags = PV_VAL_INT|PV_TYPE_INT; val.ri = (int)http_rc; if (pv_set_value(msg, param->code_pv, 0, &val) != 0) LM_ERR("failed to set output code pv\n"); } out: pkg_free(param->body.s); if (param->ctype_pv && param->ctype.s) pkg_free(param->ctype.s); curl_easy_cleanup(param->handle); if ( param->tparam ) { pkg_free( param->tparam ); } pkg_free(param); /* default async status is ASYNC_DONE */ return ret; }
int ws_process(struct tcp_connection *con) { struct ws_req *req; struct ws_req *newreq; long size = 0; enum ws_close_code ret_code = WS_ERR_NONE; unsigned char bk; char *msg_buf; int msg_len; struct receive_info local_rcv; if (con->con_req) { req=(struct ws_req *)con->con_req; LM_DBG("Using the per connection buff \n"); } else { LM_DBG("Using the global ( per process ) buff \n"); init_ws_req(&ws_current_req, 0); req=&ws_current_req; } again: if (req->tcp.error == TCP_REQ_OK) { if (req->tcp.parsed >= req->tcp.pos) { if (ws_raw_read(con, &req->tcp) < 0) { LM_ERR("failed to read %d:%s\n", errno, strerror(errno)); goto error; } } ret_code = ws_parse(req); if (ret_code) goto error; /* eof check: * is EOF if eof on fd and r. not complete yet, * if r. is complete we might have a second unparsed * request after it, so postpone release_with_eof */ if ((con->state==S_CONN_EOF) && (req->tcp.complete==0)) { LM_DBG("EOF received\n"); goto done; } /* sanity mask checks */ if ((WS_TYPE(con) == WS_CLIENT && req->is_masked) || (WS_TYPE(con) == WS_SERVER && !req->is_masked)) { LM_DBG("malformed WS msg - %s %s\n", req->is_masked ? "masked" : "not masked", WS_TYPE(con) == WS_CLIENT ? "client" : "server"); ret_code = WS_ERR_BADDATA; goto error; } } if (req->tcp.complete) { /* update the timeout - we succesfully read the request */ tcp_conn_set_lifetime(con, ws_send_timeout); con->timeout=con->lifetime; /* if we are here everything is nice and ok*/ update_stat( pt[process_no].load, +1 ); /* rcv.bind_address should always be !=0 */ bind_address=con->rcv.bind_address; con->rcv.proto_reserved1=con->id; /* copy the id */ size=req->tcp.pos-req->tcp.parsed; switch (req->op) { case WS_OP_CLOSE: if (req->tcp.content_len) { /* for now we are only interested in the code, not the reason */ ret_code = WS_CLOSE_CODE(req); switch(ret_code) { case WS_ERR_NORMAL: LM_DBG("Normal WebSocket close\n"); break; case WS_ERR_CLIENT: LM_DBG("Client error close\n"); break; case WS_ERR_PROTO: LM_DBG("WebSocket protocol error\n"); break; case WS_ERR_BADDATA: LM_DBG("Data type not consistent\n"); break; case WS_ERR_POLICY: LM_DBG("Bad policy close\n"); break; case WS_ERR_TOO_BIG: LM_DBG("Packet too big close\n"); break; case WS_ERR_BADEXT: LM_DBG("Bad extension close\n"); break; case WS_ERR_UNEXPECT: LM_DBG("Unexpected condition close\n"); break; default: LM_DBG("Unknown WebSocket close: %d\n", ret_code); } } else { ret_code = WS_ERR_NORMAL; } /* respond to close */ WS_CODE(con) = ret_code; ws_send_close(con); WS_CODE(con) = WS_ERR_NOSEND; /* release the connextion */ con->state = S_CONN_EOF; goto done; case WS_OP_PING: if (ws_send_pong(con, req) < 0) LM_ERR("cannot send PONG msg\n"); break; case WS_OP_PONG: LM_DBG("Received WebSocket PONG\n"); break; case WS_OP_TEXT: case WS_OP_BIN: bk = *req->tcp.parsed; *req->tcp.parsed = 0; msg_buf = req->tcp.body; msg_len = req->tcp.parsed-req->tcp.body; local_rcv = con->rcv; if (!size) { /* did not read any more things - we can release * the connection */ LM_DBG("We're releasing the connection in state %d \n", con->state); if (req != &ws_current_req) { /* we have the buffer in the connection tied buff - * detach it , release the conn and free it afterwards */ con->con_req = NULL; } /* TODO - we could indicate to the TCP net layer to release * the connection -> other worker may read the next available * message on the pipe */ } else { LM_DBG("We still have things on the pipe - " "keeping connection \n"); } if (receive_msg(msg_buf, msg_len, &local_rcv) <0) LM_ERR("receive_msg failed \n"); *req->tcp.parsed = bk; break; default: LM_BUG("Can't handle %d\n", req->op); goto error; } update_stat( pt[process_no].load, -1 ); if (size) memmove(req->tcp.buf, req->tcp.parsed, size); #ifdef EXTRA_DEBUG LM_DBG("preparing for new request, kept %ld bytes\n", size); #endif init_ws_req(req, size); con->msg_attempts = 0; /* if we still have some unparsed bytes, try to parse them too*/ if (size) goto again; /* cleanup the existing request */ if (req != &ws_current_req) pkg_free(req); } else { /* request not complete - check the if the thresholds are exceeded */ con->msg_attempts++; if (con->msg_attempts == ws_max_msg_chunks) { LM_ERR("Made %u read attempts but message is not complete yet - " "closing connection \n",con->msg_attempts); goto error; } if (req == &ws_current_req) { /* let's duplicate this - most likely another conn will come in */ LM_DBG("We didn't manage to read a full request\n"); newreq = pkg_malloc(sizeof(struct ws_req)); if (newreq == NULL) { LM_ERR("No more mem for dynamic con request buffer\n"); goto error; } if (req->tcp.pos != req->tcp.buf) { /* we have read some bytes */ memcpy(newreq->tcp.buf,req->tcp.buf,req->tcp.pos-req->tcp.buf); newreq->tcp.pos = newreq->tcp.buf + (req->tcp.pos-req->tcp.buf); } else { newreq->tcp.pos = newreq->tcp.buf; } if (req->tcp.start != req->tcp.buf) newreq->tcp.start = newreq->tcp.buf +(req->tcp.start-req->tcp.buf); else newreq->tcp.start = newreq->tcp.buf; if (req->tcp.parsed != req->tcp.buf) newreq->tcp.parsed =newreq->tcp.buf+(req->tcp.parsed-req->tcp.buf); else newreq->tcp.parsed = newreq->tcp.buf; if (req->tcp.body != 0) { newreq->tcp.body = newreq->tcp.buf + (req->tcp.body-req->tcp.buf); } else newreq->tcp.body = 0; newreq->tcp.complete=req->tcp.complete; newreq->tcp.has_content_len=req->tcp.has_content_len; newreq->tcp.content_len=req->tcp.content_len; newreq->tcp.bytes_to_go=req->tcp.bytes_to_go; newreq->tcp.error = req->tcp.error; newreq->tcp.state = req->tcp.state; newreq->op = req->op; newreq->mask = req->mask; newreq->is_masked = req->is_masked; con->con_req = (struct tcp_req *)newreq; } } LM_DBG("ws_read end\n"); done: /* connection will be released */ return size; error: WS_CODE(con) = ret_code; if (WS_CODE(con) != WS_ERR_NONE) { ws_send_close(con); WS_CODE(con) = WS_ERR_NOSEND; } return -1; }