/*! Run a query based on a connection definition */ int curl_get_redirect(struct sip_msg* _m, const str *connection, str* result) { curl_con_t *conn = NULL; curl_con_pkg_t *pconn = NULL; str rval; result->s = NULL; result->len = 0; /* Find connection if it exists */ if (!connection) { LM_ERR("No cURL connection specified\n"); return -1; } LM_DBG("******** CURL Connection %.*s\n", connection->len, connection->s); conn = curl_get_connection((str*)connection); if (conn == NULL) { LM_ERR("No cURL connection found: %.*s\n", connection->len, connection->s); return -1; } pconn = curl_get_pkg_connection(conn); if (pconn == NULL) { LM_ERR("No cURL connection data found: %.*s\n", connection->len, connection->s); return -1; } /* Create a STR object */ rval.s = pconn->redirecturl; rval.len = strlen(pconn->redirecturl); /* Duplicate string to return */ pkg_str_dup(result, &rval); LM_DBG("curl last redirect URL: Length %d %.*s \n", rval.len, rval.len, rval.s); return 1; }
int cl_get_my_sip_addr(int cluster_id, str *out_addr) { cluster_info_t *cl; int rc; if (!cl_list_lock) { LM_ERR("cluster shutdown\n"); memset(out_addr, 0, sizeof *out_addr); return -1; } lock_start_read(cl_list_lock); cl = get_cluster_by_id(cluster_id); if (!cl) { LM_ERR("unknown cluster id: %d\n", cluster_id); lock_stop_read(cl_list_lock); memset(out_addr, 0, sizeof *out_addr); return -1; } lock_get(cl->current_node->lock); if (ZSTR(cl->current_node->sip_addr)) { memset(out_addr, 0, sizeof *out_addr); rc = 0; } else { if (pkg_str_dup(out_addr, &cl->current_node->sip_addr) != 0) { LM_ERR("oom\n"); memset(out_addr, 0, sizeof *out_addr); rc = -1; } else { rc = 0; } } lock_release(cl->current_node->lock); lock_stop_read(cl_list_lock); return rc; }
/** * This function convert the rows returned in CQL query * and adds the values to the returning result structure. * * Handle CQLresult * \param _cql_res handle for the CQLResult * \param _r result set for storage * \return zero on success, negative value on failure */ int cql_convert_row(oac::CqlResult& _cql_res, db1_res_t* _r) { std::vector<oac::CqlRow> res_cql_rows = _cql_res.rows; int rows_no = res_cql_rows.size(); int cols_no = res_cql_rows[0].columns.size(); str col_val; RES_ROW_N(_r) = rows_no; if (db_allocate_rows(_r) < 0) { LM_ERR("Could not allocate rows.\n"); return -1; } for(int ri=0; ri < rows_no; ri++) { if (db_allocate_row(_r, &(RES_ROWS(_r)[ri])) != 0) { LM_ERR("Could not allocate row.\n"); return -2; } /* complete the row with the columns */ for(int col = 0; col< cols_no; col++) { RES_ROWS(_r)[ri].values[col].type = DB1_STR; col_val.s = (char*)res_cql_rows[ri].columns[col].value.c_str(); col_val.len = strlen(col_val.s); pkg_str_dup(&RES_ROWS(_r)[ri].values[col].val.str_val, &col_val); RES_ROWS(_r)[ri].values[col].free = 1; RES_ROWS(_r)[ri].values[col].nul = 0; LM_DBG("Field index %d. %s = %s.\n", col, res_cql_rows[ri].columns[col].name.c_str(), res_cql_rows[ri].columns[col].value.c_str()); } } return 0; }
static int cassa_convert_result_raw(db_val_t* sr_cell, str *col_val) { if(!col_val->s) { LM_DBG("Column not found in result - NULL\n"); sr_cell->nul = 1; return 0; } col_val->len = strlen(col_val->s); sr_cell->nul = 0; sr_cell->free = 0; switch (sr_cell->type) { case DB1_INT: if(str2int(col_val, (unsigned int*)&sr_cell->val.int_val) < 0) { LM_ERR("Wrong value [%s] - len=%d, expected integer\n", col_val->s, col_val->len); return -1; } break; case DB1_BIGINT: if(sscanf(col_val->s, "%lld", &sr_cell->val.ll_val) < 0) { LM_ERR("Wrong value [%s], expected integer\n", col_val->s); return -1; } break; case DB1_DOUBLE: if(sscanf(col_val->s, "%lf", &sr_cell->val.double_val) < 0) { LM_ERR("Wrong value [%s], expected integer\n", col_val->s); return -1; } break; case DB1_STR: pkg_str_dup(&sr_cell->val.str_val, col_val); sr_cell->free = 1; break; case DB1_STRING: col_val->len++; pkg_str_dup(&sr_cell->val.str_val, col_val); sr_cell->val.str_val.len--; sr_cell->val.str_val.s[col_val->len-1]='\0'; sr_cell->free = 1; break; case DB1_BLOB: pkg_str_dup(&sr_cell->val.blob_val, col_val); sr_cell->free = 1; break; case DB1_BITMAP: if(str2int(col_val, &sr_cell->val.bitmap_val) < 0) { LM_ERR("Wrong value [%s], expected integer\n", col_val->s); return -1; } break; case DB1_DATETIME: if(sscanf(col_val->s, "%ld", (long int*)&sr_cell->val.time_val) < 0) { LM_ERR("Wrong value [%s], expected integer\n", col_val->s); return -1; } break; } return 0; }
static int cassa_convert_result(db_key_t qcol, std::vector<oac::ColumnOrSuperColumn> result, int r_si, int r_fi, int prefix_len, db_val_t* sr_cell) { str col_val; int idx_rescol; oac::Column res_col; idx_rescol = cassa_get_res_col(result, r_si, r_fi, prefix_len, qcol); if(idx_rescol< 0) { LM_DBG("Column not found in result %.*s\n", qcol->len, qcol->s); sr_cell->nul = 1; return 0; } res_col = result[idx_rescol].column; col_val.s = (char*)res_col.value.c_str(); if(!col_val.s) { LM_DBG("Column not found in result %.*s- NULL\n", qcol->len, qcol->s); sr_cell->nul = 1; return 0; } col_val.len = strlen(col_val.s); sr_cell->nul = 0; sr_cell->free = 0; switch (sr_cell->type) { case DB1_INT: if(str2int(&col_val, (unsigned int*)&sr_cell->val.int_val) < 0) { LM_ERR("Wrong value [%s] - len=%d, expected integer\n", col_val.s, col_val.len); return -1; } break; case DB1_BIGINT: if(sscanf(col_val.s, "%lld", &sr_cell->val.ll_val) < 0) { LM_ERR("Wrong value [%s], expected integer\n", col_val.s); return -1; } break; case DB1_DOUBLE: if(sscanf(col_val.s, "%lf", &sr_cell->val.double_val) < 0) { LM_ERR("Wrong value [%s], expected integer\n", col_val.s); return -1; } break; case DB1_STR: pkg_str_dup(&sr_cell->val.str_val, &col_val); sr_cell->free = 1; break; case DB1_STRING: col_val.len++; pkg_str_dup(&sr_cell->val.str_val, &col_val); sr_cell->val.str_val.len--; sr_cell->val.str_val.s[col_val.len-1]='\0'; sr_cell->free = 1; break; case DB1_BLOB: pkg_str_dup(&sr_cell->val.blob_val, &col_val); sr_cell->free = 1; break; case DB1_BITMAP: if(str2int(&col_val, &sr_cell->val.bitmap_val) < 0) { LM_ERR("Wrong value [%s], expected integer\n", col_val.s); return -1; } break; case DB1_DATETIME: if(sscanf(col_val.s, "%ld", (long int*)&sr_cell->val.time_val) < 0) { LM_ERR("Wrong value [%s], expected integer\n", col_val.s); return -1; } break; } return 0; }
/* * Insert or update the table for specified row key * _h: structure representing database connection * _k: key names * _op: operators * _v: values of the keys that must match * _uk: column names to update * _uv: values for the columns to update * _n: number of key=values pairs to compare * _un: number of columns to update */ int db_cassa_modify(const db1_con_t* _h, const db_key_t* _k, const db_val_t* _v, const db_key_t* _uk, const db_val_t* _uv, int _n, int _un) { dbcassa_table_p tbc; char row_key[cassa_max_key_len]; char sec_key[cassa_max_key_len]; int64_t ts = 0; str ts_col_name={0, 0}; int seckey_len; unsigned int curr_time = time(NULL); if (!_h || !CON_TABLE(_h) || !_k || !_v) { LM_ERR("invalid parameter value\n"); return -1; } LM_DBG("modify table=%s\n", _h->table->s); /** Lock table schema and construct primary and secondary key **/ tbc = dbcassa_db_get_table(&CON_CASSA(_h)->db_name, CON_TABLE(_h)); if(!tbc) { LM_ERR("table %.*s does not exist!\n", CON_TABLE(_h)->len, CON_TABLE(_h)->s); return -1; } if(tbc->ts_col) pkg_str_dup(&ts_col_name, (const str*)&tbc->ts_col->name); cassa_constr_key(_k, _v, _n, tbc->key_len, tbc->key, 0, row_key); cassa_constr_key(_k, _v, _n, tbc->seckey_len, tbc->sec_key, 0, sec_key); seckey_len = tbc->seckey_len; dbcassa_lock_release(tbc); /** Construct and send the query to Cassandra Cluster **/ try { /* Set the columns */ std::vector<oac::Mutation> mutations; for(int i=0; i< _un; i++) { if(_uv[i].nul) continue; std::stringstream out; std::string value; int cont = 0; switch(_uv[i].type) { case DB1_INT: out << _uv[i].val.int_val; value = out.str(); break; case DB1_BIGINT:out << _uv[i].val.ll_val; value = out.str(); break; case DB1_DOUBLE:out << _uv[i].val.double_val; value = out.str(); break; case DB1_BITMAP:out << _uv[i].val.bitmap_val; value = out.str(); break; case DB1_STRING:value = _uv[i].val.string_val; break; case DB1_STR: if(!_uv[i].val.str_val.s) { cont = 1; break; } value = std::string(_uv[i].val.str_val.s, _uv[i].val.str_val.len); break; case DB1_BLOB: value = std::string(_uv[i].val.blob_val.s, _uv[i].val.blob_val.len); break; case DB1_DATETIME: unsigned int exp_time = (unsigned int)_uv[i].val.time_val; out << exp_time; value = out.str(); if(ts_col_name.s && ts_col_name.len==_uk[i]->len && strncmp(ts_col_name.s, _uk[i]->s, ts_col_name.len)==0) { ts = exp_time; LM_DBG("Found timestamp col [%.*s]\n", ts_col_name.len, ts_col_name.s); } break; } if (cont) continue; LM_DBG("ADDED column [%.*s] type [%d], value [%s]\n", _uk[i]->len, _uk[i]->s, _uv[i].type, value.c_str()); oac::Mutation mut; oac::ColumnOrSuperColumn col; if(seckey_len) { col.column.name = sec_key; col.column.name.push_back(cassa_key_delim); col.column.name.append(_uk[i]->s); } else col.column.name = _uk[i]->s; col.column.value = value; col.column.__isset.value = true; col.__isset.column = true; col.column.timestamp = curr_time; col.column.__isset.timestamp = true; mut.column_or_supercolumn = col; mut.__isset.column_or_supercolumn = true; mutations.push_back(mut); } if(ts_col_name.s) pkg_free(ts_col_name.s); ts_col_name.s = 0; if(ts) { int32_t ttl = ts - curr_time; LM_DBG("Set expires to %d seconds\n", ttl); for(size_t mi=0; mi< mutations.size(); mi++) { mutations[mi].column_or_supercolumn.column.ttl = ttl; mutations[mi].column_or_supercolumn.column.__isset.ttl = true; } } LM_DBG("Perform the mutation, add [%d] columns\n", (int)mutations.size()); std::map<std::string, std::vector<oac::Mutation> > innerMap; innerMap.insert(std::pair<std::string, std::vector<oac::Mutation> > (_h->table->s, mutations)); std::map <std::string, std::map<std::string, std::vector<oac::Mutation> > > CFMap; CFMap.insert(std::pair<std::string, std::map<std::string, std::vector<oac::Mutation> > >(row_key, innerMap)); unsigned int retr = 0; do { if(CON_CASSA(_h)->con) { try{ CON_CASSA(_h)->con->batch_mutate(CFMap, oac::ConsistencyLevel::ONE); return 0; } catch (const att::TTransportException &tx) { LM_ERR("Failed to query: %s\n", tx.what()); } } dbcassa_reconnect(CON_CASSA(_h)); } while (cassa_auto_reconnect && retr++ < cassa_retries); LM_ERR("Failed to connect, retries exceeded.\n"); } catch (const oac::InvalidRequestException ir) { LM_ERR("Failed Invalid query request: %s\n", ir.why.c_str()); } catch (const at::TException &tx) { LM_ERR("Failed generic Thrift error: %s\n", tx.what()); } catch (const std::exception &ex) { LM_ERR("Failed std error: %s\n", ex.what()); } catch (...) { LM_ERR("Failed generic error\n"); } LM_ERR("Insert/Update query failed\n"); return -1; }
/** * @brief build a dmq node */ dmq_node_t *build_dmq_node(str *uri, int shm) { dmq_node_t *ret = NULL; param_hooks_t hooks; param_t *params; /* For DNS-Lookups */ static char hn[256]; struct hostent *he; LM_DBG("build_dmq_node %.*s with %s memory\n", STR_FMT(uri), shm ? "shm" : "private"); if(shm) { ret = shm_malloc(sizeof(dmq_node_t)); if(ret == NULL) { LM_ERR("no more shm\n"); goto error; } memset(ret, 0, sizeof(dmq_node_t)); if(shm_str_dup(&ret->orig_uri, uri) < 0) { goto error; } } else { ret = pkg_malloc(sizeof(dmq_node_t)); if(ret == NULL) { LM_ERR("no more pkg\n"); goto error; } memset(ret, 0, sizeof(dmq_node_t)); if(pkg_str_dup(&ret->orig_uri, uri) < 0) { goto error; } } set_default_dmq_node_params(ret); if(parse_uri(ret->orig_uri.s, ret->orig_uri.len, &ret->uri) < 0 || ret->uri.host.len > 254) { LM_ERR("error parsing uri\n"); goto error; } /* if any parameters found, parse them */ if(parse_params(&ret->uri.params, CLASS_ANY, &hooks, ¶ms) < 0) { LM_ERR("error parsing params\n"); goto error; } /* if any params found */ if(params) { if(set_dmq_node_params(ret, params) < 0) { free_params(params); LM_ERR("error setting parameters\n"); goto error; } free_params(params); } else { LM_DBG("no dmqnode params found\n"); } /* resolve hostname */ strncpy(hn, ret->uri.host.s, ret->uri.host.len); hn[ret->uri.host.len] = '\0'; he = resolvehost(hn); if(he == 0) { LM_ERR("could not resolve %.*s\n", ret->uri.host.len, ret->uri.host.s); goto error; } hostent2ip_addr(&ret->ip_address, he, 0); return ret; error: if(ret != NULL) { destroy_dmq_node(ret, shm); } return NULL; }
/*! Send query to server, optionally post data. */ static int curL_query_url(struct sip_msg* _m, const char* _url, str* _dst, const curl_query_t * const params) { CURL *curl = NULL;; CURLcode res; char *at = NULL; curl_res_stream_t stream; long stat; str rval; double download_size; struct curl_slist *headerlist = NULL; memset(&stream, 0, sizeof(curl_res_stream_t)); stream.max_size = (size_t) params->maxdatasize; if(params->pconn) { LM_DBG("****** ##### We have a pconn - keep_connections: %d!\n", params->keep_connections); params->pconn->result_content_type[0] = '\0'; params->pconn->redirecturl[0] = '\0'; if (params->pconn->curl != NULL) { LM_DBG(" ****** ##### Reusing existing connection if possible\n"); curl = params->pconn->curl; /* Reuse existing handle */ curl_easy_reset(curl); /* Reset handle */ } } if (curl == NULL) { curl = curl_easy_init(); } if (curl == NULL) { LM_ERR("Failed to initialize curl connection\n"); return -1; } LM_DBG("****** ##### CURL URL [%s] \n", _url); res = curl_easy_setopt(curl, CURLOPT_URL, _url); /* Limit to HTTP and HTTPS protocols */ res = curl_easy_setopt(curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); res = curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); if (params->post) { char ctype[256]; ctype[0] = '\0'; snprintf(ctype, sizeof(ctype), "Content-Type: %s", params->contenttype); /* Now specify we want to POST data */ res |= curl_easy_setopt(curl, CURLOPT_POST, 1L); /* Set the content-type of the DATA */ headerlist = curl_slist_append(headerlist, ctype); res |= curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); /* Tell CURL we want to upload using POST */ res |= curl_easy_setopt(curl, CURLOPT_POSTFIELDS, params->post); } else { /* Reset post option */ res |= curl_easy_setopt(curl, CURLOPT_POST, 0L); } if (params->maxdatasize) { /* Maximum data size to download - we always download full response, but cut it off before moving to pvar */ LM_DBG("****** ##### CURL Max datasize %u\n", params->maxdatasize); } if (params->username) { res |= curl_easy_setopt(curl, CURLOPT_USERNAME, params->username); res |= curl_easy_setopt(curl, CURLOPT_HTTPAUTH, params->authmethod); } if (params->secret) { res |= curl_easy_setopt(curl, CURLOPT_PASSWORD, params->secret); } /* Client certificate */ if (params->clientcert != NULL && params->clientkey != NULL) { res |= curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM"); res |= curl_easy_setopt(curl, CURLOPT_SSLCERT, params->clientcert); res |= curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM"); res |= curl_easy_setopt(curl, CURLOPT_SSLKEY, params->clientkey); } if (params->cacert != NULL) { res |= curl_easy_setopt(curl, CURLOPT_CAINFO, params->cacert); } if (params->tlsversion != CURL_SSLVERSION_DEFAULT) { res |= curl_easy_setopt(curl, CURLOPT_SSLVERSION, (long) params->tlsversion); } if (params->ciphersuites != NULL) { res |= curl_easy_setopt(curl, CURLOPT_SSL_CIPHER_LIST, params->ciphersuites); } if (params->http_proxy != NULL) { LM_DBG("****** ##### CURL proxy [%s] \n", params->http_proxy); res |= curl_easy_setopt(curl, CURLOPT_PROXY, params->http_proxy); } else { LM_DBG("****** ##### CURL proxy NOT SET \n"); } if (params->http_proxy_port > 0) { res |= curl_easy_setopt(curl, CURLOPT_PROXYPORT, params->http_proxy_port); } res |= curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, (long) params->verify_peer); res |= curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, (long) params->verify_host?2:0); res |= curl_easy_setopt(curl, CURLOPT_NOSIGNAL, (long) 1); res |= curl_easy_setopt(curl, CURLOPT_TIMEOUT, (long) params->timeout); res |= curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, (long) params->http_follow_redirect); if (params->http_follow_redirect) { LM_DBG("****** ##### Following redirects for this request! \n"); } res |= curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_function); res |= curl_easy_setopt(curl, CURLOPT_WRITEDATA, &stream); if (res != CURLE_OK) { /* PANIC */ LM_ERR("Could not set CURL options. Library error \n"); } else { double totaltime, connecttime; res = curl_easy_perform(curl); curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &totaltime); curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME, &connecttime); LM_DBG("**** HTTP Call performed in %f s (connect time %f) \n", totaltime, connecttime); if (params->pconn) { params->pconn->querytime = totaltime; params->pconn->connecttime = connecttime; } } /* Cleanup */ if (headerlist) { curl_slist_free_all(headerlist); } if (res != CURLE_OK) { /* http://curl.haxx.se/libcurl/c/libcurl-errors.html */ if (res == CURLE_COULDNT_CONNECT) { LM_WARN("failed to connect() to host\n"); } else if ( res == CURLE_COULDNT_RESOLVE_HOST ) { LM_WARN("Couldn't resolve host\n"); } else if ( res == CURLE_COULDNT_RESOLVE_PROXY ) { LM_WARN("Couldn't resolve http_proxy host\n"); } else if ( res == CURLE_UNSUPPORTED_PROTOCOL ) { LM_WARN("URL Schema not supported by curl\n"); } else if ( res == CURLE_URL_MALFORMAT ) { LM_WARN("Malformed URL used in http_client\n"); } else if ( res == CURLE_OUT_OF_MEMORY ) { LM_WARN("Curl library out of memory\n"); } else if ( res == CURLE_OPERATION_TIMEDOUT ) { LM_WARN("Curl library timed out on request\n"); } else if ( res == CURLE_SSL_CONNECT_ERROR ) { LM_WARN("TLS error in curl connection\n"); } else if ( res == CURLE_SSL_CERTPROBLEM ) { LM_WARN("TLS local certificate error\n"); } else if ( res == CURLE_SSL_CIPHER ) { LM_WARN("TLS cipher error\n"); } else if ( res == CURLE_SSL_CACERT ) { LM_WARN("TLS server certificate validation error (No valid CA cert)\n"); } else if ( res == CURLE_SSL_CACERT_BADFILE ) { LM_WARN("TLS CA certificate read error \n"); } else if ( res == CURLE_SSL_ISSUER_ERROR ) { LM_WARN("TLS issuer certificate check error \n"); } else if ( res == CURLE_PEER_FAILED_VERIFICATION ) { LM_WARN("TLS verification error\n"); } else if ( res == CURLE_TOO_MANY_REDIRECTS ) { LM_WARN("Too many redirects\n"); } else { LM_ERR("failed to perform curl (%d)\n", res); } if (params->pconn) { params->pconn->last_result = res; } if (params->pconn && params->keep_connections) { params->pconn->curl = curl; /* Save connection, don't close */ } else { /* Cleanup and close - bye bye and thank you for all the bytes */ curl_easy_cleanup(curl); } if(stream.buf) { pkg_free(stream.buf); } counter_inc(connfail); if (params->failovercon != NULL) { LM_ERR("FATAL FAILURE: Trying failover to curl con (%s)\n", params->failovercon); return (1000 + res); } return res; } /* HTTP_CODE CHANGED TO CURLINFO_RESPONSE_CODE in curl > 7.10.7 */ curl_easy_getinfo(curl, CURLINFO_HTTP_CODE, &stat); if(res == CURLE_OK) { char *ct; char *url; /* ask for the content-type of the response */ res = curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &ct); res |= curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url); if(ct) { LM_DBG("We received Content-Type: %s\n", ct); if (params->pconn) { strncpy(params->pconn->result_content_type, ct, sizeof(params->pconn->result_content_type)); } } if(url) { LM_DBG("We visited URL: %s\n", url); if (params->pconn) { strncpy(params->pconn->redirecturl, url , sizeof(params->pconn->redirecturl)); } } } if (params->pconn) { params->pconn->last_result = stat; } if ((stat >= 200) && (stat < 500)) { double datasize = download_size; curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &download_size); LM_DBG(" -- curl download size: %u \n", (unsigned int)download_size); if (download_size > 0) { if (params->oneline) { /* search for line feed */ at = memchr(stream.buf, (char)10, download_size); datasize = (double) (at - stream.buf); LM_DBG(" -- curl download size cut to first line: %d \n", (int) datasize); } if (at == NULL) { if (params->maxdatasize && ((unsigned int) download_size) > params->maxdatasize) { /* Limit at maximum data size */ datasize = (double) params->maxdatasize; LM_DBG(" -- curl download size cut to maxdatasize : %d \n", (int) datasize); } else { /* Limit at actual downloaded data size */ datasize = (double) download_size; LM_DBG(" -- curl download size cut to download_size : %d \n", (int) datasize); //at = stream.buf + (unsigned int) download_size; } } /* Create a STR object */ rval.s = stream.buf; rval.len = datasize; /* Duplicate string to return */ pkg_str_dup(_dst, &rval); LM_DBG("curl query result: Length %d %.*s \n", rval.len, rval.len, rval.s); } else { _dst->s = NULL; _dst->len = 0; } } if (stat == 200) { counter_inc(connok); } else { counter_inc(connfail); if (stat >= 500) { if (params->failovercon != NULL) { LM_ERR("FAILURE: Trying failover to curl con (%s)\n", params->failovercon); return (1000 + stat); } } } /* CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ... ); */ if (params->pconn && params->keep_connections) { params->pconn->curl = curl; /* Save connection, don't close */ } else { curl_easy_cleanup(curl); } if (stream.buf != NULL) { pkg_free(stream.buf); } return stat; }
/** * sngtc_caller_answer - attaches an SDP body to ACK requests */ static int sngtc_caller_answer(struct sip_msg *msg) { char *p; str body; struct dlg_cell *dlg; struct lump *lump; struct sngtc_info *info; int len; LM_DBG("processing ACK\n"); if (get_body(msg, &body) != 0 || body.len > 0) { LM_ERR("ACK should not contain a SDP body\n"); return SNGTC_ERR; } dlg = dlg_binds.get_dlg(); if (!dlg) { LM_ERR("failed to fetch current dialog\n"); return SNGTC_ERR; } /* get the SDP body from the INVITE which was mangled at 200 OK */ if (dlg_binds.fetch_dlg_value(dlg, &dlg_key_sngtc_info, &body, 0) != 0) { LM_ERR("failed to fetch caller sdp\n"); return SNGTC_ERR; } info = *(struct sngtc_info **)(body.s); /* duplicate the SDP in pkg mem for the lumps mechanism */ if (pkg_str_dup(&body, &info->modified_caller_sdp) != 0) { LM_ERR("failed to dup in pkg mem\n"); return SNGTC_ERR; } LM_DBG("Duplicated SDP: '%.*s'\n", body.len, body.s); lump = anchor_lump(msg, msg->content_length->name.s - msg->buf, 0); if (!lump) { LM_ERR("failed to insert anchor lump\n"); return SNGTC_ERR; } p = pkg_malloc(SDP_CONTENT_TYPE_LEN); if (!p) { LM_ERR("no more pkg memory\n"); return SNGTC_ERR; } /* add the Content-Type header */ memcpy(p, "Content-Type: application/sdp\r\n", SDP_CONTENT_TYPE_LEN); if (!insert_new_lump_before(lump, p, SDP_CONTENT_TYPE_LEN, 0)) { LM_ERR("failed to insert Content-Type lump\n"); return SNGTC_ERR; } LM_DBG("blen: %d\n", msg->content_length->body.len); lump = del_lump(msg, msg->content_length->body.s - msg->buf, msg->content_length->body.len, HDR_OTHER_T); if (!lump) { LM_ERR("failed to insert del lump for the content length\n"); return SNGTC_ERR; } p = pkg_malloc(CONTENT_LEN_DIGITS); if (!p) { LM_ERR("no more pkg memory\n"); return SNGTC_ERR; } LM_DBG("len: %d\n", body.len); len = sprintf(p, "%d", body.len); if (!insert_new_lump_after(lump, p, len, HDR_OTHER_T)) { LM_ERR("failed to insert Content-Length lump\n"); return SNGTC_ERR; } lump = anchor_lump(msg, msg->len - CRLF_LEN, 0); if (!lump) { LM_ERR("failed to insert anchor lump\n"); return SNGTC_ERR; } if (!insert_new_lump_before(lump, body.s, body.len, 0)) { LM_ERR("failed to insert SDP body lump\n"); return SNGTC_ERR; } return 1; }
/** * performs the following operations at 200 OK time (early neg <-> late neg): * * - alters the callee's 200 OK message (adds the final decided codec) * - alters the caller's SDP (in memory), so it can be attached @ ACK * - opens transcoding sessions on the card if necessary * * Note: assumes all streams are on corresponding positions in both SDPs */ static int process_session(struct sip_msg *msg, struct sngtc_info *info, str *src, str *dst, struct sdp_session_cell *s1, struct sdp_session_cell *s2) { struct sdp_stream_cell *sm1, *sm2; struct sngtc_session_list *tc_session; struct sngtc_codec_request request; struct sngtc_codec_reply *reply = NULL; struct codec_pair pair; struct lump *lump, *nl; struct in_addr addr; int rc = 0, ret, tc_on = 0; int idx; char buf[INET_ADDRSTRLEN]; str repl; if (s1->next && s2->next) rc = process_session(msg, info, src, dst, s1->next, s2->next); else if (s1->next || s2->next) LM_ERR("endpoints have a different number of SDP sessions" " - choosing min number\n"); if (rc != 0) goto out; tc_session = info->sessions; for (idx = MAX_STREAMS - 1, sm1 = s1->streams, sm2 = s2->streams; sm1 && sm2; sm1 = sm1->next, sm2 = sm2->next, idx--) { ret = match_codecs(sm1, sm2, &pair); codec_matches[idx] = pair; switch (ret) { case SNGTC_OFF: LM_DBG("NO NEED FOR TRANSCODING\n"); /* delete codecs from 200 OK; write endpoint A codec */ /* ip and port stay the same */ lump = remove_sdp_stream_attrs(msg, sm2); if (!lump) { LM_ERR("failed to clear sdp codecs\n"); return SNGTC_SDP_ERR; } LM_DBG("sdp stream:\n"); print_sdp_stream(sm2, L_DBG); ret = write_sdp_stream_attr(msg, lump, pair.att2, NULL); if (ret != 0) { LM_ERR("failed to write sdp stream codec\n"); return ret; } break; case SNGTC_ON: tc_on = 1; if (is_processed(info)) goto use_existing_sessions; LM_DBG("TRANSCODING ([%d] %.*s:%.*s <--> [%d] %.*s:%.*s)\n", pair.tc1, s1->ip_addr.len, s1->ip_addr.s, sm1->port.len, sm1->port.s, pair.tc2, s2->ip_addr.len, s2->ip_addr.s, sm2->port.len, sm2->port.s); memset(&request, 0, sizeof(request)); request.usr_priv = NULL; /* Codec, ms, IP and port for side A */ request.a.codec_id = pair.tc1; request.a.ms = 0; sprintf(buf, "%.*s", s1->ip_addr.len, s1->ip_addr.s); ret = inet_pton(AF_INET, buf, &addr); if (ret != 1) { LM_ERR("failed to convert ip %s to binary form (%d)\n", s1->ip_addr.s, ret); return SNGTC_ERR; } request.a.host_ip = htonl(addr.s_addr); request.a.host_netmask = (unsigned int)-1; if (str2int(&sm1->port, &request.a.host_udp_port) != 0) LM_ERR("Failed to parse integer stored in port str '%.*s'\n", sm1->port.len, sm1->port.s); /* Codec, ms, IP and port for side B */ request.b.codec_id = pair.tc2; request.b.ms = 0; sprintf(buf, "%.*s", s2->ip_addr.len, s2->ip_addr.s); ret = inet_pton(AF_INET, buf, &addr); if (ret != 1) { LM_ERR("failed to convert ip %.*s to binary form (%d)\n", s2->ip_addr.len, s2->ip_addr.s, ret); return SNGTC_ERR; } request.b.host_ip = htonl(addr.s_addr); request.b.host_netmask = (unsigned int)-1; if (str2int(&sm2->port, &request.b.host_udp_port) != 0) LM_ERR("Failed to parse integer stored in port str '%.*s'\n", sm2->port.len, sm2->port.s); LM_DBG("Transcoding request: %d:%d <--> %d:%d\n", request.a.host_ip, request.a.host_udp_port, request.b.host_ip, request.b.host_udp_port); reply = create_transcoding_session(&request, info); if (!reply) { LM_ERR("Failed to create a transcoding session on the card\n"); return SNGTC_TC_ERR; } use_existing_sessions: LM_DBG("NEW TC SESSION!\n"); if (is_processed(info)) { reply = tc_session->reply; tc_session = tc_session->next; } codec_matches[idx].reply = reply; /** * delete codecs from 200 OK * write the common codec * replace IP with ip of Sangoma card * replace port with endpoint A newly opened port on card */ lump = remove_sdp_stream_attrs(msg, sm2); if (!lump) { LM_ERR("failed to clear sdp codecs\n"); return SNGTC_SDP_ERR; } nl = del_lump(msg, s2->ip_addr.s - msg->buf, s2->ip_addr.len, 0); if (!nl) { LM_ERR("failed to add del lump\n"); return SNGTC_ERR; } if (pkg_str_dup(&repl, &card_ip_b) != 0) { LM_ERR("failed to dup in pkg mem\n"); return SNGTC_ERR; } if (!insert_new_lump_after(nl, repl.s, repl.len, HDR_OTHER_T)) { LM_ERR("failed to insert lump with codec result\n"); return SNGTC_ERR; } if (replace_sdp_stream_port(msg, sm2, reply->a.codec_udp_port) != 0) { LM_ERR("failed to rewrite sdp stream port\n"); return SNGTC_ERR; } if (write_sdp_stream_attr(msg, lump, pair.att1, reply) != 0) { LM_ERR("failed to write sdp stream codecs\n"); return SNGTC_ERR; } break; case SNGTC_UNSUP_CODECS: LM_ERR("endpoints have no common codecs and at least one side " "contains only unsupported Sangoma codecs\n"); LM_ERR("caller:\n"); print_sdp_stream(sm1, L_ERR); LM_ERR("callee:\n"); print_sdp_stream(sm2, L_ERR); return SNGTC_SDP_ERR; case SNGTC_BAD_SDP: LM_ERR("received bogus sdp with no attributes\n"); LM_ERR("caller:\n"); print_sdp_stream(sm1, L_ERR); LM_ERR("callee:\n"); print_sdp_stream(sm2, L_ERR); return SNGTC_SDP_ERR; } } if (tc_on) { LM_DBG("transcoding: ON\n"); memcpy(dst->s + dst->len, src->s, s1->ip_addr.s - src->s); dst->len += s1->ip_addr.s - src->s; dst->len += sprintf(dst->s + dst->len, "%.*s", card_ip_a.len, card_ip_a.s); src->s += s1->ip_addr.s - src->s + s1->ip_addr.len; } else LM_DBG("transcoding: OFF\n"); rc |= process_stream(s1->streams, s2->streams, src, dst, MAX_STREAMS - 1); out: return rc; }
int parse_avp_db(char *s, struct db_param *dbp, int allow_scheme) { str tmp; str s0; str *s1; char have_scheme; char *p; char *p0; unsigned int flags; LM_DBG("parse: %s\n", s); tmp.s = s; /* parse the attribute name - check first if it's not an alias */ p0=strchr(tmp.s, '/'); if(p0!=NULL) *p0=0; if ( *s!='$') { if(strlen(s)<1) { LM_ERR("bad param - expected : $avp(name), *, s or i value\n"); return E_UNSPEC; } switch(*s) { /* deteleted because of the new avp format */ case 's': case 'S': case 'i': case 'I': case '*': case 'a': case 'A': dbp->a.opd = AVPOPS_VAL_NONE; break; default: LM_ERR("bad param - expected : *, s or i AVP flag\n"); return E_UNSPEC; } /* flags */ flags = 0; if(*(s+1)!='\0') { s0.s = s+1; s0.len = strlen(s0.s); if(str2int(&s0, &flags)!=0) { LM_ERR("error - bad avp flags\n"); goto error; } } dbp->a.u.sval.pvp.pvn.u.isname.type |= (flags<<8)&0xff00; dbp->a.type = AVPOPS_VAL_NONE; } else { s0.s = s; s0.len = strlen(s0.s); p = pv_parse_spec(&s0, &dbp->a.u.sval); if (p==0 || *p!='\0' || dbp->a.u.sval.type!=PVT_AVP) { LM_ERR("bad param - expected : $avp(name) or int/str value\n"); return E_UNSPEC; } dbp->a.type = AVPOPS_VAL_PVAR; } /* optimize and keep the attribute name as str also to * speed up db querie builds */ if (dbp->a.type == AVPOPS_VAL_PVAR) { dbp->a.opd = AVPOPS_VAL_PVAR; if(pv_has_iname(&dbp->a.u.sval)) { s1 = get_avp_name_id(dbp->a.u.sval.pvp.pvn.u.isname.name.n); if (!s1) { LM_ERR("cannot find avp name\n"); goto error; } dbp->sa.s=(char*)pkg_malloc(s1->len + 1); if (dbp->sa.s==0) { LM_ERR("no more pkg mem\n"); goto error; } memcpy(dbp->sa.s, s1->s, s1->len); dbp->sa.len = s1->len; dbp->sa.s[dbp->sa.len] = 0; dbp->a.opd = AVPOPS_VAL_PVAR|AVPOPS_VAL_STR; } } /* restore '/' */ if(p0) *p0 = '/'; /* is there a table name ? */ s = p0; if (s && *s) { s++; if (*s=='$') { if (allow_scheme==0) { LM_ERR("function doesn't support DB schemes\n"); goto error; } if (dbp->a.opd&AVPOPS_VAL_NONE) { LM_ERR("inconsistent usage of " "DB scheme without complet specification of AVP name\n"); goto error; } have_scheme = 1; s++; } else { have_scheme = 0; } tmp.s = s; tmp.len = 0; while ( *s ) s++; tmp.len = s - tmp.s; if (tmp.len==0) { LM_ERR("empty scheme/table name\n"); goto error; } if (have_scheme) { dbp->scheme = avp_get_db_scheme( &tmp ); if (dbp->scheme==0) { LM_ERR("scheme <%s> not found\n", tmp.s); goto error; } /* update scheme flags with AVP name type*/ dbp->scheme->db_flags|=dbp->a.opd&AVPOPS_VAL_STR?AVP_NAME_STR:0; } else { /* duplicate table str into the db_param struct */ pkg_str_dup( &dbp->table, &tmp); } } return 0; error: return -1; }
int dlg_th_onreply(struct dlg_cell *dlg, struct sip_msg *rpl, int init_req, int dir) { struct hdr_field *it; char* buf = rpl->buf; int peer_leg; struct lump* lmp; int size; char* route; str lv_str; struct dlg_leg* leg; LM_DBG("start\n"); /* parse all headers to be sure that all RR and Contact hdrs are found */ if (parse_headers(rpl, HDR_EOH_F, 0)< 0) { LM_ERR("Failed to parse reply\n"); return -1; } /* replace contact */ if(dlg_replace_contact(rpl, dlg) < 0) { LM_ERR("Failed to replace contact\n"); return -1; } if(dir == DLG_DIR_UPSTREAM) peer_leg = DLG_CALLER_LEG; else peer_leg = callee_idx(dlg); leg = &dlg->legs[peer_leg]; LM_DBG("peer_leg = %d\n", peer_leg); LM_DBG("first RR hdr = %p\n", rpl->record_route); /* delete record route */ for (it=rpl->record_route; it; it=it->sibling) { /* changed here for contact - it was & it->sibling */ /* skip the one added by this proxy */ if ((lmp = del_lump(rpl, it->name.s - buf, it->len,HDR_RECORDROUTE_T)) == 0) { LM_ERR("del_lump failed \n"); return -1; } LM_DBG("Delete record route: [%.*s]\n", it->len, it->name.s); } /* add Via headers */ lmp = anchor_lump(rpl,rpl->headers->name.s - buf,0,0); if (lmp == 0) { LM_ERR("failed anchoring new lump\n"); return -1; } if(pkg_str_dup(&lv_str, &leg->last_vias) < 0) { LM_ERR("Failed to duplicate memory\n"); return 1; } if ((lmp = insert_new_lump_after(lmp, lv_str.s, lv_str.len, HDR_VIA_T)) == 0) { LM_ERR("failed inserting new vias\n"); pkg_free(lv_str.s); return -1; } LM_DBG("Added Via headers [%.*s] leg=%p\n", lv_str.len, lv_str.s, leg); /* if dialog not confirmed and 200OK for Invite */ /* pass the record route headers for this leg */ if(init_req && dir == DLG_DIR_UPSTREAM && rpl->first_line.u.reply.statuscode==200 && leg->route_set.s) { /* changed here for contact ( take care to insert the routes after own) */ /* pass record route headers */ size = leg->route_set.len + RECORD_ROUTE_LEN + CRLF_LEN; route = pkg_malloc(size); if (route == NULL) { LM_ERR("no more pkg memory\n"); return -1; } memcpy(route, RECORD_ROUTE, RECORD_ROUTE_LEN); memcpy(route+RECORD_ROUTE_LEN, leg->route_set.s, leg->route_set.len); memcpy(route+RECORD_ROUTE_LEN+leg->route_set.len, CRLF, CRLF_LEN); /* put after Via */ if ((lmp = insert_new_lump_after(lmp, route, size, HDR_RECORDROUTE_T)) == 0) { LM_ERR("failed inserting new route set\n"); pkg_free(route); return -1; } LM_DBG("Added record route [%.*s]\n", size, route); } return 0; }