/* This function extracts meta-info from the sip_msg structure and * formats it so that it can be used to rapidly access the message structured * parts. * * RETURNS: LENGTH of structure on success, <0 if failure * if there was failure, you don't need to pkg_free the payload (it is done inside). * if there was success, you __NEED_TO_PKG_FREE_THE_PAYLOAD__ from the calling function. * * The encoded meta-info is composed by 3 sections: * * MSG_META_INFO: * 2: short int in network-byte-order, if <100, the msg is a REQUEST and the int * is the code of the METHOD. if >100, it is a RESPONSE and the int is the code * of the response. * 2: short int in NBO: payload-start based pointer (index) to where the SIP MSG starts. * 2: short int in NBO: the sip-message length * 2: METHOD or CODE string SIP-START-based pointer and length * 2: R-URI or REASON PHRASE string SIP-START-based pointer and length * 2: VERSION string SIP-START-based pointer and length * 2: short int in NBO: start of the content of the SIP message * [1+N]: in case this is a request, the length of the encoded-uri and the encoded-uri * 1: how many present headers have been found. * * MSG_HEADERS_INDEX: * N*3: groups of 3 bytes, each one describing a header struct: the first byte * is a letter that corresponds to a header type, the second and third bytes are a NBO * inidex to where this struct begins within the HEADERS_META_INFO section. * * HEADERS_META_INFO: * M: all the codified headers meta info structs one after another * * SIP_MSG: * the SIP message as it has been received. * * The length of the structure, will be ((short*)payload)[1] + ((short*)payload)[2] * * TODO: msg->parsed_uri msg->parsed_orig_uri_ok, msg->first_line->u.request.uri * buggy and little bit fuzzy */ int encode_msg(struct sip_msg *msg,char *payload,int len) { int i,j,k,u,request; unsigned short int h; struct hdr_field* hf; struct msg_start* ms; struct sip_uri miuri; char *myerror=NULL; ptrdiff_t diff; str body = {NULL,0}; if(len < MAX_ENCODED_MSG + MAX_MESSAGE_LEN) return -1; if(parse_headers(msg,HDR_EOH_F,0)<0){ myerror="in parse_headers"; goto error; } memset(payload,0,len); ms=&msg->first_line; if(ms->type == SIP_REQUEST) request=1; else if(ms->type == SIP_REPLY) request=0; else{ myerror="message is neither request nor response"; goto error; } if(request) { for(h=0,j=1;h<32;j=(0x01<<h),h++) if(j & ms->u.request.method_value) break; } else { h=(unsigned short)(ms->u.reply.statuscode); } if(h==32){/*statuscode wont be 32...*/ myerror="unknown message type\n"; goto error; } h=htons(h); /*first goes the message code type*/ memcpy(payload,&h,2); h=htons((unsigned short int)msg->len); /*then goes the message start idx, but we'll put it later*/ /*then goes the message length (we hope it to be less than 65535 bytes...)*/ memcpy(&payload[MSG_LEN_IDX],&h,2); /*then goes the content start index (starting from SIP MSG START)*/ if (get_body(msg,&body) < 0) { myerror="body parsing failed"; goto error; } if(0>(diff=(body.s-msg->buf))){ myerror="body starts before the message (uh ?)"; goto error; }else h=htons((unsigned short int)diff); memcpy(payload+CONTENT_IDX,&h,2); payload[METHOD_CODE_IDX]=(unsigned char)(request? (ms->u.request.method.s-msg->buf): (ms->u.reply.status.s-msg->buf)); payload[METHOD_CODE_IDX+1]=(unsigned char)(request? (ms->u.request.method.len): (ms->u.reply.status.len)); payload[URI_REASON_IDX]=(unsigned char)(request? (ms->u.request.uri.s-msg->buf): (ms->u.reply.reason.s-msg->buf)); payload[URI_REASON_IDX+1]=(unsigned char)(request? (ms->u.request.uri.len): (ms->u.reply.reason.len)); payload[VERSION_IDX]=(unsigned char)(request? (ms->u.request.version.s-msg->buf): (ms->u.reply.version.s-msg->buf)); if(request){ if (parse_uri(ms->u.request.uri.s,ms->u.request.uri.len, &miuri)<0){ LM_ERR("<%.*s>\n",ms->u.request.uri.len,ms->u.request.uri.s); myerror="while parsing the R-URI"; goto error; } if(0>(j=encode_uri2(msg->buf, ms->u.request.method.s-msg->buf+ms->len, ms->u.request.uri,&miuri, (unsigned char*)&payload[REQUEST_URI_IDX+1]))) { myerror="ENCODE_MSG: ERROR while encoding the R-URI"; goto error; } payload[REQUEST_URI_IDX]=(unsigned char)j; k=REQUEST_URI_IDX+1+j; }else k=REQUEST_URI_IDX; u=k; k++; for(i=0,hf=msg->headers;hf;hf=hf->next,i++); i++;/*we do as if there was an extra header, that marks the end of the previous header in the headers hashtable(read below)*/ j=k+3*i; for(i=0,hf=msg->headers;hf;hf=hf->next,k+=3){ payload[k]=(unsigned char)(hf->type & 0xFF); h=htons(j); /*now goes a payload-based-ptr to where the header-code starts*/ memcpy(&payload[k+1],&h,2); /*TODO fix this... fixed with k-=3?*/ if(0>(i=encode_header(msg,hf,(unsigned char*)(payload+j),MAX_ENCODED_MSG+MAX_MESSAGE_LEN-j))){ LM_ERR("encoding header %.*s\n",hf->name.len,hf->name.s); goto error; /* XXX: not sure if this should be considered or not, but the code is * not executed anyway; commenting it for now. k-=3; continue; */ } j+=(unsigned short int)i; } /*now goes the number of headers that have been found, right after the meta-msg-section*/ payload[u]=(unsigned char)((k-u-1)/3); j=htons(j); /*now copy the number of bytes that the headers-meta-section has occupied,right afther * headers-meta-section(the array with ['v',[2:where],'r',[2:where],'R',[2:where],...] * this is to know where the LAST header ends, since the length of each header-struct * is calculated substracting the nextHeaderStart - presentHeaderStart * the k+1 is because payload[k] is usually the letter*/ memcpy(&payload[k+1],&j,2); k+=3; j=ntohs(j); /*now we copy the headers-meta-section after the msg-headers-meta-section*/ /*memcpy(&payload[k],payload2,j);*/ /*j+=k;*/ /*pkg_free(payload2);*/ /*now we copy the actual message after the headers-meta-section*/ memcpy(&payload[j],msg->buf,msg->len); LM_DBG("msglen = %d,msg starts at %d\n",msg->len,j); j=htons(j); /*now we copy at the beginning, the index to where the actual message starts*/ memcpy(&payload[MSG_START_IDX],&j,2); return GET_PAY_SIZE( payload ); error: LM_ERR("%s\n",myerror); return -1; }
/** * @brief Initialize async module children */ static int child_init(int rank) { int pid; int i; LM_DBG("child initializing async http\n"); if(num_workers<=0) return 0; /* initialize query counter and id */ q_idx = 0; q_id[0] = '\0'; if (rank==PROC_INIT) { for(i=0; i<num_workers; i++) { LM_DBG("initializing worker notification socket: %d\n", i); if(async_http_init_sockets(&workers[i])<0) { LM_ERR("failed to initialize tasks sockets\n"); return -1; } } return 0; } if(rank>0) { for(i=0; i<num_workers; i++) { close(workers[i].notication_socket[0]); } return 0; } if (rank!=PROC_MAIN) return 0; for(i=0; i<num_workers; i++) { if(async_http_init_worker(i+1, &workers[i])<0) { LM_ERR("failed to initialize worker process: %d\n", i); return -1; } pid=fork_process(PROC_RPC, "Http Async Worker", 1); if (pid<0) return -1; /* error */ if(pid==0) { /* child */ /* enforce http_reply_parse=yes */ http_reply_parse = 1; /* initialize the config framework */ if (cfg_child_init()) return -1; /* init msg structure for http reply parsing */ ah_reply = pkg_malloc(sizeof(struct sip_msg)); if(!ah_reply) { LM_ERR("failed to allocate pkg memory\n"); return -1; } memset(ah_reply, 0, sizeof(struct sip_msg)); /* main function for workers */ async_http_run_worker(&workers[i]); } } return 0; }
static int ah_set_req(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val) { pv_value_t *tval; if(param==NULL || tmb.t_request==NULL) return -1; tval = val; if((tval!=NULL) && (tval->flags&PV_VAL_NULL)) { tval = NULL; } switch((enum http_req_name_t) param->pvn.u.isname.name.n) { case E_HRN_ALL: if (tval == NULL) set_query_params(&ah_params); break; case E_HRN_HDR: if (tval) { if (!(tval->flags & PV_VAL_STR)) { LM_ERR("invalid value type for $http_req(hdr)\n"); return -1; } header_list_add(&ah_params.headers, &tval->rs); } break; case E_HRN_METHOD: if (tval) { if (!(tval->flags & PV_VAL_STR)) { LM_ERR("invalid value type for $http_req(method)\n"); return -1; } query_params_set_method(&ah_params, &tval->rs); } else { ah_params.method = AH_METH_DEFAULT; } break; case E_HRN_TIMEOUT: if (tval) { if (!(tval->flags & PV_VAL_INT)) { LM_ERR("invalid value type for $http_req(timeout)\n"); return -1; } ah_params.timeout = tval->ri; } else { ah_params.timeout = http_timeout; } break; case E_HRN_TLS_CA_PATH: if (tval) { if (!(tval->flags & PV_VAL_STR)) { LM_ERR("invalid value type for $http_req(tls_ca_path)\n"); return -1; } set_query_cparam(&ah_params.tls_ca_path, tval->rs); } break; case E_HRN_TLS_CLIENT_KEY: if (tval) { if (!(tval->flags & PV_VAL_STR)) { LM_ERR("invalid value type for $http_req(tls_client_key)\n"); return -1; } set_query_cparam(&ah_params.tls_client_key, tval->rs); } break; case E_HRN_TLS_CLIENT_CERT: if (tval) { if (!(tval->flags & PV_VAL_STR)) { LM_ERR("invalid value type for $http_req(tls_client_cert)\n"); return -1; } set_query_cparam(&ah_params.tls_client_cert, tval->rs); } break; case E_HRN_SUSPEND: if (tval) { if (!(tval->flags & PV_VAL_INT)) { LM_ERR("invalid value type for $http_req(suspend)\n"); return -1; } ah_params.suspend_transaction = tval->ri?1:0; } else { ah_params.suspend_transaction = 1; } break; case E_HRN_BODY: if (tval) { if (!(tval->flags & PV_VAL_STR)) { LM_ERR("invalid value type for $http_req(body)\n"); return -1; } set_query_param(&ah_params.body, tval->rs); } break; case E_HRN_AUTHMETHOD: if (tval) { if (!(tval->flags & PV_VAL_INT)) { LM_ERR("invalid value type for $http_req(authmethod)\n"); return -1; } ah_params.authmethod = tval->ri; } else { ah_params.authmethod = default_authmethod; } break; case E_HRN_USERNAME: if (tval) { if (!(tval->flags & PV_VAL_STR)) { LM_ERR("invalid value type for $http_req(username)\n"); return -1; } set_query_cparam(&ah_params.username, tval->rs); } break; case E_HRN_PASSWORD: if (tval) { if (!(tval->flags & PV_VAL_STR)) { LM_ERR("invalid value type for $http_req(password)\n"); return -1; } set_query_cparam(&ah_params.password, tval->rs); } break; } return 1; }
/* parses the first line, returns pointer to next line & fills fl; also modifies buffer (to avoid extra copy ops) */ char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl) { char *tmp; char* second; char* third; char* nl; unsigned int offset; /* int l; */ char* end; char s1,s2,s3; char *prn; unsigned int t; /* grammar: request = method SP uri SP version CRLF response = version SP status SP reason CRLF (version = "SIP/2.0") */ end=buffer+len; /* see if it's a reply (status) */ /* jku -- parse well-known methods */ /* drop messages which are so short they are for sure useless; utilize knowledge of minimum size in parsing the first token */ if (len <=16 ) { LM_INFO("message too short: %d\n", len); goto error1; } tmp=buffer; /* is it perhaps a reply, ie does it start with "SIP...." ? */ if ( (*tmp=='S' || *tmp=='s') && strncasecmp( tmp+1, SIP_VERSION+1, SIP_VERSION_LEN-1)==0 && (*(tmp+SIP_VERSION_LEN)==' ')) { fl->type=SIP_REPLY; fl->u.reply.version.len=SIP_VERSION_LEN; tmp=buffer+SIP_VERSION_LEN; } else IFISMETHOD( INVITE, 'I' ) else IFISMETHOD( CANCEL, 'C') else IFISMETHOD( ACK, 'A' ) else IFISMETHOD( BYE, 'B' ) else IFISMETHOD( INFO, 'I' ) /* if you want to add another method XXX, include METHOD_XXX in H-file (this is the value which you will take later in processing and define XXX_LEN as length of method name; then just call IFISMETHOD( XXX, 'X' ) ... 'X' is the first latter; everything must be capitals */ else { /* neither reply, nor any of known method requests, let's believe it is an unknown method request */ tmp=eat_token_end(buffer,buffer+len); if ((tmp==buffer)||(tmp>=end)){ LM_INFO("empty or bad first line\n"); goto error1; } if (*tmp!=' ') { LM_INFO("method not followed by SP\n"); goto error1; } fl->type=SIP_REQUEST; /* see if it is another known method */ /* fl->u.request.method_value=METHOD_OTHER; */ if(parse_method(buffer, tmp, (unsigned int*)&fl->u.request.method_value)==0) { LM_INFO("failed to parse the method\n"); goto error1; } fl->u.request.method.len=tmp-buffer; } /* identifying type of message over now; tmp points at space after; go ahead */ fl->u.request.method.s=buffer; /* store ptr to first token */ second=tmp+1; /* jump to second token */ offset=second-buffer; /* EoJku */ /* next element */ tmp=eat_token_end(second, second+len-offset); if (tmp>=end){ goto error; } offset+=tmp-second; third=eat_space_end(tmp, tmp+len-offset); offset+=third-tmp; if ((third==tmp)||(tmp>=end)){ goto error; } fl->u.request.uri.s=second; fl->u.request.uri.len=tmp-second; /* jku: parse status code */ if (fl->type==SIP_REPLY) { if (fl->u.request.uri.len!=3) { LM_INFO("len(status code)!=3: %.*s\n", fl->u.request.uri.len, ZSW(second) ); goto error; } s1=*second; s2=*(second+1);s3=*(second+2); if (s1>='0' && s1<='9' && s2>='0' && s2<='9' && s3>='0' && s3<='9' ) { fl->u.reply.statuscode=(s1-'0')*100+10*(s2-'0')+(s3-'0'); } else { LM_INFO("status_code non-numerical: %.*s\n", fl->u.request.uri.len, ZSW(second) ); goto error; } } /* EoJku */ /* last part: for a request it must be the version, for a reply * it can contain almost anything, including spaces, so we don't care * about it*/ if (fl->type==SIP_REQUEST){ tmp=eat_token_end(third,third+len-offset); offset+=tmp-third; if ((tmp==third)||(tmp>=end)){ goto error; } if (! is_empty_end(tmp, tmp+len-offset)){ goto error; } }else{ tmp=eat_token2_end(third,third+len-offset,'\r'); /* find end of line ('\n' or '\r') */ if (tmp>=end){ /* no crlf in packet => invalid */ goto error; } offset+=tmp-third; } nl=eat_line(tmp,len-offset); if (nl>=end){ /* no crlf in packet or only 1 line > invalid */ goto error; } fl->u.request.version.s=third; fl->u.request.version.len=tmp-third; fl->len=nl-buffer; return nl; error: LM_ERR("bad %s first line\n", (fl->type==SIP_REPLY)?"reply(status)":"request"); LM_ERR("at line 0 char %d: \n", offset ); prn=pkg_malloc( offset ); if (prn) { for (t=0; t<offset; t++) if (*(buffer+t)) *(prn+t)=*(buffer+t); else *(prn+t)='°'; LM_ERR("parsed so far: %.*s\n", offset, ZSW(prn) ); pkg_free( prn ); }; error1: fl->type=SIP_INVALID; LM_INFO("bad message\n"); /* skip line */ nl=eat_line(buffer,len); return nl; }
void async_cdp_callback(int is_timeout, void *param, AAAMessage *saa, long elapsed_msecs) { struct cell *t = 0; int rc = -1, experimental_rc = -1; int result = CSCF_RETURN_TRUE; saved_transaction_t* data = 0; str xml_data = {0, 0}, ccf1 = {0, 0}, ccf2 = {0, 0}, ecf1 = {0, 0}, ecf2 = {0, 0}; ims_subscription* s = 0; rerrno = R_FINE; if (!param) { LM_DBG("No transaction data this must have been called from usrloc cb impu deleted - just log result code and then exit"); cxdx_get_result_code(saa, &rc); cxdx_get_experimental_result_code(saa, &experimental_rc); if (saa) cdpb.AAAFreeMessage(&saa); if (!rc && !experimental_rc) { LM_ERR("bad SAA result code\n"); return; } switch (rc) { case -1: LM_DBG("Received Diameter error\n"); return; case AAA_UNABLE_TO_COMPLY: LM_DBG("Unable to comply\n"); return; case AAA_SUCCESS: LM_DBG("received AAA success\n"); return; default: LM_ERR("Unknown error\n"); return; } } else { LM_DBG("There is transaction data this must have been called from save or assign server unreg"); data = (saved_transaction_t*) param; if (tmb.t_lookup_ident(&t, data->tindex, data->tlabel) < 0) { LM_ERR("t_continue: transaction not found\n"); rerrno = R_SAR_FAILED; goto error_no_send; } get_act_time(); if (is_timeout) { update_stat(stat_sar_timeouts, 1); LM_ERR("Transaction timeout - did not get SAA\n"); rerrno = R_SAR_FAILED; goto error; } if (!saa) { LM_ERR("Error sending message via CDP\n"); rerrno = R_SAR_FAILED; goto error; } update_stat(sar_replies_received, 1); update_stat(sar_replies_response_time, elapsed_msecs); /* check and see that all the required headers are available and can be parsed */ if (parse_message_for_register(t->uas.request) < 0) { LM_ERR("Unable to parse register message correctly\n"); rerrno = R_SAR_FAILED; goto error; } cxdx_get_result_code(saa, &rc); cxdx_get_experimental_result_code(saa, &experimental_rc); cxdx_get_charging_info(saa, &ccf1, &ccf2, &ecf1, &ecf2); if (!rc && !experimental_rc) { LM_ERR("bad SAA result code\n"); rerrno = R_SAR_FAILED; goto error; } switch (rc) { case -1: LM_DBG("Received Diameter error\n"); rerrno = R_SAR_FAILED; goto error; case AAA_UNABLE_TO_COMPLY: LM_DBG("Unable to comply\n"); rerrno = R_SAR_FAILED; goto error; case AAA_SUCCESS: LM_DBG("received AAA success\n"); break; default: LM_ERR("Unknown error\n"); rerrno = R_SAR_FAILED; goto error; } //success //if this is from a save (not a server assign unreg) and expires is zero we don't update usrloc as this is a dereg and usrloc was updated previously if (data->sar_assignment_type != AVP_IMS_SAR_UNREGISTERED_USER && data->expires == 0) { LM_DBG("no need to update usrloc - already done for de-reg\n"); result = CSCF_RETURN_TRUE; goto success; } xml_data = cxdx_get_user_data(saa); /*If there is XML user data we must be able to parse it*/ if (xml_data.s && xml_data.len > 0) { LM_DBG("Parsing user data string from SAA\n"); s = parse_user_data(xml_data); if (!s) { LM_ERR("Unable to parse user data XML string\n"); rerrno = R_SAR_FAILED; goto error; } LM_DBG("Successfully parse user data XML\n"); } else { if (data->require_user_data) { LM_ERR("We require User data for this assignment/register and none was supplied\n"); rerrno = R_SAR_FAILED; result = CSCF_RETURN_FALSE; goto done; } } if (data->sar_assignment_type == AVP_IMS_SAR_REGISTRATION || data->sar_assignment_type == AVP_IMS_SAR_RE_REGISTRATION) { if (build_p_associated_uri(s) != 0) { LM_ERR("Unable to build p_associated_uri\n"); rerrno = R_SAR_FAILED; goto error; } } //here we update the contacts and also build the new contact header for the 200 OK reply if (update_contacts_new(t->uas.request, data->domain, &data->public_identity, data->sar_assignment_type, &s, &ccf1, &ccf2, &ecf1, &ecf2, &data->contact_header) <= 0) { LM_ERR("Error processing REGISTER\n"); rerrno = R_SAR_FAILED; goto error; } if (data->contact_header) { LM_DBG("Updated contacts: %.*s\n", data->contact_header->data_len, data->contact_header->buf); } else { LM_DBG("Updated unreg contact\n"); } } success: update_stat(accepted_registrations, 1); done: if (data->sar_assignment_type != AVP_IMS_SAR_UNREGISTERED_USER) reg_send_reply_transactional(t->uas.request, data->contact_header, t); LM_DBG("DBG:SAR Async CDP callback: ... Done resuming transaction\n"); set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, &t->uri_avps_from); set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, &t->uri_avps_to); set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, &t->user_avps_from); set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, &t->user_avps_to); set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, &t->domain_avps_from); set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, &t->domain_avps_to); create_return_code(result); //free memory if (saa) cdpb.AAAFreeMessage(&saa); if (t) { del_nonshm_lump_rpl(&t->uas.request->reply_lump); tmb.unref_cell(t); } //free path vector pkg memory reset_path_vector(t->uas.request); tmb.t_continue(data->tindex, data->tlabel, data->act); free_saved_transaction_data(data); return; error: if (data->sar_assignment_type != AVP_IMS_SAR_UNREGISTERED_USER) reg_send_reply_transactional(t->uas.request, data->contact_header, t); error_no_send: //if we don't have the transaction then we can't send a transaction response update_stat(rejected_registrations, 1); //free memory if (saa) cdpb.AAAFreeMessage(&saa); if (t) { del_nonshm_lump_rpl(&t->uas.request->reply_lump); tmb.unref_cell(t); } tmb.t_continue(data->tindex, data->tlabel, data->act); free_saved_transaction_data(data); return; }
/** * Receive a file descriptor from another process * @param pipe_fd - pipe to read from * @param fd - file descriptor to fill * @param p - optional pipe to fill * @returns 1 on success or 0 on failure */ static int receive_fd(int pipe_fd, int* fd,peer **p) { struct msghdr msg; struct iovec iov[1]; int new_fd; int ret; #ifdef HAVE_MSGHDR_MSG_CONTROL struct cmsghdr* cmsg; union{ struct cmsghdr cm; char control[CMSG_SPACE(sizeof(new_fd))]; }control_un; msg.msg_control=control_un.control; msg.msg_controllen=sizeof(control_un.control); #else msg.msg_accrights=(caddr_t) &new_fd; msg.msg_accrightslen=sizeof(int); #endif msg.msg_name=0; msg.msg_namelen=0; iov[0].iov_base=p; iov[0].iov_len=sizeof(peer*); msg.msg_iov=iov; msg.msg_iovlen=1; again: ret=recvmsg(pipe_fd, &msg, MSG_DONTWAIT|MSG_WAITALL); if (ret<0){ if (errno==EINTR) goto again; if ((errno==EAGAIN)||(errno==EWOULDBLOCK)) goto error; LM_CRIT( "receive_fd: recvmsg on %d failed: %s\n", pipe_fd, strerror(errno)); goto error; } if (ret==0){ /* EOF */ LM_CRIT( "receive_fd: EOF on %d\n", pipe_fd); goto error; } if (ret!=sizeof(peer *)){ LM_WARN("receive_fd: different number of bytes received than expected (%d from %ld)" "trying to fix...\n", ret, (long int)sizeof(peer*)); goto error; } #ifdef HAVE_MSGHDR_MSG_CONTROL cmsg=CMSG_FIRSTHDR(&msg); if ((cmsg!=0) && (cmsg->cmsg_len==CMSG_LEN(sizeof(new_fd)))){ if (cmsg->cmsg_type!= SCM_RIGHTS){ LM_ERR("receive_fd: msg control type != SCM_RIGHTS\n"); goto error; } if (cmsg->cmsg_level!= SOL_SOCKET){ LM_ERR("receive_fd: msg level != SOL_SOCKET\n"); goto error; } *fd=*((int*) CMSG_DATA(cmsg)); }else{ if(!cmsg) LM_ERR("receive_fd: no descriptor passed, empty control message"); else LM_ERR("receive_fd: no descriptor passed, cmsg=%p," "len=%d\n", cmsg, (unsigned)cmsg->cmsg_len); *fd=-1; *p=0; /* it's not really an error */ } #else if (msg.msg_accrightslen==sizeof(int)){ *fd=new_fd; }else{ LM_ERR("receive_fd: no descriptor passed," " accrightslen=%d\n", msg.msg_accrightslen); *fd=-1; } #endif return 1; error: return 0; }
/** * Selects once on sockets for receiving and sending stuff. * Monitors: * - the fd exchange pipe, for receiving descriptors to be handled here * - the tcp sockets of all serviced peers, triggering the incoming messages do_receive() * - the send pipes of all serviced peers, triggering the sending of outgoing messages * @returns 0 on normal exit or -1 on error */ int receive_loop(peer *original_peer) { fd_set rfds,efds; struct timeval tv; int n,max=0,cnt=0; AAAMessage *msg=0; serviced_peer_t *sp,*sp2; peer *p; int fd=-1; int fd_exchange_pipe_local=0; if (original_peer) fd_exchange_pipe_local = original_peer->fd_exchange_pipe_local; else fd_exchange_pipe_local = fd_exchange_pipe_unknown_local; // if (shutdownx) return -1; while(shutdownx&&!*shutdownx){ n = 0; while(!n){ if (shutdownx&&*shutdownx) break; cfg_update(); log_serviced_peers(); max =-1; FD_ZERO(&rfds); FD_ZERO(&efds); FD_SET(fd_exchange_pipe_local,&rfds); if (fd_exchange_pipe_local>max) max = fd_exchange_pipe_local; for(sp=serviced_peers;sp;sp=sp->next){ if (sp->tcp_socket>=0){ FD_SET(sp->tcp_socket,&rfds); FD_SET(sp->tcp_socket,&efds); if (sp->tcp_socket>max) max = sp->tcp_socket; } if (sp->send_pipe_fd>=0) { FD_SET(sp->send_pipe_fd,&rfds); if (sp->send_pipe_fd>max) max = sp->send_pipe_fd; } } tv.tv_sec=1; tv.tv_usec=0; n = select(max+1,&rfds,0,&efds,&tv); if (n==-1){ if (shutdownx&&*shutdownx) return 0; LM_ERR("select_recv(): %s\n",strerror(errno)); for(sp=serviced_peers;sp;sp=sp2){ sp2 = sp->next; disconnect_serviced_peer(sp,0); if (sp->p && sp->p->is_dynamic) drop_serviced_peer(sp,0); } sleep(1); break; }else if (n){ if (FD_ISSET(fd_exchange_pipe_local,&rfds)){ /* fd exchange */ LM_DBG("select_recv(): There is something on the fd exchange pipe\n"); p = 0; fd = -1; if (!receive_fd(fd_exchange_pipe_local,&fd,&p)){ LM_ERR("select_recv(): Error reading from fd exchange pipe\n"); }else{ LM_DBG("select_recv(): fd exchange pipe says fd [%d] for peer %p:[%.*s]\n",fd, p, p?p->fqdn.len:0, p?p->fqdn.s:0); if (p){ sp2=0; for(sp=serviced_peers;sp;sp=sp->next) if (sp->p==p){ sp2 = sp; break; } if (!sp2) sp2 = add_serviced_peer(p); else make_send_pipe(sp2); if (!sp2) { LM_ERR("Error on add_serviced_peer()\n"); continue; } sp2->tcp_socket = fd; if (p->state == Wait_Conn_Ack){ p->I_sock = fd; sm_process(p,I_Rcv_Conn_Ack,0,0,fd); }else{ p->R_sock = fd; } }else{ sp2 = add_serviced_peer(NULL); if (!sp2) { LM_ERR("Error on add_serviced_peer()\n"); continue; } sp2->tcp_socket = fd; } } } for(sp=serviced_peers;sp;){ if (sp->tcp_socket>=0 && FD_ISSET(sp->tcp_socket,&efds)) { LM_INFO("select_recv(): [%.*s] Peer socket [%d] found on the exception list... dropping\n", sp->p?sp->p->fqdn.len:0, sp->p?sp->p->fqdn.s:0, sp->tcp_socket); goto drop_peer; } if (sp->send_pipe_fd>=0 && FD_ISSET(sp->send_pipe_fd,&rfds)) { /* send */ LM_DBG("select_recv(): There is something on the send pipe\n"); cnt = read(sp->send_pipe_fd,&msg,sizeof(AAAMessage *)); if (cnt==0){ //This is very stupid and might not work well - droped messages... to be fixed LM_INFO("select_recv(): ReOpening pipe for read. This should not happen...\n"); close(sp->send_pipe_fd); sp->send_pipe_fd = open(sp->send_pipe_name.s, O_RDONLY | O_NDELAY); goto receive; } if (cnt<sizeof(AAAMessage *)){ if (cnt<0) LM_ERR("select_recv(): Error reading from send pipe\n"); goto receive; } LM_DBG("select_recv(): Send pipe says [%p] %d\n",msg,cnt); if (sp->tcp_socket<0){ LM_ERR("select_recv(): got a signal to send something, but the connection was not opened"); } else { while( (cnt=write(sp->tcp_socket,msg->buf.s,msg->buf.len))==-1 ) { if (errno==EINTR) continue; LM_ERR("select_recv(): [%.*s] write on socket [%d] returned error> %s... dropping\n", sp->p?sp->p->fqdn.len:0, sp->p?sp->p->fqdn.s:0, sp->tcp_socket, strerror(errno)); AAAFreeMessage(&msg); close(sp->tcp_socket); goto drop_peer; } if (cnt!=msg->buf.len){ LM_ERR("select_recv(): [%.*s] write on socket [%d] only wrote %d/%d bytes... dropping\n", sp->p?sp->p->fqdn.len:0, sp->p?sp->p->fqdn.s:0, sp->tcp_socket, cnt, msg->buf.len); AAAFreeMessage(&msg); close(sp->tcp_socket); goto drop_peer; } } AAAFreeMessage(&msg); //don't return, maybe there is something to read } receive: /* receive */ if (sp->tcp_socket>=0 && FD_ISSET(sp->tcp_socket,&rfds)) { errno=0; cnt = do_receive(sp); if (cnt<=0) { LM_INFO("select_recv(): [%.*s] read on socket [%d] returned %d > %s... dropping\n", sp->p?sp->p->fqdn.len:0, sp->p?sp->p->fqdn.s:0, sp->tcp_socket, cnt, errno?strerror(errno):""); goto drop_peer; } } //next_sp: /* go to next serviced peer */ sp=sp->next; continue; drop_peer: /* drop this serviced peer on error */ sp2 = sp->next; disconnect_serviced_peer(sp,0); if (sp->p && sp->p->is_dynamic) drop_serviced_peer(sp,0); sp = sp2; } } } } return 0; }
static struct mi_root *mi_cachefetch(struct mi_root *cmd, void *param) { str mc_system; str attr; str value; struct mi_node* node= NULL; struct mi_root *rpl_tree= NULL; int ret; if(cmd == NULL) { LM_ERR("NULL command\n"); return init_mi_tree(404, MI_SSTR("NULL command")); } node = cmd->node.kids; if(node == NULL) return init_mi_tree(404, MI_SSTR("Too few arguments")); mc_system = node->value; if(mc_system.s == NULL || mc_system.len== 0) { LM_ERR( "empty memory cache system parameter\n"); return init_mi_tree(404, MI_SSTR("Empty memory cache id")); } node = node->next; if(node == NULL) return init_mi_tree(404, MI_SSTR("Too few arguments")); attr = node->value; if(attr.s == NULL || attr.len== 0) { LM_ERR( "empty attribute name parameter\n"); return init_mi_tree(404,MI_SSTR( "Empty attribute name")); } node = node->next; if(node != NULL) return init_mi_tree(404, MI_SSTR("Too many arguments")); ret = cachedb_fetch(&mc_system, &attr, &value); if(ret== -1) { LM_ERR("cachedb_fetch command failed\n"); return init_mi_tree(500, MI_SSTR("Cache fetch command failed")); } rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK)); if (rpl_tree==0) { if(value.s) pkg_free(value.s); return 0; } if(ret == -2 || value.s == 0 || value.len == 0) { add_mi_node_child( &rpl_tree->node, 0, 0, 0, MI_SSTR("Value not found") ); goto done; } addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "%.*s = [%.*s]", attr.len, attr.s, value.len, value.s); pkg_free(value.s); done: return rpl_tree; }
static int xlog_log_colors_param(modparam_t type, void *val) { param_t* params_list = NULL; param_hooks_t phooks; param_t *pit=NULL; str s; int level; if(val==NULL) goto error; s.s = (char*)val; s.len = strlen(s.s); if(s.len<=0) goto error; if(s.s[s.len-1]==';') s.len--; if (parse_params(&s, CLASS_ANY, &phooks, ¶ms_list)<0) goto error; for (pit = params_list; pit; pit=pit->next) { if (pit->name.len==7 && strncasecmp(pit->name.s, "l_alert", 7)==0) { level = L_ALERT; } else if (pit->name.len==5 && strncasecmp(pit->name.s, "l_bug", 5)==0) { level = L_BUG; } else if (pit->name.len==7 && strncasecmp(pit->name.s, "l_crit2", 7)==0) { level = L_CRIT2; } else if (pit->name.len==6 && strncasecmp(pit->name.s, "l_crit", 6)==0) { level = L_CRIT; } else if (pit->name.len==5 && strncasecmp(pit->name.s, "l_err", 5)==0) { level = L_ERR; } else if (pit->name.len==6 && strncasecmp(pit->name.s, "l_warn", 6)==0) { level = L_WARN; } else if (pit->name.len==8 && strncasecmp(pit->name.s, "l_notice", 8)==0) { level = L_NOTICE; } else if (pit->name.len==6 && strncasecmp(pit->name.s, "l_info", 6)==0) { level = L_INFO; } else if (pit->name.len==5 && strncasecmp(pit->name.s, "l_dbg", 5)==0) { level = L_DBG; } else { LM_ERR("invalid level name %.*s\n", pit->name.len, pit->name.s); goto error; } if(pit->body.len!=2) { LM_ERR("invalid color spec for level %.*s (%.*s)\n", pit->name.len, pit->name.s, pit->body.len, pit->body.s); goto error; } dprint_color_update(level, pit->body.s[0], pit->body.s[1]); } if(params_list!=NULL) free_params(params_list); return 0; error: if(params_list!=NULL) free_params(params_list); return -1; }
/** * Get and convert columns from a result */ int db_mysql_get_columns(const db_con_t* _h, db_res_t* _r) { int col; MYSQL_FIELD* fields; if ((!_h) || (!_r)) { LM_ERR("invalid parameter\n"); return -1; } if (CON_HAS_PS(_h)) { RES_COL_N(_r) = CON_MYSQL_PS(_h)->cols_out; } else { RES_COL_N(_r) = mysql_field_count(CON_CONNECTION(_h)); } if (!RES_COL_N(_r)) { LM_ERR("no columns returned from the query\n"); return -2; } else { LM_DBG("%d columns returned from the query\n", RES_COL_N(_r)); } if (db_allocate_columns(_r, RES_COL_N(_r)) != 0) { LM_ERR("could not allocate columns\n"); return -3; } fields = mysql_fetch_fields(CON_RESULT(_h)); for(col = 0; col < RES_COL_N(_r); col++) { /* The pointer that is here returned is part of the result structure */ RES_NAMES(_r)[col]->s = fields[col].name; RES_NAMES(_r)[col]->len = strlen(fields[col].name); LM_DBG("RES_NAMES(%p)[%d]=[%.*s]\n", RES_NAMES(_r)[col], col, RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s); switch(fields[col].type) { case MYSQL_TYPE_TINY: case MYSQL_TYPE_SHORT: case MYSQL_TYPE_LONG: case MYSQL_TYPE_INT24: case MYSQL_TYPE_LONGLONG: case MYSQL_TYPE_DECIMAL: #if MYSQL_VERSION_ID > 49999 case MYSQL_TYPE_NEWDECIMAL: #endif case MYSQL_TYPE_TIMESTAMP: LM_DBG("use DB_INT result type\n"); RES_TYPES(_r)[col] = DB_INT; break; case MYSQL_TYPE_FLOAT: case MYSQL_TYPE_DOUBLE: LM_DBG("use DB_DOUBLE result type\n"); RES_TYPES(_r)[col] = DB_DOUBLE; break; case MYSQL_TYPE_DATETIME: case MYSQL_TYPE_DATE: LM_DBG("use DB_DATETIME result type\n"); RES_TYPES(_r)[col] = DB_DATETIME; break; case MYSQL_TYPE_BLOB: LM_DBG("use DB_BLOB result type\n"); RES_TYPES(_r)[col] = DB_BLOB; break; case FIELD_TYPE_SET: LM_DBG("use DB_BITMAP result type\n"); RES_TYPES(_r)[col] = DB_BITMAP; break; case MYSQL_TYPE_STRING: case MYSQL_TYPE_VAR_STRING: LM_DBG("use DB_STRING result type\n"); RES_TYPES(_r)[col] = DB_STRING; break; default: LM_WARN("unhandled data type column (%.*s) type id (%d), " "use DB_STRING as default\n", RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s, fields[col].type); RES_TYPES(_r)[col] = DB_STRING; break; } } return 0; }
static struct mi_root *mi_cachestore(struct mi_root *cmd, void *param) { str mc_system; str attr; str value; unsigned int expires = 0; struct mi_node* node= NULL; str expires_str; if(cmd == NULL) { LM_ERR("NULL command\n"); return init_mi_tree(404, MI_SSTR("NULL command")); } node = cmd->node.kids; if(node == NULL) return init_mi_tree(404, MI_SSTR("Too few arguments")); mc_system = node->value; if(mc_system.s == NULL || mc_system.len== 0) { LM_ERR( "empty memory cache system parameter\n"); return init_mi_tree(404, MI_SSTR("Empty memory cache id")); } node = node->next; if(node == NULL) return init_mi_tree(404, MI_SSTR("Too few arguments")); attr = node->value; if(attr.s == NULL || attr.len== 0) { LM_ERR( "empty attribute name parameter\n"); return init_mi_tree(404, MI_SSTR("Empty attribute name")); } node = node->next; if(node == NULL) return init_mi_tree(404, MI_SSTR("Too few arguments")); value = node->value; if(value.s == NULL || value.len== 0) { LM_ERR( "empty value parameter\n"); return init_mi_tree(404, MI_SSTR("Empty value argument")); } /* expires parameter is not compulsory */ node = node->next; if(node!= NULL) { expires_str = node->value; if(expires_str.s == NULL || expires_str.len == 0) { LM_ERR( "empty expires parameter\n"); return init_mi_tree(404, MI_SSTR("Empty expires argument")); } if(str2int(&expires_str, &expires)< 0) { LM_ERR("wrong format for expires argument- needed int\n"); return init_mi_tree(404, MI_SSTR("Bad format for expires argument")); } node = node->next; if(node!= NULL) return init_mi_tree(404, MI_SSTR("Too many parameters")); } if(cachedb_store(&mc_system, &attr, &value,expires)< 0) { LM_ERR("cachedb_store command failed\n"); return init_mi_tree(500, MI_SSTR("Cache store command failed")); } return init_mi_tree(200, MI_SSTR(MI_OK)); }
static int load_sca_info_from_db(void) { db_res_t * res = NULL; db_val_t * values; db_row_t * rows; int i, j, nr_rows; unsigned int valid_record; unsigned int n_result_cols = 0; unsigned int shared_line_col, watchers_col; unsigned int app_shared_entity_col[MAX_APPEARANCE_INDEX]; unsigned int app_call_state_col[MAX_APPEARANCE_INDEX]; unsigned int app_call_info_uri_col[MAX_APPEARANCE_INDEX]; unsigned int app_call_info_appearance_uri_col[MAX_APPEARANCE_INDEX]; unsigned int app_b2bl_key_col[MAX_APPEARANCE_INDEX]; db_key_t q_cols[SCA_TABLE_TOTAL_COL_NO]; str shared_line, watchers_csv; //str_lst_t *watchers; //unsigned int size, watcher_size, watchers_no; //unsigned int size; unsigned int hash_index; //char *p; b2b_sca_record_t *record; b2b_sca_call_t *call; unsigned int shared_entity, appearance_index, call_state; str call_info_uri, call_info_apperance_uri, b2bl_key; b2bl_cb_ctx_t *cb_params; if(use_sca_table()) return -1; q_cols[shared_line_col = n_result_cols++] = &shared_line_column; q_cols[watchers_col = n_result_cols++] = &watchers_column; for (i=0; i<MAX_APPEARANCE_INDEX; i++) { q_cols[app_shared_entity_col[i] = n_result_cols++] = &app_shared_entity_column[i]; q_cols[app_call_state_col[i] = n_result_cols++] = &app_call_state_column[i]; q_cols[app_call_info_uri_col[i] = n_result_cols++] = &app_call_info_uri_column[i]; q_cols[app_call_info_appearance_uri_col[i] = n_result_cols++] = &app_call_info_appearance_uri_column[i]; q_cols[app_b2bl_key_col[i] = n_result_cols++] = &app_b2bl_key_column[i]; } /* select the whole tabel and all the columns */ if (DB_CAPABILITY(sca_dbf, DB_CAP_FETCH)) { if(sca_dbf.query(sca_db_handle, 0, 0, 0, q_cols, 0, SCA_TABLE_TOTAL_COL_NO, 0, 0) < 0) { LM_ERR("Error while querying (fetch) database\n"); return -1; } if(sca_dbf.fetch_result(sca_db_handle, &res, SCA_FETCH_SIZE)<0){ LM_ERR("fetching rows failed\n"); return -1; } } else { if(sca_dbf.query(sca_db_handle, 0, 0, 0, q_cols, 0, SCA_TABLE_TOTAL_COL_NO, 0, &res) < 0) { LM_ERR("Error while querying database\n"); return -1; } } nr_rows = RES_ROW_N(res); do { LM_DBG("loading [%i] records from db\n", nr_rows); rows = RES_ROWS(res); /* for every row/record */ for(i=0; i<nr_rows; i++){ values = ROW_VALUES(rows + i); if (VAL_NULL(values+shared_line_col) || VAL_NULL(values+watchers_col)) { LM_ERR("columns [%.*s] or/and [%.*s] cannot be null -> skipping\n", shared_line_column.len, shared_line_column.s, watchers_column.len, watchers_column.s); continue; } shared_line.s = (char*)values[shared_line_col].val.string_val; shared_line.len = strlen(shared_line.s); watchers_csv.s = (char*)values[watchers_col].val.string_val; watchers_csv.len = strlen(watchers_csv.s); record = restore_record(&shared_line, &watchers_csv); if (record == NULL) goto error; hash_index = core_hash(&shared_line, NULL, b2b_sca_hsize); j = 0; while (j < MAX_APPEARANCE_INDEX) { if( VAL_NULL(values + app_shared_entity_col[j]) || VAL_NULL(values + app_call_state_col[j]) || VAL_NULL(values + app_call_info_uri_col[j]) || VAL_NULL(values + app_call_info_appearance_uri_col[j]) || VAL_NULL(values + app_b2bl_key_col[j]) ) { goto cont; } appearance_index = j + 1; /* 1 - get shared_entity */ shared_entity = values[app_shared_entity_col[j]].val.int_val; if (shared_entity!=0 && shared_entity!=1) { LM_ERR("Unexpected shared_entity [%d] " "for shared_line [%.*s]\n", shared_entity, shared_line.len, shared_line.s); goto cont; } /* 2 - get call_state */ call_state = values[app_call_state_col[j]].val.int_val; if (call_state == IDLE_STATE) { LM_DBG("empty call[%d]\n", appearance_index); goto cont; } if (call_state > MAX_INDEX_STATE) { LM_ERR("Unexpected call_state [%d] for shared_line [%.*s]\n", call_state, shared_line.len, shared_line.s); goto cont; } /* 3 - get call_info_uri */ call_info_uri.s = (char*)values[app_call_info_uri_col[j]].val.string_val; if (call_info_uri.s) call_info_uri.len = strlen(call_info_uri.s); else { LM_ERR("Missing call_info_uri for shared_line [%.*s][%d]\n", shared_line.len, shared_line.s, appearance_index); goto cont; } LM_DBG("call_info_uri=[%.*s]\n", call_info_uri.len, call_info_uri.s); /* 4 - get call_info_apperance_uri */ call_info_apperance_uri.s = (char*) values[app_call_info_appearance_uri_col[j]].val.string_val; if (call_info_apperance_uri.s) call_info_apperance_uri.len = strlen(call_info_apperance_uri.s); else { LM_ERR("Missing call_info_apperance_uri for " "shared_line [%.*s][%d]\n", shared_line.len, shared_line.s, appearance_index); goto cont; } LM_DBG("call_info_apperance_uri=[%.*s]\n", call_info_apperance_uri.len, call_info_apperance_uri.s); /* 5 - get b2bl_key */ b2bl_key.s = (char*)values[app_b2bl_key_col[j]].val.string_val; if (b2bl_key.s) { b2bl_key.len = strlen(b2bl_key.s); if (b2bl_key.len > B2BL_MAX_KEY_LEN) { LM_ERR("buffer overflow on b2bl_key [%.*s]" " for shared_line [%.*s][%d]\n", b2bl_key.len, b2bl_key.s, shared_line.len, shared_line.s, appearance_index); goto cont; } LM_DBG("b2bl_key=[%.*s]\n", b2bl_key.len, b2bl_key.s); } else { LM_ERR("Missing b2bl_key for shared_line [%.*s][1]\n", shared_line.len, shared_line.s); goto cont; } /* restore the call */ call = restore_call(record, appearance_index, shared_entity, call_state, &call_info_uri, &call_info_apperance_uri); if (call == NULL) { goto error; } /* update record */ if (0!=b2b_sca_update_call_record_key(call, &b2bl_key)) { LM_ERR("Unable to update b2bl_key [%.*s]\n", b2bl_key.len, b2bl_key.s); shm_free(call); call = NULL; record->call[appearance_index-1] = NULL; goto cont; } /* Prepare b2b_logic callback params. */ cb_params = build_cb_params(hash_index, &shared_line, appearance_index); if (cb_params == NULL) { LM_ERR("Unable to build cb_params\n"); goto error; } /* re-register callbacks */ if(b2bl_api.register_cb(&b2bl_key, &sca_logic_notify, cb_params, B2B_RE_INVITE_CB|B2B_CONFIRMED_CB|B2B_DESTROY_CB) != 0){ LM_ERR("Unable register b2b cb\n"); shm_free(call); call = NULL; record->call[appearance_index-1] = NULL; goto cont; } cont: j++; } valid_record = j = 0; while (j < MAX_APPEARANCE_INDEX) { if (record->call[j]) { valid_record = 1; goto check_valid_record; } j++; } check_valid_record: if (valid_record) { b2b_sca_print_record(record); insert_record(hash_index, record); } else { LM_DBG("removing the record from db!\n"); delete_sca_info_from_db(record); } LM_DBG("Done\n"); } /* any more data to be fetched ?*/ if (DB_CAPABILITY(sca_dbf, DB_CAP_FETCH)) { if (sca_dbf.fetch_result(sca_db_handle, &res, SCA_FETCH_SIZE)<0) { LM_ERR("fetching more rows failed\n"); goto error; } nr_rows = RES_ROW_N(res); } else { nr_rows = 0; } }while (nr_rows>0); sca_dbf.free_result(sca_db_handle, res); return 0; error: sca_dbf.free_result(sca_db_handle, res); return -1; }
int insert_sca_info_into_db(b2b_sca_record_t *record) { b2b_sca_call_t *call = NULL; unsigned int n_q_cols = 0; unsigned int i; unsigned int appearance_index = MAX_APPEARANCE_INDEX; unsigned int shared_line_col, watchers_col; unsigned int app_shared_entity_col[MAX_APPEARANCE_INDEX]; unsigned int app_call_state_col[MAX_APPEARANCE_INDEX]; unsigned int app_call_info_uri_col[MAX_APPEARANCE_INDEX]; unsigned int app_call_info_appearance_uri_col[MAX_APPEARANCE_INDEX]; unsigned int app_b2bl_key_col[MAX_APPEARANCE_INDEX]; db_key_t q_cols[SCA_TABLE_TOTAL_COL_NO]; db_val_t q_vals[SCA_TABLE_TOTAL_COL_NO]; LM_DBG("\n"); if(use_sca_table()) return -1; memset(q_vals, 0, SCA_TABLE_TOTAL_COL_NO * sizeof(db_val_t)); q_cols[shared_line_col = n_q_cols++] = &shared_line_column; q_vals[shared_line_col].type = DB_STR; q_cols[watchers_col = n_q_cols++] = &watchers_column; q_vals[watchers_col].type = DB_STR; for (i=0; i<MAX_APPEARANCE_INDEX; i++) { q_cols[app_shared_entity_col[i] = n_q_cols++] = &app_shared_entity_column[i]; q_vals[app_shared_entity_col[i]].type = DB_INT; q_cols[app_call_state_col[i] = n_q_cols++] = &app_call_state_column[i]; q_vals[app_call_state_col[i]].type = DB_INT; q_cols[app_call_info_uri_col[i] = n_q_cols++] = &app_call_info_uri_column[i]; q_vals[app_call_info_uri_col[i]].type = DB_STR; q_cols[app_call_info_appearance_uri_col[i] = n_q_cols++] = &app_call_info_appearance_uri_column[i]; q_vals[app_call_info_appearance_uri_col[i]].type = DB_STR; q_cols[app_b2bl_key_col[i] = n_q_cols++] = &app_b2bl_key_column[i]; q_vals[app_b2bl_key_col[i]].type = DB_STR; } q_vals[shared_line_col].val.str_val = record->shared_line; /* FIXME: get all the watchers */ if (record->watchers) { q_vals[watchers_col].val.str_val = record->watchers->watcher; } for (i=0; i<MAX_APPEARANCE_INDEX; i++) { if (record->call[i]) { if (call) { LM_ERR("This should be an UPDATE not an INSERT\n"); return -1; } call = record->call[i]; appearance_index = i; } } if (call) { q_vals[app_shared_entity_col[appearance_index]].val.int_val = call->shared_entity; q_vals[app_call_state_col[appearance_index]].val.int_val = call->call_state; q_vals[app_call_info_uri_col[appearance_index]].val.str_val = call->call_info_uri; q_vals[app_call_info_appearance_uri_col[appearance_index]].val.str_val = call->call_info_apperance_uri; q_vals[app_b2bl_key_col[appearance_index]].val.str_val = call->b2bl_key; if((sca_dbf.insert(sca_db_handle, q_cols, q_vals, SCA_TABLE_TOTAL_COL_NO)) != 0) { LM_ERR("could not add record\n"); return -1; } } else { LM_ERR("Empty record?\n"); return -1; } return 0; }
int update_sca_info_to_db(b2b_sca_record_t *record, unsigned int appearance_index) { b2b_sca_call_t *call; unsigned int i; unsigned int n_q_cols = 0, n_q_vals = 0; unsigned int shared_line_col, watchers_col; unsigned int app_shared_entity_col[MAX_APPEARANCE_INDEX]; unsigned int app_call_state_col[MAX_APPEARANCE_INDEX]; unsigned int app_call_info_uri_col[MAX_APPEARANCE_INDEX]; unsigned int app_call_info_appearance_uri_col[MAX_APPEARANCE_INDEX]; unsigned int app_b2bl_key_col[MAX_APPEARANCE_INDEX]; db_key_t q_cols[SCA_TABLE_TOTAL_COL_NO]; db_val_t q_vals[SCA_TABLE_TOTAL_COL_NO]; LM_DBG("\n"); if(use_sca_table()) return -1; memset(q_vals, 0, SCA_TABLE_TOTAL_COL_NO * sizeof(db_val_t)); q_cols[shared_line_col = n_q_cols++] = &shared_line_column; q_vals[shared_line_col].type = DB_STR; q_cols[watchers_col = n_q_cols++] = &watchers_column; q_vals[watchers_col].type = DB_STR; for (i=0; i<MAX_APPEARANCE_INDEX; i++) { q_cols[app_shared_entity_col[i] = n_q_cols++] = &app_shared_entity_column[i]; q_vals[app_shared_entity_col[i]].type = DB_INT; q_cols[app_call_state_col[i] = n_q_cols++] = &app_call_state_column[i]; q_vals[app_call_state_col[i]].type = DB_INT; q_cols[app_call_info_uri_col[i] = n_q_cols++] = &app_call_info_uri_column[i]; q_vals[app_call_info_uri_col[i]].type = DB_STR; q_cols[app_call_info_appearance_uri_col[i] = n_q_cols++] = &app_call_info_appearance_uri_column[i]; q_vals[app_call_info_appearance_uri_col[i]].type = DB_STR; q_cols[app_b2bl_key_col[i] = n_q_cols++] = &app_b2bl_key_column[i]; q_vals[app_b2bl_key_col[i]].type = DB_STR; } q_vals[shared_line_col].val.str_val = record->shared_line; i = appearance_index - 1; if (i >= MAX_APPEARANCE_INDEX) { LM_ERR("Non matching call\n"); return -1; } call = record->call[i]; if (call) { LM_DBG("update shared_entity [%d] and call_state [%d] for call[%d][%.*s]\n", call->shared_entity, call->call_state, i, call->b2bl_key.len, call->b2bl_key.s); switch(call->call_state) { case ALERTING_STATE: q_vals[app_call_info_uri_col[i]].val.str_val = call->call_info_uri; q_vals[app_call_info_appearance_uri_col[i]].val.str_val = call->call_info_apperance_uri; q_vals[app_b2bl_key_col[i]].val.str_val = call->b2bl_key; LM_DBG("update [%.*s][%.*s][%.*s]\n", call->call_info_uri.len, call->call_info_uri.s, call->call_info_apperance_uri.len, call->call_info_apperance_uri.s, call->b2bl_key.len, call->b2bl_key.s); n_q_vals += 3; default: q_vals[app_shared_entity_col[i]].val.int_val = call->shared_entity; q_vals[app_call_state_col[i]].val.int_val = call->call_state; n_q_vals += 2; } } else { n_q_vals = 5; } if(sca_dbf.update(sca_db_handle, q_cols, 0, q_vals, q_cols + app_shared_entity_col[i], q_vals + app_shared_entity_col[i], 1, n_q_vals) != 0) { LM_ERR("failed to update record\n"); return -1; } return 0; }
void lua_sr_kemi_register_libs(lua_State *L) { luaL_Reg *_sr_crt_KSRMethods = NULL; sr_kemi_module_t *emods = NULL; int emods_size = 0; int i; int k; int n; char mname[128]; #if 0 /* dynamic lookup on function name */ lua_sr_kemi_register_core(L); lua_sr_kemi_register_modules(L); #endif _sr_KSRMethods = malloc(SR_LUA_KSR_METHODS_SIZE * sizeof(luaL_Reg)); if(_sr_KSRMethods==NULL) { LM_ERR("no more pkg memory\n"); return; } memset(_sr_KSRMethods, 0, SR_LUA_KSR_METHODS_SIZE * sizeof(luaL_Reg)); emods_size = sr_kemi_modules_size_get(); emods = sr_kemi_modules_get(); n = 0; _sr_crt_KSRMethods = _sr_KSRMethods; if(emods_size==0 || emods[0].kexp==NULL) { LM_ERR("no kemi exports registered\n"); return; } for(i=0; emods[0].kexp[i].func!=NULL; i++) { LM_DBG("exporting KSR.%s(...)\n", emods[0].kexp[i].fname.s); _sr_crt_KSRMethods[i].name = emods[0].kexp[i].fname.s; _sr_crt_KSRMethods[i].func = sr_kemi_lua_export_associate(&emods[0].kexp[i]); if(_sr_crt_KSRMethods[i].func == NULL) { LM_ERR("failed to associate kemi function with lua export\n"); free(_sr_KSRMethods); _sr_KSRMethods = NULL; return; } n++; } luaL_openlib(L, "KSR", _sr_crt_KSRMethods, 0); /* special modules - pv.get(...) can return int or str */ luaL_openlib(L, "KSR.pv", _sr_pv_Map, 0); luaL_openlib(L, "KSR.x", _sr_kemi_x_Map, 0); /* registered kemi modules */ if(emods_size>1) { for(k=1; k<emods_size; k++) { n++; _sr_crt_KSRMethods = _sr_KSRMethods + n; snprintf(mname, 128, "KSR.%s", emods[k].kexp[0].mname.s); for(i=0; emods[k].kexp[i].func!=NULL; i++) { LM_DBG("exporting %s.%s(...)\n", mname, emods[k].kexp[i].fname.s); _sr_crt_KSRMethods[i].name = emods[k].kexp[i].fname.s; _sr_crt_KSRMethods[i].func = sr_kemi_lua_export_associate(&emods[k].kexp[i]); if(_sr_crt_KSRMethods[i].func == NULL) { LM_ERR("failed to associate kemi function with func export\n"); free(_sr_KSRMethods); _sr_KSRMethods = NULL; return; } n++; } luaL_openlib(L, mname, _sr_crt_KSRMethods, 0); LM_DBG("initializing kemi sub-module: %s (%s)\n", mname, emods[k].kexp[0].mname.s); } } LM_DBG("module 'KSR' has been initialized\n"); }
/*! * \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) { dlg_cell_t *dlg; dlg_iuid_t *iuid; str val, callid, ftag, ttag; int h_entry, h_id, new_state, old_state, unref, event, timeout, reset; unsigned int dir; int ret = 0; dlg = dlg_get_ctx_dialog(); if (dlg!=NULL) { dlg_release(dlg); 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 = dlg_lookup(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 dlg_release(dlg); 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, callee tag='%.*s'/%d\n", dlg->callid.len, dlg->callid.s, dlg->callid.len, dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s, dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s, dlg->tag[DLG_CALLEE_LEG].len); // lookup_dlg has incremented the ref count by 1 dlg_release(dlg); // 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==0){ 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.iuid.h_entry = dlg->h_entry; _dlg_ctx.iuid.h_id = dlg->h_id; if (req->first_line.u.request.method_value != METHOD_ACK) { iuid = dlg_get_iuid_shm_clone(dlg); if(iuid!=NULL) { /* register callback for the replies of this request */ if ( d_tmb.register_tmcb( req, 0, TMCB_RESPONSE_IN|TMCB_ON_FAILURE, dlg_onreply, (void*)iuid, dlg_iuid_sfree)<0 ) { LM_ERR("failed to register TMCB (3)\n"); shm_free(iuid); } iuid = NULL; } } /* 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); CURR_DLG_ID = req->id; CURR_DLG_LIFETIME = (unsigned int)(time(0))-dlg->start_ts; CURR_DLG_STATUS = new_state; dlg_run_event_route(dlg, req, old_state, new_state); /* delay deletion of dialog until transaction has died off in order * to absorb in-air messages */ if (new_state==DLG_STATE_DELETED && old_state!=DLG_STATE_DELETED) { iuid = dlg_get_iuid_shm_clone(dlg); if(iuid!=NULL) { if ( d_tmb.register_tmcb(req, NULL, TMCB_DESTROY, unref_dlg_from_cb, (void*)iuid, dlg_iuid_sfree)<0 ) { LM_ERR("failed to register deletion delay function\n"); shm_free(iuid); } else { dlg_ref(dlg, 1); } } } if (new_state==DLG_STATE_CONFIRMED && old_state!=DLG_STATE_CONFIRMED) dlg_ka_add(dlg); /* 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' '%.*s'\n", dlg, dlg->h_entry, dlg->h_id, dlg->callid.len, dlg->callid.s, dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s, dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s); } else if (ret > 0) { LM_WARN("inconsitent dlg timer data on dlg %p [%u:%u] " "with clid '%.*s' and tags '%.*s' '%.*s'\n", dlg, dlg->h_entry, dlg->h_id, dlg->callid.len, dlg->callid.s, dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s, dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s); } else { /* one extra unref due to removal from timer list */ unref++; } /* dialog terminated (BYE) */ dlg_terminated( req, dlg, dir); dlg_unref(dlg, unref); _dlg_ctx.cpid = my_pid(); _dlg_ctx.expect_t = 1; dlg_set_ctx_iuid(dlg); if_update_stat( dlg_enable_stats, active_dlgs, -1); goto done; } 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; } reset = !((dlg->iflags & DLG_IFLAG_TIMER_NORESET) || dlg_timeout_noreset); if ((new_state!=DLG_STATE_EARLY) && (old_state!=DLG_STATE_CONFIRMED || reset)) { if (update_dlg_timer( &dlg->tl, dlg->lifetime )==-1) { LM_ERR("failed to update dialog lifetime\n"); } else { dlg->dflags |= DLG_FLAG_CHANGED; } } if(event != DLG_EVENT_REQACK) { if(update_cseqs(dlg, req, dir)!=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_NA) { 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 ) { iuid = dlg_get_iuid_shm_clone(dlg); if(iuid!=NULL) { /* 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*)iuid, dlg_iuid_sfree)<0 ) { LM_ERR("failed to register TMCB (2)\n"); shm_free(iuid); } } } } } if(new_state==DLG_STATE_CONFIRMED && old_state==DLG_STATE_CONFIRMED_NA){ dlg->dflags |= DLG_FLAG_CHANGED; if(dlg_db_mode == DB_MODE_REALTIME) update_dialog_dbinfo(dlg); } done: dlg_release(dlg); return; }
/** * Receives a message and does basic processing or call the sm_process(). * This gets called from the do_receive() for every message that is received. * Basic processing, before the state machine, is done here. * @param msg - the message received * @param sp - the serviced peer that it was receiver on */ void receive_message(AAAMessage *msg,serviced_peer_t *sp) { AAA_AVP *avp1,*avp2; LM_DBG("receive_message(): [%.*s] Recv msg %d\n", sp->p?sp->p->fqdn.len:0, sp->p?sp->p->fqdn.s:0, msg->commandCode); if (!sp->p){ switch (msg->commandCode){ case Code_CE: if (is_req(msg)){ avp1 = AAAFindMatchingAVP(msg,msg->avpList.head,AVP_Origin_Host,0,0); avp2 = AAAFindMatchingAVP(msg,msg->avpList.head,AVP_Origin_Realm,0,0); if (avp1&&avp2){ sp->p = get_peer_from_fqdn(avp1->data,avp2->data); } if (!sp->p) { LM_ERR("receive_msg(): Received CER from unknown peer (accept unknown=%d) -ignored\n", config->accept_unknown_peers); AAAFreeMessage(&msg); }else{ LM_DBG("receive_message(): [%.*s] This receiver has no peer associated\n", sp->p?sp->p->fqdn.len:0, sp->p?sp->p->fqdn.s:0 ); //set_peer_pipe(); make_send_pipe(sp); sm_process(sp->p,R_Conn_CER,msg,0,sp->tcp_socket); } } else{ LM_ERR("receive_msg(): Received CEA from an unknown peer -ignored\n"); AAAFreeMessage(&msg); } break; default: LM_ERR("receive_msg(): Received non-CE from an unknown peer -ignored\n"); AAAFreeMessage(&msg); } }else{ touch_peer(sp->p); switch (sp->p->state){ case Wait_I_CEA: if (msg->commandCode!=Code_CE||is_req(msg)){ sm_process(sp->p,I_Rcv_Non_CEA,msg,0,sp->tcp_socket); }else sm_process(sp->p,I_Rcv_CEA,msg,0,sp->tcp_socket); break; case I_Open: switch (msg->commandCode){ case Code_CE: if (is_req(msg)) sm_process(sp->p,I_Rcv_CER,msg,0,sp->tcp_socket); else sm_process(sp->p,I_Rcv_CEA,msg,0,sp->tcp_socket); break; case Code_DW: if (is_req(msg)) sm_process(sp->p,I_Rcv_DWR,msg,0,sp->tcp_socket); else sm_process(sp->p,I_Rcv_DWA,msg,0,sp->tcp_socket); break; case Code_DP: if (is_req(msg)) sm_process(sp->p,I_Rcv_DPR,msg,0,sp->tcp_socket); else sm_process(sp->p,I_Rcv_DPA,msg,0,sp->tcp_socket); break; default: sm_process(sp->p,I_Rcv_Message,msg,0,sp->tcp_socket); } break; case R_Open: switch (msg->commandCode){ case Code_CE: if (is_req(msg)) sm_process(sp->p,R_Rcv_CER,msg,0,sp->tcp_socket); else sm_process(sp->p,R_Rcv_CEA,msg,0,sp->tcp_socket); break; case Code_DW: if (is_req(msg)) sm_process(sp->p,R_Rcv_DWR,msg,0,sp->tcp_socket); else sm_process(sp->p,R_Rcv_DWA,msg,0,sp->tcp_socket); break; case Code_DP: if (is_req(msg)) sm_process(sp->p,R_Rcv_DPR,msg,0,sp->tcp_socket); else sm_process(sp->p,R_Rcv_DPA,msg,0,sp->tcp_socket); break; default: sm_process(sp->p,R_Rcv_Message,msg,0,sp->tcp_socket); } break; default: LM_ERR("receive_msg(): [%.*s] Received msg while peer in state %d -ignored\n", sp->p->fqdn.len, sp->p->fqdn.s, sp->p->state); AAAFreeMessage(&msg); } } }
/*! * \brief Parse SIP message and populate leg informations * * Parse SIP message and populate leg informations. * \param dlg the dialog to add cseq, contact & record_route * \param msg sip message * \param t transaction * \param leg type of the call leg * \param tag SIP To tag * \return 0 on success, -1 on failure * \note for a request: get record route in normal order, for a reply get * in reverse order, skipping the ones from the request and the proxies' own */ int populate_leg_info( struct dlg_cell *dlg, struct sip_msg *msg, struct cell* t, unsigned int leg, str *tag) { unsigned int skip_recs; str cseq; str contact; str rr_set; dlg->bind_addr[leg] = msg->rcv.bind_address; /* extract the cseq number as string */ if (leg==DLG_CALLER_LEG) { if((!msg->cseq && (parse_headers(msg,HDR_CSEQ_F,0)<0 || !msg->cseq)) || !msg->cseq->parsed){ LM_ERR("bad sip message or missing CSeq hdr :-/\n"); goto error0; } cseq = (get_cseq(msg))->number; } else { /* use the same as in request */ cseq = dlg->cseq[DLG_CALLEE_LEG]; } /* extract the contact address */ if (!msg->contact&&(parse_headers(msg,HDR_CONTACT_F,0)<0||!msg->contact)){ LM_ERR("bad sip message or missing Contact hdr\n"); goto error0; } if ( parse_contact(msg->contact)<0 || ((contact_body_t *)msg->contact->parsed)->contacts==NULL || ((contact_body_t *)msg->contact->parsed)->contacts->next!=NULL ) { LM_ERR("bad Contact HDR\n"); goto error0; } contact = ((contact_body_t *)msg->contact->parsed)->contacts->uri; /* extract the RR parts */ if(!msg->record_route && (parse_headers(msg,HDR_EOH_F,0)<0) ){ LM_ERR("failed to parse record route header\n"); goto error0; } if (leg==DLG_CALLER_LEG) { skip_recs = 0; } else { /* was the 200 OK received or local generated */ skip_recs = dlg->from_rr_nb + ((t->relayed_reply_branch>=0)? ((t->uac[t->relayed_reply_branch].flags&TM_UAC_FLAG_R2)?2: ((t->uac[t->relayed_reply_branch].flags&TM_UAC_FLAG_RR)?1:0)) :0); } if(msg->record_route){ if( print_rr_body(msg->record_route, &rr_set, leg, &skip_recs) != 0 ){ LM_ERR("failed to print route records \n"); goto error0; } } else { rr_set.s = 0; rr_set.len = 0; } if(leg==DLG_CALLER_LEG) dlg->from_rr_nb = skip_recs; LM_DBG("route_set %.*s, contact %.*s, cseq %.*s and bind_addr %.*s\n", rr_set.len, rr_set.s, contact.len, contact.s, cseq.len, cseq.s, msg->rcv.bind_address->sock_str.len, msg->rcv.bind_address->sock_str.s); if (dlg_set_leg_info( dlg, tag, &rr_set, &contact, &cseq, leg)!=0) { LM_ERR("dlg_set_leg_info failed\n"); if (rr_set.s) pkg_free(rr_set.s); goto error0; } if (rr_set.s) pkg_free(rr_set.s); return 0; error0: return -1; }
/** * Does the actual receive operations on the Diameter TCP socket, for retrieving incoming messages. * The functions is to be called iteratively, each time there is something to be read from the TCP socket. It uses * a simple state machine to read first the version, then the header and then the rest of the message. When an * entire message is received, it is decoded and passed to the processing functions. * @param sp - the serviced peer to operate on * @return 1 on success, 0 on failure */ static inline int do_receive(serviced_peer_t *sp) { int cnt,n,version; char *dst; AAAMessage *dmsg; switch (sp->state){ case Receiver_Waiting: n = 1; /* wait for version */ dst = sp->buf; break; case Receiver_Header: n = DIAMETER_HEADER_LEN - sp->buf_len; /* waiting for rest of header */ dst = sp->buf+sp->buf_len; break; case Receiver_Rest_of_Message: n = sp->length - sp->msg_len; /* waiting for the rest of the message */ dst = sp->msg+sp->msg_len; break; default: LM_ERR("do_receive(): [%.*s] Unknown state %d\n", sp->p?sp->p->fqdn.len:0, sp->p?sp->p->fqdn.s:0, sp->state); goto error_and_reset; } cnt = recv(sp->tcp_socket,dst,n,0); if (cnt<=0) goto error_and_reset; switch (sp->state){ case Receiver_Waiting: version = (unsigned char)(sp->buf[0]); if (version!=1) { LM_ERR("do_receive(): [%.*s] Received Unknown version [%d]\n", sp->p->fqdn.len, sp->p->fqdn.s, (unsigned char)sp->buf[0]); goto error_and_reset; }else{ sp->state = Receiver_Header; sp->buf_len = 1; } break; case Receiver_Header: sp->buf_len+=cnt; if (sp->buf_len==DIAMETER_HEADER_LEN){ sp->length = get_3bytes(sp->buf+1); if (sp->length>DP_MAX_MSG_LENGTH){ LM_ERR("do_receive(): [%.*s] Msg too big [%d] bytes\n", sp->p?sp->p->fqdn.len:0, sp->p?sp->p->fqdn.s:0, sp->length); goto error_and_reset; } LM_DBG("receive_loop(): [%.*s] Recv Version %d Length %d\n", sp->p?sp->p->fqdn.len:0, sp->p?sp->p->fqdn.s:0, (unsigned char)(sp->buf[0]), sp->length); sp->msg = shm_malloc(sp->length); if (!sp->msg) { LOG_NO_MEM("shm",sp->length); goto error_and_reset; } memcpy(sp->msg,sp->buf,sp->buf_len); sp->msg_len=sp->buf_len; sp->state = Receiver_Rest_of_Message; } break; case Receiver_Rest_of_Message: sp->msg_len+=cnt; if (sp->msg_len==sp->length){ dmsg = AAATranslateMessage((unsigned char*)sp->msg,(unsigned int)sp->msg_len,1); if (dmsg) { sp->msg = 0; receive_message(dmsg,sp); } else { shm_free(sp->msg); sp->msg = 0; } sp->msg_len = 0; sp->buf_len = 0; sp->state = Receiver_Waiting; } break; default: LM_ERR("do_receive(): [%.*s] Unknown state %d\n", sp->p?sp->p->fqdn.len:0, sp->p?sp->p->fqdn.s:0, sp->state); goto error_and_reset; } return 1; error_and_reset: if (sp->msg){ shm_free(sp->msg); sp->msg = 0; sp->msg_len = 0; sp->buf_len = 0; sp->state = Receiver_Waiting; } return 0; }
/*! * \brief Function that is registered as TM callback and called on replies * * Function that is registered as TM callback and called on replies. It * parses the reply and set the appropriate event. This is then used to * update the dialog state, run eventual dialog callbacks and save or * update the necessary informations about the dialog. * \see next_state_dlg * \param t transaction, unused * \param type type of the entered callback * \param param saved dialog structure in the callback */ static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param) { dlg_cell_t *dlg = NULL; dlg_iuid_t *iuid = NULL; int new_state, old_state, unref, event; str tag; sip_msg_t *req = param->req; sip_msg_t *rpl = param->rpl; if (shutdown_done) return; iuid = (dlg_iuid_t*)(*param->param); dlg = dlg_get_by_iuid(iuid); if(dlg==0) return; unref = 0; if (type & (TMCB_RESPONSE_IN|TMCB_ON_FAILURE)) { /* Set the dialog context so it is available in onreply_route and failure_route*/ set_current_dialog(req, dlg); dlg_set_ctx_iuid(dlg); goto done; } if (type==TMCB_RESPONSE_FWDED) { /* The state does not change, but the msg is mutable in this callback*/ run_dlg_callbacks(DLGCB_RESPONSE_FWDED, dlg, req, rpl, DLG_DIR_UPSTREAM, 0); goto done; } if (type==TMCB_DESTROY) event = DLG_EVENT_TDEL; else if (param->code<200) event = DLG_EVENT_RPL1xx; else if (param->code<300) event = DLG_EVENT_RPL2xx; else event = DLG_EVENT_RPL3xx; next_state_dlg( dlg, event, &old_state, &new_state, &unref); dlg_run_event_route(dlg, (rpl==FAKED_REPLY)?NULL:rpl, old_state, new_state); if (new_state==DLG_STATE_EARLY) { run_dlg_callbacks(DLGCB_EARLY, dlg, req, rpl, DLG_DIR_UPSTREAM, 0); if (old_state!=DLG_STATE_EARLY) if_update_stat(dlg_enable_stats, early_dlgs, 1); goto done; } if (new_state==DLG_STATE_CONFIRMED_NA && old_state!=DLG_STATE_CONFIRMED_NA && old_state!=DLG_STATE_CONFIRMED ) { LM_DBG("dialog %p confirmed (ACK pending)\n",dlg); if (rpl != FAKED_REPLY) { /* get to tag*/ if ( !rpl->to && ((parse_headers(rpl, HDR_TO_F,0)<0) || !rpl->to) ) { LM_ERR("bad reply or missing TO hdr :-/\n"); tag.s = 0; tag.len = 0; } else { tag = get_to(rpl)->tag_value; if (tag.s==0 || tag.len==0) { LM_ERR("missing TAG param in TO hdr :-/\n"); tag.s = 0; tag.len = 0; } } /* save callee's tag, cseq, contact and record route*/ if (populate_leg_info( dlg, rpl, t, DLG_CALLEE_LEG, &tag) !=0) { LM_ERR("could not add further info to the dialog\n"); } } else { LM_ERR("Faked reply!\n"); } /* set start time */ dlg->start_ts = (unsigned int)(time(0)); /* save the settings to the database, * if realtime saving mode configured- save dialog now * else: the next time the timer will fire the update*/ dlg->dflags |= DLG_FLAG_NEW; if ( dlg_db_mode==DB_MODE_REALTIME ) update_dialog_dbinfo(dlg); if (0 != insert_dlg_timer( &dlg->tl, dlg->lifetime )) { LM_CRIT("Unable to insert dlg %p [%u:%u] on event %d [%d->%d] " "with clid '%.*s' and tags '%.*s' '%.*s'\n", dlg, dlg->h_entry, dlg->h_id, event, old_state, new_state, dlg->callid.len, dlg->callid.s, dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s, dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s); } else { /* dialog pointer inserted in timer list */ dlg_ref(dlg, 1); } /* dialog confirmed (ACK pending) */ run_dlg_callbacks( DLGCB_CONFIRMED_NA, dlg, req, rpl, DLG_DIR_UPSTREAM, 0); if (old_state==DLG_STATE_EARLY) if_update_stat(dlg_enable_stats, early_dlgs, -1); if (unref) dlg_unref(dlg, unref); if_update_stat(dlg_enable_stats, active_dlgs, 1); goto done; } if ( new_state==DLG_STATE_DELETED && (old_state==DLG_STATE_UNCONFIRMED || old_state==DLG_STATE_EARLY) ) { LM_DBG("dialog %p failed (negative reply)\n", dlg); /* dialog setup not completed (3456XX) */ run_dlg_callbacks( DLGCB_FAILED, dlg, req, rpl, DLG_DIR_UPSTREAM, 0); if(dlg_wait_ack==1) dlg_set_tm_waitack(t, dlg); /* do unref */ if (unref) dlg_unref(dlg, unref); if (old_state==DLG_STATE_EARLY) if_update_stat(dlg_enable_stats, early_dlgs, -1); if_update_stat(dlg_enable_stats, failed_dlgs, 1); goto done; } if (unref) dlg_unref(dlg, unref); done: /* unref due to dlg_get_by_iuid() */ dlg_release(dlg); return; }
/** * Initiate a connection to a peer. * The obtained socket is then sent to the respective receiver. * This is typically called from the timer, but otherwise it can be called from any other process. * @param p - peer to connect to * @returns socket if OK, -1 on error */ int peer_connect(peer *p) { int sock; unsigned int option = 1; struct addrinfo *ainfo=0,*res=0,*sainfo=0,hints; char buf[256],host[256],serv[256]; int error; memset (&hints, 0, sizeof(hints)); //hints.ai_protocol = IPPROTO_SCTP; //hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = AI_ADDRCONFIG; hints.ai_socktype = SOCK_STREAM; sprintf(buf,"%d",p->port); error = getaddrinfo(p->fqdn.s, buf, &hints, &res); if (error!=0){ LM_WARN("peer_connect(): Error opening connection to %.*s:%d >%s\n", p->fqdn.len,p->fqdn.s,p->port,gai_strerror(error)); goto error; } for(ainfo = res;ainfo;ainfo = ainfo->ai_next) { if (getnameinfo(ainfo->ai_addr,ainfo->ai_addrlen, host,256,serv,256,NI_NUMERICHOST|NI_NUMERICSERV)==0){ LM_WARN("peer_connect(): Trying to connect to %s port %s\n", host,serv); } if ((sock = socket(ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol)) == -1) { LM_ERR("peer_connect(): error creating client socket to %s port %s >" " %s\n",host,serv,strerror(errno)); continue; } /* try to set the local socket used to connect to the peer */ if (p->src_addr.s && p->src_addr.len > 0) { LM_DBG("peer_connect(): connetting to peer via src addr=%.*s",p->src_addr.len, p->src_addr.s); memset (&hints, 0, sizeof(hints)); hints.ai_flags = AI_NUMERICHOST; hints.ai_socktype = SOCK_STREAM; error = getaddrinfo(p->src_addr.s, NULL, &hints, &sainfo); if (error!=0){ LM_WARN("peer_connect(): error getting client socket on %.*s:%s\n", p->src_addr.len,p->src_addr.s,gai_strerror(error)); } else { if (bind(sock, sainfo->ai_addr, sainfo->ai_addrlen )) { LM_WARN("peer_connect(): error opening client socket on %.*s:%s\n", p->src_addr.len,p->src_addr.s,strerror(errno)); } } } {// Connect with timeout int x; x=fcntl(sock,F_GETFL,0); fcntl(sock,F_SETFL,x | O_NONBLOCK); int res = connect(sock,ainfo->ai_addr,ainfo->ai_addrlen); if (res<0){ if (errno==EINPROGRESS){ struct timeval tv={ .tv_sec = config->connect_timeout, .tv_usec = 0, }; fd_set myset; FD_ZERO(&myset); FD_SET(sock, &myset); if (select(sock+1, NULL, &myset, NULL, &tv) > 0) { socklen_t lon = sizeof(int); int valopt; getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &lon); if (valopt) { LM_WARN("peer_connect(): Error opening connection to to %s port %s >%s\n",host,serv,strerror(valopt)); close(sock); continue; } }else{ LM_WARN("peer_connect(): Timeout or error opening connection to to %s port %s >%s\n",host,serv,strerror(errno)); close(sock); continue; } } }else{ LM_WARN("peer_connect(): Error opening connection to to %s port %s >%s\n",host,serv,strerror(errno)); close(sock); continue; } x=fcntl(sock,F_GETFL,0); fcntl(sock,F_SETFL,x & (~O_NONBLOCK)); } setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&option,sizeof(option)); LM_INFO("peer_connect(): Peer %.*s:%d connected\n",p->fqdn.len,p->fqdn.s,p->port); if (!send_fd(p->fd_exchange_pipe,sock,p)){ LM_ERR("peer_connect(): [%.*s] Error sending fd to respective receiver\n",p->fqdn.len,p->fqdn.s); close(sock); goto error; } if (res) freeaddrinfo(res); return sock; } error: if (res) freeaddrinfo(res); return -1; }
/*! * \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 req SIP message * \param t transaction * \param run_initial_cbs if set zero, initial callbacks are not executed * \return 0 on success, -1 on failure */ int dlg_new_dialog(sip_msg_t *req, struct cell *t, const int run_initial_cbs) { dlg_cell_t *dlg; str s; str callid; str ftag; str ttag; str req_uri; unsigned int dir; int mlock; dlg = dlg_get_ctx_dialog(); if(dlg != NULL) { dlg_release(dlg); return -1; } if(req->first_line.u.request.method_value != METHOD_INVITE) 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); dir = DLG_DIR_NONE; mlock = 1; /* search dialog by SIP attributes * - if not found, hash table slot is left locked, to avoid races * to add 'same' dialog on parallel forking or not-handled-yet * retransmissions. Release slot after linking new dialog */ dlg = search_dlg(&callid, &ftag, &ttag, &dir); if(dlg) { mlock = 0; if (detect_spirals) { if (spiral_detected == 1) return 0; if ( dlg->state != DLG_STATE_DELETED ) { 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); /* set ctx dlg id shortcuts */ _dlg_ctx.iuid.h_entry = dlg->h_entry; _dlg_ctx.iuid.h_id = dlg->h_id; /* search_dlg() has incremented the ref count by 1 */ dlg_release(dlg); return 0; } dlg_release(dlg); } } spiral_detected = 0; dlg = build_new_dlg (&callid /*callid*/, &(get_from(req)->uri) /*from uri*/, &(get_to(req)->uri) /*to uri*/, &ftag/*from_tag*/, &req_uri /*r-uri*/ ); if (dlg==0) { if(likely(mlock==1)) dlg_hash_release(&callid); 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) { if(likely(mlock==1)) dlg_hash_release(&callid); LM_ERR("could not add further info to the dialog\n"); shm_free(dlg); return -1; } /* Populate initial varlist: */ dlg->vars = get_local_varlist_pointer(req, 1); /* if search_dlg() returned NULL, slot was kept locked */ link_dlg(dlg, 0, mlock); if(likely(mlock==1)) dlg_hash_release(&callid); 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; dlg->iflags |= _dlg_ctx.iflags; if (dlg_send_bye!=0 || _dlg_ctx.to_bye!=0) dlg->iflags |= DLG_IFLAG_TIMEOUTBYE; if (run_initial_cbs) run_create_callbacks( dlg, req); /* first INVITE seen (dialog created, unconfirmed) */ if ( seq_match_mode!=SEQ_MATCH_NO_ID && add_dlg_rr_param( req, dlg->h_entry, dlg->h_id)<0 ) { LM_ERR("failed to add RR param\n"); goto error; } if_update_stat( dlg_enable_stats, processed_dlgs, 1); _dlg_ctx.cpid = my_pid(); _dlg_ctx.iuid.h_entry = dlg->h_entry; _dlg_ctx.iuid.h_id = dlg->h_id; set_current_dialog(req, dlg); return 0; error: if (!spiral_detected) dlg_unref(dlg, 1); // undo ref regarding linking return -1; }
char* parse_fline(char* buffer, char* end, struct msg_start* fl) { char* tmp; register int state; unsigned short stat; stat=0; fl->type=SIP_REQUEST; state=START; for(tmp=buffer;tmp<end;tmp++){ switch(*tmp){ case ' ': case '\t': switch(state){ case START: /*allow space at the beginning, although not legal*/ break; case L_URI: case L_VER: case L_STATUS: case L_REASON: case L_LF: /*eat space*/ break; case FIN_INVITE: *tmp=0; fl->u.request.method.len=tmp-fl->u.request.method.s; fl->u.request.method_value=METHOD_INVITE; state=L_URI; break; case FIN_ACK: *tmp=0; fl->u.request.method.len=tmp-fl->u.request.method.s; fl->u.request.method_value=METHOD_ACK; state=L_URI; break; case FIN_CANCEL: *tmp=0; fl->u.request.method.len=tmp-fl->u.request.method.s; fl->u.request.method_value=METHOD_CANCEL; state=L_URI; break; case FIN_BYE: *tmp=0; fl->u.request.method.len=tmp-fl->u.request.method.s; fl->u.request.method_value=METHOD_BYE; state=L_URI; break; case FIN_SIP: *tmp=0; fl->u.reply.version.len=tmp-fl->u.reply.version.s; state=L_STATUS; fl->type=SIP_REPLY; break; case P_URI: *tmp=0; fl->u.request.uri.len=tmp-fl->u.request.uri.s; state=L_VER; break; case FIN_VER: *tmp=0; fl->u.request.version.len=tmp-fl->u.request.version.s; state=L_LF; break; case P_STATUS: *tmp=0; fl->u.reply.status.len=tmp-fl->u.reply.status.s; state=L_REASON; break; case P_REASON: /* *tmp=0; fl->u.reply.reason.len=tmp-fl->u.reply.reason.s; */ break; case VER1: case VER2: case VER3: case VER4: case VER5: case VER6: LM_ERR("invalid version in request\n"); goto error; case P_METHOD: default: *tmp=0; fl->u.request.method.len=tmp-fl->u.request.method.s; fl->u.request.method_value=METHOD_OTHER; state=L_URI; } break; case 's': case 'S': switch(state){ case START: state=SIP1; fl->u.reply.version.s=tmp; break; case P_URI: case P_REASON: case P_METHOD: break; case L_REASON: fl->u.reply.reason.s=tmp; state=P_REASON; break; case P_STATUS: case L_STATUS: LM_ERR("non-number character <%c> in request" "status\n", *tmp); goto error; case L_LF: LM_ERR("invalid character <%c> in request\n", *tmp); goto error; case L_URI: fl->u.request.uri.s=tmp; state=P_URI; break; case L_VER: fl->u.request.version.s=tmp; state=VER1; break; case VER1: case VER2: case VER3: case VER4: case VER5: case VER6: case FIN_VER: LM_ERR("invalid version in request\n"); goto error; default: state=P_METHOD; } break; case 'i': case 'I': switch(state){ case START: state=INVITE1; fl->u.request.method.s=tmp; break; case INVITE3: state=INVITE4; break; case SIP1: state=SIP2; break; case P_URI: case P_REASON: case P_METHOD: break; case L_REASON: fl->u.reply.reason.s=tmp; state=P_REASON; break; case P_STATUS: case L_STATUS: LM_ERR("non-number " "character <%c> in request status\n", *tmp); goto error; case L_LF: LM_ERR("invalid " "character <%c> in request\n", *tmp); goto error; case L_URI: fl->u.request.uri.s=tmp; state=P_URI; break; case VER1: state=VER2; break; case L_VER: case VER2: case VER3: case VER4: case VER5: case VER6: case FIN_VER: LM_ERR("invalid version in request\n"); goto error; default: state=P_METHOD; } break; case 'p': case 'P': switch(state){ case START: state=P_METHOD; fl->u.request.method.s=tmp; break; case SIP2: state=SIP3; break; case P_URI: case P_REASON: case P_METHOD: break; case L_REASON: fl->u.reply.reason.s=tmp; state=P_REASON; break; case P_STATUS: case L_STATUS: LM_ERR("non-number " "character <%c> in request status\n", *tmp); goto error; case L_LF: LM_ERR("invalid " "character <%c> in request\n", *tmp); goto error; case L_URI: fl->u.request.uri.s=tmp; state=P_URI; break; case VER2: state=VER3; break; case L_VER: case VER1: case VER3: case VER4: case VER5: case VER6: case FIN_VER: LM_ERR("invalid version in request\n"); goto error; default: state=P_METHOD; } break; case '/': switch(state){ case START: state=P_METHOD; fl->u.request.method.s=tmp; break; case SIP3: state=SIP4; break; case P_URI: case P_REASON: case P_METHOD: break; case L_REASON: fl->u.reply.reason.s=tmp; state=P_REASON; break; case P_STATUS: case L_STATUS: LM_ERR("non-number " "character <%c> in request status\n", *tmp); goto error; case L_LF: LM_ERR("invalid " "character <%c> in request\n", *tmp); goto error; case L_URI: fl->u.request.uri.s=tmp; state=P_URI; break; case VER3: state=VER4; break; case L_VER: case VER1: case VER2: case VER4: case VER5: case VER6: case FIN_VER: LM_ERR("invalid version in request\n"); goto error; default: state=P_METHOD; } break; case '2': switch(state){ case START: state=P_METHOD; fl->u.request.method.s=tmp; break; case SIP4: state=SIP5; break; case P_URI: case P_REASON: case P_METHOD: break; case L_REASON: fl->u.reply.reason.s=tmp; state=P_REASON; break; case P_STATUS: stat=stat*10+*tmp-'0'; break; case L_STATUS: stat=*tmp-'0'; fl->u.reply.status.s=tmp; break; case L_LF: LM_ERR("invalid " "character <%c> in request\n", *tmp); goto error; case L_URI: fl->u.request.uri.s=tmp; state=P_URI; break; case VER4: state=VER5; break; case L_VER: case VER1: case VER2: case VER3: case VER5: case VER6: case FIN_VER: LM_ERR("invalid version in request\n"); goto error; default: state=P_METHOD; } break; case '.': switch(state){ case START: state=P_METHOD; fl->u.request.method.s=tmp; break; case SIP5: state=SIP6; break; case P_URI: case P_REASON: case P_METHOD: break; case L_REASON: fl->u.reply.reason.s=tmp; state=P_REASON; break; case P_STATUS: case L_STATUS: LM_ERR("non-number " "character <%c> in request status\n", *tmp); goto error; case L_LF: LM_ERR("invalid " "character <%c> in request\n", *tmp); goto error; case L_URI: fl->u.request.uri.s=tmp; state=P_URI; break; case VER5: state=VER6; break; case L_VER: case VER1: case VER2: case VER3: case VER4: case VER6: case FIN_VER: LM_ERR("invalid version in request\n"); goto error; default: state=P_METHOD; } break; case '0': switch(state){ case START: state=P_METHOD; fl->u.request.method.s=tmp; break; case SIP6: state=FIN_SIP; break; case P_URI: case P_REASON: case P_METHOD: break; case L_REASON: fl->u.reply.reason.s=tmp; state=P_REASON; break; case P_STATUS: stat=stat*10; break; case L_STATUS: stat=0; fl->u.reply.status.s=tmp; break; case L_LF: LM_ERR("invalid " "character <%c> in request\n", *tmp); goto error; case L_URI: fl->u.request.uri.s=tmp; state=P_URI; break; case VER6: state=FIN_VER; break; case L_VER: case VER1: case VER2: case VER3: case VER4: case VER5: case FIN_VER: LM_ERR("invalid version " " in request\n"); goto error; default: state=P_METHOD; } break; case 'n': case 'N': switch(state){ case START: state=P_METHOD; fl->u.request.method.s=tmp; break; case INVITE1: state=INVITE2; break; case CANCEL2: state=CANCEL3; break; case P_URI: case P_REASON: case P_METHOD: break; case L_REASON: fl->u.reply.reason.s=tmp; state=P_REASON; break; case P_STATUS: case L_STATUS: LM_ERR("non-number " "character <%c> in request status\n", *tmp); goto error; case L_LF: LM_ERR("invalid " "character <%c> in request\n", *tmp); goto error; case L_URI: fl->u.request.uri.s=tmp; state=P_URI; break; case L_VER: case VER1: case VER2: case VER3: case VER4: case VER5: case VER6: case FIN_VER: LM_ERR("invalid version in request\n"); goto error; default: state=P_METHOD; } break; case 'v': case 'V': switch(state){ case START: state=P_METHOD; fl->u.request.method.s=tmp; break; case INVITE2: state=INVITE3; break; case P_URI: case P_REASON: case P_METHOD: break; case L_REASON: fl->u.reply.reason.s=tmp; state=P_REASON; break; case P_STATUS: case L_STATUS: LM_ERR("non-number " "character <%c> in request status\n", *tmp); goto error; case L_LF: LM_ERR("invalid " "character <%c> in request\n", *tmp); goto error; case L_URI: fl->u.request.uri.s=tmp; state=P_URI; break; case L_VER: case VER1: case VER2: case VER3: case VER4: case VER5: case VER6: case FIN_VER: LM_ERR("invalid version in request\n"); goto error; default: state=P_METHOD; } break; case 't': case 'T': switch(state){ case START: state=P_METHOD; fl->u.request.method.s=tmp; break; case INVITE4: state=INVITE5; break; case P_URI: case P_REASON: case P_METHOD: break; case L_REASON: fl->u.reply.reason.s=tmp; state=P_REASON; break; case P_STATUS: case L_STATUS: LM_ERR("non-number " "character <%c> in request status\n", *tmp); goto error; case L_LF: LM_ERR("invalid " "character <%c> in request\n", *tmp); goto error; case L_URI: fl->u.request.uri.s=tmp; state=P_URI; break; case L_VER: case VER1: case VER2: case VER3: case VER4: case VER5: case VER6: case FIN_VER: LM_ERR("invalid version in request\n"); goto error; default: state=P_METHOD; } break; case 'e': case 'E': switch(state){ case START: state=P_METHOD; fl->u.request.method.s=tmp; break; case INVITE5: state=FIN_INVITE; break; case CANCEL4: state=CANCEL5; break; case BYE2: state=FIN_BYE; break; case P_URI: case P_REASON: case P_METHOD: break; case L_REASON: fl->u.reply.reason.s=tmp; state=P_REASON; break; case P_STATUS: case L_STATUS: LM_ERR("non-number " "character <%c> in request status\n", *tmp); goto error; case L_LF: LM_ERR("invalid " "character <%c> in request\n", *tmp); goto error; case L_URI: fl->u.request.uri.s=tmp; state=P_URI; break; case L_VER: case VER1: case VER2: case VER3: case VER4: case VER5: case VER6: case FIN_VER: LM_ERR("invalid version in request\n"); goto error; default: state=P_METHOD; } break; case 'a': case 'A': switch(state){ case START: state=ACK1; fl->u.request.method.s=tmp; break; case CANCEL1: state=CANCEL2; break; case BYE2: state=FIN_BYE; break; case P_URI: case P_REASON: case P_METHOD: break; case L_REASON: fl->u.reply.reason.s=tmp; state=P_REASON; break; case P_STATUS: case L_STATUS: LM_ERR("non-number " "character <%c> in request status\n", *tmp); goto error; case L_LF: LM_ERR("invalid " "character <%c> in request\n", *tmp); goto error; case L_URI: fl->u.request.uri.s=tmp; state=P_URI; break; case L_VER: case VER1: case VER2: case VER3: case VER4: case VER5: case VER6: case FIN_VER: LM_ERR("invalid version in request\n"); goto error; default: state=P_METHOD; } break; case 'c': case 'C': switch(state){ case START: state=CANCEL1; fl->u.request.method.s=tmp; break; case CANCEL3: state=CANCEL4; break; case ACK1: state=ACK2; break; case P_URI: case P_REASON: case P_METHOD: break; case L_REASON: fl->u.reply.reason.s=tmp; state=P_REASON; break; case P_STATUS: case L_STATUS: LM_ERR("non-number " "character <%c> in request status\n", *tmp); goto error; case L_LF: LM_ERR("invalid " "character <%c> in request\n", *tmp); goto error; case L_URI: fl->u.request.uri.s=tmp; state=P_URI; break; case L_VER: case VER1: case VER2: case VER3: case VER4: case VER5: case VER6: case FIN_VER: LM_ERR("invalid version in request\n"); goto error; default: state=P_METHOD; } break; case 'k': case 'K': switch(state){ case START: state=P_METHOD; fl->u.request.method.s=tmp; break; case ACK2: state=FIN_ACK; break; case P_URI: case P_REASON: case P_METHOD: break; case L_REASON: fl->u.reply.reason.s=tmp; state=P_REASON; break; case P_STATUS: case L_STATUS: LM_ERR("non-number " "character <%c> in request status\n", *tmp); goto error; case L_LF: LM_ERR("invalid " "character <%c> in request\n", *tmp); goto error; case L_URI: fl->u.request.uri.s=tmp; state=P_URI; break; case L_VER: case VER1: case VER2: case VER3: case VER4: case VER5: case VER6: case FIN_VER: LM_ERR("invalid version in request\n"); goto error; default: state=P_METHOD; } break; case 'l': case 'L': switch(state){ case START: state=P_METHOD; fl->u.request.method.s=tmp; break; case CANCEL5: state=FIN_CANCEL; break; case P_URI: case P_REASON: case P_METHOD: break; case L_REASON: fl->u.reply.reason.s=tmp; state=P_REASON; break; case P_STATUS: case L_STATUS: LM_ERR("non-number " "character <%c> in request status\n", *tmp); goto error; case L_LF: LM_ERR("invalid " "character <%c> in request\n", *tmp); goto error; case L_URI: fl->u.request.uri.s=tmp; state=P_URI; break; case L_VER: case VER1: case VER2: case VER3: case VER4: case VER5: case VER6: case FIN_VER: LM_ERR("invalid version in request\n"); goto error; default: state=P_METHOD; } break; case 'b': case 'B': switch(state){ case START: state=BYE1; fl->u.request.method.s=tmp; break; case P_URI: case P_REASON: case P_METHOD: break; case L_REASON: fl->u.reply.reason.s=tmp; state=P_REASON; break; case P_STATUS: case L_STATUS: LM_ERR("non-number " "character <%c> in request status\n", *tmp); goto error; case L_LF: LM_ERR("invalid " "character <%c> in request\n", *tmp); goto error; case L_URI: fl->u.request.uri.s=tmp; state=P_URI; break; case L_VER: case VER1: case VER2: case VER3: case VER4: case VER5: case VER6: case FIN_VER: LM_ERR("invalid version in request\n"); goto error; default: state=P_METHOD; } break; case 'y': case 'Y': switch(state){ case START: state=P_METHOD; fl->u.request.method.s=tmp; break; case BYE1: state=BYE2; break; case P_URI: case P_REASON: case P_METHOD: break; case L_REASON: fl->u.reply.reason.s=tmp; state=P_REASON; break; case P_STATUS: case L_STATUS: LM_ERR("non-number " "character <%c> in request status\n", *tmp); goto error; case L_LF: LM_ERR("invalid " "character <%c> in request\n", *tmp); goto error; case L_URI: fl->u.request.uri.s=tmp; state=P_URI; break; case L_VER: case VER1: case VER2: case VER3: case VER4: case VER5: case VER6: case FIN_VER: LM_ERR("invalid version in request\n"); goto error; default: state=P_METHOD; } break; case '\r': switch(state){ case P_REASON: *tmp=0; fl->u.reply.reason.len=tmp-fl->u.reply.reason.s; state=F_CR; break; case L_LF: state=F_CR; break; case FIN_VER: *tmp=0; fl->u.request.version.len=tmp-fl->u.request.version.s; state=F_CR; break; case L_REASON: state=F_CR; break; default: LM_ERR("invalid message\n"); goto error; } break; case '\n': switch(state){ case P_REASON: *tmp=0; fl->u.reply.reason.len=tmp-fl->u.reply.reason.s; state=F_LF; goto skip; case FIN_VER: *tmp=0; fl->u.request.version.len=tmp-fl->u.request.version.s; state=F_LF; goto skip; case L_REASON: case L_LF: case F_CR: state=F_LF; goto skip; default: LM_ERR("invalid message\n"); goto error; } break; case '1': case '3': case '4': case '5': case '6': case '7': case '8': case '9': switch(state){ case START: state=P_METHOD; fl->u.request.method.s=tmp; break; case P_URI: case P_REASON: case P_METHOD: break; case L_REASON: fl->u.reply.reason.s=tmp; state=P_REASON; break; case P_STATUS: stat=stat*10+*tmp-'0'; break; case L_STATUS: stat=*tmp-'0'; state=P_STATUS; fl->u.reply.status.s=tmp; break; case L_LF: LM_ERR("invalid character <%c> in request\n", *tmp); goto error; case L_URI: fl->u.request.uri.s=tmp; state=P_URI; break; case L_VER: case VER1: case VER2: case VER3: case VER4: case VER5: case VER6: case FIN_VER: LM_ERR("invalid version in request\n"); goto error; default: state=P_METHOD; } default: switch(state){ case START: state=P_METHOD; fl->u.request.method.s=tmp; break; case P_URI: case P_REASON: case P_METHOD: break; case L_REASON: fl->u.reply.reason.s=tmp; state=P_REASON; break; case P_STATUS: case L_STATUS: LM_ERR("non-number " "character <%c> in request status\n", *tmp); goto error; case L_LF: LM_ERR("invalid character <%c> in request\n", *tmp); goto error; case L_URI: fl->u.request.uri.s=tmp; state=P_URI; break; case L_VER: case VER1: case VER2: case VER3: case VER4: case VER5: case VER6: case FIN_VER: LM_ERR("invalid version in request\n"); goto error; default: state=P_METHOD; } } } skip: fl->len=tmp-buf; if (fl->type==SIP_REPLY){ fl->u.reply.statuscode=stat; /* fl->u.reply.statusclass=stat/100; */ } return tmp; error: LM_ERR("while parsing first line (state=%d)\n", state); fl->type=SIP_INVALID; return tmp; }
static int lua_sr_modf (lua_State *L) { int ret; char *luav[MAX_ACTIONS]; char *argv[MAX_ACTIONS]; int argc; int i; int mod_type; struct run_act_ctx ra_ctx; unsigned modver; struct action *act; sr31_cmd_export_t* expf; sr_lua_env_t *env_L; ret = 1; act = NULL; argc = 0; memset(luav, 0, MAX_ACTIONS*sizeof(char*)); memset(argv, 0, MAX_ACTIONS*sizeof(char*)); env_L = sr_lua_env_get(); if(env_L->msg==NULL) goto error; #if 0 app_lua_dump_stack(L); #endif argc = lua_gettop(L); if(argc==0) { LM_ERR("name of module function not provided\n"); goto error; } if(argc>=MAX_ACTIONS) { LM_ERR("too many parameters\n"); goto error; } /* first is function name, then parameters */ for(i=1; i<=argc; i++) { if (!lua_isstring(L, i)) { LM_ERR("invalid parameter type (%d)\n", i); goto error; } luav[i-1] = (char*)lua_tostring(L, i); } /* pkg copy only parameters */ for(i=1; i<MAX_ACTIONS; i++) { if(luav[i]!=NULL) { argv[i] = (char*)pkg_malloc(strlen(luav[i])+1); if(argv[i]==NULL) { LM_ERR("no more pkg\n"); goto error; } strcpy(argv[i], luav[i]); } } expf = find_export_record(luav[0], argc-1, 0, &modver); if (expf==NULL) { LM_ERR("function '%s' is not available\n", luav[0]); goto error; } /* check fixups */ if (expf->fixup!=NULL && expf->free_fixup==NULL) { LM_ERR("function '%s' has fixup - cannot be used\n", luav[0]); goto error; } switch(expf->param_no) { case 0: mod_type = MODULE0_T; break; case 1: mod_type = MODULE1_T; break; case 2: mod_type = MODULE2_T; break; case 3: mod_type = MODULE3_T; break; case 4: mod_type = MODULE4_T; break; case 5: mod_type = MODULE5_T; break; case 6: mod_type = MODULE6_T; break; case VAR_PARAM_NO: mod_type = MODULEX_T; break; default: LM_ERR("unknown/bad definition for function '%s' (%d params)\n", luav[0], expf->param_no); goto error; } act = mk_action(mod_type, argc+1 /* number of (type, value) pairs */, MODEXP_ST, expf, /* function */ NUMBER_ST, argc-1, /* parameter number */ STRING_ST, argv[1], /* param. 1 */ STRING_ST, argv[2], /* param. 2 */ STRING_ST, argv[3], /* param. 3 */ STRING_ST, argv[4], /* param. 4 */ STRING_ST, argv[5], /* param. 5 */ STRING_ST, argv[6] /* param. 6 */ ); if (act==NULL) { LM_ERR("action structure could not be created for '%s'\n", luav[0]); goto error; } /* handle fixups */ if (expf->fixup) { if(argc==1) { /* no parameters */ if(expf->fixup(0, 0)<0) { LM_ERR("Error in fixup (0) for '%s'\n", luav[0]); goto error; } } else { for(i=1; i<argc; i++) { if(expf->fixup(&(act->val[i+1].u.data), i)<0) { LM_ERR("Error in fixup (%d) for '%s'\n", i, luav[0]); goto error; } act->val[i+1].type = MODFIXUP_ST; } } } init_run_actions_ctx(&ra_ctx); ret = do_action(&ra_ctx, act, env_L->msg); /* free fixups */ if (expf->fixup) { for(i=1; i<argc; i++) { if ((act->val[i+1].type == MODFIXUP_ST) && (act->val[i+1].u.data)) { expf->free_fixup(&(act->val[i+1].u.data), i); } } } pkg_free(act); for(i=0; i<MAX_ACTIONS; i++) { if(argv[i]!=NULL) pkg_free(argv[i]); argv[i] = 0; } lua_pushinteger(L, ret); return 1; error: if(act!=NULL) pkg_free(act); for(i=0; i<MAX_ACTIONS; i++) { if(argv[i]!=NULL) pkg_free(argv[i]); argv[i] = 0; } lua_pushinteger(L, -1); return 1; }
/** * 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; }
/** * puts a table with content of a xavp */ static int lua_sr_xavp_get(lua_State *L) { str xavp_name; int indx = 0; sr_lua_env_t *env_L; sr_xavp_t *avp; int num_param = 0; int param = -1; int all_flag = 0; int simple_flag = 0; lua_Number elem = 1; int xavp_size = 0; env_L = sr_lua_env_get(); num_param = lua_gettop(L); if(num_param<2 && num_param>3) { LM_ERR("wrong number of parameters [%d]\n", num_param); return 0; } if(num_param==3) { if(!lua_isnumber(L, param)) { LM_ERR("invalid int parameter\n"); return 0; } simple_flag = lua_tointeger(L, param); param = param - 1; } if(!lua_isnumber(L, param)) { if(lua_isnil(L, param)) { all_flag = 1; } else { LM_ERR("invalid parameter, must be int or nil\n"); return 0; } } else { indx = lua_tointeger(L, param); } param = param - 1; xavp_name.s = (char*)lua_tostring(L, param); if(xavp_name.s==NULL || env_L->msg==NULL) { LM_ERR("No xavp name in %d param\n", param); return 0; } xavp_name.len = strlen(xavp_name.s); if(all_flag>0) { indx = 0; lua_newtable(L); } xavp_size = xavp_count(&xavp_name, NULL); if(indx<0) { if((indx*-1)>xavp_size) { LM_ERR("can't get xavp:%.*s index:%d\n", xavp_name.len, xavp_name.s, indx); lua_pushnil(L); return 1; } indx = xavp_size + indx; } avp = xavp_get_by_index(&xavp_name, indx, NULL); do { if(avp==NULL){ LM_ERR("can't get xavp:%.*s index:%d\n", xavp_name.len, xavp_name.s, indx); lua_pushnil(L); return 1; } if(all_flag!=0) { lua_pushnumber(L, elem); elem = elem + 1; } lua_sr_push_xavp_table(L, avp, simple_flag); if(all_flag!=0) { lua_rawset(L, -3); indx = indx + 1; avp = xavp_get_by_index(&xavp_name, indx, NULL); } else return 1; }while(avp!=NULL); return 1; }
static int ah_parse_req_name(pv_spec_p sp, str *in) { if(sp==NULL || in==NULL || in->len<=0) return -1; switch(in->len) { case 3: if(strncmp(in->s, "all", 3)==0) sp->pvp.pvn.u.isname.name.n = E_HRN_ALL; else if(strncmp(in->s, "hdr", 3)==0) sp->pvp.pvn.u.isname.name.n = E_HRN_HDR; else goto error; break; case 4: if(strncmp(in->s, "body", 4)==0) sp->pvp.pvn.u.isname.name.n = E_HRN_BODY; else goto error; break; case 6: if(strncmp(in->s, "method", 6)==0) sp->pvp.pvn.u.isname.name.n = E_HRN_METHOD; else goto error; break; case 7: if(strncmp(in->s, "timeout", 7)==0) sp->pvp.pvn.u.isname.name.n = E_HRN_TIMEOUT; else if(strncmp(in->s, "suspend", 7)==0) sp->pvp.pvn.u.isname.name.n = E_HRN_SUSPEND; else goto error; break; case 8: if(strncmp(in->s, "username", 8)==0) sp->pvp.pvn.u.isname.name.n = E_HRN_USERNAME; else if(strncmp(in->s, "password", 8)==0) sp->pvp.pvn.u.isname.name.n = E_HRN_PASSWORD; else goto error; break; case 10: if(strncmp(in->s, "authmethod", 10)==0) sp->pvp.pvn.u.isname.name.n = E_HRN_AUTHMETHOD; else goto error; break; case 11: if(strncmp(in->s, "tls_ca_path", 11)==0) sp->pvp.pvn.u.isname.name.n = E_HRN_TLS_CA_PATH; else goto error; break; case 14: if(strncmp(in->s, "tls_client_key", 14)==0) sp->pvp.pvn.u.isname.name.n = E_HRN_TLS_CLIENT_KEY; else goto error; break; case 15: if(strncmp(in->s, "tls_client_cert", 15)==0) sp->pvp.pvn.u.isname.name.n = E_HRN_TLS_CLIENT_CERT; else goto error; break; default: goto error; } sp->pvp.pvn.type = PV_NAME_INTSTR; sp->pvp.pvn.u.isname.type = 0; return 0; error: LM_ERR("unknown http_req name %.*s\n", in->len, in->s); return -1; }
int sr_kemi_lua_exec_func_ex(lua_State* L, sr_kemi_t *ket, int pdelta) { int i; int argc; int ret; str *fname; str *mname; sr_kemi_val_t vps[SR_KEMI_PARAMS_MAX]; sr_lua_env_t *env_L; env_L = sr_lua_env_get(); if(env_L==NULL || env_L->msg==NULL || ket==NULL) { LM_ERR("invalid Lua environment attributes or parameters\n"); return app_lua_return_false(L); } fname = &ket->fname; mname = &ket->mname; argc = lua_gettop(L); if(argc==pdelta && ket->ptypes[0]==SR_KEMIP_NONE) { ret = ((sr_kemi_fm_f)(ket->func))(env_L->msg); return sr_kemi_lua_return_int(L, ket, ret); } if(argc==pdelta && ket->ptypes[0]!=SR_KEMIP_NONE) { LM_ERR("invalid number of parameters for: %.*s.%.*s\n", mname->len, mname->s, fname->len, fname->s); return app_lua_return_false(L); } if(argc>=SR_KEMI_PARAMS_MAX+pdelta) { LM_ERR("too many parameters for: %.*s.%.*s\n", mname->len, mname->s, fname->len, fname->s); return app_lua_return_false(L); } memset(vps, 0, SR_KEMI_PARAMS_MAX*sizeof(sr_kemi_val_t)); for(i=0; i<SR_KEMI_PARAMS_MAX; i++) { if(ket->ptypes[i]==SR_KEMIP_NONE) { break; } else if(ket->ptypes[i]==SR_KEMIP_STR) { vps[i].s.s = (char*)lua_tostring(L, i+pdelta+1); vps[i].s.len = strlen(vps[i].s.s); LM_DBG("param[%d] for: %.*s is str: %.*s\n", i, fname->len, fname->s, vps[i].s.len, vps[i].s.s); } else if(ket->ptypes[i]==SR_KEMIP_INT) { vps[i].n = lua_tointeger(L, i+pdelta+1); LM_DBG("param[%d] for: %.*s is int: %d\n", i, fname->len, fname->s, vps[i].n); } else { LM_ERR("unknown parameter type %d (%d)\n", ket->ptypes[i], i); return app_lua_return_false(L); } } switch(i) { case 1: if(ket->ptypes[0]==SR_KEMIP_INT) { ret = ((sr_kemi_fmn_f)(ket->func))(env_L->msg, vps[0].n); return sr_kemi_lua_return_int(L, ket, ret); } else if(ket->ptypes[0]==SR_KEMIP_STR) { ret = ((sr_kemi_fms_f)(ket->func))(env_L->msg, &vps[0].s); return sr_kemi_lua_return_int(L, ket, ret); } else { LM_ERR("invalid parameters for: %.*s\n", fname->len, fname->s); return app_lua_return_false(L); } break; case 2: if(ket->ptypes[0]==SR_KEMIP_INT) { if(ket->ptypes[1]==SR_KEMIP_INT) { ret = ((sr_kemi_fmnn_f)(ket->func))(env_L->msg, vps[0].n, vps[1].n); return sr_kemi_lua_return_int(L, ket, ret); } else if(ket->ptypes[1]==SR_KEMIP_STR) { ret = ((sr_kemi_fmns_f)(ket->func))(env_L->msg, vps[0].n, &vps[1].s); return sr_kemi_lua_return_int(L, ket, ret); } else { LM_ERR("invalid parameters for: %.*s\n", fname->len, fname->s); return app_lua_return_false(L); } } else if(ket->ptypes[0]==SR_KEMIP_STR) { if(ket->ptypes[1]==SR_KEMIP_INT) { ret = ((sr_kemi_fmsn_f)(ket->func))(env_L->msg, &vps[0].s, vps[1].n); return sr_kemi_lua_return_int(L, ket, ret); } else if(ket->ptypes[1]==SR_KEMIP_STR) { ret = ((sr_kemi_fmss_f)(ket->func))(env_L->msg, &vps[0].s, &vps[1].s); return sr_kemi_lua_return_int(L, ket, ret); } else { LM_ERR("invalid parameters for: %.*s\n", fname->len, fname->s); return app_lua_return_false(L); } } else { LM_ERR("invalid parameters for: %.*s\n", fname->len, fname->s); return app_lua_return_false(L); } break; case 3: if(ket->ptypes[0]==SR_KEMIP_INT) { if(ket->ptypes[1]==SR_KEMIP_INT) { if(ket->ptypes[2]==SR_KEMIP_INT) { ret = ((sr_kemi_fmnnn_f)(ket->func))(env_L->msg, vps[0].n, vps[1].n, vps[2].n); return sr_kemi_lua_return_int(L, ket, ret); } else if(ket->ptypes[2]==SR_KEMIP_STR) { ret = ((sr_kemi_fmnns_f)(ket->func))(env_L->msg, vps[0].n, vps[1].n, &vps[2].s); return sr_kemi_lua_return_int(L, ket, ret); } else { LM_ERR("invalid parameters for: %.*s\n", fname->len, fname->s); return app_lua_return_false(L); } } else if(ket->ptypes[1]==SR_KEMIP_STR) { if(ket->ptypes[2]==SR_KEMIP_INT) { ret = ((sr_kemi_fmnsn_f)(ket->func))(env_L->msg, vps[0].n, &vps[1].s, vps[2].n); return sr_kemi_lua_return_int(L, ket, ret); } else if(ket->ptypes[2]==SR_KEMIP_STR) { ret = ((sr_kemi_fmnss_f)(ket->func))(env_L->msg, vps[0].n, &vps[1].s, &vps[2].s); return sr_kemi_lua_return_int(L, ket, ret); } else { LM_ERR("invalid parameters for: %.*s\n", fname->len, fname->s); return app_lua_return_false(L); } } else { LM_ERR("invalid parameters for: %.*s\n", fname->len, fname->s); return app_lua_return_false(L); } } else if(ket->ptypes[0]==SR_KEMIP_STR) { if(ket->ptypes[1]==SR_KEMIP_INT) { if(ket->ptypes[2]==SR_KEMIP_INT) { ret = ((sr_kemi_fmsnn_f)(ket->func))(env_L->msg, &vps[0].s, vps[1].n, vps[2].n); return sr_kemi_lua_return_int(L, ket, ret); } else if(ket->ptypes[2]==SR_KEMIP_STR) { ret = ((sr_kemi_fmsns_f)(ket->func))(env_L->msg, &vps[0].s, vps[1].n, &vps[2].s); return sr_kemi_lua_return_int(L, ket, ret); } else { LM_ERR("invalid parameters for: %.*s\n", fname->len, fname->s); return app_lua_return_false(L); } } else if(ket->ptypes[1]==SR_KEMIP_STR) { if(ket->ptypes[2]==SR_KEMIP_INT) { ret = ((sr_kemi_fmssn_f)(ket->func))(env_L->msg, &vps[0].s, &vps[1].s, vps[2].n); return sr_kemi_lua_return_int(L, ket, ret); } else if(ket->ptypes[2]==SR_KEMIP_STR) { ret = ((sr_kemi_fmsss_f)(ket->func))(env_L->msg, &vps[0].s, &vps[1].s, &vps[2].s); return sr_kemi_lua_return_int(L, ket, ret); } else { LM_ERR("invalid parameters for: %.*s\n", fname->len, fname->s); return app_lua_return_false(L); } } else { LM_ERR("invalid parameters for: %.*s\n", fname->len, fname->s); return app_lua_return_false(L); } } else { LM_ERR("invalid parameters for: %.*s\n", fname->len, fname->s); return app_lua_return_false(L); } break; case 4: if(ket->ptypes[0]==SR_KEMIP_STR || ket->ptypes[1]==SR_KEMIP_STR || ket->ptypes[2]==SR_KEMIP_STR || ket->ptypes[3]==SR_KEMIP_STR) { ret = ((sr_kemi_fmssss_f)(ket->func))(env_L->msg, &vps[0].s, &vps[1].s, &vps[2].s, &vps[3].s); return sr_kemi_lua_return_int(L, ket, ret); } else if(ket->ptypes[0]==SR_KEMIP_STR || ket->ptypes[1]==SR_KEMIP_STR || ket->ptypes[2]==SR_KEMIP_INT || ket->ptypes[3]==SR_KEMIP_INT) { ret = ((sr_kemi_fmssnn_f)(ket->func))(env_L->msg, &vps[0].s, &vps[1].s, vps[2].n, vps[3].n); return sr_kemi_lua_return_int(L, ket, ret); } else { LM_ERR("invalid parameters for: %.*s\n", fname->len, fname->s); return app_lua_return_false(L); } break; case 5: if(ket->ptypes[0]==SR_KEMIP_STR || ket->ptypes[1]==SR_KEMIP_STR || ket->ptypes[2]==SR_KEMIP_STR || ket->ptypes[3]==SR_KEMIP_STR || ket->ptypes[4]==SR_KEMIP_STR) { ret = ((sr_kemi_fmsssss_f)(ket->func))(env_L->msg, &vps[0].s, &vps[1].s, &vps[2].s, &vps[3].s, &vps[4].s); return sr_kemi_lua_return_int(L, ket, ret); } else { LM_ERR("invalid parameters for: %.*s\n", fname->len, fname->s); return app_lua_return_false(L); } break; case 6: if(ket->ptypes[0]==SR_KEMIP_STR || ket->ptypes[1]==SR_KEMIP_STR || ket->ptypes[2]==SR_KEMIP_STR || ket->ptypes[3]==SR_KEMIP_STR || ket->ptypes[4]==SR_KEMIP_STR || ket->ptypes[5]==SR_KEMIP_STR) { ret = ((sr_kemi_fmssssss_f)(ket->func))(env_L->msg, &vps[0].s, &vps[1].s, &vps[2].s, &vps[3].s, &vps[4].s, &vps[5].s); return sr_kemi_lua_return_int(L, ket, ret); } else { LM_ERR("invalid parameters for: %.*s\n", fname->len, fname->s); return app_lua_return_false(L); } break; default: LM_ERR("invalid parameters for: %.*s\n", fname->len, fname->s); return app_lua_return_false(L); } }
static void pipe_handle_subscribe(struct purple_subscribe *subscribe) { PurpleAccount *account = NULL; extern_account_t *accounts = NULL; extern_user_t *users = NULL; int naccounts = 0, nusers = 0; int i, j; PurpleBuddy *buddy = NULL; int d = 0; const char *note; enum purple_publish_basic basic; enum purple_publish_activity activity; LM_DBG("calling find_accounts(\"%s\", &naccounts)\n", subscribe->from); accounts = find_accounts(subscribe->from, &naccounts); LM_DBG("found %d extra account(s) for <%s>", naccounts, subscribe->from); LM_DBG("calling find_users(\"%s\", &nusers)\n", subscribe->to); users = find_users(subscribe->to, &nusers); LM_DBG("found %d extra user(s) for <%s>", nusers, subscribe->to); for (i = 0; i < naccounts; i++) { LM_DBG("calling client_find_account(\"%s\")\n", accounts[i].username); account = client_find_account(&accounts[i]); //if ((account) && (purple_account_is_connected(account) || purple_account_is_connecting(account))) { if (account) { for (j = 0; j < nusers; j++) { if (!strcmp(accounts[i].protocol, users[j].protocol)) { LM_DBG("found matching protocol: %s\n", accounts[i].protocol); LM_DBG("subscribe expires : %d\n", subscribe->expires); if (subscribe->expires == 0) d = hashtable_dec_counter(users[j].username); else d = hashtable_inc_counter(users[j].username); LM_DBG("<%s> is now referenced %d times\n", users[j].username, d); if (d == 0) { LM_DBG("<%s> is no more referenced, removing presence...\n", users[j].username); if (purple_send_sip_publish(subscribe->to, users[j].username, PURPLE_BASIC_CLOSED, 0, NULL) < 0) LM_ERR("error sending presence for %s", subscribe->to); else LM_DBG("presence message sent successfully\n"); } else { buddy = purple_find_buddy(account, users[j].username); if (buddy == NULL) { LM_DBG("<%s> not found in <%s> buddy list, adding\n", users[j].username, accounts[i].username); buddy = purple_buddy_new(account, users[j].username, users[j].username); //purple_blist_add_buddy(buddy, NULL, NULL, NULL); purple_account_add_buddy(account, buddy); } else { LM_DBG("<%s> found in <%s> buddy list, sending publish\n", users[j].username, accounts[i].username); PurplePresence *presence = purple_buddy_get_presence(buddy); PurpleStatus *status = purple_presence_get_active_status(presence); PurpleStatusType *type = purple_status_get_type(status); PurpleStatusPrimitive primitive = purple_status_type_get_primitive(type); note = purple_status_get_attr_string(status, "message"); primitive_parse(primitive, &basic, &activity); if (purple_send_sip_publish(subscribe->to, users[j].username, basic, activity, note) < 0) LM_ERR("error sending presence for %s", subscribe->to); else LM_DBG("presence message sent successfully\n"); } } break; } } } } if (accounts) extern_account_free(accounts, naccounts); if (users) extern_user_free(users, nusers); }
/* * Convert db_val to pv_spec */ int db_val2pv_spec(struct sip_msg* msg, db_val_t *dbval, pv_spec_t *pvs) { pv_value_t pv; #define LL_LEN 21 /* sign, 19 digits and \0 */ static char ll_buf[LL_LEN]; if(dbval->nul) { pv.flags = PV_VAL_NULL; } else { switch(dbval->type) { case DB1_STRING: pv.flags = PV_VAL_STR; pv.rs.s = (char*)dbval->val.string_val; pv.rs.len = strlen(pv.rs.s); break; case DB1_STR: pv.flags = PV_VAL_STR; pv.rs.s = (char*)dbval->val.str_val.s; pv.rs.len = dbval->val.str_val.len; break; case DB1_BLOB: pv.flags = PV_VAL_STR; pv.rs.s = (char*)dbval->val.blob_val.s; pv.rs.len = dbval->val.blob_val.len; break; case DB1_INT: pv.flags = PV_VAL_INT | PV_TYPE_INT; pv.ri = (int)dbval->val.int_val; break; case DB1_DATETIME: pv.flags = PV_VAL_INT | PV_TYPE_INT; pv.ri = (int)dbval->val.time_val; break; case DB1_BITMAP: pv.flags = PV_VAL_INT | PV_TYPE_INT; pv.ri = (int)dbval->val.bitmap_val; break; case DB1_BIGINT: /* BIGINT is stored as string */ pv.flags = PV_VAL_STR; pv.rs.len = LL_LEN; db_longlong2str(dbval->val.ll_val, ll_buf, &pv.rs.len); pv.rs.s = ll_buf; /* if it fits, also store as 32 bit integer*/ if (! ((unsigned long long)dbval->val.ll_val & 0xffffffff00000000ULL)) { pv.flags |= PV_VAL_INT | PV_TYPE_INT; pv.ri = (int)dbval->val.ll_val; } break; default: LM_NOTICE("unknown field type: %d, setting value to null\n", dbval->type); pv.flags = PV_VAL_NULL; } } /* null values are ignored for avp type PV */ if (pv.flags == PV_VAL_NULL && pvs->type == PVT_AVP) return 0; /* add value to result pv */ if (pv_set_spec_value(msg, pvs, 0, &pv) != 0) { LM_ERR("Failed to add value to spec\n"); return -1; } return 0; }