int update_sock_struct_from_via( union sockaddr_union* to, struct sip_msg* msg, struct via_body* via ) { struct hostent* he; str* name; int err; unsigned short port; port=0; if(via==msg->via1){ /* _local_ reply, we ignore any rport or received value * (but we will send back to the original port if rport is * present) */ if ((msg->msg_flags&FL_FORCE_RPORT)||(via->rport)) port=msg->rcv.src_port; else port=via->port; if(via->maddr) name= &(via->maddr->value); else name=&(via->host); /* received=ip in 1st via is ignored (it's not added by us so it's bad) */ }else{ /* "normal" reply, we use rport's & received value if present */ if (via->rport && via->rport->value.s){ LM_DBG("using 'rport'\n"); port=str2s(via->rport->value.s, via->rport->value.len, &err); if (err){ LM_NOTICE("bad rport value(%.*s)\n", via->rport->value.len,via->rport->value.s); port=0; } } if (via->maddr){ name= &(via->maddr->value); if (port==0) port=via->port?via->port:SIP_PORT; } else if (via->received){ LM_DBG("using 'received'\n"); name=&(via->received->value); /* making sure that we won't do SRV lookup on "received" */ if (port==0) port=via->port?via->port:SIP_PORT; }else{ LM_DBG("using via host\n"); name=&(via->host); if (port==0) port=via->port; } } LM_DBG("trying SRV lookup\n"); he=sip_resolvehost(name, &port, &via->proto, 0, 0); if (he==0){ LM_NOTICE("resolve_host(%.*s) failure\n", name->len, name->s); return -1; } hostent2su( to, he, 0, port); return 1; }
static int trace_send_duplicate(char *buf, int len) { union sockaddr_union* to; struct socket_info* send_sock; struct proxy_l * p; int proto; int ret; if(buf==NULL || len <= 0) return -1; if(dup_uri_str.s==0 || dup_uri==NULL) return 0; to=(union sockaddr_union*)pkg_malloc(sizeof(union sockaddr_union)); if (to==0){ LM_ERR("out of pkg memory\n"); return -1; } /* create a temporary proxy*/ proto = PROTO_UDP; p=mk_proxy(&dup_uri->host, (dup_uri->port_no)?dup_uri->port_no:SIP_PORT, proto, 0); if (p==0){ LM_ERR("bad host name in uri\n"); pkg_free(to); return -1; } hostent2su(to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT); ret = -1; do { send_sock=get_send_socket(0, to, proto); if (send_sock==0){ LM_ERR("can't forward to af %d, proto %d no corresponding listening socket\n", to->s.sa_family,proto); continue; } if (msg_send(send_sock, proto, to, 0, buf, len, NULL)<0){ LM_ERR("cannot send duplicate message\n"); continue; } ret = 0; break; }while( get_next_su( p, to, 0)==0 ); free_proxy(p); /* frees only p content, not p itself */ pkg_free(p); pkg_free(to); return ret; }
static union sockaddr_union *jsonrpc_get_dst(str *ip_port) { static union sockaddr_union _su; struct hostent *hentity; char *p, bk; str host; str port; int iport; int err; if (!ip_port || !ip_port->len) { LM_ERR("no IP:port specified!\n"); return NULL; } /* search for the port */ p = memchr(ip_port->s, ':', ip_port->len); if (!p) { LM_ERR("invalid IP:port %.*s\n", ip_port->len, ip_port->s); return NULL; } host.s = ip_port->s; host.len = p - ip_port->s; /* remaining should be port */ port.s = p + 1; port.len = ip_port->len - (host.len + 1/* : */); trim(&port); iport = str2s(port.s, port.len, &err); if (iport <= 0 || err != 0 || iport > 65535) { LM_ERR("Invalid port specified [%.*s]\n", port.len, port.s); return NULL; } trim(&host); /* null terminate host */ bk = host.s[host.len]; host.s[host.len] = 0; hentity = resolvehost(host.s, 0); host.s[host.len] = bk; if (!hentity) { LM_ERR("cannot resolve host %s\n", host.s); return NULL; } if(hostent2su(&_su, hentity, 0, iport)){ LM_ERR("failed to resolve %s\n", host.s); return NULL; } return &_su; }
static int fixup_siptrace(void** param, int param_no) { char *duri = (char*) *param; struct sip_uri dup_uri; struct dest_info *dst = NULL; struct proxy_l * p = NULL; str dup_uri_str = { 0, 0 }; if (param_no != 1) { LM_DBG("params:%s\n", (char*)*param); return 0; } if (!(*duri)) { LM_ERR("invalid dup URI\n"); return -1; } LM_DBG("sip_trace URI:%s\n", (char*)*param); dup_uri_str.s = duri; dup_uri_str.len = strlen(dup_uri_str.s); memset(&dup_uri, 0, sizeof(struct sip_uri)); if (parse_uri(dup_uri_str.s, dup_uri_str.len, &dup_uri) < 0) { LM_ERR("bad dup uri\n"); return -1; } dst = (struct dest_info *) pkg_malloc(sizeof(struct dest_info)); if (dst == 0) { LM_ERR("no more pkg memory left\n"); return -1; } init_dest_info(dst); /* create a temporary proxy*/ dst->proto = PROTO_UDP; p = mk_proxy(&dup_uri.host, (dup_uri.port_no) ? dup_uri.port_no : SIP_PORT, dst->proto); if (p == 0) { LM_ERR("bad host name in uri\n"); pkg_free(dst); return -1; } hostent2su(&dst->to, &p->host, p->addr_idx, (p->port) ? p->port : SIP_PORT); pkg_free(*param); /* free temporary proxy*/ if (p) { free_proxy(p); /* frees only p content, not p itself */ pkg_free(p); } *param = (void*) dst; return 0; }
int rl_add_repl_dst(modparam_t type, void *val) { char *host; int hlen, port; int proto; struct hostent *he; str st; rl_dests = pkg_realloc(rl_dests, (rl_dests_nr + 1) * sizeof(rl_repl_dst_t)); if (!rl_dests) { LM_ERR("oom\n"); return -1; } if (parse_phostport(val, strlen(val), &host, &hlen, &port, &proto) < 0) { LM_ERR("Bad replication destination IP!\n"); return -1; } if (proto == PROTO_NONE) proto = PROTO_UDP; st.s = host; st.len = hlen; he = sip_resolvehost(&st, (unsigned short *)&port, (unsigned short *)&proto, 0, 0); if (!he) { LM_ERR("Cannot resolve host: %.*s\n", hlen, host); return -1; } if (!port) { LM_ERR("no port specified for host %.*s\n", hlen, host); return -1; } rl_dests[rl_dests_nr].id = rl_dests_nr; rl_dests[rl_dests_nr].dst.s = (char *)val; rl_dests[rl_dests_nr].dst.len = strlen(rl_dests[rl_dests_nr].dst.s); hostent2su(&rl_dests[rl_dests_nr].to, he, 0, port); LM_DBG("Added destination <%.*s>\n", rl_dests[rl_dests_nr].dst.len, rl_dests[rl_dests_nr].dst.s); /* init done */ rl_dests_nr++; return 1; }
int natping_contact(str contact, struct dest_info *dst) { struct sip_uri curi; struct hostent *he; str p_method, p_from; if (natping_method != NULL) { /* XXX: add send_sock handling */ p_method.s = natping_method; p_method.len = strlen(p_method.s); p_from.s = "sip:registrar"; /* XXX */ p_from.len = strlen(p_from.s); if (tmb.t_request(&p_method, &contact, &contact, &p_from, NULL, NULL, NULL, NULL, NULL) == -1) { LOG(L_ERR, "ERROR: nathelper::natping(): t_request() failed\n"); return -1; } } else { if (parse_uri(contact.s, contact.len, &curi) < 0) { LOG(L_ERR, "ERROR: nathelper::natping: can't parse contact uri\n"); return -1; } if (curi.proto != PROTO_UDP && curi.proto != PROTO_NONE) return -1; if (curi.port_no == 0) curi.port_no = SIP_PORT; he = sip_resolvehost(&curi.host, &curi.port_no, PROTO_UDP); if (he == NULL){ LOG(L_ERR, "ERROR: nathelper::natping: can't resolve host\n"); return -1; } hostent2su(&dst->to, he, 0, curi.port_no); if (dst->send_sock == NULL) { dst->send_sock = force_socket ? force_socket : get_send_socket(0, &dst->to, PROTO_UDP); } if (dst->send_sock == NULL) { LOG(L_ERR, "ERROR: nathelper::natping: can't get sending socket\n"); return -1; } dst->proto=PROTO_UDP; udp_send(dst, (char *)sbuf, sizeof(sbuf)); } return 1; }
static int add_replication_dest(modparam_t type, void *val) { struct replication_dest *rd; char *host; int hlen, port; int proto; struct hostent *he; str st; rd = pkg_malloc(sizeof(*rd)); memset(rd, 0, sizeof(*rd)); if (parse_phostport(val, strlen(val), &host, &hlen, &port, &proto) < 0) { LM_ERR("Bad replication destination IP!\n"); return -1; } if (proto == PROTO_NONE) proto = PROTO_UDP; if (proto != PROTO_UDP) { LM_ERR("Dialog replication only supports UDP packets!\n"); return -1; } st.s = host; st.len = hlen; he = sip_resolvehost(&st, (unsigned short *)&port, (unsigned short *)&proto, 0, 0); if (!he) { LM_ERR("Cannot resolve host: %.*s\n", hlen, host); return -1; } hostent2su(&rd->to, he, 0, port); rd->next = replication_dests; replication_dests = rd; return 1; }
/* resolve host, port, proto using sip rules (e.g. use SRV if port=0 a.s.o) * and write the result in the sockaddr_union to * returns -1 on error (resolve failed), 0 on success */ int sip_hostport2su(union sockaddr_union* su, str* name, unsigned short port, char* proto) { struct hostent* he; he=sip_resolvehost(name, &port, proto); if (he==0){ ser_error=E_BAD_ADDRESS; LOG(L_ERR, "ERROR: sip_hostport2su: could not resolve hostname:" " \"%.*s\"\n", name->len, name->s); goto error; } /* port filled by sip_resolvehost if empty*/ if (hostent2su(su, he, 0, port)<0){ ser_error=E_BAD_ADDRESS; goto error; } return 0; error: return -1; }
/* add a new information in the backend list*/ int add_info(table_entry_t **data, int *int_vals, unsigned long last_attempt, char **str_vals) { char *host; int hlen, port; struct hostent *he; struct module_list *module; struct module_timestamp *new_timestamp; uint64_t ctime; int proto; int cluster_id; table_entry_t *head = NULL; table_entry_info_t *info_head = NULL; table_entry_value_t *value = NULL; str st; char *url; char *description; if (int_vals[INT_VALS_MACHINE_ID_COL] == server_id) { return 0; } url = str_vals[STR_VALS_URL_COL]; if (url == NULL) { LM_ERR("no path specified\n"); goto error; } if (parse_phostport(url, strlen(url), &host, &hlen, &port, &proto) < 0) { LM_ERR("Bad replication destination IP!\n"); goto error; } if (proto == PROTO_NONE) proto = PROTO_UDP; cluster_id = int_vals[INT_VALS_CLUSTER_ID_COL]; for (head = *data; head; head = head->next) { if (head->cluster_id == cluster_id) { info_head = head->info; while (info_head && info_head->proto != proto) info_head = info_head->next; if (!info_head) { info_head = shm_malloc(sizeof *info_head); if (!info_head) { LM_ERR("no more shm memory\n"); goto error; } info_head->proto = proto; info_head->next = head->info; info_head->value = NULL; head->info = info_head; } break; } } if (!head) { head = shm_malloc(sizeof *head); if (!head) { LM_ERR("no more shm memory\n"); goto error; } head->cluster_id = cluster_id; head->info = shm_malloc(sizeof(table_entry_info_t)); if (!head->info) { LM_ERR("no more shm memory\n"); goto error; } head->info->proto = proto; head->info->next = NULL; head->info->value = NULL; info_head = head->info; info_head->proto = proto; head->next = *data; *data = head; } /* allocating memory*/ value = shm_malloc(sizeof *value); if (!value) { LM_ERR("no more shm memory\n"); goto error; } value->machine_id = int_vals[INT_VALS_MACHINE_ID_COL]; value->id = int_vals[INT_VALS_CLUSTERER_ID_COL]; value->state = int_vals[INT_VALS_STATE_COL]; value->last_attempt = last_attempt; value->duration = int_vals[INT_VALS_DURATION_COL]; value->failed_attempts = int_vals[INT_VALS_FAILED_ATTEMPTS_COL]; value->no_tries = int_vals[INT_VALS_NO_TRIES_COL]; value->dirty_bit = 0; value->prev_no_tries = -1; value->in_timestamps = NULL; description = str_vals[STR_VALS_DESCRIPTION_COL]; value->path.s = shm_malloc(strlen(url) * sizeof(char)); if (!value->path.s) { LM_ERR("insufficient shm memory\n"); goto error; } st.s = host; st.len = hlen; he = sip_resolvehost(&st, (unsigned short *) &port, (unsigned short *) &proto, 0, 0); if (!he) { LM_ERR("Cannot resolve host: %.*s\n", hlen, host); goto error; } hostent2su(&value->addr, he, 0, port); value->path.len = strlen(url); memcpy(value->path.s, url, value->path.len); if (strlen(description) != 0) { value->description.len = strlen(description); value->description.s = shm_malloc(value->description.len * sizeof(char)); if (value->description.s == NULL) { LM_ERR("no more shm memory\n"); goto error; } memcpy(value->description.s, description, value->description.len); } else { value->description.s = NULL; value->description.len = 0; } ctime = time(0); for (module = clusterer_modules; module; module = module->next) { if (cluster_id == module->accept_cluster_id && proto == module->proto) { new_timestamp = create_module_timestamp(ctime, module); if (new_timestamp == NULL) break; new_timestamp->next = value->in_timestamps; value->in_timestamps = new_timestamp; } } value->next = info_head->value; info_head->value = value; /* everything ok */ return 0; error: if (value) { if (value->description.s) shm_free(value->description.s); if (value->path.s) shm_free(value->path.s); shm_free(value); } if (info_head) { if (info_head->value == NULL) { if (head != NULL) head->info = head->info->next; shm_free(info_head); } } if (head) { if (head->info == NULL) { *tdata = (*tdata)->next; shm_free(head); } } return -1; }
/* introduce a new uac to transaction; returns its branch id (>=0) or error (<0); it doesn't send a message yet -- a reply to it might interfere with the processes of adding multiple branches */ static int add_uac( struct cell *t, struct sip_msg *request, str *uri, str* next_hop, str* path, struct proxy_l *proxy) { unsigned short branch; int do_free_proxy; int ret; branch=t->nr_of_outgoings; if (branch==MAX_BRANCHES) { LM_ERR("maximum number of branches exceeded\n"); ret=E_CFG; goto error; } /* check existing buffer -- rewriting should never occur */ if (t->uac[branch].request.buffer.s) { LM_CRIT("buffer rewrite attempt\n"); ret=ser_error=E_BUG; goto error; } /* set proper RURI to request to reflect the branch */ request->new_uri=*uri; request->parsed_uri_ok=0; request->dst_uri=*next_hop; request->path_vec=*path; if ( pre_print_uac_request( t, branch, request)!= 0 ) { ret = -1; goto error01; } /* check DNS resolution */ if (proxy){ do_free_proxy = 0; }else { proxy=uri2proxy( request->dst_uri.len ? &request->dst_uri:&request->new_uri, PROTO_NONE ); if (proxy==0) { ret=E_BAD_ADDRESS; goto error01; } do_free_proxy = 1; } msg_callback_process(request, REQ_PRE_FORWARD, (void *)proxy); if ( !(t->flags&T_NO_DNS_FAILOVER_FLAG) ) { t->uac[branch].proxy = shm_clone_proxy( proxy , do_free_proxy ); if (t->uac[branch].proxy==NULL) { ret = E_OUT_OF_MEM; goto error02; } } /* use the first address */ hostent2su( &t->uac[branch].request.dst.to, &proxy->host, proxy->addr_idx, proxy->port ? proxy->port:SIP_PORT); t->uac[branch].request.dst.proto = proxy->proto; if ( update_uac_dst( request, &t->uac[branch] )!=0) { ret = ser_error; goto error02; } /* things went well, move ahead */ t->uac[branch].uri.s=t->uac[branch].request.buffer.s+ request->first_line.u.request.method.len+1; t->uac[branch].uri.len=request->new_uri.len; t->uac[branch].br_flags = getb0flags(); t->uac[branch].added_rr = count_local_rr( request ); t->nr_of_outgoings++; /* done! */ ret=branch; error02: if(do_free_proxy) { free_proxy( proxy ); pkg_free( proxy ); } error01: post_print_uac_request( request, uri, next_hop); error: return ret; }
static int trace_send_hep_duplicate(str *body, str *fromproto, str *fromip, unsigned short fromport, str *toproto, str *toip, unsigned short toport) { struct proxy_l * p=NULL /* make gcc happy */; int ret; union sockaddr_union from_su; union sockaddr_union to_su; unsigned int proto; struct socket_info* send_sock; union sockaddr_union* to = NULL; int heplen; char *hepbuf; if(body->s==NULL || body->len <= 0) return -1; if(dup_uri_str.s==0 || dup_uri==NULL) return 0; /* Convert proto:ip:port to sockaddress union SRC IP */ if (pipport2su(fromproto, fromip, fromport, &from_su, &proto)==-1 || (pipport2su(toproto, toip, toport, &to_su, &proto)==-1)) goto error; /* check if from and to are in the same family*/ if(from_su.s.sa_family != to_su.s.sa_family) { LM_ERR("ERROR: trace_send_hep_duplicate: interworking detected ?\n"); goto error; } /* create a temporary proxy*/ proto = PROTO_UDP; p=mk_proxy(&dup_uri->host, (dup_uri->port_no)?dup_uri->port_no:SIP_PORT,proto, 0); if (p==0){ LM_ERR("bad host name in uri\n"); return -1; } to=(union sockaddr_union*)pkg_malloc(sizeof(union sockaddr_union)); if (to==0){ LM_ERR("out of pkg memory\n"); return -1; } hostent2su(to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT); if (hep_api.pack_hep(&from_su, to, proto, body->s, body->len, &hepbuf, &heplen)) { LM_ERR("failed to do hep packing\n"); return -1; } ret = -1; do { send_sock=get_send_socket(0, to, proto); if (send_sock==0){ LM_ERR("can't forward to af %d, proto %d no corresponding listening socket\n", to->s.sa_family,proto); continue; } if (msg_send(send_sock, PROTO_HEP, to, 0, hepbuf, heplen, NULL)<0){ LM_ERR("cannot send duplicate message\n"); continue; } ret = 0; break; }while( get_next_su( p, to, 0)==0 ); free_proxy(p); /* frees only p content, not p itself */ pkg_free(p); pkg_free(to); pkg_free(hepbuf); return ret; error: if(p) { free_proxy(p); /* frees only p content, not p itself */ pkg_free(p); } if(to) pkg_free(to); return -1; }
static int mi_mod_init(void) { unsigned int port_no; int n; struct stat filestat; struct hostent * host; char *p, *host_s; str port_str; /* checking the mi_socket module param */ LM_DBG("testing socket existance...\n"); if( mi_socket==NULL || *mi_socket == 0) { LM_ERR("no DATAGRAM_ socket configured\n"); return -1; } LM_DBG("the socket's name/address is %s\n", mi_socket); memset( &mi_dtgram_addr, 0, sizeof(mi_dtgram_addr) ); if(strncmp(mi_socket, "udp:",4) == 0) { /*for an UDP socket*/ LM_DBG("we have an udp socket\n"); /*separate proto and host */ p = mi_socket+4; if( (*(p)) == '\0') { LM_ERR("malformed ip address\n"); return -1; } host_s=p; LM_DBG("the remaining address after separating the protocol is %s\n",p); if( (p = strrchr(p+1, ':')) == 0 ) { LM_ERR("no port specified\n"); return -1; } /*the address contains a port number*/ *p = '\0'; p++; port_str.s = p; port_str.len = strlen(p); LM_DBG("the port string is %s\n", p); if(str2int(&port_str, &port_no) != 0 ) { LM_ERR("there is not a valid number port\n"); return -1; } *p = '\0'; if (port_no<1024 || port_no>MAX_NB_PORT) { LM_ERR("invalid port number; must be in [1024,%d]\n",MAX_NB_PORT); return -1; } if(! (host = resolvehost(host_s)) ) { LM_ERR("failed to resolve %s\n", host_s); return -1; } LM_DBG("the ip is %s\n",host_s); if(hostent2su( &(mi_dtgram_addr.udp_addr), host, 0, port_no ) !=0){ LM_ERR("failed to resolve %s\n", mi_socket); return -1; } mi_socket_domain = host->h_addrtype; goto done; } /* in case of a Unix socket*/ LM_DBG("we have an UNIX socket\n"); n=stat(mi_socket, &filestat); if( n==0) { LM_INFO("the socket %s already exists, trying to delete it...\n", mi_socket); if(config_check==0) { if (unlink(mi_socket)<0) { LM_ERR("cannot delete old socket: %s\n", strerror(errno)); return -1; } } } else if (n<0 && errno!=ENOENT) { LM_ERR("socket stat failed:%s\n", strerror(errno)); return -1; } /* check mi_unix_socket_mode */ if(!mi_unix_socket_mode) { LM_WARN("cannot specify mi_unix_socket_mode = 0, forcing it to rw-------\n"); mi_unix_socket_mode = S_IRUSR| S_IWUSR; } if (mi_unix_socket_uid_s) { if (user2uid(&mi_unix_socket_uid, &mi_unix_socket_gid, mi_unix_socket_uid_s)<0) { LM_ERR("bad user name %s\n", mi_unix_socket_uid_s); return -1; } } if (mi_unix_socket_gid_s) { if (group2gid(&mi_unix_socket_gid, mi_unix_socket_gid_s)<0) { LM_ERR("bad group name %s\n", mi_unix_socket_gid_s); return -1; } } /*create the unix socket address*/ mi_dtgram_addr.unix_addr.sun_family = AF_LOCAL; memcpy( mi_dtgram_addr.unix_addr.sun_path, mi_socket, strlen(mi_socket)); done: /* add space for extra processes */ register_procs(mi_procs[0].no); /* add child to update local config framework structures */ cfg_register_child(mi_procs[0].no); return 0; }
static evi_reply_sock* datagram_parse(str socket, int is_unix) { evi_reply_sock *sock = NULL; unsigned short port = 0; char *p = NULL, *host = 0; int len = 0; struct hostent *hentity; if (!socket.len || !socket.s) { LM_ERR("no socket specified\n"); return NULL; } len = socket.len; host = socket.s; if (!is_unix) { p = memchr(host, COLON_C, len); if (!p || p == host) { LM_ERR("port not specified <%.*s>\n", len, host); return NULL; } port = str2s(p + 1, host + len - p - 1, 0); if (port == 0) { LM_DBG("malformed port: %.*s\n", (int)(host + len - p - 1), p + 1); return NULL; } LM_DBG("port is %d\n", port); len = p - host; } /* host */ if (!host || len <= 0) { LM_ERR("malformed address %s\n", host); goto error; } sock = shm_malloc(sizeof(evi_reply_sock) + len); if (!sock) { LM_ERR("no more memory for socket\n"); return NULL; } memset(sock, 0, sizeof(evi_reply_sock)); /* only UDP has port */ if (port) { sock->flags = EVI_PORT; sock->port = port; /* also build sockaddr */ *p = 0; hentity = resolvehost(host, 0); if (!hentity) { LM_ERR("cannot resolve host %s\n", host); goto error; } if(hostent2su(&sock->src_addr.udp_addr, hentity, 0, port)){ LM_ERR("failed to resolve %s\n", host); goto error; } sock->flags |= EVI_SOCKET | DGRAM_UDP_FLAG; } else { sock->src_addr.unix_addr.sun_family = AF_LOCAL; memcpy(sock->src_addr.unix_addr.sun_path, host, len); sock->src_addr.unix_addr.sun_path[len] = 0; sock->flags |= EVI_SOCKET | DGRAM_UNIX_FLAG; } LM_DBG("address is <%.*s>\n", len, host); sock->address.s = (char *) (sock + 1); sock->address.len = len; memcpy(sock->address.s, host, len); sock->flags |= EVI_ADDRESS; /* needs expire */ sock->flags |= EVI_EXPIRE; return sock; error: if (sock) shm_free(sock); return NULL; }
/* ret= 0! if action -> end of list(e.g DROP), > 0 to continue processing next actions and <0 on error */ int do_action(struct action* a, struct sip_msg* msg) { int ret; int v; int sec,usec; union sockaddr_union* to; struct proxy_l* p; char* tmp; char *new_uri, *end, *crt; int len,i; int user = 0; int expires = 0; str vals[5]; str result; struct sip_uri uri, next_hop; struct sip_uri *u; unsigned short port; int cmatch; struct action *aitem; struct action *adefault; pv_spec_t *spec; pv_elem_p model; pv_value_t val; pv_elem_t *pve; str name_s; struct timeval start; int end_time; action_elem_t *route_params_bak; int route_params_number_bak; /* reset the value of error to E_UNSPEC so avoid unknowledgable functions to return with error (status<0) and not setting it leaving there previous error; cache the previous value though for functions which want to process it */ prev_ser_error=ser_error; ser_error=E_UNSPEC; start_expire_timer(start,execmsgthreshold); ret=E_BUG; switch ((unsigned char)a->type){ case DROP_T: script_trace("core", "drop", msg, a->line) ; action_flags |= ACT_FL_DROP; case EXIT_T: script_trace("core", "exit", msg, a->line) ; ret=0; action_flags |= ACT_FL_EXIT; break; case RETURN_T: script_trace("core", "return", msg, a->line) ; if (a->elem[0].type == SCRIPTVAR_ST) { spec = (pv_spec_t*)a->elem[0].u.data; if(pv_get_spec_value(msg, spec, &val)!=0 || (val.flags&PV_VAL_NULL)) { ret=-1; } else { if(!(val.flags&PV_VAL_INT)) ret = 1; else ret = val.ri; } pv_value_destroy(&val); } else { ret=a->elem[0].u.number; } action_flags |= ACT_FL_RETURN; break; case FORWARD_T: script_trace("core", "forward", msg, a->line) ; if (a->elem[0].type==NOSUBTYPE){ /* parse uri and build a proxy */ if (msg->dst_uri.len) { ret = parse_uri(msg->dst_uri.s, msg->dst_uri.len, &next_hop); u = &next_hop; } else { ret = parse_sip_msg_uri(msg); u = &msg->parsed_uri; } if (ret<0) { LM_ERR("forward: bad_uri dropping packet\n"); break; } /* create a temporary proxy*/ p=mk_proxy(u->maddr_val.len?&u->maddr_val:&u->host, u->port_no, u->proto, (u->type==SIPS_URI_T)?1:0 ); if (p==0){ LM_ERR("bad host name in uri, dropping packet\n"); ret=E_BAD_ADDRESS; goto error_fwd_uri; } ret=forward_request(msg, p); free_proxy(p); /* frees only p content, not p itself */ pkg_free(p); if (ret==0) ret=1; }else if ((a->elem[0].type==PROXY_ST)) { ret=forward_request(msg,(struct proxy_l*)a->elem[0].u.data); if (ret==0) ret=1; }else{ LM_ALERT("BUG in forward() types %d, %d\n", a->elem[0].type, a->elem[1].type); ret=E_BUG; } break; case SEND_T: script_trace("core", "send", msg, a->line) ; if (a->elem[0].type!= PROXY_ST){ LM_ALERT("BUG in send() type %d\n", a->elem[0].type); ret=E_BUG; break; } if (a->elem[1].u.data) { if (a->elem[1].type != SCRIPTVAR_ELEM_ST){ LM_ALERT("BUG in send() header type %d\n",a->elem[1].type); ret=E_BUG; break; } else { pve = (pv_elem_t *)a->elem[1].u.data; } } else { pve = NULL; } to=(union sockaddr_union*) pkg_malloc(sizeof(union sockaddr_union)); if (to==0){ LM_ERR("memory allocation failure\n"); ret=E_OUT_OF_MEM; break; } p=(struct proxy_l*)a->elem[0].u.data; ret=hostent2su(to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT ); if (ret==0){ if (pve) { if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_UNSPEC; break; } /* build new msg */ tmp = pkg_malloc(msg->len + name_s.len); if (!tmp) { LM_ERR("memory allocation failure\n"); ret = E_OUT_OF_MEM; break; } LM_DBG("searching for first line %d\n", msg->first_line.len); /* search first line of previous msg */ /* copy headers */ len = msg->first_line.len; memcpy(tmp, msg->buf, len); memcpy(tmp + len, name_s.s, name_s.len); memcpy(tmp + len + name_s.len, msg->buf + len, msg->len - len); ret = msg_send(0/*send_sock*/, p->proto, to, 0/*id*/, tmp, msg->len + name_s.len); pkg_free(tmp); } else { ret = msg_send(0/*send_sock*/, p->proto, to, 0/*id*/, msg->buf, msg->len); } if (ret!=0 && p->host.h_addr_list[p->addr_idx+1]) p->addr_idx++; } pkg_free(to); if (ret==0) ret=1; break; case LOG_T: script_trace("core", "log", msg, a->line) ; if ((a->elem[0].type!=NUMBER_ST)|(a->elem[1].type!=STRING_ST)){ LM_ALERT("BUG in log() types %d, %d\n", a->elem[0].type, a->elem[1].type); ret=E_BUG; break; } LM_GEN1(a->elem[0].u.number, "%s", a->elem[1].u.string); ret=1; break; case APPEND_BRANCH_T: script_trace("core", "append_branch", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in append_branch %d\n", a->elem[0].type ); ret=E_BUG; break; } if (a->elem[0].u.s.s==NULL) { ret = append_branch(msg, 0, &msg->dst_uri, &msg->path_vec, get_ruri_q(), getb0flags(), msg->force_send_socket); /* reset all branch info */ msg->force_send_socket = 0; setb0flags(0); set_ruri_q(Q_UNSPECIFIED); if(msg->dst_uri.s!=0) pkg_free(msg->dst_uri.s); msg->dst_uri.s = 0; msg->dst_uri.len = 0; if(msg->path_vec.s!=0) pkg_free(msg->path_vec.s); msg->path_vec.s = 0; msg->path_vec.len = 0; } else { ret = append_branch(msg, &a->elem[0].u.s, &msg->dst_uri, &msg->path_vec, a->elem[1].u.number, getb0flags(), msg->force_send_socket); } break; case REMOVE_BRANCH_T: script_trace("core", "remove_branch", msg, a->line) ; if (a->elem[0].type == SCRIPTVAR_ST) { spec = (pv_spec_t*)a->elem[0].u.data; if( pv_get_spec_value(msg, spec, &val)!=0 || (val.flags&PV_VAL_NULL) || !(val.flags&PV_VAL_INT) ) { ret=-1; break; } i = val.ri; } else { i=a->elem[0].u.number; } ret = (remove_branch((unsigned int)i)==0)?1:-1; break; case LEN_GT_T: script_trace("core", "len_gt", msg, a->line) ; if (a->elem[0].type!=NUMBER_ST) { LM_ALERT("BUG in len_gt type %d\n", a->elem[0].type ); ret=E_BUG; break; } ret = (msg->len >= (unsigned int)a->elem[0].u.number) ? 1 : -1; break; case SET_DEBUG_T: script_trace("core", "set_debug", msg, a->line) ; if (a->elem[0].type==NUMBER_ST) set_proc_debug_level(a->elem[0].u.number); else reset_proc_debug_level(); ret = 1; break; case SETFLAG_T: script_trace("core", "setflag", msg, a->line) ; ret = setflag( msg, a->elem[0].u.number ); break; case RESETFLAG_T: script_trace("core", "resetflag", msg, a->line) ; ret = resetflag( msg, a->elem[0].u.number ); break; case ISFLAGSET_T: script_trace("core", "isflagset", msg, a->line) ; ret = isflagset( msg, a->elem[0].u.number ); break; case SETSFLAG_T: script_trace("core", "setsflag", msg, a->line) ; ret = setsflag( a->elem[0].u.number ); break; case RESETSFLAG_T: script_trace("core", "resetsflag", msg, a->line) ; ret = resetsflag( a->elem[0].u.number ); break; case ISSFLAGSET_T: script_trace("core", "issflagset", msg, a->line) ; ret = issflagset( a->elem[0].u.number ); break; case SETBFLAG_T: script_trace("core", "setbflag", msg, a->line) ; ret = setbflag( a->elem[0].u.number, a->elem[1].u.number ); break; case RESETBFLAG_T: script_trace("core", "resetbflag", msg, a->line) ; ret = resetbflag( a->elem[0].u.number, a->elem[1].u.number ); break; case ISBFLAGSET_T: script_trace("core", "isbflagset", msg, a->line) ; ret = isbflagset( a->elem[0].u.number, a->elem[1].u.number ); break; case ERROR_T: script_trace("core", "error", msg, a->line) ; if ((a->elem[0].type!=STRING_ST)|(a->elem[1].type!=STRING_ST)){ LM_ALERT("BUG in error() types %d, %d\n", a->elem[0].type, a->elem[1].type); ret=E_BUG; break; } LM_ERR("error(\"%s\", \"%s\") not implemented yet\n", a->elem[0].u.string, a->elem[1].u.string); ret=1; break; case ROUTE_T: script_trace("route", rlist[a->elem[0].u.number].name, msg, a->line) ; if (a->elem[0].type!=NUMBER_ST){ LM_ALERT("BUG in route() type %d\n", a->elem[0].type); ret=E_BUG; break; } if ((a->elem[0].u.number>RT_NO)||(a->elem[0].u.number<0)){ LM_ALERT("BUG - invalid routing table number in" "route(%lu)\n", a->elem[0].u.number); ret=E_CFG; break; } /* check if the route has parameters */ if (a->elem[1].type != 0) { if (a->elem[1].type != NUMBER_ST || a->elem[2].type != SCRIPTVAR_ELEM_ST) { LM_ALERT("BUG in route() type %d/%d\n", a->elem[1].type, a->elem[2].type); ret=E_BUG; break; } route_params_bak = route_params; route_params = (action_elem_t *)a->elem[2].u.data; route_params_number_bak = route_params_number; route_params_number = a->elem[1].u.number; return_code=run_actions(rlist[a->elem[0].u.number].a, msg); route_params = route_params_bak; route_params_number = route_params_number_bak; } else { return_code=run_actions(rlist[a->elem[0].u.number].a, msg); } ret=return_code; break; case REVERT_URI_T: script_trace("core", "revert_uri", msg, a->line) ; if (msg->new_uri.s) { pkg_free(msg->new_uri.s); msg->new_uri.len=0; msg->new_uri.s=0; msg->parsed_uri_ok=0; /* invalidate current parsed uri*/ }; ret=1; break; case SET_HOST_T: case SET_HOSTPORT_T: case SET_USER_T: case SET_USERPASS_T: case SET_PORT_T: case SET_URI_T: case PREFIX_T: case STRIP_T: case STRIP_TAIL_T: script_trace("core", (unsigned char)a->type == SET_HOST_T ? "set_host" : (unsigned char)a->type == SET_HOSTPORT_T ? "set_hostport" : (unsigned char)a->type == SET_USER_T ? "set_user" : (unsigned char)a->type == SET_USERPASS_T ? "set_userpass" : (unsigned char)a->type == SET_PORT_T ? "set_port" : (unsigned char)a->type == SET_URI_T ? "set_uri" : (unsigned char)a->type == PREFIX_T ? "prefix" : (unsigned char)a->type == STRIP_T ? "strip" : "strip_tail", msg, a->line); user=0; if (a->type==STRIP_T || a->type==STRIP_TAIL_T) { if (a->elem[0].type!=NUMBER_ST) { LM_ALERT("BUG in set*() type %d\n", a->elem[0].type); break; } } else if (a->elem[0].type!=STR_ST){ LM_ALERT("BUG in set*() type %d\n", a->elem[0].type); ret=E_BUG; break; } if (a->type==SET_URI_T) { if (set_ruri( msg, &a->elem[0].u.s) ) { LM_ERR("failed to set new RURI\n"); ret=E_OUT_OF_MEM; break; } ret=1; break; } if (msg->new_uri.s) { tmp=msg->new_uri.s; len=msg->new_uri.len; }else{ tmp=msg->first_line.u.request.uri.s; len=msg->first_line.u.request.uri.len; } if (parse_uri(tmp, len, &uri)<0){ LM_ERR("bad uri <%.*s>, dropping packet\n", len, tmp); ret=E_UNSPEC; break; } new_uri=pkg_malloc(MAX_URI_SIZE); if (new_uri==0){ LM_ERR("memory allocation failure\n"); ret=E_OUT_OF_MEM; break; } end=new_uri+MAX_URI_SIZE; crt=new_uri; /* begin copying */ len = (uri.user.len?uri.user.s:uri.host.s) - tmp; if (crt+len>end) goto error_uri; memcpy(crt,tmp,len);crt+=len; if (a->type==PREFIX_T) { if (crt+a->elem[0].u.s.len>end) goto error_uri; memcpy( crt, a->elem[0].u.s.s, a->elem[0].u.s.len); crt+=a->elem[0].u.s.len; /* whatever we had before, with prefix we have username now */ user=1; } if ((a->type==SET_USER_T)||(a->type==SET_USERPASS_T)) { tmp=a->elem[0].u.s.s; len=a->elem[0].u.s.len; } else if (a->type==STRIP_T) { if (a->elem[0].u.number>uri.user.len) { LM_WARN("too long strip asked; " " deleting username: %lu of <%.*s>\n", a->elem[0].u.number, uri.user.len, uri.user.s); len=0; } else if (a->elem[0].u.number==uri.user.len) { len=0; } else { tmp=uri.user.s + a->elem[0].u.number; len=uri.user.len - a->elem[0].u.number; } } else if (a->type==STRIP_TAIL_T) { if (a->elem[0].u.number>uri.user.len) { LM_WARN("too long strip_tail asked;" " deleting username: %lu of <%.*s>\n", a->elem[0].u.number, uri.user.len, uri.user.s); len=0; } else if (a->elem[0].u.number==uri.user.len) { len=0; } else { tmp=uri.user.s; len=uri.user.len - a->elem[0].u.number; } } else { tmp=uri.user.s; len=uri.user.len; } if (len){ if(crt+len>end) goto error_uri; memcpy(crt,tmp,len);crt+=len; user=1; /* we have an user field so mark it */ } if (a->type==SET_USERPASS_T) tmp=0; else tmp=uri.passwd.s; /* passwd */ if (tmp){ len=uri.passwd.len; if(crt+len+1>end) goto error_uri; *crt=':'; crt++; memcpy(crt,tmp,len);crt+=len; } /* host */ if (user || tmp){ /* add @ */ if(crt+1>end) goto error_uri; *crt='@'; crt++; } if ((a->type==SET_HOST_T) ||(a->type==SET_HOSTPORT_T)) { tmp=a->elem[0].u.s.s; len=a->elem[0].u.s.len; } else { tmp=uri.host.s; len = uri.host.len; } if (tmp){ if(crt+len>end) goto error_uri; memcpy(crt,tmp,len);crt+=len; } /* port */ if (a->type==SET_HOSTPORT_T) tmp=0; else if (a->type==SET_PORT_T) { tmp=a->elem[0].u.s.s; len=a->elem[0].u.s.len; } else { tmp=uri.port.s; len = uri.port.len; } if (tmp && len>0){ if(crt+len+1>end) goto error_uri; *crt=':'; crt++; memcpy(crt,tmp,len);crt+=len; } /* params */ tmp=uri.params.s; if (tmp){ /* include in param string the starting ';' */ len=uri.params.len+1; tmp--; if(crt+len+1>end) goto error_uri; /* if a maddr param is present, strip it out */ if (uri.maddr.len && (a->type==SET_HOSTPORT_T || a->type==SET_HOST_T)) { memcpy(crt,tmp,uri.maddr.s-tmp-1); crt+=uri.maddr.s-tmp-1; memcpy(crt,uri.maddr_val.s+uri.maddr_val.len, tmp+len-uri.maddr_val.s-uri.maddr_val.len); crt+=tmp+len-uri.maddr_val.s-uri.maddr_val.len; } else { memcpy(crt,tmp,len);crt+=len; } } /* headers */ tmp=uri.headers.s; if (tmp){ len=uri.headers.len; if(crt+len+1>end) goto error_uri; *crt='?'; crt++; memcpy(crt,tmp,len);crt+=len; } *crt=0; /* null terminate the thing */ /* copy it to the msg */ if (msg->new_uri.s) pkg_free(msg->new_uri.s); msg->new_uri.s=new_uri; msg->new_uri.len=crt-new_uri; msg->parsed_uri_ok=0; ret=1; break; case SET_DSTURI_T: script_trace("core", "set_dsturi", msg, a->line) ; if (a->elem[0].type!=STR_ST){ LM_ALERT("BUG in setdsturi() type %d\n", a->elem[0].type); ret=E_BUG; break; } if(set_dst_uri(msg, &a->elem[0].u.s)!=0) ret = -1; else ret = 1; break; case SET_DSTHOST_T: case SET_DSTPORT_T: script_trace("core", (unsigned char) a->type == SET_DSTHOST_T ? "set_dsturi" : "set_dstport", msg, a->line); if (a->elem[0].type!=STR_ST){ LM_ALERT("BUG in domain setting type %d\n", a->elem[0].type); ret=E_BUG; break; } tmp = msg->dst_uri.s; len = msg->dst_uri.len; if (tmp == NULL || len == 0) { LM_ERR("failure - null uri\n"); ret = E_UNSPEC; break; } if (a->type == SET_DSTHOST_T && (a->elem[0].u.s.s == NULL || a->elem[0].u.s.len == 0)) { LM_ERR("cannot set a null uri domain\n"); break; } if (parse_uri(tmp, len, &uri)<0) { LM_ERR("bad uri <%.*s>, dropping packet\n", len, tmp); break; } new_uri=pkg_malloc(MAX_URI_SIZE); if (new_uri == NULL) { LM_ERR("memory allocation failure\n"); ret=E_OUT_OF_MEM; break; } end=new_uri+MAX_URI_SIZE; crt=new_uri; len = (uri.user.len?uri.user.s:uri.host.s) - tmp; if (crt+len>end) goto error_uri; memcpy(crt,tmp,len); crt += len; /* user */ tmp = uri.user.s; len = uri.user.len; if (tmp) { if (crt+len>end) goto error_uri; memcpy(crt,tmp,len); crt += len; user = 1; } /* passwd */ tmp = uri.passwd.s; len = uri.passwd.len; if (user || tmp) { if (crt+len+1>end) goto error_uri; *crt++=':'; memcpy(crt, tmp, len); crt += len; } /* host */ if (a->type==SET_DSTHOST_T) { tmp = a->elem[0].u.s.s; len = a->elem[0].u.s.len; } else { tmp = uri.host.s; len = uri.host.len; } if (tmp) { if (user) { if (crt+1>end) goto error_uri; *crt++='@'; } if (crt+len+1>end) goto error_uri; memcpy(crt, tmp, len); crt += len; } /* port */ if (a->type==SET_DSTPORT_T) { tmp = a->elem[0].u.s.s; len = a->elem[0].u.s.len; } else { tmp = uri.port.s; len = uri.port.len; } if (tmp) { if (crt+len+1>end) goto error_uri; *crt++=':'; memcpy(crt, tmp, len); crt += len; } /* params */ tmp=uri.params.s; if (tmp){ len=uri.params.len; if(crt+len+1>end) goto error_uri; *crt++=';'; memcpy(crt,tmp,len); crt += len; } /* headers */ tmp=uri.headers.s; if (tmp){ len=uri.headers.len; if(crt+len+1>end) goto error_uri; *crt++='?'; memcpy(crt,tmp,len); crt += len; } *crt=0; /* null terminate the thing */ /* copy it to the msg */ pkg_free(msg->dst_uri.s); msg->dst_uri.s=new_uri; msg->dst_uri.len=crt-new_uri; ret = 1; break; case RESET_DSTURI_T: script_trace("core", "reset_dsturi", msg, a->line) ; if(msg->dst_uri.s!=0) pkg_free(msg->dst_uri.s); msg->dst_uri.s = 0; msg->dst_uri.len = 0; ret = 1; break; case ISDSTURISET_T: script_trace("core", "isdsturiset", msg, a->line) ; if(msg->dst_uri.s==0 || msg->dst_uri.len<=0) ret = -1; else ret = 1; break; case IF_T: script_trace("core", "if", msg, a->line) ; /* if null expr => ignore if? */ if ((a->elem[0].type==EXPR_ST)&&a->elem[0].u.data){ v=eval_expr((struct expr*)a->elem[0].u.data, msg, 0); /* set return code to expr value */ if (v<0 || (action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT) ){ if (v==EXPR_DROP || (action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT) ){ /* hack to quit on DROP*/ ret=0; return_code = 0; break; }else{ LM_WARN("error in expression (l=%d)\n", a->line); } } ret=1; /*default is continue */ if (v>0) { if ((a->elem[1].type==ACTIONS_ST)&&a->elem[1].u.data){ ret=run_action_list( (struct action*)a->elem[1].u.data,msg ); return_code = ret; } else return_code = v; }else{ if ((a->elem[2].type==ACTIONS_ST)&&a->elem[2].u.data){ ret=run_action_list( (struct action*)a->elem[2].u.data,msg); return_code = ret; } else return_code = v; } } break; case WHILE_T: script_trace("core", "while", msg, a->line) ; /* if null expr => ignore if? */ if ((a->elem[0].type==EXPR_ST)&&a->elem[0].u.data){ len = 0; while(1) { if(len++ >= max_while_loops) { LM_INFO("max while loops are encountered\n"); break; } v=eval_expr((struct expr*)a->elem[0].u.data, msg, 0); /* set return code to expr value */ if (v<0 || (action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT) ){ if (v==EXPR_DROP || (action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT) ){ ret=0; return_code = 0; break; }else{ LM_WARN("error in expression (l=%d)\n", a->line); } } ret=1; /*default is continue */ if (v>0) { if ((a->elem[1].type==ACTIONS_ST) &&a->elem[1].u.data){ ret=run_action_list( (struct action*)a->elem[1].u.data,msg ); /* check if return was done */ if ((action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT) ){ break; } return_code = ret; } else { /* we should not get here */ return_code = v; break; } } else { /* condition was false */ return_code = v; break; } } } break; case CACHE_STORE_T: script_trace("core", "cache_store", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_store() - first argument not of" " type string [%d]\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_store() - second argument not of " "type string [%d]\n", a->elem[1].type ); ret=E_BUG; break; } if ((a->elem[2].type!=STR_ST)) { LM_ALERT("BUG in cache_store() - third argument not of type" " string%d\n", a->elem[2].type ); ret=E_BUG; break; } str val_s; /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } /* parse the value argument */ pve = (pv_elem_t *)a->elem[2].u.data; if ( pv_printf_s(msg, pve, &val_s)!=0 || val_s.len == 0 || val_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } /* get the expires value */ if ( a->elem[3].type == SCRIPTVAR_ST ) { spec = (pv_spec_t*)a->elem[3].u.data; memset(&val, 0, sizeof(pv_value_t)); if(pv_get_spec_value(msg, spec, &val) < 0) { LM_DBG("Failed to get scriptvar value while executing cache_store\n"); ret=E_BUG; break; } if (!(val.flags&PV_VAL_INT)) { LM_ERR("Wrong value for cache_store expires, not an integer [%.*s]\n", val.rs.len, val.rs.s); } expires = val.ri; } else if ( a->elem[3].type == NUMBER_ST ) { expires = (int)a->elem[3].u.number; } ret = cachedb_store( &a->elem[0].u.s, &name_s, &val_s,expires); break; case CACHE_REMOVE_T: script_trace("core", "cache_remove", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_remove() %d\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_remove() %d\n", a->elem[1].type ); ret=E_BUG; break; } /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } ret = cachedb_remove( &a->elem[0].u.s, &name_s); break; case CACHE_FETCH_T: script_trace("core", "cache_fetch", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[1].type ); ret=E_BUG; break; } if (a->elem[2].type!=SCRIPTVAR_ST){ LM_ALERT("BUG in cache_fetch() type %d\n", a->elem[2].type); ret=E_BUG; break; } str aux = {0, 0}; /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } ret = cachedb_fetch( &a->elem[0].u.s, &name_s, &aux); if(ret > 0) { val.rs = aux; val.flags = PV_VAL_STR; spec = (pv_spec_t*)a->elem[2].u.data; if (pv_set_value(msg, spec, 0, &val) < 0) { LM_ERR("cannot set the variable value\n"); pkg_free(aux.s); return -1; } pkg_free(aux.s); } break; case CACHE_COUNTER_FETCH_T: script_trace("core", "cache_counter_fetch", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[1].type ); ret=E_BUG; break; } if (a->elem[2].type!=SCRIPTVAR_ST){ LM_ALERT("BUG in cache_fetch() type %d\n", a->elem[2].type); ret=E_BUG; break; } int aux_counter; /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } ret = cachedb_counter_fetch( &a->elem[0].u.s, &name_s, &aux_counter); if(ret > 0) { val.ri = aux_counter; val.flags = PV_TYPE_INT|PV_VAL_INT; spec = (pv_spec_t*)a->elem[2].u.data; if (pv_set_value(msg, spec, 0, &val) < 0) { LM_ERR("cannot set the variable value\n"); pkg_free(aux.s); return -1; } } break; case CACHE_ADD_T: script_trace("core", "cache_add", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_add() - first argument not of" " type string [%d]\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_add() - second argument not of " "type string [%d]\n", a->elem[1].type ); ret=E_BUG; break; } /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } int increment=0; /* get the increment value */ if ( a->elem[2].type == SCRIPTVAR_ST ) { spec = (pv_spec_t*)a->elem[2].u.data; memset(&val, 0, sizeof(pv_value_t)); if(pv_get_spec_value(msg, spec, &val) < 0) { LM_DBG("Failed to get scriptvar value while executing cache_add\n"); ret=E_BUG; break; } if (!(val.flags&PV_VAL_INT)) { LM_ERR("Wrong value for cache_add, not an integer [%.*s]\n", val.rs.len, val.rs.s); } increment = val.ri; } else if ( a->elem[2].type == NUMBER_ST ) { increment = (int)a->elem[2].u.number; } expires = (int)a->elem[3].u.number; /* TODO - return the new value to script ? */ ret = cachedb_add(&a->elem[0].u.s, &name_s, increment,expires,NULL); break; case CACHE_SUB_T: script_trace("core", "cache_sub", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_sub() - first argument not of" " type string [%d]\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_sub() - second argument not of " "type string [%d]\n", a->elem[1].type ); ret=E_BUG; break; } /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } int decrement=0; /* get the increment value */ if ( a->elem[2].type == SCRIPTVAR_ST ) { spec = (pv_spec_t*)a->elem[2].u.data; memset(&val, 0, sizeof(pv_value_t)); if(pv_get_spec_value(msg, spec, &val) < 0) { LM_DBG("Failed to get scriptvar value while executing cache_sub\n"); ret=E_BUG; break; } if (!(val.flags&PV_VAL_INT)) { LM_ERR("Wrong value for cache_sub, not an integer [%.*s]\n", val.rs.len, val.rs.s); } decrement = val.ri; } else if ( a->elem[2].type == NUMBER_ST ) { decrement = (int)a->elem[2].u.number; } expires = (int)a->elem[3].u.number; /* TODO - return new value to script ? */ ret = cachedb_sub(&a->elem[0].u.s, &name_s, decrement,expires,NULL); break; case CACHE_RAW_QUERY_T: if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[1].type ); ret=E_BUG; break; } if (a->elem[2].u.data != NULL && a->elem[2].type!=STR_ST){ LM_ALERT("BUG in cache_raw_query() type %d\n", a->elem[2].type); ret=E_BUG; break; } /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } cdb_raw_entry **cdb_reply; int val_number=0,i,j; int key_number=0; pvname_list_t *cdb_res,*it; int_str avp_val; int_str avp_name; unsigned short avp_type; if (a->elem[2].u.data) { cdb_res = (pvname_list_t*)a->elem[2].u.data; for (it=cdb_res;it;it=it->next) val_number++; LM_DBG("The query expects %d results back\n",val_number); ret = cachedb_raw_query( &a->elem[0].u.s, &name_s, &cdb_reply,val_number,&key_number); if (ret >= 0 && val_number > 0) { for (i=key_number-1; i>=0;i--) { it=cdb_res; for (j=0;j < val_number;j++) { avp_type = 0; if (pv_get_avp_name(msg,&it->sname.pvp,&avp_name.n, &avp_type) != 0) { LM_ERR("cannot get avp name [%d/%d]\n",i,j); goto next_avp; } switch (cdb_reply[i][j].type) { case CDB_INT: avp_val.n = cdb_reply[i][j].val.n; break; case CDB_STR: avp_type |= AVP_VAL_STR; avp_val.s = cdb_reply[i][j].val.s; break; default: LM_WARN("Unknown type %d\n",cdb_reply[i][j].type); goto next_avp; } if (add_avp(avp_type,avp_name.n,avp_val) != 0) { LM_ERR("Unable to add AVP\n"); free_raw_fetch(cdb_reply,val_number,key_number); return -1; } next_avp: if (it) { it = it->next; if (it==NULL); break; } } } free_raw_fetch(cdb_reply,val_number,key_number); } } else ret = cachedb_raw_query( &a->elem[0].u.s, &name_s, NULL,0,NULL); break; case XDBG_T: script_trace("core", "xdbg", msg, a->line) ; if (a->elem[0].type == SCRIPTVAR_ELEM_ST) { if (xdbg(msg, a->elem[0].u.data, val.rs.s) < 0) { LM_ALERT("Cannot print message"); break; } } else { LM_ALERT("BUG in xdbg() type %d\n", a->elem[0].type); ret=E_BUG; } break; case XLOG_T: script_trace("core", "xlog", msg, a->line) ; if (a->elem[1].u.data != NULL) { if (a->elem[1].type != SCRIPTVAR_ELEM_ST) { LM_ALERT("BUG in xlog() type %d\n", a->elem[1].type); ret=E_BUG; break; } if (a->elem[0].type != STR_ST) { LM_ALERT("BUG in xlog() type %d\n", a->elem[0].type); ret=E_BUG; break; } if (xlog_2(msg,a->elem[0].u.data, a->elem[1].u.data) < 0) { LM_ALERT("Cannot print xlog debug message"); break; } } else { if (a->elem[0].type != SCRIPTVAR_ELEM_ST) { LM_ALERT("BUG in xlog() type %d\n", a->elem[0].type); ret=E_BUG; break; } if (xlog_1(msg,a->elem[0].u.data, val.rs.s) < 0) { LM_ALERT("Cannot print xlog debug message"); break; } } break; case RAISE_EVENT_T: script_trace("core", "raise_event", msg, a->line) ; if (a->elem[0].type != NUMBER_ST) { LM_ERR("invalid event id\n"); ret=E_BUG; break; } if (a->elem[2].u.data) { /* three parameters specified */ ret = evi_raise_script_event(msg, (event_id_t)a->elem[0].u.number, a->elem[1].u.data, a->elem[2].u.data); } else { /* two parameters specified */ ret = evi_raise_script_event(msg, (event_id_t)a->elem[0].u.number, NULL, a->elem[1].u.data); } if (ret <= 0) { LM_ERR("cannot raise event\n"); ret=E_UNSPEC; break; } break; case SUBSCRIBE_EVENT_T: script_trace("core", "subscribe_event", msg, a->line) ; if (a->elem[0].type != STR_ST || a->elem[1].type != STR_ST) { LM_ERR("BUG in subscribe arguments\n"); ret=E_BUG; break; } if (a->elem[2].u.data) { if (a->elem[2].type != NUMBER_ST) { LM_ERR("BUG in subscribe expiration time\n"); ret=E_BUG; break; } else { i = a->elem[2].u.number; } } else { i = 0; } name_s.s = a->elem[0].u.data; name_s.len = strlen(name_s.s); /* result should be the socket */ result.s = a->elem[1].u.data; result.len = strlen(result.s); ret = evi_event_subscribe(name_s, result, i, 0); break; case CONSTRUCT_URI_T: script_trace("core", "construct_uri", msg, a->line) ; for (i=0;i<5;i++) { pve = (pv_elem_t *)a->elem[i].u.data; if (pve->spec.getf) { if ( pv_printf_s(msg, pve, &vals[i])!=0 || vals[i].len == 0 || vals[i].s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; return -1; } } else vals[i] = pve->text; } result.s = construct_uri(&vals[0],&vals[1],&vals[2],&vals[3],&vals[4], &result.len); if (result.s) { int_str res; int avp_name; unsigned short avp_type; spec = (pv_spec_t*)a->elem[5].u.data; if (pv_get_avp_name( msg, &(spec->pvp), &avp_name, &avp_type)!=0){ LM_CRIT("BUG in getting AVP name\n"); return -1; } res.s = result; if (add_avp(AVP_VAL_STR|avp_type, avp_name, res)<0){ LM_ERR("cannot add AVP\n"); return -1; } } break; case GET_TIMESTAMP_T: script_trace("core", "get_timestamp", msg, a->line) ; if (get_timestamp(&sec,&usec) == 0) { int avp_name; int_str res; unsigned short avp_type; spec = (pv_spec_t*)a->elem[0].u.data; if (pv_get_avp_name(msg, &(spec->pvp), &avp_name, &avp_type) != 0) { LM_CRIT("BUG in getting AVP name\n"); return -1; } res.n = sec; if (add_avp(avp_type, avp_name, res) < 0) { LM_ERR("cannot add AVP\n"); return -1; } spec = (pv_spec_t*)a->elem[1].u.data; if (pv_get_avp_name(msg, &(spec->pvp), &avp_name, &avp_type) != 0) { LM_CRIT("BUG in getting AVP name\n"); return -1; } res.n = usec; if (add_avp(avp_type, avp_name, res) < 0) { LM_ERR("cannot add AVP\n"); return -1; } } else { LM_ERR("failed to get time\n"); return -1; } break; case SWITCH_T: script_trace("core", "switch", msg, a->line) ; if (a->elem[0].type!=SCRIPTVAR_ST){ LM_ALERT("BUG in switch() type %d\n", a->elem[0].type); ret=E_BUG; break; } spec = (pv_spec_t*)a->elem[0].u.data; if(pv_get_spec_value(msg, spec, &val)!=0) { LM_ALERT("BUG - no value in switch()\n"); ret=E_BUG; break; } /* get the value of pvar */ if(a->elem[1].type!=ACTIONS_ST) { LM_ALERT("BUG in switch() actions\n"); ret=E_BUG; break; } return_code=1; adefault = NULL; aitem = (struct action*)a->elem[1].u.data; cmatch=0; while(aitem) { if((unsigned char)aitem->type==DEFAULT_T) adefault=aitem; if(cmatch==0) { if(aitem->elem[0].type==STR_ST) { if(val.flags&PV_VAL_STR && val.rs.len==aitem->elem[0].u.s.len && strncasecmp(val.rs.s, aitem->elem[0].u.s.s, val.rs.len)==0) cmatch = 1; } else { /* number */ if(val.flags&PV_VAL_INT && val.ri==aitem->elem[0].u.number) cmatch = 1; } } if(cmatch==1) { if(aitem->elem[1].u.data) { return_code=run_action_list( (struct action*)aitem->elem[1].u.data, msg); if ((action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT)) break; } if(aitem->elem[2].u.number==1) break; } aitem = aitem->next; } if((cmatch==0) && (adefault!=NULL)) { LM_DBG("switch: running default statement\n"); if(adefault->elem[0].u.data) return_code=run_action_list( (struct action*)adefault->elem[0].u.data, msg); } ret=return_code; break; case MODULE_T: script_trace("module", ((cmd_export_t*)(a->elem[0].u.data))->name, msg, a->line) ; if ( (a->elem[0].type==CMD_ST) && a->elem[0].u.data ) { ret=((cmd_export_t*)(a->elem[0].u.data))->function(msg, (char*)a->elem[1].u.data, (char*)a->elem[2].u.data, (char*)a->elem[3].u.data, (char*)a->elem[4].u.data, (char*)a->elem[5].u.data, (char*)a->elem[6].u.data); }else{ LM_ALERT("BUG in module call\n"); } break; case FORCE_RPORT_T: script_trace("core", "force_rport", msg, a->line) ; msg->msg_flags|=FL_FORCE_RPORT; ret=1; /* continue processing */ break; case FORCE_LOCAL_RPORT_T: script_trace("core", "force_local_rport", msg, a->line) ; msg->msg_flags|=FL_FORCE_LOCAL_RPORT; ret=1; /* continue processing */ break; case SET_ADV_ADDR_T: script_trace("core", "set_adv_addr", msg, a->line) ; if (a->elem[0].type!=STR_ST){ LM_ALERT("BUG in set_advertised_address() " "type %d\n", a->elem[0].type); ret=E_BUG; break; } str adv_addr; pve = (pv_elem_t *)a->elem[0].u.data; if ( pv_printf_s(msg, pve, &adv_addr)!=0 || adv_addr.len == 0 || adv_addr.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } LM_DBG("adv address = [%.*s]\n",adv_addr.len,adv_addr.s); msg->set_global_address=adv_addr; ret=1; /* continue processing */ break; case SET_ADV_PORT_T: script_trace("core", "set_adv_port", msg, a->line) ; if (a->elem[0].type!=STR_ST){ LM_ALERT("BUG in set_advertised_port() " "type %d\n", a->elem[0].type); ret=E_BUG; break; } msg->set_global_port=*((str*)a->elem[0].u.data); ret=1; /* continue processing */ break; #ifdef USE_TCP case FORCE_TCP_ALIAS_T: script_trace("core", "force_tcp_alias", msg, a->line) ; if ( msg->rcv.proto==PROTO_TCP #ifdef USE_TLS || msg->rcv.proto==PROTO_TLS #endif ){ if (a->elem[0].type==NOSUBTYPE) port=msg->via1->port; else if (a->elem[0].type==NUMBER_ST) port=(int)a->elem[0].u.number; else{ LM_ALERT("BUG in force_tcp_alias" " port type %d\n", a->elem[0].type); ret=E_BUG; break; } if (tcpconn_add_alias(msg->rcv.proto_reserved1, port, msg->rcv.proto)!=0){ LM_ERR("tcp alias failed\n"); ret=E_UNSPEC; break; } } #endif ret=1; /* continue processing */ break; case FORCE_SEND_SOCKET_T: script_trace("core", "force_send_socket", msg, a->line) ; if (a->elem[0].type!=SOCKETINFO_ST){ LM_ALERT("BUG in force_send_socket argument" " type: %d\n", a->elem[0].type); ret=E_BUG; break; } msg->force_send_socket=(struct socket_info*)a->elem[0].u.data; ret=1; /* continue processing */ break; case SERIALIZE_BRANCHES_T: script_trace("core", "serialize_branches", msg, a->line) ; if (a->elem[0].type!=NUMBER_ST){ LM_ALERT("BUG in serialize_branches argument" " type: %d\n", a->elem[0].type); ret=E_BUG; break; } if (serialize_branches(msg,(int)a->elem[0].u.number)!=0) { LM_ERR("serialize_branches failed\n"); ret=E_UNSPEC; break; } ret=1; /* continue processing */ break; case NEXT_BRANCHES_T: script_trace("core", "next_branches", msg, a->line) ; if ((ret=next_branches(msg))<0) { LM_ERR("next_branches failed\n"); ret=E_UNSPEC; break; } /* continue processing */ break; case EQ_T: case COLONEQ_T: case PLUSEQ_T: case MINUSEQ_T: case DIVEQ_T: case MULTEQ_T: case MODULOEQ_T: case BANDEQ_T: case BOREQ_T: case BXOREQ_T: ret = do_assign(msg, a); break; case USE_BLACKLIST_T: script_trace("core", "use_blacklist", msg, a->line) ; mark_for_search((struct bl_head*)a->elem[0].u.data, 1); break; case UNUSE_BLACKLIST_T: script_trace("core", "unuse_blacklist", msg, a->line); mark_for_search((struct bl_head*)a->elem[0].u.data, 0); break; case PV_PRINTF_T: script_trace("core", "pv_printf", msg, a->line); ret = -1; spec = (pv_spec_p)a->elem[0].u.data; if(!pv_is_w(spec)) { LM_ERR("read only PV in first parameter of pv_printf\n"); goto error; } model = (pv_elem_p)a->elem[1].u.data; memset(&val, 0, sizeof(pv_value_t)); if(pv_printf_s(msg, model, &val.rs)!=0) { LM_ERR("cannot eval second parameter\n"); goto error; } val.flags = PV_VAL_STR; if(pv_set_value(msg, spec, EQ_T, &val)<0) { LM_ERR("setting PV failed\n"); goto error; } ret = 1; break; case SCRIPT_TRACE_T: script_trace("core", "script_trace", msg, a->line); if (a->elem[0].type==NOSUBTYPE) { use_script_trace = 0; } else { use_script_trace = 1; if (a->elem[0].type != NUMBER_ST || a->elem[1].type != SCRIPTVAR_ELEM_ST) { LM_ERR("BUG in use_script_trace() arguments\n"); ret=E_BUG; break; } if (a->elem[2].type!=NOSUBTYPE) { script_trace_info = (char *)a->elem[2].u.data; } else { script_trace_info = NULL; } script_trace_log_level = (int)a->elem[0].u.number; script_trace_elem = *(pv_elem_p)a->elem[1].u.data; } break; default: LM_ALERT("BUG - unknown type %d\n", a->type); goto error; } if((unsigned char)a->type!=IF_T && (unsigned char)a->type!=ROUTE_T) return_code = ret; /*skip:*/ update_longest_action(); return ret; error: LM_ERR("error at line: %d\n", a->line); update_longest_action(); return ret; error_uri: LM_ERR("set*: uri too long\n"); if (new_uri) pkg_free(new_uri); update_longest_action(); return E_UNSPEC; error_fwd_uri: update_longest_action(); return ret; }
/* ret= 0! if action -> end of list(e.g DROP), > 0 to continue processing next actions and <0 on error */ int do_action(struct action* a, struct sip_msg* msg) { int ret; int v; union sockaddr_union* to; struct socket_info* send_sock; struct proxy_l* p; char* tmp; char *new_uri, *end, *crt; int len; int user; struct sip_uri uri, next_hop; struct sip_uri* u; unsigned short port; int proto; /* reset the value of error to E_UNSPEC so avoid unknowledgable functions to return with errror (status<0) and not setting it leaving there previous error; cache the previous value though for functions which want to process it */ prev_ser_error=ser_error; ser_error=E_UNSPEC; ret=E_BUG; switch ((unsigned char)a->type){ case DROP_T: ret=0; break; case FORWARD_T: #ifdef USE_TCP case FORWARD_TCP_T: #endif #ifdef USE_TLS case FORWARD_TLS_T: #endif case FORWARD_UDP_T: if (a->type==FORWARD_UDP_T) proto=PROTO_UDP; #ifdef USE_TCP else if (a->type==FORWARD_TCP_T) proto= PROTO_TCP; #endif #ifdef USE_TLS else if (a->type==FORWARD_TLS_T) proto= PROTO_TLS; #endif else proto=msg->rcv.proto; if (a->p1_type==URIHOST_ST){ /*parse uri*/ if (msg->dst_uri.len) { ret = parse_uri(msg->dst_uri.s, msg->dst_uri.len, &next_hop); u = &next_hop; } else { ret = parse_sip_msg_uri(msg); u = &msg->parsed_uri; } if (ret<0) { LOG(L_ERR, "ERROR: do_action: forward: bad_uri " " dropping packet\n"); break; } switch (a->p2_type){ case URIPORT_ST: port=u->port_no; break; case NUMBER_ST: port=a->p2.number; break; default: LOG(L_CRIT, "BUG: do_action bad forward 2nd" " param type (%d)\n", a->p2_type); ret=E_UNSPEC; goto error_fwd_uri; } switch(u->proto){ case PROTO_NONE: proto=PROTO_UDP; break; case PROTO_UDP: #ifdef USE_TCP case PROTO_TCP: #endif #ifdef USE_TLS case PROTO_TLS: #endif proto=u->proto; break; default: LOG(L_ERR,"ERROR: do action: forward: bad uri" " transport %d\n", u->proto); ret=E_BAD_PROTO; goto error_fwd_uri; } #ifdef USE_TLS if (u->secure){ if (u->proto==PROTO_UDP){ LOG(L_ERR, "ERROR: do_action: forward: secure uri" " incompatible with transport %d\n", u->proto); ret=E_BAD_PROTO; goto error_fwd_uri; } proto=PROTO_TLS; } #endif /* create a temporary proxy*/ p=mk_proxy(&u->host, port, proto); if (p==0){ LOG(L_ERR, "ERROR: bad host name in uri," " dropping packet\n"); ret=E_BAD_ADDRESS; goto error_fwd_uri; } ret=forward_request(msg, p, proto); /*free_uri(&uri); -- no longer needed, in sip_msg*/ free_proxy(p); /* frees only p content, not p itself */ pkg_free(p); if (ret>=0) ret=1; }else if ((a->p1_type==PROXY_ST) && (a->p2_type==NUMBER_ST)){ ret=forward_request(msg,(struct proxy_l*)a->p1.data, proto); if (ret>=0) ret=1; }else{ LOG(L_CRIT, "BUG: do_action: bad forward() types %d, %d\n", a->p1_type, a->p2_type); ret=E_BUG; } break; case SEND_T: case SEND_TCP_T: if ((a->p1_type!= PROXY_ST)|(a->p2_type!=NUMBER_ST)){ LOG(L_CRIT, "BUG: do_action: bad send() types %d, %d\n", a->p1_type, a->p2_type); ret=E_BUG; break; } to=(union sockaddr_union*) pkg_malloc(sizeof(union sockaddr_union)); if (to==0){ LOG(L_ERR, "ERROR: do_action: " "memory allocation failure\n"); ret=E_OUT_OF_MEM; break; } p=(struct proxy_l*)a->p1.data; if (p->ok==0){ if (p->host.h_addr_list[p->addr_idx+1]) p->addr_idx++; else p->addr_idx=0; p->ok=1; } ret=hostent2su( to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT ); if (ret==0){ p->tx++; p->tx_bytes+=msg->len; if (a->type==SEND_T){ /*udp*/ send_sock=get_send_socket(to, PROTO_UDP); if (send_sock!=0){ ret=udp_send(send_sock, msg->buf, msg->len, to); }else{ ret=-1; } } #ifdef USE_TCP else{ /*tcp*/ ret=tcp_send(PROTO_TCP, msg->buf, msg->len, to, 0); } #endif } pkg_free(to); if (ret<0){ p->errors++; p->ok=0; }else ret=1; break; case LOG_T: if ((a->p1_type!=NUMBER_ST)|(a->p2_type!=STRING_ST)){ LOG(L_CRIT, "BUG: do_action: bad log() types %d, %d\n", a->p1_type, a->p2_type); ret=E_BUG; break; } LOG(a->p1.number, a->p2.string); ret=1; break; /* jku -- introduce a new branch */ case APPEND_BRANCH_T: if ((a->p1_type!=STRING_ST)) { LOG(L_CRIT, "BUG: do_action: bad append_branch_t %d\n", a->p1_type ); ret=E_BUG; break; } ret=append_branch( msg, a->p1.string, a->p1.string ? strlen(a->p1.string):0 ); break; /* jku begin: is_length_greater_than */ case LEN_GT_T: if (a->p1_type!=NUMBER_ST) { LOG(L_CRIT, "BUG: do_action: bad len_gt type %d\n", a->p1_type ); ret=E_BUG; break; } /* DBG("XXX: message length %d, max %d\n", msg->len, a->p1.number ); */ ret = msg->len >= a->p1.number ? 1 : -1; break; /* jku end: is_length_greater_than */ /* jku - begin : flag processing */ case SETFLAG_T: if (a->p1_type!=NUMBER_ST) { LOG(L_CRIT, "BUG: do_action: bad setflag() type %d\n", a->p1_type ); ret=E_BUG; break; } if (!flag_in_range( a->p1.number )) { ret=E_CFG; break; } setflag( msg, a->p1.number ); ret=1; break; case RESETFLAG_T: if (a->p1_type!=NUMBER_ST) { LOG(L_CRIT, "BUG: do_action: bad resetflag() type %d\n", a->p1_type ); ret=E_BUG; break; } if (!flag_in_range( a->p1.number )) { ret=E_CFG; break; } resetflag( msg, a->p1.number ); ret=1; break; case ISFLAGSET_T: if (a->p1_type!=NUMBER_ST) { LOG(L_CRIT, "BUG: do_action: bad isflagset() type %d\n", a->p1_type ); ret=E_BUG; break; } if (!flag_in_range( a->p1.number )) { ret=E_CFG; break; } ret=isflagset( msg, a->p1.number ); break; /* jku - end : flag processing */ case ERROR_T: if ((a->p1_type!=STRING_ST)|(a->p2_type!=STRING_ST)){ LOG(L_CRIT, "BUG: do_action: bad error() types %d, %d\n", a->p1_type, a->p2_type); ret=E_BUG; break; } LOG(L_NOTICE, "WARNING: do_action: error(\"%s\", \"%s\") " "not implemented yet\n", a->p1.string, a->p2.string); ret=1; break; case ROUTE_T: if (a->p1_type!=NUMBER_ST){ LOG(L_CRIT, "BUG: do_action: bad route() type %d\n", a->p1_type); ret=E_BUG; break; } if ((a->p1.number>RT_NO)||(a->p1.number<0)){ LOG(L_ERR, "ERROR: invalid routing table number in" "route(%lu)\n", a->p1.number); ret=E_CFG; break; } ret=((ret=run_actions(rlist[a->p1.number], msg))<0)?ret:1; break; case EXEC_T: if (a->p1_type!=STRING_ST){ LOG(L_CRIT, "BUG: do_action: bad exec() type %d\n", a->p1_type); ret=E_BUG; break; } LOG(L_NOTICE, "WARNING: exec(\"%s\") not fully implemented," " using dumb version...\n", a->p1.string); ret=system(a->p1.string); if (ret!=0){ LOG(L_NOTICE, "WARNING: exec() returned %d\n", ret); } ret=1; break; case REVERT_URI_T: if (msg->new_uri.s) { pkg_free(msg->new_uri.s); msg->new_uri.len=0; msg->new_uri.s=0; msg->parsed_uri_ok=0; /* invalidate current parsed uri*/ }; ret=1; break; case SET_HOST_T: case SET_HOSTPORT_T: case SET_USER_T: case SET_USERPASS_T: case SET_PORT_T: case SET_URI_T: case PREFIX_T: case STRIP_T: case STRIP_TAIL_T: user=0; if (a->type==STRIP_T || a->type==STRIP_TAIL_T) { if (a->p1_type!=NUMBER_ST) { LOG(L_CRIT, "BUG: do_action: bad set*() type %d\n", a->p1_type); break; } } else if (a->p1_type!=STRING_ST){ LOG(L_CRIT, "BUG: do_action: bad set*() type %d\n", a->p1_type); ret=E_BUG; break; } if (a->type==SET_URI_T){ if (msg->new_uri.s) { pkg_free(msg->new_uri.s); msg->new_uri.len=0; } msg->parsed_uri_ok=0; len=strlen(a->p1.string); msg->new_uri.s=pkg_malloc(len+1); if (msg->new_uri.s==0){ LOG(L_ERR, "ERROR: do_action: memory allocation" " failure\n"); ret=E_OUT_OF_MEM; break; } memcpy(msg->new_uri.s, a->p1.string, len); msg->new_uri.s[len]=0; msg->new_uri.len=len; ret=1; break; } if (msg->new_uri.s) { tmp=msg->new_uri.s; len=msg->new_uri.len; }else{ tmp=msg->first_line.u.request.uri.s; len=msg->first_line.u.request.uri.len; } if (parse_uri(tmp, len, &uri)<0){ LOG(L_ERR, "ERROR: do_action: bad uri <%s>, dropping" " packet\n", tmp); ret=E_UNSPEC; break; } new_uri=pkg_malloc(MAX_URI_SIZE); if (new_uri==0){ LOG(L_ERR, "ERROR: do_action: memory allocation " " failure\n"); ret=E_OUT_OF_MEM; break; } end=new_uri+MAX_URI_SIZE; crt=new_uri; /* begin copying */ len=strlen("sip:"); if(crt+len>end) goto error_uri; memcpy(crt,"sip:",len);crt+=len; /* user */ /* prefix (-jiri) */ if (a->type==PREFIX_T) { tmp=a->p1.string; len=strlen(tmp); if(crt+len>end) goto error_uri; memcpy(crt,tmp,len);crt+=len; /* whatever we had before, with prefix we have username now */ user=1; } if ((a->type==SET_USER_T)||(a->type==SET_USERPASS_T)) { tmp=a->p1.string; len=strlen(tmp); } else if (a->type==STRIP_T) { if (a->p1.number>uri.user.len) { LOG(L_WARN, "Error: too long strip asked; " " deleting username: %lu of <%.*s>\n", a->p1.number, uri.user.len, uri.user.s ); len=0; } else if (a->p1.number==uri.user.len) { len=0; } else { tmp=uri.user.s + a->p1.number; len=uri.user.len - a->p1.number; } } else if (a->type==STRIP_TAIL_T) { if (a->p1.number>uri.user.len) { LOG(L_WARN, "WARNING: too long strip_tail asked; " " deleting username: %lu of <%.*s>\n", a->p1.number, uri.user.len, uri.user.s ); len=0; } else if (a->p1.number==uri.user.len) { len=0; } else { tmp=uri.user.s; len=uri.user.len - a->p1.number; } } else { tmp=uri.user.s; len=uri.user.len; } if (len){ if(crt+len>end) goto error_uri; memcpy(crt,tmp,len);crt+=len; user=1; /* we have an user field so mark it */ } if (a->type==SET_USERPASS_T) tmp=0; else tmp=uri.passwd.s; /* passwd */ if (tmp){ len=uri.passwd.len; if(crt+len+1>end) goto error_uri; *crt=':'; crt++; memcpy(crt,tmp,len);crt+=len; } /* host */ if (user || tmp){ /* add @ */ if(crt+1>end) goto error_uri; *crt='@'; crt++; } if ((a->type==SET_HOST_T) ||(a->type==SET_HOSTPORT_T)) { tmp=a->p1.string; if (tmp) len = strlen(tmp); else len=0; } else { tmp=uri.host.s; len = uri.host.len; } if (tmp){ if(crt+len>end) goto error_uri; memcpy(crt,tmp,len);crt+=len; } /* port */ if (a->type==SET_HOSTPORT_T) tmp=0; else if (a->type==SET_PORT_T) { tmp=a->p1.string; if (tmp) len = strlen(tmp); else len = 0; } else { tmp=uri.port.s; len = uri.port.len; } if (tmp){ if(crt+len+1>end) goto error_uri; *crt=':'; crt++; memcpy(crt,tmp,len);crt+=len; } /* params */ tmp=uri.params.s; if (tmp){ len=uri.params.len; if(crt+len+1>end) goto error_uri; *crt=';'; crt++; memcpy(crt,tmp,len);crt+=len; } /* headers */ tmp=uri.headers.s; if (tmp){ len=uri.headers.len; if(crt+len+1>end) goto error_uri; *crt='?'; crt++; memcpy(crt,tmp,len);crt+=len; } *crt=0; /* null terminate the thing */ /* copy it to the msg */ if (msg->new_uri.s) pkg_free(msg->new_uri.s); msg->new_uri.s=new_uri; msg->new_uri.len=crt-new_uri; msg->parsed_uri_ok=0; ret=1; break; case IF_T: /* if null expr => ignore if? */ if ((a->p1_type==EXPR_ST)&&a->p1.data){ v=eval_expr((struct expr*)a->p1.data, msg); if (v<0){ if (v==EXPR_DROP){ /* hack to quit on DROP*/ ret=0; break; }else{ LOG(L_WARN,"WARNING: do_action:" "error in expression\n"); } } ret=1; /*default is continue */ if (v>0) { if ((a->p2_type==ACTIONS_ST)&&a->p2.data){ ret=run_actions((struct action*)a->p2.data, msg); } }else if ((a->p3_type==ACTIONS_ST)&&a->p3.data){ ret=run_actions((struct action*)a->p3.data, msg); } } break; case MODULE_T: if ( ((a->p1_type==CMDF_ST)&&a->p1.data)/*&& ((a->p2_type==STRING_ST)&&a->p2.data)*/ ){ ret=((cmd_function)(a->p1.data))(msg, (char*)a->p2.data, (char*)a->p3.data); }else{ LOG(L_CRIT,"BUG: do_action: bad module call\n"); } break; case FORCE_RPORT_T: msg->msg_flags|=FL_FORCE_RPORT; ret=1; /* continue processing */ break; case SET_ADV_ADDR_T: if (a->p1_type!=STR_ST){ LOG(L_CRIT, "BUG: do_action: bad set_advertised_address() " "type %d\n", a->p1_type); ret=E_BUG; break; } msg->set_global_address=*((str*)a->p1.data); ret=1; /* continue processing */ break; case SET_ADV_PORT_T: if (a->p1_type!=STR_ST){ LOG(L_CRIT, "BUG: do_action: bad set_advertised_port() " "type %d\n", a->p1_type); ret=E_BUG; break; } msg->set_global_port=*((str*)a->p1.data); ret=1; /* continue processing */ break; default: LOG(L_CRIT, "BUG: do_action: unknown type %d\n", a->type); } /*skip:*/ return ret; error_uri: LOG(L_ERR, "ERROR: do_action: set*: uri too long\n"); if (new_uri) pkg_free(new_uri); return E_UNSPEC; error_fwd_uri: /*free_uri(&uri); -- not needed anymore, using msg->parsed_uri*/ return ret; }
/* opens, binds and listens-on a control tcp socket * returns socket fd or -1 on error */ int init_tcpudp_sock(union sockaddr_union* sa_un, char* address, int port, enum socket_protos type) { union sockaddr_union su; struct hostent* he; int s; int optval; s=-1; if ((type!=UDP_SOCK) && (type!=TCP_SOCK)){ LOG(L_CRIT, "BUG: init_tcpudp_sock called with bad type: %d\n", type); goto error; } memset(&su, 0, sizeof (su)); /* if no address specified, or address=='*', listen on all * ipv4 addresses */ if ((address==0)||((*address)==0)||((*address=='*') && (*(address+1)==0))){ su.sin.sin_family=AF_INET; su.sin.sin_port=htons(port); su.sin.sin_addr.s_addr=INADDR_ANY; #ifdef HAVE_SOCKADDR_SA_LEN su.sin.sin_len=sizeof(struct sockaddr_in); #endif }else{ he=resolvehost(address); if (he==0){ LOG(L_ERR, "ERROR: init_tcpudp_sock: bad address %s\n", address); goto error; } if (hostent2su(&su, he, 0, port)==-1) goto error; } s=socket(AF2PF(su.s.sa_family), (type==TCP_SOCK)?SOCK_STREAM:SOCK_DGRAM,0); if (s==-1){ LOG(L_ERR, "ERROR: init_tcpudp_sock: cannot create tcp socket:" " %s [%d]\n", strerror(errno), errno); goto error; } /* REUSEADDR */ optval=1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))==-1){ LOG(L_ERR, "ERROR: init_tcpudp_sock: setsockopt: %s [%d]\n", strerror(errno), errno); /* continue */ } /* tos */ optval=IPTOS_LOWDELAY; if (setsockopt(s, IPPROTO_IP, IP_TOS, (void*)&optval,sizeof(optval)) ==-1){ LOG(L_WARN, "WARNING: init_tcpudp_sock: setsockopt tos: %s\n", strerror(errno)); /* continue since this is not critical */ } if (set_non_blocking(s)==-1){ LOG(L_ERR, "ERROR: init_tcpudp_sock: set non blocking failed\n"); } if (bind(s, &su.s, sockaddru_len(su))==-1){ LOG(L_ERR, "ERROR: init_tcpudp_sock: bind: %s [%d]\n", strerror(errno), errno); goto error; } if ((type==TCP_SOCK) && (listen(s, 128)==-1)){ LOG(L_ERR, "ERROR: init_tcpudp_sock: listen: %s [%d]\n", strerror(errno), errno); goto error; } *sa_un=su; return s; error: if (s!=-1) close(s); return -1; }
int add_node_info(node_info_t **new_info, cluster_info_t **cl_list, int *int_vals, char **str_vals) { char *host; int hlen, port; int proto; struct hostent *he; int cluster_id; cluster_info_t *cluster = NULL; struct timeval t; str st; str seed_flag = str_init(SEED_NODE_FLAG_STR); cluster_id = int_vals[INT_VALS_CLUSTER_ID_COL]; /* new_info is checked whether it is initialized or not in case of error, * so we have to initialize it as soon as possible */ *new_info = NULL; for (cluster = *cl_list; cluster && cluster->cluster_id != cluster_id; cluster = cluster->next) ; if (!cluster) { cluster = shm_malloc(sizeof *cluster); if (!cluster) { LM_ERR("no more shm memory\n"); goto error; } memset(cluster, 0, sizeof *cluster); cluster->cluster_id = cluster_id; cluster->next = *cl_list; if ((cluster->lock = lock_alloc()) == NULL) { LM_CRIT("Failed to allocate lock\n"); goto error; } if (!lock_init(cluster->lock)) { lock_dealloc(cluster->lock); LM_CRIT("Failed to init lock\n"); goto error; } *cl_list = cluster; } *new_info = shm_malloc(sizeof **new_info); if (!*new_info) { LM_ERR("no more shm memory\n"); goto error; } memset(*new_info, 0, sizeof **new_info); (*new_info)->flags = 0; (*new_info)->id = int_vals[INT_VALS_ID_COL]; (*new_info)->node_id = int_vals[INT_VALS_NODE_ID_COL]; if (int_vals[INT_VALS_STATE_COL]) (*new_info)->flags |= NODE_STATE_ENABLED; else (*new_info)->flags &= ~NODE_STATE_ENABLED; if (int_vals[INT_VALS_NODE_ID_COL] != current_id) (*new_info)->link_state = LS_RESTART_PINGING; else (*new_info)->link_state = LS_UP; if (str_vals[STR_VALS_DESCRIPTION_COL] && strlen(str_vals[STR_VALS_DESCRIPTION_COL]) != 0) { (*new_info)->description.len = strlen(str_vals[STR_VALS_DESCRIPTION_COL]); (*new_info)->description.s = shm_malloc((*new_info)->description.len * sizeof(char)); if ((*new_info)->description.s == NULL) { LM_ERR("no more shm memory\n"); goto error; } memcpy((*new_info)->description.s, str_vals[STR_VALS_DESCRIPTION_COL], (*new_info)->description.len); } else { (*new_info)->description.s = NULL; (*new_info)->description.len = 0; } if (str_vals[STR_VALS_SIP_ADDR_COL] && strlen(str_vals[STR_VALS_SIP_ADDR_COL]) != 0) { (*new_info)->sip_addr.len = strlen(str_vals[STR_VALS_SIP_ADDR_COL]); (*new_info)->sip_addr.s = shm_malloc((*new_info)->sip_addr.len * sizeof(char)); if ((*new_info)->sip_addr.s == NULL) { LM_ERR("no more shm memory\n"); goto error; } memcpy((*new_info)->sip_addr.s, str_vals[STR_VALS_SIP_ADDR_COL], (*new_info)->sip_addr.len); } else { (*new_info)->sip_addr.s = NULL; (*new_info)->sip_addr.len = 0; } if (str_vals[STR_VALS_FLAGS_COL] && strlen(str_vals[STR_VALS_FLAGS_COL]) != 0) if (memcmp(str_vals[STR_VALS_FLAGS_COL], seed_flag.s, seed_flag.len) == 0) (*new_info)->flags |= NODE_IS_SEED; if (str_vals[STR_VALS_URL_COL] == NULL) { LM_ERR("no url specified in DB\n"); return 1; } (*new_info)->url.len = strlen(str_vals[STR_VALS_URL_COL]); (*new_info)->url.s = shm_malloc(strlen(str_vals[STR_VALS_URL_COL]) * sizeof(char)); if (!(*new_info)->url.s) { LM_ERR("no more shm memory\n"); goto error; } memcpy((*new_info)->url.s, str_vals[STR_VALS_URL_COL], (*new_info)->url.len); if (int_vals[INT_VALS_NODE_ID_COL] != current_id) { if (parse_phostport((*new_info)->url.s, (*new_info)->url.len, &host, &hlen, &port, &proto) < 0) { LM_ERR("Bad URL!\n"); return 1; } if (proto == PROTO_NONE) proto = clusterer_proto; if (proto != clusterer_proto) { LM_ERR("Clusterer currently supports only BIN protocol, but node: %d " "has proto=%d\n", int_vals[INT_VALS_NODE_ID_COL], proto); return 1; } st.s = host; st.len = hlen; he = sip_resolvehost(&st, (unsigned short *) &port, (unsigned short *)&proto, 0, 0); if (!he) { LM_ERR("Cannot resolve host: %.*s\n", hlen, host); return 1; } hostent2su(&((*new_info)->addr), he, 0, port); t.tv_sec = 0; t.tv_usec = 0; (*new_info)->last_ping = t; (*new_info)->last_pong = t; } (*new_info)->priority = int_vals[INT_VALS_PRIORITY_COL]; (*new_info)->no_ping_retries = int_vals[INT_VALS_NO_PING_RETRIES_COL]; (*new_info)->cluster = cluster; (*new_info)->ls_seq_no = -1; (*new_info)->top_seq_no = -1; (*new_info)->ls_timestamp = 0; (*new_info)->top_timestamp = 0; (*new_info)->sp_info = shm_malloc(sizeof(struct node_search_info)); if (!(*new_info)->sp_info) { LM_ERR("no more shm memory\n"); goto error; } (*new_info)->sp_info->node = *new_info; if (int_vals[INT_VALS_NODE_ID_COL] != current_id) { (*new_info)->next = cluster->node_list; cluster->node_list = *new_info; cluster->no_nodes++; if (cluster->no_nodes > MAX_NO_NODES) { LM_ERR("Defined: %d nodes for cluster: %d, maximum number of nodes " "supported(%d) exceeded\n", cluster->no_nodes, cluster->cluster_id, MAX_NO_NODES); goto error; } } else { (*new_info)->next = NULL; cluster->current_node = *new_info; } if (((*new_info)->lock = lock_alloc()) == NULL) { LM_CRIT("Failed to allocate lock\n"); goto error; } if (!lock_init((*new_info)->lock)) { lock_dealloc((*new_info)->lock); LM_CRIT("Failed to init lock\n"); goto error; } return 0; error: if (*new_info) { if ((*new_info)->sip_addr.s) shm_free((*new_info)->sip_addr.s); if ((*new_info)->description.s) shm_free((*new_info)->description.s); if ((*new_info)->url.s) shm_free((*new_info)->url.s); if ((*new_info)->sp_info) shm_free((*new_info)->sp_info); shm_free(*new_info); } return -1; }
static void timer(unsigned int ticks, void *param) { int rval; void *buf, *cp; str c; struct sip_uri curi; union sockaddr_union to; struct hostent* he; struct socket_info* send_sock; buf = NULL; if (cblen > 0) { buf = pkg_malloc(cblen); if (buf == NULL) { LOG(L_ERR, "ERROR: nathelper::timer: out of memory\n"); return; } } rval = get_all_ucontacts(buf, cblen); if (rval > 0) { if (buf != NULL) pkg_free(buf); cblen = rval * 2; buf = pkg_malloc(cblen); if (buf == NULL) { LOG(L_ERR, "ERROR: nathelper::timer: out of memory\n"); return; } rval = get_all_ucontacts(buf, cblen); if (rval != 0) { pkg_free(buf); return; } } if (buf == NULL) return; cp = buf; while (1) { memcpy(&(c.len), cp, sizeof(c.len)); if (c.len == 0) break; c.s = (char*)cp + sizeof(c.len); cp = (char*)cp + sizeof(c.len) + c.len; if (parse_uri(c.s, c.len, &curi) < 0) { LOG(L_ERR, "ERROR: nathelper::timer: can't parse contact uri\n"); continue; } if (curi.proto != PROTO_UDP && curi.proto != PROTO_NONE) continue; if (curi.port_no == 0) curi.port_no = SIP_PORT; he = sip_resolvehost(&curi.host, &curi.port_no, PROTO_UDP); if (he == NULL){ LOG(L_ERR, "ERROR: nathelper::timer: can't resolve_hos\n"); continue; } hostent2su(&to, he, 0, curi.port_no); send_sock = get_send_socket(&to, PROTO_UDP); if (send_sock == NULL) { LOG(L_ERR, "ERROR: nathelper::timer: can't get sending socket\n"); continue; } udp_send(send_sock, (char *)sbuf, sizeof(sbuf), &to); } pkg_free(buf); }
/* * This is the parsing function * The socket grammar should be: * ip ':' port '/optional/path' ':' method */ static evi_reply_sock* xmlrpc_parse(str socket) { evi_reply_sock *sock = NULL; unsigned short port = 0; char *p = NULL; str host, path=str_init(NULL); struct hostent *hentity; int len; struct xmlrpc_sock_param *params; int http_buf_len=0; if (!socket.len || !socket.s) { LM_ERR("no socket specified\n"); return NULL; } if (!(params=shm_malloc(sizeof(struct xmlrpc_sock_param)))) { LM_ERR("no more pkg mem!\n"); return NULL; } memset(params, 0, sizeof(struct xmlrpc_sock_param)); /* extract host */ host.s = socket.s; p = memchr(socket.s, COLON_C, socket.len); if (!p || p == socket.s) { LM_ERR("port not specified <%.*s>\n", socket.len, socket.s); return NULL; } host.len = p - socket.s; /* used to resolve host */ *p = '\0'; /* skip colon */ socket.s += host.len + 1; socket.len -= host.len + 1; LM_DBG("host is %.*s - remains <%.*s>[%d]\n", host.len, host.s, socket.len, socket.s, socket.len); if (!socket.len || *socket.s == '\0') { LM_ERR("invalid port number\n"); return NULL; } p = memchr(socket.s, COLON_C, socket.len); if (!p || p == socket.s) { LM_ERR("method not specified <%.*s>\n", socket.len, socket.s); return NULL; } port = str2s(socket.s, p - socket.s, 0); if (port == 0) { /* most probably we've got path */ if ((path.s=(q_memchr(socket.s, SLASH_C, p-socket.s)))==NULL) { LM_ERR("malformed port: %.*s\n",(int)(p - socket.s), socket.s); return NULL; } else { port=str2s(socket.s, path.s-socket.s, 0); if (port == 0) { LM_ERR("malformed port: %.*s\n",(int)(p - socket.s), socket.s); return NULL; } path.len = p - path.s; socket.len -= ((path.s+path.len)-socket.s); socket.s = path.s+path.len; } /* will use this later for allocation */ http_buf_len=LENOF(XMLRPC_HTTP_METHOD) + path.len + LENOF(XMLRPC_HTTP_PROTO_HOST); } /* jump over ':' */ socket.len = socket.len - (p - socket.s + 1); socket.s = p + 1; LM_DBG("port is %hu - remains <%.*s>[%d]\n", port, socket.len, socket.s, socket.len); if (socket.len <= 0 || *socket.s == '\0') { LM_ERR("invalid method name\n"); return NULL; } len = sizeof(evi_reply_sock) + host.len + sizeof(struct xmlrpc_sock_param) + socket.len /* this is method */+ http_buf_len; sock = shm_malloc(len); if (!sock) { LM_ERR("no more memory for socket\n"); return NULL; } memset(sock, 0, len); /* only UDP has port */ sock->flags = EVI_PORT; sock->port = port; /* also build sockaddr */ hentity = resolvehost(host.s, 0); if (!hentity) { LM_ERR("cannot resolve host %s\n", host.s); goto error; } if(hostent2su(&sock->src_addr.udp_addr, hentity, 0, port)){ LM_ERR("failed to resolve %s\n", host.s); goto error; } sock->flags |= EVI_SOCKET; /* address */ sock->address.s = (char*)(sock+1); sock->address.len = host.len; memcpy(sock->address.s, host.s, host.len); sock->flags |= EVI_ADDRESS; /* copy parameters: path and method */ params = (struct xmlrpc_sock_param*)(sock->address.s + host.len); params->method.s = (char*)(params+1); memcpy(params->method.s, socket.s, socket.len); params->method.len = socket.len; if (http_buf_len) { /* build only once; not for every message */ params->first_line.s = (char*)(params->method.s+socket.len); memcpy(params->method.s, socket.s, socket.len); params->first_line.len = 0; memcpy(params->first_line.s, XMLRPC_HTTP_METHOD, LENOF(XMLRPC_HTTP_METHOD)); params->first_line.len = LENOF(XMLRPC_HTTP_METHOD); memcpy(params->first_line.s+params->first_line.len, path.s, path.len); params->first_line.len += path.len; memcpy(params->first_line.s+params->first_line.len, XMLRPC_HTTP_PROTO_HOST, LENOF(XMLRPC_HTTP_PROTO_HOST)); params->first_line.len += LENOF(XMLRPC_HTTP_PROTO_HOST); } else { params->first_line.s = XMLRPC_HTTP_CONST; params->first_line.len = LENOF(XMLRPC_HTTP_CONST); } sock->flags |= EVI_PARAMS; /* needs expire */ sock->flags |= EVI_EXPIRE|XMLRPC_FLAG; sock->params= params; return sock; error: if (sock) shm_free(sock); return NULL; }
int jsonrpc_dgram_mod_init(void) { unsigned int port_no; int n; struct stat filestat; struct hostent *host; char *p, *host_s; str port_str; int len; int sep; /* checking the mi_socket module param */ LM_DBG("testing socket existance...\n"); if( jsonrpc_dgram_socket==NULL || *jsonrpc_dgram_socket == 0) { LM_ERR("no DATAGRAM_ socket configured\n"); return -1; } LM_DBG("the socket's name/address is %s\n", jsonrpc_dgram_socket); memset( &jsonrpc_dgram_addr, 0, sizeof(jsonrpc_dgram_sockaddr_t) ); if(strlen(jsonrpc_dgram_socket)<6) { LM_ERR("lenght of socket address is too short: %s\n", jsonrpc_dgram_socket); return -1; } if(strncmp(jsonrpc_dgram_socket, "udp:", 4) == 0) { /*for an UDP socket*/ LM_DBG("udp socket provided\n"); /*separate proto and host */ p = jsonrpc_dgram_socket+4; if( (*(p)) == '\0') { LM_ERR("malformed ip address\n"); return -1; } host_s=p; LM_DBG("remaining address after separating the protocol is %s\n", p); if( (p = strrchr(p+1, ':')) == 0 ) { LM_ERR("no port specified\n"); return -1; } /*the address contains a port number*/ *p = '\0'; p++; port_str.s = p; port_str.len = strlen(p); LM_DBG("the port string is %s\n", p); if(str2int(&port_str, &port_no) != 0 ) { LM_ERR("there is not a valid number port\n"); return -1; } *p = '\0'; if (port_no<1024 || port_no>65535) { LM_ERR("invalid port number; must be in [1024,65535]\n"); return -1; } if(! (host = resolvehost(host_s)) ) { LM_ERR("failed to resolve %s\n", host_s); return -1; } LM_DBG("the ip is %s\n",host_s); if(hostent2su( &(jsonrpc_dgram_addr.udp_addr), host, 0, port_no ) !=0) { LM_ERR("failed to resolve %s\n", jsonrpc_dgram_socket); return -1; } jsonrpc_dgram_socket_domain = host->h_addrtype; goto done; } /* in case of a Unix socket*/ LM_DBG("UNIX socket provided\n"); if(*jsonrpc_dgram_socket != '/') { if(runtime_dir!=NULL && *runtime_dir!=0) { len = strlen(runtime_dir); sep = 0; if(runtime_dir[len-1]!='/') { sep = 1; } len += sep + strlen(jsonrpc_dgram_socket); p = pkg_malloc(len + 1); if(p==NULL) { LM_ERR("no more pkg\n"); return -1; } strcpy(p, runtime_dir); if(sep) strcat(p, "/"); strcat(p, jsonrpc_dgram_socket); jsonrpc_dgram_socket = p; LM_DBG("unix socket path is [%s]\n", jsonrpc_dgram_socket); } } n=stat(jsonrpc_dgram_socket, &filestat); if( n==0) { LM_INFO("the socket %s already exists, trying to delete it...\n", jsonrpc_dgram_socket); if(config_check==0) { if (unlink(jsonrpc_dgram_socket)<0) { LM_ERR("cannot delete old socket: %s\n", strerror(errno)); return -1; } } } else if (n<0 && errno!=ENOENT) { LM_ERR("socket stat failed:%s\n", strerror(errno)); return -1; } /* check mi_unix_socket_mode */ if(!jsonrpc_dgram_unix_socket_mode) { LM_WARN("cannot specify jsonrpc_dgram_unix_socket_mode = 0," " forcing it to rw-------\n"); jsonrpc_dgram_unix_socket_mode = S_IRUSR| S_IWUSR; } if (jsonrpc_dgram_unix_socket_uid_s) { if (user2uid(&jsonrpc_dgram_unix_socket_uid, &jsonrpc_dgram_unix_socket_gid, jsonrpc_dgram_unix_socket_uid_s)<0) { LM_ERR("bad user name %s\n", jsonrpc_dgram_unix_socket_uid_s); return -1; } } if (jsonrpc_dgram_unix_socket_gid_s) { if (group2gid(&jsonrpc_dgram_unix_socket_gid, jsonrpc_dgram_unix_socket_gid_s)<0) { LM_ERR("bad group name %s\n", jsonrpc_dgram_unix_socket_gid_s); return -1; } } /*create the unix socket address*/ jsonrpc_dgram_addr.unix_addr.sun_family = AF_LOCAL; if(strlen(jsonrpc_dgram_socket) >= sizeof(jsonrpc_dgram_addr.unix_addr.sun_path)-1) { LM_ERR("socket path is too long\n"); return -1; } memcpy(jsonrpc_dgram_addr.unix_addr.sun_path, jsonrpc_dgram_socket, strlen(jsonrpc_dgram_socket)); done: /* add space for extra processes */ register_procs(jsonrpc_dgram_workers); /* add child to update local config framework structures */ cfg_register_child(jsonrpc_dgram_workers); return 0; }
/* * This is the parsing function * The socket grammar should be: * ip ':' port ':' method */ static evi_reply_sock* xmlrpc_parse(str socket) { evi_reply_sock *sock = NULL; unsigned short port = 0; char *p = NULL; str host, *method; struct hostent *hentity; int len; if (!socket.len || !socket.s) { LM_ERR("no socket specified\n"); return NULL; } /* extract host */ host.s = socket.s; p = memchr(socket.s, COLON_C, socket.len); if (!p || p == socket.s) { LM_ERR("port not specified <%.*s>\n", socket.len, socket.s); return NULL; } host.len = p - socket.s; /* used to resolve host */ *p = '\0'; /* skip colon */ socket.s += host.len + 1; socket.len -= host.len + 1; LM_DBG("host is %.*s - remains <%.*s>[%d]\n", host.len, host.s, socket.len, socket.s, socket.len); if (!socket.len || *socket.s == '\0') { LM_ERR("invalid port number\n"); return NULL; } p = memchr(socket.s, COLON_C, socket.len); if (!p || p == socket.s) { LM_ERR("method not specified <%.*s>\n", socket.len, socket.s); return NULL; } port = str2s(socket.s, p - socket.s, 0); if (port == 0) { LM_DBG("malformed port: %.*s\n",(int)(p - socket.s), socket.s); return NULL; } /* skip colon */ socket.len = socket.len - (p - socket.s + 1); socket.s = p + 1; LM_DBG("port is %hu - remains <%.*s>[%d]\n", port, socket.len, socket.s, socket.len); if (socket.len <= 0 || *socket.s == '\0') { LM_ERR("invalid method name\n"); return NULL; } LM_DBG("method is %.*s[%d]\n", socket.len, socket.s, socket.len); len = sizeof(evi_reply_sock) - sizeof(void*) + sizeof(str) + host.len + socket.len; sock = shm_malloc(len); if (!sock) { LM_ERR("no more memory for socket\n"); return NULL; } memset(sock, 0, len); /* only UDP has port */ sock->flags = EVI_PORT; sock->port = port; /* also build sockaddr */ hentity = resolvehost(host.s, 0); if (!hentity) { LM_ERR("cannot resolve host %s\n", host.s); goto error; } if(hostent2su(&sock->src_addr.udp_addr, hentity, 0, port)){ LM_ERR("failed to resolve %s\n", host.s); goto error; } sock->flags |= EVI_SOCKET; /* copy method - this should point to same address as params*/ method = (str *) &sock->params; method->s = (char *) (method + 1); method->len = socket.len; memcpy(method->s, socket.s, socket.len); sock->flags |= EVI_PARAMS; /* address should point below method name */ sock->address.s = method->s + method->len; sock->address.len = host.len; memcpy(sock->address.s, host.s, host.len); sock->flags |= EVI_ADDRESS; /* needs expire */ sock->flags |= EVI_EXPIRE|XMLRPC_FLAG; return sock; error: if (sock) shm_free(sock); return NULL; }
/* introduce a new uac to transaction; returns its branch id (>=0) or error (<0); it doesn't send a message yet -- a reply to it might interfere with the processes of adding multiple branches */ static int add_uac( struct cell *t, struct sip_msg *request, str *uri, str* next_hop, unsigned int bflags, str* path, struct proxy_l *proxy) { unsigned short branch; struct sip_msg_body *body_clone=NO_BODY_CLONE_MARKER; int do_free_proxy; int ret; branch=t->nr_of_outgoings; if (branch==MAX_BRANCHES) { LM_ERR("maximum number of branches exceeded\n"); ret=E_CFG; goto error; } /* check existing buffer -- rewriting should never occur */ if (t->uac[branch].request.buffer.s) { LM_CRIT("buffer rewrite attempt\n"); ret=ser_error=E_BUG; goto error; } /* set proper RURI to request to reflect the branch */ request->new_uri=*uri; request->parsed_uri_ok=0; request->dst_uri=*next_hop; request->path_vec=*path; request->ruri_bflags=bflags; if ( pre_print_uac_request( t, branch, request, &body_clone)!= 0 ) { ret = -1; goto error01; } /* check DNS resolution */ if (proxy){ do_free_proxy = 0; }else { proxy=uri2proxy( request->dst_uri.len ? &request->dst_uri:&request->new_uri, request->force_send_socket ? request->force_send_socket->proto : PROTO_NONE ); if (proxy==0) { ret=E_BAD_ADDRESS; goto error01; } do_free_proxy = 1; } msg_callback_process(request, REQ_PRE_FORWARD, (void *)proxy); if ( !(t->flags&T_NO_DNS_FAILOVER_FLAG) ) { t->uac[branch].proxy = shm_clone_proxy( proxy , do_free_proxy ); if (t->uac[branch].proxy==NULL) { ret = E_OUT_OF_MEM; goto error02; } } /* use the first address */ hostent2su( &t->uac[branch].request.dst.to, &proxy->host, proxy->addr_idx, proxy->port ? proxy->port:SIP_PORT); t->uac[branch].request.dst.proto = proxy->proto; /* do print of the uac request */ if ( update_uac_dst( request, &t->uac[branch] )!=0) { ret = ser_error; goto error02; } /* things went well, move ahead */ t->uac[branch].uri.s=t->uac[branch].request.buffer.s+ request->first_line.u.request.method.len+1; t->uac[branch].uri.len=request->new_uri.len; t->uac[branch].br_flags = request->ruri_bflags; t->uac[branch].added_rr = count_local_rr( request ); t->nr_of_outgoings++; /* done! */ ret=branch; error02: if(do_free_proxy) { free_proxy( proxy ); pkg_free( proxy ); } error01: post_print_uac_request( request, uri, next_hop, body_clone); if (ret < 0) { /* destroy all the bavps added, the path vector and the destination, * since this branch will never be properly added to * the UAC list, otherwise we'll have memory leaks - razvanc */ clean_branch(t->uac[branch]); memset(&t->uac[branch], 0, sizeof(t->uac[branch])); init_branch(&t->uac[branch], branch, t->wait_tl.set, t); } error: return ret; }
/* introduce a new uac to transaction; returns its branch id (>=0) or error (<0); it doesn't send a message yet -- a reply to it might interfere with the processes of adding multiple branches */ int add_uac( struct cell *t, struct sip_msg *request, str *uri, str* next_hop, struct proxy_l *proxy, int proto ) { int ret; short temp_proxy; union sockaddr_union to; unsigned short branch; struct socket_info* send_sock; char *shbuf; unsigned int len; branch=t->nr_of_outgoings; if (branch==MAX_BRANCHES) { LOG(L_ERR, "ERROR: add_uac: maximum number of branches exceeded\n"); ret=E_CFG; goto error; } /* check existing buffer -- rewriting should never occur */ if (t->uac[branch].request.buffer) { LOG(L_CRIT, "ERROR: add_uac: buffer rewrite attempt\n"); ret=ser_error=E_BUG; goto error; } /* check DNS resolution */ if (proxy) { temp_proxy=0; proto=get_proto(proto, proxy->proto); } else { proxy=uri2proxy( next_hop ? next_hop : uri, proto ); if (proxy==0) { ret=E_BAD_ADDRESS; goto error; } proto=proxy->proto; /* uri2proxy will fix it for us */ temp_proxy=1; } if (proxy->ok==0) { if (proxy->host.h_addr_list[proxy->addr_idx+1]) proxy->addr_idx++; else proxy->addr_idx=0; proxy->ok=1; } hostent2su( &to, &proxy->host, proxy->addr_idx, proxy->port ? proxy->port:SIP_PORT); send_sock=get_send_socket( request, &to , proto); if (send_sock==0) { LOG(L_ERR, "ERROR: add_uac: can't fwd to af %d, proto %d " " (no corresponding listening socket)\n", to.s.sa_family, proto ); ret=ser_error=E_NO_SOCKET; goto error01; } /* now message printing starts ... */ shbuf=print_uac_request( t, request, branch, uri, &len, send_sock, proto ); if (!shbuf) { ret=ser_error=E_OUT_OF_MEM; goto error01; } /* things went well, move ahead and install new buffer! */ t->uac[branch].request.dst.to=to; t->uac[branch].request.dst.send_sock=send_sock; t->uac[branch].request.dst.proto=proto; t->uac[branch].request.dst.proto_reserved1=0; t->uac[branch].request.buffer=shbuf; t->uac[branch].request.buffer_len=len; t->uac[branch].uri.s=t->uac[branch].request.buffer+ request->first_line.u.request.method.len+1; t->uac[branch].uri.len=uri->len; t->nr_of_outgoings++; /* update stats */ proxy->tx++; proxy->tx_bytes+=len; /* done! */ ret=branch; error01: if (temp_proxy) { free_proxy( proxy ); pkg_free( proxy ); } error: return ret; }
/* * Send a request using data from the dialog structure */ int t_uac(str* method, str* headers, str* body, dlg_t* dialog, transaction_cb cb, void* cbp,release_tmcb_param release_func) { union sockaddr_union to_su, new_to_su; struct cell *new_cell; struct cell *backup_cell; struct retr_buf *request; static struct sip_msg *req; struct usr_avp **backup; char *buf, *buf1; int buf_len, buf_len1; int ret, flags, sflag_bk; int backup_route_type; int sip_msg_len; unsigned int hi; struct socket_info *new_send_sock; str h_to, h_from, h_cseq, h_callid; struct proxy_l *proxy, *new_proxy; unsigned short dst_changed; ret=-1; /*** added by dcm * - needed by external ua to send a request within a dlg */ if(!dialog->hooks.next_hop && w_calculate_hooks(dialog)<0) goto error3; if(dialog->obp.s) dialog->hooks.next_hop = &dialog->obp; LM_DBG("next_hop=<%.*s>\n",dialog->hooks.next_hop->len, dialog->hooks.next_hop->s); /* calculate the socket corresponding to next hop */ proxy = uri2proxy( dialog->hooks.next_hop, dialog->send_sock ? dialog->send_sock->proto : PROTO_NONE ); if (proxy==0) { ret=E_BAD_ADDRESS; goto error3; } /* use the first address */ hostent2su( &to_su, &proxy->host, proxy->addr_idx, proxy->port ? proxy->port:SIP_PORT); /* check/discover the send socket */ if (dialog->send_sock) { /* if already set, the protocol of send sock must have the the same type as the proto required by destination URI */ if (proxy->proto != dialog->send_sock->proto) dialog->send_sock = NULL; } if (dialog->send_sock==NULL) { /* get the send socket */ dialog->send_sock = get_send_socket( NULL/*msg*/, &to_su, proxy->proto); if (!dialog->send_sock) { LM_ERR("no corresponding socket for af %d\n", to_su.s.sa_family); ser_error = E_NO_SOCKET; goto error2; } } LM_DBG("sending socket is %.*s \n", dialog->send_sock->name.len,dialog->send_sock->name.s); /* ***** Create TRANSACTION and all related ***** */ new_cell = build_cell( NULL/*msg*/, 1/*full UAS clone*/); if (!new_cell) { ret=E_OUT_OF_MEM; LM_ERR("short of cell shmem\n"); goto error2; } /* pass the transaction flags from dialog to transaction */ new_cell->flags |= dialog->T_flags; /* add the callback the transaction for LOCAL_COMPLETED event */ flags = TMCB_LOCAL_COMPLETED; /* Add also TMCB_LOCAL_RESPONSE_OUT if provisional replies are desired */ if (pass_provisional_replies || pass_provisional(new_cell)) flags |= TMCB_LOCAL_RESPONSE_OUT; if(cb && insert_tmcb(&(new_cell->tmcb_hl),flags,cb,cbp,release_func)!=1){ ret=E_OUT_OF_MEM; LM_ERR("short of tmcb shmem\n"); goto error2; } if (method->len==INVITE_LEN && memcmp(method->s, INVITE, INVITE_LEN)==0) new_cell->flags |= T_IS_INVITE_FLAG; new_cell->flags |= T_IS_LOCAL_FLAG; request = &new_cell->uac[0].request; if (dialog->forced_to_su.s.sa_family == AF_UNSPEC) request->dst.to = to_su; else request->dst.to = dialog->forced_to_su; request->dst.send_sock = dialog->send_sock; request->dst.proto = dialog->send_sock->proto; request->dst.proto_reserved1 = 0; hi=dlg2hash(dialog); LOCK_HASH(hi); insert_into_hash_table_unsafe(new_cell, hi); UNLOCK_HASH(hi); /* copy AVPs into transaction */ new_cell->user_avps = dialog->avps; dialog->avps = NULL; /* ***** Create the message buffer ***** */ buf = build_uac_req(method, headers, body, dialog, 0, new_cell, &buf_len); if (!buf) { LM_ERR("failed to build message\n"); ret=E_OUT_OF_MEM; goto error1; } if (local_rlist.a) { LM_DBG("building sip_msg from buffer\n"); req = buf_to_sip_msg(buf, buf_len, dialog); if (req==NULL) { LM_ERR("failed to build sip_msg from buffer\n"); } else { /* set this transaction as active one */ backup_cell = get_t(); set_t( new_cell ); /* set transaction AVP list */ backup = set_avp_list( &new_cell->user_avps ); /* backup script flags */ sflag_bk = getsflags(); /* disable parallel forking */ set_dset_state( 0 /*disable*/); /* run the route */ swap_route_type( backup_route_type, LOCAL_ROUTE); run_top_route( local_rlist.a, req); set_route_type( backup_route_type ); /* transfer current message context back to t */ new_cell->uac[0].br_flags = getb0flags(req); /* restore the prevoius active transaction */ set_t( backup_cell ); set_dset_state( 1 /*enable*/); setsflagsval(sflag_bk); set_avp_list( backup ); /* check for changes - if none, do not regenerate the buffer */ dst_changed = 1; if (req->new_uri.s || req->force_send_socket!=dialog->send_sock || req->dst_uri.len != dialog->hooks.next_hop->len || memcmp(req->dst_uri.s,dialog->hooks.next_hop->s,req->dst_uri.len) || (dst_changed=0)==0 || req->add_rm || req->body_lumps){ new_send_sock = NULL; /* do we also need to change the destination? */ if (dst_changed) { /* calculate the socket corresponding to next hop */ new_proxy = uri2proxy( req->dst_uri.s ? &(req->dst_uri) : &req->new_uri, PROTO_NONE ); if (new_proxy==0) goto abort_update; /* use the first address */ hostent2su( &new_to_su, &new_proxy->host, new_proxy->addr_idx, new_proxy->port ? new_proxy->port:SIP_PORT); /* get the send socket */ new_send_sock = get_send_socket( req, &new_to_su, new_proxy->proto); if (!new_send_sock) { free_proxy( new_proxy ); pkg_free( new_proxy ); LM_ERR("no socket found for the new destination\n"); goto abort_update; } } /* if interface change, we need to re-build the via */ if (new_send_sock && new_send_sock != dialog->send_sock) { LM_DBG("Interface change in local route -> " "rebuilding via\n"); if (!del_lump(req,req->h_via1->name.s - req->buf, req->h_via1->len,0)) { LM_ERR("Failed to remove initial via \n"); goto abort_update; } memcpy(req->add_to_branch_s,req->via1->branch->value.s, req->via1->branch->value.len); req->add_to_branch_len = req->via1->branch->value.len; /* update also info about new destination and send sock */ dialog->send_sock = new_send_sock; free_proxy( proxy ); pkg_free( proxy ); proxy = new_proxy; request->dst.send_sock = new_send_sock; request->dst.proto = new_send_sock->proto; request->dst.proto_reserved1 = 0; /* build the shm buffer now */ set_init_lump_flags(LUMPFLAG_BRANCH); buf1 = build_req_buf_from_sip_req(req, (unsigned int*)&buf_len1, new_send_sock, new_send_sock->proto, MSG_TRANS_SHM_FLAG); reset_init_lump_flags(); del_flaged_lumps( &req->add_rm, LUMPFLAG_BRANCH); } else { LM_DBG("Change in local route -> rebuilding buffer\n"); /* build the shm buffer now */ buf1 = build_req_buf_from_sip_req(req, (unsigned int*)&buf_len1, dialog->send_sock, dialog->send_sock->proto, MSG_TRANS_SHM_FLAG|MSG_TRANS_NOVIA_FLAG); /* now as it used, hide the original VIA header */ del_lump(req,req->h_via1->name.s - req->buf, req->h_via1->len, 0); } if (!buf1) { LM_ERR("no more shm mem\n"); /* keep original buffer */ goto abort_update; } /* update shortcuts */ if(!req->add_rm && !req->new_uri.s) { /* headers are not affected, simply tranlate */ new_cell->from.s = new_cell->from.s - buf + buf1; new_cell->to.s = new_cell->to.s - buf + buf1; new_cell->callid.s = new_cell->callid.s - buf + buf1; new_cell->cseq_n.s = new_cell->cseq_n.s - buf + buf1; } else { /* use heavy artilery :D */ if (extract_ftc_hdrs( buf1, buf_len1, &h_from, &h_to, &h_cseq, &h_callid)!=0 ) { LM_ERR("failed to update shortcut pointers\n"); shm_free(buf1); goto abort_update; } new_cell->from = h_from; new_cell->to = h_to; new_cell->callid = h_callid; new_cell->cseq_n = h_cseq; } /* here we rely on how build_uac_req() builds the first line */ new_cell->uac[0].uri.s = buf1 + req->first_line.u.request.method.len + 1; new_cell->uac[0].uri.len = GET_RURI(req)->len; /* update also info about new destination and send sock */ if (new_send_sock) request->dst.to = new_to_su; shm_free(buf); buf = buf1; buf_len = buf_len1; /* use new buffer */ } else { /* no changes over the message, buffer is already generated, just hide the original VIA for potential further branches */ del_lump(req,req->h_via1->name.s-req->buf,req->h_via1->len,0); } abort_update: /* save the SIP message into transaction */ new_cell->uas.request = sip_msg_cloner( req, &sip_msg_len, 1); if (new_cell->uas.request==NULL) { /* reset any T triggering */ new_cell->on_negative = 0; new_cell->on_reply = 0; } else { new_cell->uas.end_request= ((char*)new_cell->uas.request)+sip_msg_len; } /* no parallel support in UAC transactions */ new_cell->on_branch = 0; free_sip_msg(req); } } /* for DNS based failover, copy the DNS proxy into transaction */ if (!disable_dns_failover) { new_cell->uac[0].proxy = shm_clone_proxy( proxy, 1/*do_free*/); if (new_cell->uac[0].proxy==NULL) LM_ERR("failed to store DNS info -> no DNS based failover\n"); } new_cell->method.s = buf; new_cell->method.len = method->len; request->buffer.s = buf; request->buffer.len = buf_len; new_cell->nr_of_outgoings++; if(last_localT) { *last_localT = new_cell; REF_UNSAFE(new_cell); } if (SEND_BUFFER(request) == -1) { LM_ERR("attempt to send to '%.*s' failed\n", dialog->hooks.next_hop->len, dialog->hooks.next_hop->s); } if (method->len==ACK_LEN && memcmp(method->s, ACK, ACK_LEN)==0 ) { t_release_transaction(new_cell); } else { start_retr(request); } free_proxy( proxy ); pkg_free( proxy ); return 1; error1: LOCK_HASH(hi); remove_from_hash_table_unsafe(new_cell); UNLOCK_HASH(hi); free_cell(new_cell); error2: free_proxy( proxy ); pkg_free( proxy ); error3: return ret; }
int forward_request( struct sip_msg* msg, struct proxy_l * p) { union sockaddr_union to; unsigned int len; char* buf; struct socket_info* send_sock; struct socket_info* last_sock; str *branch; buf=0; /* calculate branch for outbound request - if the branch buffer is already * set (maybe by an upper level as TM), used it; otherwise computes * the branch for stateless fwd. . According to the latest discussions * on the topic, you should reuse the latest statefull branch * --bogdan */ if ( msg->add_to_branch_len==0 ) { branch = get_sl_branch(msg); if (branch==0) { LM_ERR("unable to compute branch\n"); goto error; } msg->add_to_branch_len = branch->len; memcpy( msg->add_to_branch_s, branch->s, branch->len); } msg_callback_process(msg, REQ_PRE_FORWARD, (void *)p); hostent2su( &to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT); last_sock = 0; if (getb0flags() & tcp_no_new_conn_bflag) tcp_no_new_conn = 1; do { send_sock=get_send_socket( msg, &to, p->proto); if (send_sock==0){ LM_ERR("cannot forward to af %d, proto %d no corresponding" "listening socket\n", to.s.sa_family, p->proto); ser_error=E_NO_SOCKET; continue; } if ( last_sock!=send_sock ) { if (buf) pkg_free(buf); buf = build_req_buf_from_sip_req(msg, &len, send_sock, p->proto, 0); if (!buf){ LM_ERR("building req buf failed\n"); tcp_no_new_conn = 0; goto error; } last_sock = send_sock; } if (check_blacklists( p->proto, &to, buf, len)) { LM_DBG("blocked by blacklists\n"); ser_error=E_IP_BLOCKED; continue; } /* send it! */ LM_DBG("sending:\n%.*s.\n", (int)len, buf); LM_DBG("orig. len=%d, new_len=%d, proto=%d\n", msg->len, len, p->proto ); if (msg_send(send_sock, p->proto, &to, 0, buf, len)<0){ ser_error=E_SEND; continue; } run_fwd_callbacks( msg, buf, len, send_sock, p->proto, &to); ser_error = 0; break; }while( get_next_su( p, &to, (ser_error==E_IP_BLOCKED)?0:1)==0 ); tcp_no_new_conn = 0; if (ser_error) { update_stat( drp_reqs, 1); goto error; } /* sent requests stats */ update_stat( fwd_reqs, 1); pkg_free(buf); /* received_buf & line_buf will be freed in receive_msg by free_lump_list*/ return 0; error: if (buf) pkg_free(buf); return -1; }
int update_sock_struct_from_via( union sockaddr_union* to, struct sip_msg* msg, struct via_body* via ) { struct hostent* he; str* name; int err; unsigned short port; char proto; port=0; if(via==msg->via1){ /* _local_ reply, we ignore any rport or received value * (but we will send back to the original port if rport is * present) */ if ((msg->msg_flags&FL_FORCE_RPORT)||(via->rport)) port=msg->rcv.src_port; else port=via->port; name=&(via->host); /* received=ip in 1st via is ignored (it's not added by us so it's bad) */ }else{ /* "normal" reply, we use rport's & received value if present */ if (via->rport && via->rport->value.s){ DBG("update_sock_struct_from_via: using 'rport'\n"); port=str2s(via->rport->value.s, via->rport->value.len, &err); if (err){ LOG(L_NOTICE, "ERROR: update_sock_struct_from_via: bad rport value(%.*s)\n", via->rport->value.len, via->rport->value.s); port=0; } } if (via->received){ DBG("update_sock_struct_from_via: using 'received'\n"); name=&(via->received->value); /* making sure that we won't do SRV lookup on "received" * (possible if no DNS_IP_HACK is used)*/ if (port==0) port=via->port?via->port:SIP_PORT; }else{ DBG("update_sock_struct_from_via: using via host\n"); name=&(via->host); if (port==0) port=via->port; } } /* we do now a malloc/memcpy because gethostbyname loves \0-terminated strings; -jiri but only if host is not null terminated (host.s[len] will always be ok for a via) BTW: when is via->host.s non null terminated? tm copy? - andrei Yes -- it happened on generating a 408 by TM; -jiri sip_resolvehost now accepts str -janakj */ DBG("update_sock_struct_from_via: trying SRV lookup\n"); proto=via->proto; he=sip_resolvehost(name, &port, &proto); if (he==0){ LOG(L_NOTICE, "ERROR:forward_reply:resolve_host(%.*s) failure\n", name->len, name->s); return -1; } hostent2su(to, he, 0, port); return 1; }
static int trace_send_hep_duplicate(str *body, str *from, str *to, struct dest_info * dst2) { struct dest_info dst; struct socket_info *si; struct dest_info* dst_fin = NULL; struct proxy_l * p=NULL /* make gcc happy */; void* buffer = NULL; union sockaddr_union from_su; union sockaddr_union to_su; unsigned int len, buflen, proto; struct hep_hdr hdr; struct hep_iphdr hep_ipheader; struct hep_timehdr hep_time; struct timeval tvb; struct timezone tz; struct hep_ip6hdr hep_ip6header; if(body->s==NULL || body->len <= 0) return -1; if(dup_uri_str.s==0 || dup_uri==NULL) return 0; gettimeofday( &tvb, &tz ); /* message length */ len = body->len + sizeof(struct hep_ip6hdr) + sizeof(struct hep_hdr) + sizeof(struct hep_timehdr);; /* The packet is too big for us */ if (unlikely(len>BUF_SIZE)){ goto error; } /* Convert proto:ip:port to sockaddress union SRC IP */ if (pipport2su(from->s, &from_su, &proto)==-1 || (pipport2su(to->s, &to_su, &proto)==-1)) goto error; /* check if from and to are in the same family*/ if(from_su.s.sa_family != to_su.s.sa_family) { LM_ERR("interworking detected ?\n"); goto error; } if (!dst2){ init_dest_info(&dst); /* create a temporary proxy*/ dst.proto = PROTO_UDP; p=mk_proxy(&dup_uri->host, (dup_uri->port_no)?dup_uri->port_no:SIP_PORT, dst.proto); if (p==0) { LM_ERR("bad host name in uri\n"); goto error; } hostent2su(&dst.to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT); LM_DBG("setting up the socket_info\n"); dst_fin = &dst; } else { dst_fin = dst2; } if (force_send_sock_str.s) { LM_DBG("force_send_sock activated, grep for the sock_info\n"); si = grep_sock_info(&force_send_sock_uri->host, (force_send_sock_uri->port_no)?force_send_sock_uri->port_no:SIP_PORT, PROTO_UDP); if (!si) { LM_WARN("cannot grep socket info\n"); } else { LM_DBG("found socket while grep: [%.*s] [%.*s]\n", si->name.len, si->name.s, si->address_str.len, si->address_str.s); dst_fin->send_sock = si; } } if (dst_fin->send_sock == 0) { dst_fin->send_sock=get_send_socket(0, &dst_fin->to, dst_fin->proto); if (dst_fin->send_sock == 0) { LM_ERR("can't forward to af %d, proto %d no corresponding" " listening socket\n", dst_fin->to.s.sa_family, dst_fin->proto); goto error; } } /* Version && proto && length */ hdr.hp_l = sizeof(struct hep_hdr); hdr.hp_v = hep_version; hdr.hp_p = proto; /* AND the last */ if (from_su.s.sa_family==AF_INET){ /* prepare the hep headers */ hdr.hp_f = AF_INET; hdr.hp_sport = htons(from_su.sin.sin_port); hdr.hp_dport = htons(to_su.sin.sin_port); hep_ipheader.hp_src = from_su.sin.sin_addr; hep_ipheader.hp_dst = to_su.sin.sin_addr; len = sizeof(struct hep_iphdr); } else if (from_su.s.sa_family==AF_INET6){ /* prepare the hep6 headers */ hdr.hp_f = AF_INET6; hdr.hp_sport = htons(from_su.sin6.sin6_port); hdr.hp_dport = htons(to_su.sin6.sin6_port); hep_ip6header.hp6_src = from_su.sin6.sin6_addr; hep_ip6header.hp6_dst = to_su.sin6.sin6_addr; len = sizeof(struct hep_ip6hdr); } else { LM_ERR("Unsupported protocol family\n"); goto error;; } hdr.hp_l +=len; if (hep_version == 2){ len += sizeof(struct hep_timehdr); } len += sizeof(struct hep_hdr) + body->len; buffer = (void *)pkg_malloc(len+1); if (buffer==0){ LM_ERR("out of memory\n"); goto error; } /* Copy job */ memset(buffer, '\0', len+1); /* copy hep_hdr */ memcpy((void*)buffer, &hdr, sizeof(struct hep_hdr)); buflen = sizeof(struct hep_hdr); /* hep_ip_hdr */ if(from_su.s.sa_family==AF_INET) { memcpy((void*)buffer + buflen, &hep_ipheader, sizeof(struct hep_iphdr)); buflen += sizeof(struct hep_iphdr); } else { memcpy((void*)buffer+buflen, &hep_ip6header, sizeof(struct hep_ip6hdr)); buflen += sizeof(struct hep_ip6hdr); } if(hep_version == 2) { hep_time.tv_sec = tvb.tv_sec; hep_time.tv_usec = tvb.tv_usec; hep_time.captid = hep_capture_id; memcpy((void*)buffer+buflen, &hep_time, sizeof(struct hep_timehdr)); buflen += sizeof(struct hep_timehdr); } /* PAYLOAD */ memcpy((void*)(buffer + buflen) , (void*)body->s, body->len); buflen +=body->len; if (msg_send_buffer(dst_fin, buffer, buflen, 1)<0) { LM_ERR("cannot send hep duplicate message\n"); goto error; } if (p) { free_proxy(p); /* frees only p content, not p itself */ pkg_free(p); } pkg_free(buffer); return 0; error: if(p) { free_proxy(p); /* frees only p content, not p itself */ pkg_free(p); } if(buffer) pkg_free(buffer); return -1; }