FreeCalypso > hg > themwi-system-sw
comparison sip-in/invite_dup.c @ 146:54c2f271380d
sip-in: implement play-along responses to re-INVITEs
| author | Mychaela Falconia <falcon@freecalypso.org> |
|---|---|
| date | Sat, 08 Oct 2022 19:53:23 -0800 |
| parents | 4b685a5d9bd4 |
| children |
comparison
equal
deleted
inserted
replaced
| 145:4b685a5d9bd4 | 146:54c2f271380d |
|---|---|
| 1 /* | 1 /* |
| 2 * Here we process SIP INVITE retransmissions and/or re-INVITEs | 2 * Here we process SIP INVITE retransmissions and/or re-INVITEs |
| 3 * for existing calls. | 3 * for existing calls. Our new approach is that we shall generate |
| 4 * the same stateless response without caring if it's a retransmission | |
| 5 * or a re-INVITE, using CSeq and Via from the (re-)INVITE packet | |
| 6 * we are responding to. Our previous approach was to reject all | |
| 7 * re-INVITE requests, but it turns out that we have to support them | |
| 8 * in order to satisfy BulkVS and other calling servers that use | |
| 9 * session timers. | |
| 4 */ | 10 */ |
| 5 | 11 |
| 6 #include <sys/types.h> | 12 #include <sys/types.h> |
| 7 #include <sys/socket.h> | 13 #include <sys/socket.h> |
| 8 #include <sys/time.h> | 14 #include <sys/time.h> |
| 9 #include <netinet/in.h> | 15 #include <netinet/in.h> |
| 16 #include <arpa/inet.h> | |
| 10 #include <stdio.h> | 17 #include <stdio.h> |
| 11 #include <stdint.h> | 18 #include <stdint.h> |
| 12 #include <stdlib.h> | 19 #include <stdlib.h> |
| 13 #include <string.h> | 20 #include <string.h> |
| 14 #include <strings.h> | 21 #include <strings.h> |
| 17 #include "../libsip/uas_basic.h" | 24 #include "../libsip/uas_basic.h" |
| 18 #include "../libsip/sdp.h" | 25 #include "../libsip/sdp.h" |
| 19 #include "../libsip/out_msg.h" | 26 #include "../libsip/out_msg.h" |
| 20 #include "call.h" | 27 #include "call.h" |
| 21 | 28 |
| 29 extern struct in_addr sip_bind_ip; | |
| 30 extern unsigned sip_bind_port; | |
| 31 | |
| 32 static | |
| 33 fill_reinvite_resp(msg, call, ess) | |
| 34 struct sip_msg_out *msg; | |
| 35 struct call *call; | |
| 36 struct uas_parse_hdrs *ess; | |
| 37 { | |
| 38 char cseq_str[32]; | |
| 39 int rc; | |
| 40 | |
| 41 rc = out_msg_add_header(msg, "From", call->invite_from); | |
| 42 if (rc < 0) | |
| 43 return rc; | |
| 44 rc = out_msg_add_header(msg, "To", call->invite_to); | |
| 45 if (rc < 0) | |
| 46 return rc; | |
| 47 rc = out_msg_add_header(msg, "Call-ID", call->sip_call_id); | |
| 48 if (rc < 0) | |
| 49 return rc; | |
| 50 sprintf(cseq_str, "%u INVITE", ess->cseq_num); | |
| 51 rc = out_msg_add_header(msg, "CSeq", cseq_str); | |
| 52 if (rc < 0) | |
| 53 return rc; | |
| 54 return out_msg_add_header(msg, "Via", ess->via); | |
| 55 } | |
| 56 | |
| 57 static | |
| 58 fill_reinvite_resp_200(msg, call, ess) | |
| 59 struct sip_msg_out *msg; | |
| 60 struct call *call; | |
| 61 struct uas_parse_hdrs *ess; | |
| 62 { | |
| 63 char contact_str[80]; | |
| 64 struct sdp_gen sdp; | |
| 65 int rc; | |
| 66 | |
| 67 start_response_out_msg(msg, "200 CONNECT"); | |
| 68 rc = fill_reinvite_resp(msg, call, ess); | |
| 69 if (rc < 0) | |
| 70 return rc; | |
| 71 sprintf(contact_str, "<sip:%s:%u;transport=udp>", | |
| 72 inet_ntoa(sip_bind_ip), sip_bind_port); | |
| 73 rc = out_msg_add_header(msg, "Contact", contact_str); | |
| 74 if (rc < 0) | |
| 75 return rc; | |
| 76 rc = out_msg_add_header(msg, "Content-Type", "application/sdp"); | |
| 77 if (rc < 0) | |
| 78 return rc; | |
| 79 bzero(&sdp, sizeof sdp); | |
| 80 sdp.conn_ip = call->pstn_rtp_local.sin_addr; | |
| 81 sdp.conn_port = ntohs(call->pstn_rtp_local.sin_port); | |
| 82 sdp.codec_mask = call->use_pcma ? SDP_CODEC_MASK_PCMA | |
| 83 : SDP_CODEC_MASK_PCMU; | |
| 84 sdp.session_id = (sdp.conn_port << 16) | call->sdp_addend; | |
| 85 sdp.owner_ip = sip_bind_ip; | |
| 86 return out_msg_finish_sdp(msg, &sdp); | |
| 87 } | |
| 88 | |
| 22 void | 89 void |
| 23 invite_existing_call(req, ess, sin, call) | 90 invite_existing_call(req, ess, sin, call) |
| 24 struct sip_pkt_rx *req; | 91 struct sip_pkt_rx *req; |
| 25 struct uas_parse_hdrs *ess; | 92 struct uas_parse_hdrs *ess; |
| 26 struct sockaddr_in *sin; | 93 struct sockaddr_in *sin; |
| 27 struct call *call; | 94 struct call *call; |
| 28 { | 95 { |
| 29 struct sip_msg_out resp; | 96 struct sip_msg_out resp; |
| 30 int rc; | 97 int rc; |
| 31 | 98 |
| 32 if (ess->cseq_num != call->invite_cseq) { | 99 switch (call->sip_state) { |
| 33 start_response_out_msg(&resp, "501 Re-INVITE not supported"); | 100 case SIP_STATE_INVITE_PROC: |
| 34 rc = add_resp_basic_headers(&resp, ess, req->req_method); | 101 start_response_out_msg(&resp, "100 Proceeding"); |
| 102 rc = fill_reinvite_resp(&resp, call, ess); | |
| 35 if (rc < 0) { | 103 if (rc < 0) { |
| 36 syslog(LOG_ERR, | 104 msg_size_err: syslog(LOG_ERR, |
| 37 "sending 501 Re-INVITE error: response length exceeded"); | 105 "Call in%06u: msg size error on re-INVITE response", |
| 106 call->in_tag_num); | |
| 38 return; | 107 return; |
| 39 } | 108 } |
| 40 out_msg_finish(&resp); | 109 out_msg_finish(&resp); |
| 41 sip_tx_packet(&resp, sin); | 110 sip_tx_packet(&resp, sin); |
| 42 return; | 111 return; |
| 43 } | |
| 44 /* it's a retransmission, not a re-INVITE */ | |
| 45 switch (call->sip_state) { | |
| 46 case SIP_STATE_INVITE_PROC: | |
| 47 start_response_out_msg(&resp, "100 Proceeding"); | |
| 48 fill_invite_resp_from_call(&resp, call); | |
| 49 out_msg_finish(&resp); | |
| 50 sip_tx_packet(&resp, sin); | |
| 51 return; | |
| 52 case SIP_STATE_RINGING: | 112 case SIP_STATE_RINGING: |
| 53 start_response_out_msg(&resp, "180 Ringing"); | |
| 54 fill_invite_resp_from_call(&resp, call); | |
| 55 out_msg_finish(&resp); | |
| 56 sip_tx_packet(&resp, sin); | |
| 57 return; | |
| 58 case SIP_STATE_RINGING_REL: | 113 case SIP_STATE_RINGING_REL: |
| 59 start_response_out_msg(&resp, "180 Ringing"); | 114 start_response_out_msg(&resp, "180 Ringing"); |
| 60 fill_invite_resp_from_call(&resp, call); | 115 rc = fill_reinvite_resp(&resp, call, ess); |
| 61 out_msg_add_header(&resp, "Require", "100rel"); | 116 if (rc < 0) |
| 62 out_msg_add_header(&resp, "RSeq", "1"); | 117 goto msg_size_err; |
| 63 out_msg_finish(&resp); | 118 out_msg_finish(&resp); |
| 64 sip_tx_packet(&resp, sin); | 119 sip_tx_packet(&resp, sin); |
| 65 return; | 120 return; |
| 66 case SIP_STATE_INVITE_200: | 121 case SIP_STATE_INVITE_200: |
| 67 case SIP_STATE_CONNECTED: | 122 case SIP_STATE_CONNECTED: |
| 68 fill_invite_200_resp(&resp, call); | 123 rc = fill_reinvite_resp_200(&resp, call, ess); |
| 124 if (rc < 0) | |
| 125 goto msg_size_err; | |
| 69 sip_tx_packet(&resp, sin); | 126 sip_tx_packet(&resp, sin); |
| 70 return; | 127 return; |
| 71 case SIP_STATE_INVITE_ERR: | 128 case SIP_STATE_INVITE_ERR: |
| 72 start_response_out_msg(&resp, call->invite_fail); | 129 start_response_out_msg(&resp, call->invite_fail); |
| 73 fill_invite_resp_from_call(&resp, call); | 130 rc = fill_reinvite_resp(&resp, call, ess); |
| 131 if (rc < 0) | |
| 132 goto msg_size_err; | |
| 74 out_msg_finish(&resp); | 133 out_msg_finish(&resp); |
| 75 sip_tx_packet(&resp, sin); | 134 sip_tx_packet(&resp, sin); |
| 76 return; | 135 return; |
| 77 default: | 136 default: |
| 78 /* silently discard */ | 137 /* silently discard */ |
