diff --git a/cfg.lex b/cfg.lex index 20979abe285..04058d789c1 100644 --- a/cfg.lex +++ b/cfg.lex @@ -212,6 +212,8 @@ LOGSTDERROR log_stderror LOGFACILITY log_facility LOGNAME log_name LISTEN listen +LISTEN_SCTP_SEC listen_sctp_sec +SCTP_SEND_TTL_MS sctp_send_ttl_ms MEMGROUP mem-group ALIAS alias AUTO_ALIASES auto_aliases @@ -417,6 +419,8 @@ SPACE [ ] <INITIAL>{LOGFACILITY} { yylval.strval=yytext; return LOGFACILITY; } <INITIAL>{LOGNAME} { yylval.strval=yytext; return LOGNAME; } <INITIAL>{LISTEN} { count(); yylval.strval=yytext; return LISTEN; } +<INITIAL>{LISTEN_SCTP_SEC} { count(); yylval.strval=yytext; return LISTEN_SCTP_SEC; } +<INITIAL>{SCTP_SEND_TTL_MS} { count(); yylval.strval=yytext; return SCTP_SEND_TTL_MS; } <INITIAL>{MEMGROUP} { count(); yylval.strval=yytext; return MEMGROUP; } <INITIAL>{ALIAS} { count(); yylval.strval=yytext; return ALIAS; } <INITIAL>{AUTO_ALIASES} { count(); yylval.strval=yytext; return AUTO_ALIASES; } diff --git a/cfg.y b/cfg.y index e48baa808b5..30cd80e1513 100644 --- a/cfg.y +++ b/cfg.y @@ -341,6 +341,8 @@ extern int cfg_parse_only_routes; %token LOGNAME %token AVP_ALIASES %token LISTEN +%token LISTEN_SCTP_SEC +%token SCTP_SEND_TTL_MS %token MEMGROUP %token ALIAS %token AUTO_ALIASES @@ -1137,6 +1139,17 @@ assign_stm: DEBUG EQUAL snumber | LISTEN EQUAL error { yyerror("ip address or hostname " "expected (use quotes if the hostname includes" " config keywords)"); } + | LISTEN_SCTP_SEC EQUAL ip { + if (init_su(&sctp_sec_addr, $3, 0)!=0){ + LM_CRIT("cfg. parser: failed" + " to add secondary sctp address\n"); + break; + } + } + | LISTEN_SCTP_SEC EQUAL error { yyerror("ip address expected"); } + | SCTP_SEND_TTL_MS EQUAL NUMBER { IFOR(); + sctp_send_ttl_ms=$3; } + | SCTP_SEND_TTL_MS EQUAL error { yyerror("number expected"); } | MEMGROUP EQUAL STRING COLON multi_string { IFOR(); /* convert STIRNG ($3) to an ID */ /* update the memstats type for each module */ diff --git a/globals.h b/globals.h index 118537c669d..c84690aa54e 100644 --- a/globals.h +++ b/globals.h @@ -150,4 +150,7 @@ extern int disable_503_translation; extern int enable_asserts; extern int abort_on_assert; + +extern union sockaddr_union sctp_sec_addr; +extern uint32_t sctp_send_ttl_ms; #endif diff --git a/main.c b/main.c index 86d132789cf..de1aed266d0 100644 --- a/main.c +++ b/main.c @@ -314,6 +314,8 @@ int is_main = 1; /* flag = is this the "main" process? */ char* pid_file = 0; /* filename as asked by user */ char* pgid_file = 0; +union sockaddr_union sctp_sec_addr = { .s.sa_family = 0 }; +uint32_t sctp_send_ttl_ms = 0; /** * Clean up on exit. This should be called before exiting. diff --git a/modules/proto_sctp/sctp_server.c b/modules/proto_sctp/sctp_server.c index f1a302dec8a..a4e20fc9da6 100644 --- a/modules/proto_sctp/sctp_server.c +++ b/modules/proto_sctp/sctp_server.c @@ -43,6 +43,7 @@ #include <linux/types.h> #include <linux/errqueue.h> #endif +#include <fcntl.h> #include "../../mem/shm_mem.h" #include "../../sr_module.h" @@ -89,16 +90,32 @@ int proto_sctp_init_listener(struct socket_info* sock_info) } #endif +#ifdef SCTP_EVENTS + struct sctp_event_subscribe ev_s = {0}; + ev_s.sctp_association_event = 1; + ev_s.sctp_send_failure_event = 1; + + if(setsockopt(sock_info->socket, IPPROTO_SCTP, SCTP_EVENTS, &ev_s, sizeof(ev_s)) == -1) { + LM_WARN("setsockopt SCTP_EVENTS: %s (%d)\n", + strerror(errno), errno); + } +#endif + /* this sockopt causes a kernel panic in some sctp implementations. * commenting it out. -gmarmon */ - /* tos optval=tos; - if (setsockopt(sock_info->socket, IPPROTO_IP, IP_TOS, (void*)&optval, - sizeof(optval)) ==-1){ - LM_WARN("setsockopt tos: %s\n", strerror(errno)); + if (addr->s.sa_family == AF_INET) { + if (setsockopt(sock_info->socket, IPPROTO_IP, IP_TOS, (void*)&optval, + sizeof(optval)) ==-1){ + LM_WARN("setsockopt tos: %s\n", strerror(errno)); + } + } else if (addr->s.sa_family == AF_INET6) { + if (setsockopt(sock_info->socket, IPPROTO_IPV6, IPV6_TCLASS, (void*)&optval, + sizeof(optval)) ==-1){ + LM_WARN("setsockopt v6 tos: %s\n", strerror(errno)); + } } - */ #if defined (__linux__) && defined(SCTP_ERRORS) /* will SCTP_ERRORS ever be defined? -gmarmon */ @@ -125,6 +142,30 @@ int proto_sctp_init_listener(struct socket_info* sock_info) " local address, try site local or global\n"); goto error; } + if (sctp_sec_addr.s.sa_family != 0) { + if (sctp_bindx(sock_info->socket, + (struct sockaddr *)&sctp_sec_addr, 1, + SCTP_BINDX_ADD_ADDR) == -1) + LM_ERR("bindx(%x, %p) : %s\n", + sock_info->socket, &sctp_sec_addr.s, + strerror(errno)); + else + LM_INFO("sctp bindx success to: %s\n", + inet_ntoa(((struct sockaddr_in *)&sctp_sec_addr)->sin_addr)); + } + + /* make non-blocking sending */ + optval=fcntl(sock_info->socket, F_GETFL); + if (optval==-1){ + LM_ERR("fnctl failed with %s [%d]\n", strerror(errno), errno); + goto error; + } + if (fcntl(sock_info->socket, F_SETFL, optval|O_NONBLOCK)==-1){ + LM_ERR("fcntl: set non-blocking failed with %s [%d]\n", + strerror(errno), errno); + goto error; + } + if(listen(sock_info->socket, LISTEN_BACKLOG)<0){ LM_ERR("listen(%x, %d) on %s: %s\n", sock_info->socket, @@ -139,11 +180,37 @@ int proto_sctp_init_listener(struct socket_info* sock_info) return -1; } +static char *sctp_assoc_change_state2s(short int state) +{ + char *s; + + switch(state) { + case SCTP_COMM_UP: + s = "SCTP_COMM_UP"; + break; + case SCTP_COMM_LOST: + s = "SCTP_COMM_LOST"; + break; + case SCTP_RESTART: + s = "SCTP_RESTART"; + break; + case SCTP_SHUTDOWN_COMP: + s = "SCTP_SHUTDOWN_COMP"; + break; + case SCTP_CANT_STR_ASSOC: + s = "SCTP_CANT_STR_ASSOC"; + break; + default: + s = "UNKNOWN"; + break; + }; + return s; +} int proto_sctp_read(struct socket_info *si, int* bytes_read) { struct receive_info ri; - int len; + int len, msg_flags = 0; static char buf [BUF_SIZE+1]; char *tmp; unsigned int fromlen; @@ -151,7 +218,7 @@ int proto_sctp_read(struct socket_info *si, int* bytes_read) fromlen=sockaddru_len(si->su); len = sctp_recvmsg(si->socket, buf, BUF_SIZE, &ri.src_su.s, &fromlen, - &sinfo, 0); + &sinfo, &msg_flags); if (len==-1){ if (errno==EAGAIN){ LM_DBG("packet with bad checksum received\n"); @@ -163,6 +230,43 @@ int proto_sctp_read(struct socket_info *si, int* bytes_read) return -2; } + if (msg_flags & MSG_NOTIFICATION) { + union sctp_notification *snp = (union sctp_notification *)buf; + + switch(snp->sn_header.sn_type) { + case SCTP_ASSOC_CHANGE: + su2ip_addr(&ri.src_ip, &ri.src_su); + if (snp->sn_assoc_change.sac_state == SCTP_COMM_UP) + LM_NOTICE("SCTP_ASSOC_CHANGE assoc_id: %d, peer ip:%s," + "peer port:%d, state: %s\n", + snp->sn_assoc_change.sac_assoc_id, + ip_addr2a(&ri.src_ip), + su_getport(&ri.src_su), + sctp_assoc_change_state2s(snp->sn_assoc_change.sac_state)); + else + LM_ERR("SCTP_ASSOC_CHANGE assoc_id: %d, peer ip:%s, " + "peer port:%d, state: %s\n", + snp->sn_assoc_change.sac_assoc_id, + ip_addr2a(&ri.src_ip), + su_getport(&ri.src_su), + sctp_assoc_change_state2s(snp->sn_assoc_change.sac_state)); + break; + case SCTP_SEND_FAILED: + su2ip_addr(&ri.src_ip, &ri.src_su); + LM_ERR("SCTP_SEND_FAILED assoc_id: %d, peer ip:%s, " + "peer port:%d, error: %d\n", + snp->sn_send_failed.ssf_assoc_id, + ip_addr2a(&ri.src_ip), + su_getport(&ri.src_su), + snp->sn_send_failed.ssf_error); + break; + default: + LM_INFO("unexpected sctp notification type: %d\n", + snp->sn_header.sn_type); + } + return 0; + } + /* we must 0-term the messages, receive_msg expects it */ buf[len]=0; /* no need to save the previous char */ @@ -197,19 +301,21 @@ int proto_sctp_send(struct socket_info *source, char *buf, unsigned len, tolen=sockaddru_len(*to); again: - n=sctp_sendmsg(source->socket, buf, len, &to->s, tolen, 0, 0, 0, 0, 0); + n=sctp_sendmsg(source->socket, buf, len, &to->s, tolen, 0, SCTP_UNORDERED, 0, sctp_send_ttl_ms, 0); #ifdef XL_DEBUG LM_INFO("send status: %d\n", n); #endif if (n==-1){ - LM_ERR("sctp_sendmsg(sock,%p,%d,%p,%d,0,0,0,0,0): %s(%d)\n", - buf,len,&to->s,tolen, strerror(errno),errno); - if (errno==EINTR) goto again; if (errno==EINVAL) { LM_CRIT("invalid sendtoparameters\n" "one possible reason is the server is bound to localhost and\n" "attempts to send to the net\n"); + } else if(errno == EAGAIN || errno == EWOULDBLOCK) { + LM_ERR(L_ERR, "sctp_sendmsg failed, send buffer full\n"); + } else { + LM_ERR("sctp_sendmsg(sock,%p,%d,%p,%d...): %s(%d)\n", + buf,len,&to->s,tolen, strerror(errno),errno); } } return n; diff --git a/modules/sip_i/isup.c b/modules/sip_i/isup.c index e8e22ef8cd7..99e748b12d3 100644 --- a/modules/sip_i/isup.c +++ b/modules/sip_i/isup.c @@ -152,6 +152,27 @@ static struct isup_subfield calling_party_num_subf[] = { {str_init("Address signal"), {0, {{0, 0}}, {0}}}, SUBF_INIT_EMPTY}; +static struct isup_subfield generic_num_subf[] = { + {str_init("Number qualifier indicator"), {3, + {str_init("additional called party num"), str_init("additional connected num"), + str_init("additional calling party num")}, {1,5,6}}}, + {str_init("Odd/even indicator"), {2, + {str_init("even"), str_init("odd")}, {0,1}}}, + {str_init("Nature of address indicator"), {4, + {str_init("subscriber"), str_init("unknown"), str_init("national"), + str_init("international")}, {1,2,3,4}}}, + {str_init("Number Incomplete indicator"), {2, + {str_init("complete"), str_init("incomplete")}, {0,1}}}, + {str_init("Numbering plan indicator"), {3, + {str_init("ISDN"), str_init("Data"), str_init("Telex")}, {1,3,4}}}, + {str_init("Address presentation restricted indicator"), {4, + {str_init("allowed"), str_init("restricted"), str_init("not available"), + str_init("reserved")}, {0,1,2,3}}}, + {str_init("Screening indicator"), {2, + {str_init("user"), str_init("network")}, {1,3}}}, + {str_init("Address signal"), {0, {{0, 0}}, {0}}}, + SUBF_INIT_EMPTY}; + static struct isup_subfield backward_call_ind_subf[] = { {str_init("Charge indicator"), {2, {str_init("no indication"), str_init("no charge")}, {0,1}}}, @@ -745,6 +766,64 @@ int calling_party_num_writef(int param_idx, int subfield_idx, unsigned char *par return 0; } +void generic_num_parsef(int subfield_idx, unsigned char *param_val, int len, + int *int_res, str *str_res) +{ + int idx[] = {0,1,1,2,2,2,2}; + int shift[] = {0,7,0,7,4,2,0}; + int mask[] = {0xff,1,0x7f,1,7,3,3}; + int oddeven = (param_val[1] >> 7) & 0x1; + + if (subfield_idx < 0 || subfield_idx > 7) { + LM_ERR("BUG - bad subfield\n"); + return; + } + + switch (subfield_idx) { + case 1: + *int_res = oddeven; + break; + case 7: + isup_get_number(str_res, param_val + 3, len - 3, oddeven); + break; + default: + *int_res = (param_val[idx[subfield_idx]] >> shift[subfield_idx]) & mask[subfield_idx]; + } +} + +int generic_num_writef(int param_idx, int subfield_idx, unsigned char *param_val, int *len, + pv_value_t *val) +{ + int new_val; + int num_len, oddeven; + str num; + int idx[] = {0,1,1,2,2,2,2}; + int mask[] = {0xff,0x80,0x7f,0x80,0x70,0xc,0x3}; + int shift[] = {0,7,0,7,4,2,0}; + + NUM_PARAM_GET_VAL_PV(7); + + if (subfield_idx < 0 || subfield_idx > 7) { + LM_ERR("BUG - bad subfield\n"); + return -1; + } + + if (subfield_idx == 7) { + isup_put_number(param_val + 2, num, &num_len, &oddeven); + /* also set oddeven, just in case it wasn't already */ + param_val[1] = SET_BITS(param_val[1], 0x80, 7, oddeven); + } else + param_val[idx[subfield_idx]] = SET_BITS(param_val[idx[subfield_idx]], + mask[subfield_idx], shift[subfield_idx], new_val); + + if (subfield_idx == 7) + *len = num_len + 2; + else if (*len == 0) + *len = 2; + + return 0; +} + void backward_call_ind_parsef(int subfield_idx, unsigned char *param_val, int len, int *int_res, str *str_res) { @@ -1144,7 +1223,7 @@ struct isup_param_data isup_params[NO_ISUP_PARAMS] = { {ISUP_PARM_CORRELATION_ID, str_init("Correlation id"), NULL, NULL, NULL, NULL, 0}, {ISUP_PARM_SCF_ID, str_init("SCF id"), NULL, NULL, NULL, NULL, 0}, {ISUP_PARM_CALL_DIVERSION_TREATMENT_IND, str_init("Call diversion treatment indicators"), NULL, NULL, NULL, NULL, 0}, - {ISUP_PARM_CALLED_IN_NUMBER, str_init("Called IN number"), NULL, NULL, NULL, NULL, 0}, + {ISUP_PARM_CALLED_IN_NUMBER, str_init("Called IN number"), original_called_num_parsef, original_called_num_writef, original_called_num_subf, NULL, 0}, {ISUP_PARM_CALL_OFFERING_TREATMENT_IND, str_init("Call offering treatment indicators"), NULL, NULL, NULL, NULL, 0}, {ISUP_PARM_CHARGED_PARTY_IDENT, str_init("Charged party identification"), NULL, NULL, NULL, NULL, 0}, {ISUP_PARM_CONFERENCE_TREATMENT_IND, str_init("Conference treatment indicators"), NULL, NULL, NULL, NULL, 0}, @@ -1171,7 +1250,7 @@ struct isup_param_data isup_params[NO_ISUP_PARAMS] = { {ISUP_PARM_REDIRECT_FORWARD_INFO, str_init("Redirect forward information"), NULL, NULL, NULL, NULL, 0}, {ISUP_PARM_REDIRECT_BACKWARD_INFO, str_init("Redirect backward information"), NULL, NULL, NULL, NULL, 0}, {ISUP_PARM_NUM_PORTABILITY_FORWARD_INFO, str_init("Number portability forward information"), NULL, NULL, NULL, NULL, 0}, - {ISUP_PARM_GENERIC_ADDR, str_init("Generic Number"), NULL, NULL, NULL, NULL, 0}, + {ISUP_PARM_GENERIC_ADDR, str_init("Generic Number"), generic_num_parsef, generic_num_writef, generic_num_subf, NULL, 0}, {ISUP_PARM_GENERIC_DIGITS, str_init("Generic Digits"), NULL, NULL, NULL, NULL, 0}, {ISUP_PARM_EGRESS_SERV, str_init("Egress Service"), NULL, NULL, NULL, NULL, 0}, {ISUP_PARM_JIP, str_init("Jurisdiction Information Parameter"), NULL, NULL, NULL, NULL, 0}, diff --git a/modules/tm/timer.c b/modules/tm/timer.c index 1aa851c143d..d11b190aeee 100644 --- a/modules/tm/timer.c +++ b/modules/tm/timer.c @@ -286,7 +286,7 @@ inline static void retransmission_handler( struct timer_link *retr_tl ) /* re-transmission */ if ( r_buf->activ_type==TYPE_LOCAL_CANCEL || r_buf->activ_type==TYPE_REQUEST ) { - LM_DBG("retransmission_handler : request resending" + LM_INFO("retransmission_handler : request resending" " (t=%p, %.9s ... )\n", r_buf->my_T, r_buf->buffer.s); set_t(r_buf->my_T); if (SEND_BUFFER( r_buf )==0) {