#include <sofia-sip/su_log.h>
#include <sofia-sip/sdp.h>
#include <sofia-sip/sip_header.h>
+#include <sofia-sip/stun.h>
+#include <sofia-sip/stun_tag.h>
#ifndef SOFIA_SIP_GCC_4_8_PATCH_APLLIED
#warning ********************************************************
//pthread_mutex_t mutex_msg;
su_home_t sip_home[1];
+#define REGISTER_STATE_UNREGISTERED 1
+#define REGISTER_STATE_REGISTERING 2
+#define REGISTER_STATE_REGISTERED 3
+#define REGISTER_STATE_FAILED 4
+
+#define STUN_RETRY_TIMER 10, 0
+#define REGISTER_RETRY_TIMER 10, 0
+
+#define STUN_STATE_UNRESOLVED 1
+#define STUN_STATE_RESOLVING 2
+#define STUN_STATE_RESOLVED 3
+#define STUN_STATE_FAILED 4
+
+#define RTP_PORT_BASE 30000
+#define RTP_PORT_MAX 39998
+
struct sip_inst {
char interface_name[64];
- char local_peer[32];
- char remote_peer[32];
+ char local_peer[128];
+ char remote_peer[128];
+ int register_state;
+ char register_user[128];
+ char register_host[128];
+ nua_handle_t *register_handle;
+ struct lcr_timer register_retry_timer;
+ struct lcr_timer register_option_timer;
+ int options_timeout;
+ char auth_user[128];
+ char auth_password[128];
su_root_t *root;
nua_t *nua;
+
+ int stun_state;
+ char stun_server[128];
+ stun_handle_t *stun_handle;
+ su_socket_t stun_socket;
+ char stun_ipaddr[128];
+ struct lcr_timer stun_retry_timer;
+ int stun_interval;
+
+ unsigned short rtp_port_from;
+ unsigned short rtp_port_to;
+ unsigned short next_rtp_port;
+
};
static int delete_event(struct lcr_work *work, void *instance, int index);
+static int invite_option_timer(struct lcr_timer *timer, void *instance, int index);
static int load_timer(struct lcr_timer *timer, void *instance, int index);
/*
p_s_b_active = 0;
p_s_rxpos = 0;
p_s_rtp_tx_action = 0;
+ p_s_rtp_is_connected = 0;
+
+ /* create option timer */
+ memset(&p_s_invite_option_timer, 0, sizeof(p_s_invite_option_timer));
+ add_timer(&p_s_invite_option_timer, invite_option_timer, this, 0);
+ p_s_invite_direction = 0;
/* audio */
- memset(&p_s_loadtimer, 0, sizeof(p_s_loadtimer));
- add_timer(&p_s_loadtimer, load_timer, this, 0);
+ memset(&p_s_load_timer, 0, sizeof(p_s_load_timer));
+ add_timer(&p_s_load_timer, load_timer, this, 0);
p_s_next_tv_sec = 0;
PDEBUG(DEBUG_SIP, "Created new Psip(%s).\n", portname);
{
PDEBUG(DEBUG_SIP, "Destroyed SIP process(%s).\n", p_name);
- del_timer(&p_s_loadtimer);
+ del_timer(&p_s_invite_option_timer);
+ del_timer(&p_s_load_timer);
del_work(&p_s_delete);
rtp_close();
return "UKN";
}
-static void sip_trace_header(class Psip *sip, const char *message, int direction)
+static void sip_trace_header(class Psip *sip, const char *interface_name, const char *message, int direction)
{
+ struct interface *interface = NULL;
+
+ if (interface_name)
+ interface = getinterfacebyname(interface_name);
+
/* init trace with given values */
start_trace(-1,
- NULL,
+ interface,
sip?numberrize_callerinfo(sip->p_callerinfo.id, sip->p_callerinfo.ntype, options.national, options.international):NULL,
sip?sip->p_dialinginfo.id:NULL,
direction,
return 0;
}
-#define RTP_PORT_BASE 30000
-#define RTP_PORT_MAX 39998
-static unsigned short next_udp_port = RTP_PORT_BASE;
-
static int rtp_sub_socket_bind(int fd, struct sockaddr_in *sin_local, uint32_t ip, uint16_t port)
{
int rc;
int Psip::rtp_open(void)
{
+ struct sip_inst *inst = (struct sip_inst *) p_s_sip_inst;
int rc, rc2;
- struct in_addr ia;
+// struct in_addr ia;
unsigned int ip;
unsigned short start_port;
/* bind socket */
ip = htonl(INADDR_ANY);
- ia.s_addr = ip;
- start_port = next_udp_port;
+// ia.s_addr = ip;
+ start_port = inst->next_rtp_port;
while (1) {
- rc = rtp_sub_socket_bind(p_s_rtp_fd.fd, &p_s_rtp_sin_local, ip, next_udp_port);
+ rc = rtp_sub_socket_bind(p_s_rtp_fd.fd, &p_s_rtp_sin_local, ip, inst->next_rtp_port);
if (rc != 0)
goto try_next_port;
- rc = rtp_sub_socket_bind(p_s_rtcp_fd.fd, &p_s_rtcp_sin_local, ip, next_udp_port + 1);
+ rc = rtp_sub_socket_bind(p_s_rtcp_fd.fd, &p_s_rtcp_sin_local, ip, inst->next_rtp_port + 1);
if (rc == 0) {
- p_s_rtp_port_local = next_udp_port;
- next_udp_port = (next_udp_port + 2 > RTP_PORT_MAX) ? RTP_PORT_BASE : next_udp_port + 2;
+ p_s_rtp_port_local = inst->next_rtp_port;
+ inst->next_rtp_port = (inst->next_rtp_port + 2 > inst->rtp_port_to) ? inst->rtp_port_from : inst->next_rtp_port + 2;
break;
}
/* reopen rtp socket and try again with next udp port */
register_fd(&p_s_rtp_fd, LCR_FD_READ, rtp_sock_callback, this, 0);
try_next_port:
- next_udp_port = (next_udp_port + 2 > RTP_PORT_MAX) ? RTP_PORT_BASE : next_udp_port + 2;
- if (next_udp_port == start_port)
+ inst->next_rtp_port = (inst->next_rtp_port + 2 > inst->rtp_port_to) ? inst->rtp_port_from : inst->next_rtp_port + 2;
+ if (inst->next_rtp_port == start_port)
break;
/* we must use rc2, in order to preserve rc */
}
case 23:
s = 410; *st = sip_410_Gone;
break;
+ case 26:
+ s = 404; *st = sip_404_Not_found;
+ break;
case 27:
s = 502; *st = sip_502_Bad_gateway;
break;
case 102:
s = 504; *st = sip_504_Gateway_time_out;
break;
+ case 111:
+ s = 500; *st = sip_500_Internal_server_error;
+ break;
+ case 127:
+ s = 500; *st = sip_500_Internal_server_error;
+ break;
default:
s = 468; *st = sip_486_Busy_here;
}
return s;
}
+/* use STUN ip, or return the ip without change */
+unsigned int Psip::get_local_ip(unsigned int ip)
+{
+ struct sip_inst *inst = (struct sip_inst *) p_s_sip_inst;
+
+ if (inst->stun_handle && inst->stun_ipaddr[0]) {
+ PDEBUG(DEBUG_SIP, "RTP local IP is replaced by STUN ip %s\n", inst->stun_ipaddr);
+ inet_pton(AF_INET, inst->stun_ipaddr, &ip);
+ return htonl(ip);
+ }
+ return ip;
+}
+
/*
* endpoint sends messages to the SIP port
*/
int Psip::message_connect(unsigned int epoint_id, int message_id, union parameter *param)
{
+ struct sip_inst *inst = (struct sip_inst *) p_s_sip_inst;
char sdp_str[256];
struct in_addr ia;
struct lcr_msg *message;
nua_cancel(p_s_handle, TAG_END());
nua_handle_destroy(p_s_handle);
p_s_handle = NULL;
- sip_trace_header(this, "CANCEL", DIRECTION_OUT);
+ sip_trace_header(this, inst->interface_name, "CANCEL", DIRECTION_OUT);
add_trace("reason", NULL, "failed to connect RTP/RTCP sockts");
end_trace();
message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
}
}
- ia.s_addr = htonl(p_s_rtp_ip_local);
-
+ memset(&ia, 0, sizeof(ia));
+ ia.s_addr = htonl(get_local_ip(p_s_rtp_ip_local));
SPRINT(sdp_str,
- "v=0\n"
- "o=LCR-Sofia-SIP 0 0 IN IP4 %s\n"
- "s=SIP Call\n"
- "c=IN IP4 %s\n"
- "t=0 0\n"
- "m=audio %d RTP/AVP %d\n"
- "a=rtpmap:%d %s/8000\n"
+ "v=0\r\n"
+ "o=LCR-Sofia-SIP 0 0 IN IP4 %s\r\n"
+ "s=SIP Call\r\n"
+ "c=IN IP4 %s\r\n"
+ "t=0 0\r\n"
+ "m=audio %d RTP/AVP %d\r\n"
+ "a=rtpmap:%d %s/8000\r\n"
, inet_ntoa(ia), inet_ntoa(ia), p_s_rtp_port_local, payload_type, payload_type, media_type2name(media_type));
PDEBUG(DEBUG_SIP, "Using SDP response: %s\n", sdp_str);
NUTAG_MEDIA_ENABLE(0),
SIPTAG_CONTENT_TYPE_STR("application/sdp"),
SIPTAG_PAYLOAD_STR(sdp_str), TAG_END());
+
new_state(PORT_STATE_CONNECT);
- sip_trace_header(this, "RESPOND", DIRECTION_OUT);
+ sip_trace_header(this, inst->interface_name, "RESPOND", DIRECTION_OUT);
add_trace("respond", "value", "200 OK");
add_trace("reason", NULL, "call connected");
add_trace("rtp", "ip", "%s", inet_ntoa(ia));
int Psip::message_release(unsigned int epoint_id, int message_id, union parameter *param)
{
+ struct sip_inst *inst = (struct sip_inst *) p_s_sip_inst;
struct lcr_msg *message;
char cause_str[128] = "";
int cause = param->disconnectinfo.cause;
case PORT_STATE_OUT_PROCEEDING:
case PORT_STATE_OUT_ALERTING:
PDEBUG(DEBUG_SIP, "RELEASE/DISCONNECT will cancel\n");
- sip_trace_header(this, "CANCEL", DIRECTION_OUT);
+ sip_trace_header(this, inst->interface_name, "CANCEL", DIRECTION_OUT);
if (cause_str[0])
add_trace("cause", "value", "%d", cause);
end_trace();
case PORT_STATE_IN_ALERTING:
PDEBUG(DEBUG_SIP, "RELEASE/DISCONNECT will respond\n");
status = cause2status(cause, location, &status_text);
- sip_trace_header(this, "RESPOND", DIRECTION_OUT);
+ sip_trace_header(this, inst->interface_name, "RESPOND", DIRECTION_OUT);
if (cause_str[0])
add_trace("cause", "value", "%d", cause);
add_trace("respond", "value", "%d %s", status, status_text);
break;
default:
PDEBUG(DEBUG_SIP, "RELEASE/DISCONNECT will perform nua_bye\n");
- sip_trace_header(this, "BYE", DIRECTION_OUT);
+ sip_trace_header(this, inst->interface_name, "BYE", DIRECTION_OUT);
if (cause_str[0])
add_trace("cause", "value", "%d", cause);
end_trace();
int Psip::message_setup(unsigned int epoint_id, int message_id, union parameter *param)
{
struct sip_inst *inst = (struct sip_inst *) p_s_sip_inst;
- char from[128];
- char to[128];
+ char from[128] = "";
+ char to[128] = "";
+ char contact[128] = "";
const char *local = inst->local_peer;
char local_ip[16];
const char *remote = inst->remote_peer;
sip_cseq_t *cseq = NULL;
struct lcr_msg *message;
int lcr_media = { (options.law=='a') ? MEDIA_TYPE_ALAW : MEDIA_TYPE_ULAW };
- unsigned char lcr_payload = { (options.law=='a') ? PAYLOAD_TYPE_ALAW : PAYLOAD_TYPE_ULAW };
+ unsigned char lcr_payload = { (options.law=='a') ? (unsigned char )PAYLOAD_TYPE_ALAW : (unsigned char )PAYLOAD_TYPE_ULAW };
int *media_types;
unsigned char *payload_types;
int payloads = 0;
memcpy(&p_dialinginfo, ¶m->setup.dialinginfo, sizeof(p_dialinginfo));
memcpy(&p_callerinfo, ¶m->setup.callerinfo, sizeof(p_callerinfo));
- memcpy(&p_redirinfo, ¶m->setup.redirinfo, sizeof(p_redirinfo));
+// memcpy(&p_redirinfo, ¶m->setup.redirinfo, sizeof(p_redirinfo));
+ do_screen(1, p_callerinfo.id, sizeof(p_callerinfo.id), &p_callerinfo.ntype, &p_callerinfo.present, inst->interface_name);
+// do_screen(1, p_redirinfo.id, sizeof(p_redirinfo.id), &p_redirinfo.ntype, &p_redirinfo.present, inst->interface_name);
if (param->setup.rtpinfo.port) {
PDEBUG(DEBUG_SIP, "RTP info given by remote, forward that\n");
trigger_work(&p_s_delete);
return 0;
}
+ if (!p_s_rtp_ip_local) {
+ char *p;
+
+ /* extract IP from local peer */
+ SCPY(local_ip, local);
+ p = strchr(local_ip, ':');
+ if (p)
+ *p = '\0';
+ PDEBUG(DEBUG_SIP, "RTP local IP not known, so we use our local SIP ip %s\n", local_ip);
+ inet_pton(AF_INET, local_ip, &p_s_rtp_ip_local);
+ p_s_rtp_ip_local = ntohl(p_s_rtp_ip_local);
+ }
}
+ memset(&ia, 0, sizeof(ia));
+ ia.s_addr = htonl(get_local_ip(p_s_rtp_ip_local));
p_s_handle = nua_handle(inst->nua, NULL, TAG_END());
if (!p_s_handle) {
PERROR("Failed to create handle\n");
trigger_work(&p_s_delete);
return 0;
}
- /* apply handle */
- sip_trace_header(this, "NEW handle", DIRECTION_IN);
+ /* apply handle to trace */
+ sip_trace_header(this, inst->interface_name, "NEW handle", DIRECTION_IN);
add_trace("handle", "new", "0x%x", p_s_handle);
end_trace();
- if (!p_s_rtp_ip_local) {
- char *p;
-
- /* extract IP from local peer */
- SCPY(local_ip, local);
- p = strchr(local_ip, ':');
- if (p)
- *p = '\0';
- PDEBUG(DEBUG_SIP, "RTP local IP not known, so we use our local SIP ip %s\n", local_ip);
- inet_pton(AF_INET, local_ip, &p_s_rtp_ip_local);
- p_s_rtp_ip_local = ntohl(p_s_rtp_ip_local);
- }
- ia.s_addr = htonl(p_s_rtp_ip_local);
SPRINT(sdp_str,
- "v=0\n"
- "o=LCR-Sofia-SIP 0 0 IN IP4 %s\n"
- "s=SIP Call\n"
- "c=IN IP4 %s\n"
- "t=0 0\n"
+ "v=0\r\n"
+ "o=LCR-Sofia-SIP 0 0 IN IP4 %s\r\n"
+ "s=SIP Call\r\n"
+ "c=IN IP4 %s\r\n"
+ "t=0 0\r\n"
"m=audio %d RTP/AVP"
, inet_ntoa(ia), inet_ntoa(ia), p_s_rtp_port_local);
for (i = 0; i < payloads; i++) {
SPRINT(pt_str, " %d", payload_types[i]);
SCAT(sdp_str, pt_str);
}
- SCAT(sdp_str, "\n");
+ SCAT(sdp_str, "\r\n");
for (i = 0; i < payloads; i++) {
- SPRINT(pt_str, "a=rtpmap:%d %s/8000\n", payload_types[i], media_type2name(media_types[i]));
+ SPRINT(pt_str, "a=rtpmap:%d %s/8000\r\n", payload_types[i], media_type2name(media_types[i]));
SCAT(sdp_str, pt_str);
}
PDEBUG(DEBUG_SIP, "Using SDP for invite: %s\n", sdp_str);
- SPRINT(from, "sip:%s@%s", param->setup.callerinfo.id, local);
- SPRINT(to, "sip:%s@%s", param->setup.dialinginfo.id, remote);
+ SPRINT(from, "sip:%s@%s", p_callerinfo.id, remote);
+ SPRINT(to, "sip:%s@%s", p_dialinginfo.id, remote);
+ if (inst->stun_handle && inst->stun_ipaddr[0])
+ SPRINT(contact, "sip:%s@%s", p_callerinfo.id, inst->stun_ipaddr);
- sip_trace_header(this, "INVITE", DIRECTION_OUT);
+ sip_trace_header(this, inst->interface_name, "INVITE", DIRECTION_OUT);
add_trace("from", "uri", "%s", from);
add_trace("to", "uri", "%s", to);
add_trace("rtp", "ip", "%s", inet_ntoa(ia));
nua_invite(p_s_handle,
TAG_IF(from[0], SIPTAG_FROM_STR(from)),
TAG_IF(to[0], SIPTAG_TO_STR(to)),
+ TAG_IF(contact[0], SIPTAG_CONTACT_STR(contact)),
TAG_IF(cseq, SIPTAG_CSEQ(cseq)),
NUTAG_MEDIA_ENABLE(0),
SIPTAG_CONTENT_TYPE_STR("application/sdp"),
SIPTAG_PAYLOAD_STR(sdp_str), TAG_END());
new_state(PORT_STATE_OUT_SETUP);
+ p_s_invite_direction = DIRECTION_OUT;
+
#if 0
PDEBUG(DEBUG_SIP, "do overlap\n");
new_state(PORT_STATE_OUT_OVERLAP);
int Psip::message_notify(unsigned int epoint_id, int message_id, union parameter *param)
{
-// char sdp_str[256];
+// char
// struct in_addr ia;
switch (param->notifyinfo.notify) {
case INFO_NOTIFY_REMOTE_HOLD:
#if 0
SPRINT(sdp_str,
- "v=0\n"
- "o=LCR-Sofia-SIP 0 0 IN IP4 0.0.0.0\n"
- "s=SIP Call\n"
- "c=IN IP4 0.0.0.0\n"
- "t=0 0\n"
+ "v=0\r\n"
+ "o=LCR-Sofia-SIP 0 0 IN IP4 0.0.0.0\r\n"
+ "s=SIP Call\r\n"
+ "c=IN IP4 0.0.0.0\r\n"
+ "t=0 0\r\n"
);
PDEBUG(DEBUG_SIP, "Using SDP for hold: %s\n", sdp_str);
nua_info(p_s_handle,
break;
case INFO_NOTIFY_REMOTE_RETRIEVAL:
#if 0
- ia.s_addr = htonl(p_s_rtp_ip_local);
+ memset(&ia, 0, sizeof(ia));
+ ia.s_addr = htonl(get_local_ip(p_s_rtp_ip_local));
SPRINT(sdp_str,
- "v=0\n"
- "o=LCR-Sofia-SIP 0 0 IN IP4 %s\n"
- "s=SIP Call\n"
- "c=IN IP4 %s\n"
- "t=0 0\n"
- "m=audio %d RTP/AVP %d\n"
- "a=rtpmap:%d %s/8000\n"
+ "v=0\r\n"
+ "o=LCR-Sofia-SIP 0 0 IN IP4 %s\r\n"
+ "s=SIP Call\r\n"
+ "c=IN IP4 %s\r\n"
+ "t=0 0\r\n"
+ "m=audio %d RTP/AVP %d\r\n"
+ "a=rtpmap:%d %s/8000\r\n"
, inet_ntoa(ia), inet_ntoa(ia), p_s_rtp_port_local, p_s_rtp_payload_type, p_s_rtp_payload_type, media_type2name(p_s_rtp_media_type));
PDEBUG(DEBUG_SIP, "Using SDP for rertieve: %s\n", sdp_str);
nua_info(p_s_handle,
int Psip::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
{
+ struct sip_inst *inst = (struct sip_inst *) p_s_sip_inst;
+
if (Port::message_epoint(epoint_id, message_id, param))
return 1;
&& p_state != PORT_STATE_IN_PROCEEDING)
return 0;
nua_respond(p_s_handle, SIP_180_RINGING, TAG_END());
- sip_trace_header(this, "RESPOND", DIRECTION_OUT);
+ sip_trace_header(this, inst->interface_name, "RESPOND", DIRECTION_OUT);
add_trace("respond", "value", "180 Ringing");
end_trace();
new_state(PORT_STATE_IN_ALERTING);
}
PDEBUG(DEBUG_SIP, "invite received (%s->%s)\n", from, to);
- sip_trace_header(this, "Payload received", DIRECTION_NONE);
+ sip_trace_header(this, inst->interface_name, "Payload received", DIRECTION_NONE);
ret = parse_sdp(sip, &p_s_rtp_ip_remote, &p_s_rtp_port_remote, payload_types, media_types, &payloads, sizeof(payload_types));
if (!ret) {
/* if no RTP bridge, we must support LAW codec, otherwise we forward what we have */
nua_respond(nh, SIP_415_UNSUPPORTED_MEDIA, TAG_END());
nua_handle_destroy(nh);
p_s_handle = NULL;
- sip_trace_header(this, "RESPOND", DIRECTION_OUT);
+ sip_trace_header(this, inst->interface_name, "RESPOND", DIRECTION_OUT);
if (ret == 400)
add_trace("respond", "value", "415 Unsupported Media");
else
nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
nua_handle_destroy(nh);
p_s_handle = NULL;
- sip_trace_header(this, "RESPOND", DIRECTION_OUT);
+ sip_trace_header(this, inst->interface_name, "RESPOND", DIRECTION_OUT);
add_trace("respond", "value", "500 Internal Server Error");
add_trace("reason", NULL, "failed to open RTP/RTCP sockts");
end_trace();
}
/* apply handle */
- sip_trace_header(this, "NEW handle", DIRECTION_IN);
+ sip_trace_header(this, inst->interface_name, "NEW handle", DIRECTION_IN);
add_trace("handle", "new", "0x%x", nh);
p_s_handle = nh;
end_trace();
- sip_trace_header(this, "INVITE", DIRECTION_IN);
+ sip_trace_header(this, inst->interface_name, "INVITE", DIRECTION_IN);
add_trace("rtp", "port", "%d", p_s_rtp_port_remote);
/* caller information */
if (!from[0]) {
#ifdef NUTAG_AUTO100
/* send trying (proceeding) */
nua_respond(nh, SIP_100_TRYING, TAG_END());
- sip_trace_header(this, "RESPOND", DIRECTION_OUT);
+ sip_trace_header(this, inst->interface_name, "RESPOND", DIRECTION_OUT);
add_trace("respond", "value", "100 Trying");
end_trace();
#endif
}
message_put(message);
+ PDEBUG(DEBUG_SIP, "Invite received, scheduling option timer\n");
+ if (inst->options_timeout)
+ schedule_timer(&p_s_invite_option_timer, inst->options_timeout, 0);
+ p_s_invite_direction = DIRECTION_IN;
+
/* send progress, if tones are available and if we don't bridge */
if (!p_s_rtp_bridge && interface->is_tones == IS_YES) {
char sdp_str[256];
nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
nua_handle_destroy(nh);
p_s_handle = NULL;
- sip_trace_header(this, "RESPOND", DIRECTION_OUT);
+ sip_trace_header(this, inst->interface_name, "RESPOND", DIRECTION_OUT);
add_trace("respond", "value", "500 Internal Server Error");
add_trace("reason", NULL, "failed to connect RTP/RTCP sockts");
end_trace();
return;
}
- ia.s_addr = htonl(p_s_rtp_ip_local);
-
+ memset(&ia, 0, sizeof(ia));
+ ia.s_addr = htonl(get_local_ip(p_s_rtp_ip_local));
SPRINT(sdp_str,
- "v=0\n"
- "o=LCR-Sofia-SIP 0 0 IN IP4 %s\n"
- "s=SIP Call\n"
- "c=IN IP4 %s\n"
- "t=0 0\n"
- "m=audio %d RTP/AVP %d\n"
- "a=rtpmap:%d %s/8000\n"
+ "v=0\r\n"
+ "o=LCR-Sofia-SIP 0 0 IN IP4 %s\r\n"
+ "s=SIP Call\r\n"
+ "c=IN IP4 %s\r\n"
+ "t=0 0\r\n"
+ "m=audio %d RTP/AVP %d\r\n"
+ "a=rtpmap:%d %s/8000\r\n"
, inet_ntoa(ia), inet_ntoa(ia), p_s_rtp_port_local, payload_type, payload_type, media_type2name(media_type));
PDEBUG(DEBUG_SIP, "Using SDP response: %s\n", sdp_str);
NUTAG_MEDIA_ENABLE(0),
SIPTAG_CONTENT_TYPE_STR("application/sdp"),
SIPTAG_PAYLOAD_STR(sdp_str), TAG_END());
- sip_trace_header(this, "RESPOND", DIRECTION_OUT);
+ sip_trace_header(this, inst->interface_name, "RESPOND", DIRECTION_OUT);
add_trace("respond", "value", "183 SESSION PROGRESS");
add_trace("reason", NULL, "audio available");
add_trace("rtp", "ip", "%s", inet_ntoa(ia));
void Psip::i_bye(int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, nua_hmagic_t *hmagic, sip_t const *sip, tagi_t tagss[])
{
+ struct sip_inst *inst = (struct sip_inst *) p_s_sip_inst;
struct lcr_msg *message;
int cause = 0;
PDEBUG(DEBUG_SIP, "bye received\n");
- sip_trace_header(this, "BYE", DIRECTION_IN);
+ sip_trace_header(this, inst->interface_name, "BYE", DIRECTION_IN);
if (sip->sip_reason && sip->sip_reason->re_protocol && !strcasecmp(sip->sip_reason->re_protocol, "Q.850") && sip->sip_reason->re_cause) {
cause = atoi(sip->sip_reason->re_cause);
add_trace("cause", "value", "%d", cause);
// let stack do bye automaticall, since it will not accept our response for some reason
// nua_respond(nh, SIP_200_OK, TAG_END());
- sip_trace_header(this, "RESPOND", DIRECTION_OUT);
+ sip_trace_header(this, inst->interface_name, "RESPOND", DIRECTION_OUT);
add_trace("respond", "value", "200 OK");
end_trace();
// nua_handle_destroy(nh);
void Psip::i_cancel(int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, nua_hmagic_t *hmagic, sip_t const *sip, tagi_t tagss[])
{
+ struct sip_inst *inst = (struct sip_inst *) p_s_sip_inst;
struct lcr_msg *message;
PDEBUG(DEBUG_SIP, "cancel received\n");
- sip_trace_header(this, "CANCEL", DIRECTION_IN);
+ sip_trace_header(this, inst->interface_name, "CANCEL", DIRECTION_IN);
end_trace();
nua_handle_destroy(nh);
trigger_work(&p_s_delete);
}
+#warning i_invite
+#warning r_invite
void Psip::r_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, nua_hmagic_t *hmagic, sip_t const *sip, tagi_t tagss[])
{
+ struct sip_inst *inst = (struct sip_inst *) p_s_sip_inst;
struct lcr_msg *message;
int cause = 0, location = 0;
int media_types[32];
PDEBUG(DEBUG_SIP, "response to invite received (status = %d)\n", status);
- sip_trace_header(this, "RESPOND", DIRECTION_OUT);
+ sip_trace_header(this, inst->interface_name, "RESPOND", DIRECTION_OUT);
add_trace("respond", "value", "%d", status);
end_trace();
if (status == 183 || (status >= 200 && status <= 299)) {
int ret;
- sip_trace_header(this, "Payload received", DIRECTION_NONE);
+ sip_trace_header(this, inst->interface_name, "Payload received", DIRECTION_NONE);
ret = parse_sdp(sip, &p_s_rtp_ip_remote, &p_s_rtp_port_remote, payload_types, media_types, &payloads, sizeof(payload_types));
if (!ret) {
if (payloads != 1)
end_trace();
if (ret) {
nua_cancel(nh, TAG_END());
- sip_trace_header(this, "CANCEL", DIRECTION_OUT);
+ sip_trace_header(this, inst->interface_name, "CANCEL", DIRECTION_OUT);
add_trace("reason", NULL, "accepted codec does not match");
end_trace();
cause = 88;
/* connect to remote RTP (if not bridging) */
if (!p_s_rtp_bridge && rtp_connect() < 0) {
nua_cancel(nh, TAG_END());
- sip_trace_header(this, "CANCEL", DIRECTION_OUT);
+ sip_trace_header(this, inst->interface_name, "CANCEL", DIRECTION_OUT);
add_trace("reason", NULL, "failed to open RTP/RTCP sockts");
end_trace();
cause = 31;
}
}
+ PDEBUG(DEBUG_SIP, "Invite response, scheduling option timer\n");
+ if (inst->options_timeout)
+ schedule_timer(&p_s_invite_option_timer, inst->options_timeout, 0);
+
/* process 1xx */
switch (status) {
case 100:
trigger_work(&p_s_delete);
}
+void Psip::r_options(int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, nua_hmagic_t *hmagic, sip_t const *sip, tagi_t tagss[])
+{
+ struct sip_inst *inst = (struct sip_inst *) p_s_sip_inst;
+ int cause = 0, location = 0;
+ struct lcr_msg *message;
+
+ PDEBUG(DEBUG_SIP, "options result %d received\n", status);
+
+ if (status == 200) {
+ PDEBUG(DEBUG_SIP, "options ok, scheduling timer\n");
+ schedule_timer(&p_s_invite_option_timer, inst->options_timeout, 0);
+ return;
+ }
+
+ nua_handle_destroy(nh);
+ p_s_handle = NULL;
+
+ rtp_close();
+
+ cause = status2cause(status);
+ location = LOCATION_BEYOND;
+
+ while(p_epointlist) {
+ /* send setup message to endpoit */
+ message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
+ message->param.disconnectinfo.cause = cause;
+ message->param.disconnectinfo.location = location;
+ message_put(message);
+ /* remove epoint */
+ free_epointlist(p_epointlist);
+ }
+ new_state(PORT_STATE_RELEASE);
+ trigger_work(&p_s_delete);
+}
+
+static void challenge(struct sip_inst *inst, class Psip *psip, int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, nua_hmagic_t *hmagic, sip_t const *sip, tagi_t tagss[])
+{
+ sip_www_authenticate_t const *authenticate = NULL;
+ char const *realm = NULL;
+ char const *scheme = NULL;
+ int i;
+ char *cur;
+ char authentication[256] = "";
+
+ PDEBUG(DEBUG_SIP, "challenge order received\n");
+
+ if (sip->sip_www_authenticate) {
+ authenticate = sip->sip_www_authenticate;
+ } else if (sip->sip_proxy_authenticate) {
+ authenticate = sip->sip_proxy_authenticate;
+ } else {
+ PDEBUG(DEBUG_SIP, "No authentication header found\n");
+ sip_trace_header(psip, inst->interface_name, "AUTHENTICATE", DIRECTION_OUT);
+ add_trace("error", NULL, "Authentication method unknwon");
+ end_trace();
+ return;
+ }
+
+ scheme = (char const *) authenticate->au_scheme;
+ if (authenticate->au_params) {
+ for (i = 0; (cur = (char *) authenticate->au_params[i]); i++) {
+ if ((realm = strstr(cur, "realm="))) {
+ realm += 6;
+ break;
+ }
+ }
+ }
+
+ if (!scheme || !realm) {
+ PDEBUG(DEBUG_SIP, "No scheme or no realm in authentication header found\n");
+ sip_trace_header(psip, inst->interface_name, "AUTHENTICATE", DIRECTION_OUT);
+ add_trace("error", NULL, "Authentication header has no realm or scheme");
+ end_trace();
+ return;
+ }
+
+ SPRINT(authentication, "%s:%s:%s:%s", scheme, realm, inst->auth_user, inst->auth_password);
+ PDEBUG(DEBUG_SIP, "auth: '%s'\n", authentication);
+
+ sip_trace_header(psip, inst->interface_name, "AUTHENTICATE", DIRECTION_OUT);
+ add_trace("scheme", NULL, "%s", scheme);
+ add_trace("realm", NULL, "%s", realm);
+ add_trace("user", NULL, "%s", inst->auth_user);
+ add_trace("pass", NULL, "%s", inst->auth_password);
+ end_trace();
+
+#warning hier als option
+ nua_authenticate(nh, /*SIPTAG_EXPIRES_STR("3600"),*/ NUTAG_AUTH(authentication), TAG_END());
+}
+
static void sip_callback(nua_event_t event, int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, nua_hmagic_t *hmagic, sip_t const *sip, tagi_t tags[])
{
struct sip_inst *inst = (struct sip_inst *) magic;
class Port *port;
class Psip *psip = NULL;
- PDEBUG(DEBUG_SIP, "Event %d from stack received (handle=%p)\n", event, nh);
+ PDEBUG(DEBUG_SIP, "Event %d from SIP stack received (handle=%p)\n", event, nh);
if (!nh)
return;
+ if (inst->register_handle == nh) {
+ sip_trace_header(NULL, inst->interface_name, "STATUS", DIRECTION_OUT);
+ add_trace("value", NULL, "%d", status);
+ add_trace("phrase", NULL, "%s", phrase);
+ end_trace();
+
+ switch (status) {
+ case 200:
+ inst->register_state = REGISTER_STATE_REGISTERED;
+ if (inst->options_timeout)
+ schedule_timer(&inst->register_option_timer, inst->options_timeout, 0);
+ break;
+ case 401:
+ case 407:
+ PDEBUG(DEBUG_SIP, "Register challenge received\n");
+ challenge(inst, NULL, status, phrase, nua, magic, nh, hmagic, sip, tags);
+ break;
+ default:
+ if (status < 400)
+ break;
+ PDEBUG(DEBUG_SIP, "Register failed, starting register timer\n");
+ inst->register_state = REGISTER_STATE_FAILED;
+ nua_handle_destroy(inst->register_handle);
+ unsched_timer(&inst->register_option_timer);
+ schedule_timer(&inst->register_retry_timer, REGISTER_RETRY_TIMER);
+ inst->register_handle = NULL;
+ break;
+ }
+ return;
+ }
+
/* create or find port instance */
if (event == nua_i_invite)
{
return;
}
+ sip_trace_header(psip, inst->interface_name, "STATUS", DIRECTION_OUT);
+ add_trace("value", NULL, "%d", status);
+ add_trace("phrase", NULL, "%s", phrase);
+ end_trace();
+
+ switch (status) {
+ case 401:
+ case 407:
+ challenge(inst, psip, status, phrase, nua, magic, nh, hmagic, sip, tags);
+ return;
+ }
+
switch (event) {
case nua_r_set_params:
PDEBUG(DEBUG_SIP, "setparam response\n");
break;
+ case nua_r_options:
+ psip->r_options(status, phrase, nua, magic, nh, hmagic, sip, tags);
+ break;
case nua_i_error:
PDEBUG(DEBUG_SIP, "error received\n");
break;
}
}
+static void stun_bind_cb(stun_discovery_magic_t *magic, stun_handle_t *sh, stun_discovery_t *sd, stun_action_t action, stun_state_t event)
+{
+ struct sip_inst *inst = (struct sip_inst *) magic;
+ su_sockaddr_t sa;
+ socklen_t addrlen;
+
+ PDEBUG(DEBUG_SIP, "Event %d from STUN stack received\n", event);
+
+ switch (event) {
+ case stun_discovery_done:
+ addrlen = sizeof(sa);
+ memset(&sa, 0, addrlen);
+ if (stun_discovery_get_address(sd, &sa, &addrlen) < 0) {
+ PDEBUG(DEBUG_SIP, "stun_discovery_get_address failed\n");
+ goto failed;
+ }
+ su_inet_ntop(sa.su_family, SU_ADDR(&sa), inst->stun_ipaddr, sizeof(inst->stun_ipaddr));
+ inst->stun_state = STUN_STATE_RESOLVED;
+ schedule_timer(&inst->stun_retry_timer, inst->stun_interval, 0);
+ sip_trace_header(NULL, inst->interface_name, "STUN resolved", DIRECTION_OUT);
+ add_trace("ip", "addr", "%s", inst->stun_ipaddr);
+ end_trace();
+ break;
+ default:
+failed:
+ PDEBUG(DEBUG_SIP, "STUN failed, starting timer\n");
+ inst->stun_state = STUN_STATE_FAILED;
+ schedule_timer(&inst->stun_retry_timer, STUN_RETRY_TIMER);
+ sip_trace_header(NULL, inst->interface_name, "STUN failed", DIRECTION_OUT);
+ end_trace();
+ }
+}
+
/* received shutdown due to termination of RTP */
void Psip::rtp_shutdown(void)
{
+ struct sip_inst *inst = (struct sip_inst *) p_s_sip_inst;
struct lcr_msg *message;
PDEBUG(DEBUG_SIP, "RTP stream terminated\n");
- sip_trace_header(this, "RTP terminated", DIRECTION_IN);
+ sip_trace_header(this, inst->interface_name, "RTP terminated", DIRECTION_IN);
end_trace();
nua_handle_destroy(p_s_handle);
trigger_work(&p_s_delete);
}
+static int invite_option_timer(struct lcr_timer *timer, void *instance, int index)
+{
+ class Psip *psip = (class Psip *)instance;
+ struct sip_inst *inst = (struct sip_inst *) psip->p_s_sip_inst;
+
+ sip_trace_header(psip, inst->interface_name, "OPTIONS", psip->p_s_invite_direction);
+ end_trace();
+
+ nua_options(psip->p_s_handle,
+ TAG_END());
+
+// schedule_timer(&psip->p_s_invite_option_timer, inst->options_timeout, 0);
+
+ return 0;
+}
+
+static int stun_retry_timer(struct lcr_timer *timer, void *instance, int index)
+{
+ struct sip_inst *inst = (struct sip_inst *)instance;
+
+ PDEBUG(DEBUG_SIP, "timeout, restart stun lookup\n");
+ inst->stun_state = STUN_STATE_UNRESOLVED;
+
+ return 0;
+}
+
+static int register_retry_timer(struct lcr_timer *timer, void *instance, int index)
+{
+ struct sip_inst *inst = (struct sip_inst *)instance;
+
+ PDEBUG(DEBUG_SIP, "timeout, restart register\n");
+ inst->register_state = REGISTER_STATE_UNREGISTERED;
+
+ return 0;
+}
+
+static int register_option_timer(struct lcr_timer *timer, void *instance, int index)
+{
+ struct sip_inst *inst = (struct sip_inst *)instance;
+ sip_trace_header(NULL, inst->interface_name, "OPTIONS", DIRECTION_OUT);
+ end_trace();
+
+ nua_options(inst->register_handle,
+ TAG_END());
+
+// schedule_timer(&inst->register_option_timer, inst->options_timeout, 0);
+
+ return 0;
+}
+
int sip_init_inst(struct interface *interface)
{
struct sip_inst *inst = (struct sip_inst *) MALLOC(sizeof(*inst));
- char local[64];
+ char local[256];
interface->sip_inst = inst;
SCPY(inst->interface_name, interface->name);
SCPY(inst->local_peer, interface->sip_local_peer);
SCPY(inst->remote_peer, interface->sip_remote_peer);
+ if (interface->sip_register) {
+ inst->register_state = REGISTER_STATE_UNREGISTERED;
+ SCPY(inst->register_user, interface->sip_register_user);
+ SCPY(inst->register_host, interface->sip_register_host);
+ }
+ SCPY(inst->auth_user, interface->sip_auth_user);
+ SCPY(inst->auth_password, interface->sip_auth_password);
+ inst->options_timeout = interface->sip_options_timer;
+
+ inst->rtp_port_from = interface->rtp_port_from;
+ inst->rtp_port_to = interface->rtp_port_to;
+ if (!inst->rtp_port_from || !inst->rtp_port_to) {
+ inst->rtp_port_from = RTP_PORT_BASE;
+ inst->rtp_port_to = RTP_PORT_MAX;
+ }
+ inst->next_rtp_port = inst->rtp_port_from;
+
+ /* create timers */
+ memset(&inst->stun_retry_timer, 0, sizeof(inst->stun_retry_timer));
+ add_timer(&inst->stun_retry_timer, stun_retry_timer, inst, 0);
+ memset(&inst->register_retry_timer, 0, sizeof(inst->register_retry_timer));
+ add_timer(&inst->register_retry_timer, register_retry_timer, inst, 0);
+ memset(&inst->register_option_timer, 0, sizeof(inst->register_option_timer));
+ add_timer(&inst->register_option_timer, register_option_timer, inst, 0);
/* init root object */
inst->root = su_root_create(inst);
NUTAG_AUTOANSWER(0),
TAG_NULL());
+ if (interface->sip_stun_server[0]) {
+#if 0
+ inst->stun_root = su_root_create(inst);
+ if (!inst->stun_root) {
+ PERROR("Failed to create STUN root\n");
+ sip_exit_inst(interface);
+ return -EINVAL;
+ }
+ auch im exit
+#endif
+ SCPY(inst->stun_server, interface->sip_stun_server);
+ inst->stun_interval = interface->sip_stun_interval;
+ inst->stun_handle = stun_handle_init(inst->root,
+ STUNTAG_SERVER(inst->stun_server),
+ TAG_NULL());
+ if (!inst->stun_handle) {
+ PERROR("Failed to create STUN handle\n");
+ sip_exit_inst(interface);
+ return -EINVAL;
+ }
+ inst->stun_socket = su_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (inst->stun_socket < 0) {
+ PERROR("Failed to create STUN socket\n");
+ sip_exit_inst(interface);
+ return -EINVAL;
+ }
+ inst->stun_state = STUN_STATE_UNRESOLVED;
+ }
+
PDEBUG(DEBUG_SIP, "SIP interface created (inst=%p)\n", inst);
any_sip_interface = 1;
if (!inst)
return;
+ del_timer(&inst->stun_retry_timer);
+ del_timer(&inst->register_retry_timer);
+ del_timer(&inst->register_option_timer);
+ if (inst->stun_socket)
+ su_close(inst->stun_socket);
+ if (inst->stun_handle)
+ stun_handle_destroy(inst->stun_handle);
+ if (inst->register_handle)
+ nua_handle_destroy(inst->register_handle);
if (inst->root)
su_root_destroy(inst->root);
- if (inst->nua) {
+ if (inst->nua)
nua_destroy(inst->nua);
- }
FREE(inst, sizeof(*inst));
interface->sip_inst = NULL;
PDEBUG(DEBUG_SIP, "SIP globals de-initialized\n");
}
+static void sip_handle_stun(struct sip_inst *inst)
+{
+ int rc;
+
+ switch (inst->stun_state) {
+ case STUN_STATE_UNRESOLVED:
+ PDEBUG(DEBUG_SIP, "Trying to to get local IP from stun server\n");
+ rc = stun_bind(inst->stun_handle, stun_bind_cb, (stun_discovery_magic_t *)inst,
+ STUNTAG_SOCKET(inst->stun_socket),
+ STUNTAG_REGISTER_EVENTS(1),
+ TAG_NULL());
+ if (rc < 0) {
+ PERROR("Failed to call stun_bind()\n");
+ inst->stun_state = STUN_STATE_FAILED;
+ break;
+ }
+ inst->stun_state = STUN_STATE_RESOLVING;
+ sip_trace_header(NULL, inst->interface_name, "STUN resolving", DIRECTION_OUT);
+ add_trace("server", "addr", "%s", inst->stun_server);
+ end_trace();
+ break;
+ }
+}
+
+static void sip_handle_register(struct sip_inst *inst)
+{
+ char from[128] = "";
+ char to[128] = "";
+ char contact[128] = "";
+
+ switch (inst->register_state) {
+ case REGISTER_STATE_UNREGISTERED:
+ /* wait for resoved stun */
+ if (inst->stun_handle && inst->stun_state != STUN_STATE_RESOLVED)
+ return;
+
+ PDEBUG(DEBUG_SIP, "Registering to peer\n");
+ inst->register_handle = nua_handle(inst->nua, NULL, TAG_END());
+ if (!inst->register_handle) {
+ PERROR("Failed to create handle\n");
+ inst->register_state = REGISTER_STATE_FAILED;
+ break;
+ }
+ /* apply handle to trace */
+ sip_trace_header(NULL, inst->interface_name, "NEW handle", DIRECTION_NONE);
+ add_trace("handle", "new", "0x%x", inst->register_handle);
+ end_trace();
+
+ SPRINT(from, "sip:%s@%s", inst->register_user, inst->register_host);
+ SPRINT(to, "sip:%s@%s", inst->register_user, inst->register_host);
+ if (inst->stun_handle && inst->stun_ipaddr[0])
+ SPRINT(contact, "sip:%s@%s", inst->register_user, inst->stun_ipaddr);
+
+ sip_trace_header(NULL, inst->interface_name, "REGISTER", DIRECTION_OUT);
+ add_trace("from", "uri", "%s", from);
+ add_trace("to", "uri", "%s", to);
+ end_trace();
+
+ nua_register(inst->register_handle,
+ TAG_IF(from[0], SIPTAG_FROM_STR(from)),
+ TAG_IF(to[0], SIPTAG_TO_STR(to)),
+ TAG_IF(contact[0], SIPTAG_CONTACT_STR(contact)),
+ TAG_END());
+
+ inst->register_state = REGISTER_STATE_REGISTERING;
+
+ break;
+ }
+
+}
+
void sip_handle(void)
{
struct interface *interface = interface_first;
if (interface->sip_inst) {
inst = (struct sip_inst *) interface->sip_inst;
su_root_step(inst->root, 0);
+ sip_handle_stun(inst);
+ sip_handle_register(inst);
}
interface = interface->next;
}
void Psip::update_load(void)
{
/* don't trigger load event if event already active */
- if (p_s_loadtimer.active)
+ if (p_s_load_timer.active)
return;
/* don't start timer if ... */
return;
p_s_next_tv_sec = 0;
- schedule_timer(&p_s_loadtimer, 0, 0); /* no delay the first time */
+ schedule_timer(&p_s_load_timer, 0, 0); /* no delay the first time */
}
static int load_timer(struct lcr_timer *timer, void *instance, int index)
p_s_next_tv_usec -= 1000000;
p_s_next_tv_sec++;
}
- schedule_timer(&p_s_loadtimer, 0, SEND_SIP_LEN * 125);
+ schedule_timer(&p_s_load_timer, 0, SEND_SIP_LEN * 125);
} else {
diff = 1000000 * (current_time.tv_sec - p_s_next_tv_sec)
+ (current_time.tv_usec - p_s_next_tv_usec);
p_s_next_tv_sec++;
}
}
- schedule_timer(&p_s_loadtimer, 0, SEND_SIP_LEN * 125 - diff);
+ schedule_timer(&p_s_load_timer, 0, SEND_SIP_LEN * 125 - diff);
}
/* copy tones */