1 /**************************************************************************
2  **
3  ** sngrep - SIP Messages flow viewer
4  **
5  ** Copyright (C) 2013-2018 Ivan Alonso (Kaian)
6  ** Copyright (C) 2013-2018 Irontec SL. All rights reserved.
7  **
8  ** This program is free software: you can redistribute it and/or modify
9  ** it under the terms of the GNU General Public License as published by
10  ** the Free Software Foundation, either version 3 of the License, or
11  ** (at your option) any later version.
12  **
13  ** This program is distributed in the hope that it will be useful,
14  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  ** GNU General Public License for more details.
17  **
18  ** You should have received a copy of the GNU General Public License
19  ** along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  **
21  ****************************************************************************/
22 /**
23  * @file sip_call.c
24  * @author Ivan Alonso [aka Kaian] <kaian@irontec.com>
25  *
26  * @brief Functions to manage SIP call data
27  *
28  * This file contains the functions and structure to manage SIP call data
29  *
30  */
31 
32 #include "sip_call.h"
33 #include "sip.h"
34 #include "setting.h"
35 
36 sip_call_t *
call_create(char * callid,char * xcallid)37 call_create(char *callid, char *xcallid)
38 {
39     sip_call_t *call;
40 
41     // Initialize a new call structure
42     if (!(call = sng_malloc(sizeof(sip_call_t))))
43         return NULL;
44 
45     // Create a vector to store call messages
46     call->msgs = vector_create(2, 2);
47     vector_set_destroyer(call->msgs, msg_destroyer);
48 
49     // Create an empty vector to store rtp packets
50     if (setting_enabled(SETTING_CAPTURE_RTP)) {
51         call->rtp_packets = vector_create(0, 40);
52         vector_set_destroyer(call->rtp_packets, packet_destroyer);
53     }
54 
55     // Create an empty vector to strore stream data
56     call->streams = vector_create(0, 2);
57     vector_set_destroyer(call->streams, vector_generic_destroyer);
58 
59     // Create an empty vector to store x-calls
60     call->xcalls = vector_create(0, 1);
61 
62     // Initialize call filter status
63     call->filtered = -1;
64 
65     // Set message callid
66     call->callid = strdup(callid);
67     call->xcallid = strdup(xcallid);
68 
69     return call;
70 }
71 
72 void
call_destroy(sip_call_t * call)73 call_destroy(sip_call_t *call)
74 {
75     // Remove all call messages
76     vector_destroy(call->msgs);
77     // Remove all call streams
78     vector_destroy(call->streams);
79     // Remove all call rtp packets
80     vector_destroy(call->rtp_packets);
81     // Remove all xcalls
82     vector_destroy(call->xcalls);
83     // Deallocate call memory
84     sng_free(call->callid);
85     sng_free(call->xcallid);
86     sng_free(call->reasontxt);
87     sng_free(call);
88 }
89 
90 void
call_destroyer(void * call)91 call_destroyer(void *call)
92 {
93     call_destroy((sip_call_t*)call);
94 }
95 
96 bool
call_has_changed(sip_call_t * call)97 call_has_changed(sip_call_t *call)
98 {
99     return call->changed;
100 }
101 
102 void
call_add_message(sip_call_t * call,sip_msg_t * msg)103 call_add_message(sip_call_t *call, sip_msg_t *msg)
104 {
105     // Set the message owner
106     msg->call = call;
107     // Put this msg at the end of the msg list
108     msg->index = vector_append(call->msgs, msg);
109     // Flag this call as changed
110     call->changed = true;
111 }
112 
113 void
call_add_stream(sip_call_t * call,rtp_stream_t * stream)114 call_add_stream(sip_call_t *call, rtp_stream_t *stream)
115 {
116     // Store stream
117     vector_append(call->streams, stream);
118     // Flag this call as changed
119     call->changed = true;
120 }
121 
122 void
call_add_rtp_packet(sip_call_t * call,packet_t * packet)123 call_add_rtp_packet(sip_call_t *call, packet_t *packet)
124 {
125     // Store packet
126     vector_append(call->rtp_packets, packet);
127     // Flag this call as changed
128     call->changed = true;
129 }
130 
131 int
call_msg_count(sip_call_t * call)132 call_msg_count(sip_call_t *call)
133 {
134     return vector_count(call->msgs);
135 }
136 
137 int
call_is_active(sip_call_t * call)138 call_is_active(sip_call_t *call)
139 {
140     return (call->state == SIP_CALLSTATE_CALLSETUP || call->state == SIP_CALLSTATE_INCALL);
141 }
142 
143 int
call_is_invite(sip_call_t * call)144 call_is_invite(sip_call_t *call)
145 {
146     sip_msg_t *first;
147     if ((first = vector_first(call->msgs)))
148         return (first->reqresp == SIP_METHOD_INVITE);
149 
150     return 0;
151 }
152 
153 void
call_msg_retrans_check(sip_msg_t * msg)154 call_msg_retrans_check(sip_msg_t *msg)
155 {
156     sip_msg_t *prev = NULL;
157     vector_iter_t it;
158 
159     // Get previous message in call with same origin and destination
160     it = vector_iterator(msg->call->msgs);
161     vector_iterator_set_current(&it, vector_index(msg->call->msgs, msg));
162     while ((prev = vector_iterator_prev(&it))) {
163         if (addressport_equals(prev->packet->src, msg->packet->src) &&
164                 addressport_equals(prev->packet->dst, msg->packet->dst))
165             break;
166     }
167 
168     // Store the flag that determines if message is retrans
169     if (prev && !strcasecmp(msg_get_payload(msg), msg_get_payload(prev))) {
170         msg->retrans = prev;
171     }
172 }
173 
174 sip_msg_t *
call_msg_with_media(sip_call_t * call,address_t dst)175 call_msg_with_media(sip_call_t *call, address_t dst)
176 {
177     sip_msg_t *msg;
178     sdp_media_t *media;
179     vector_iter_t itmsg;
180     vector_iter_t itmedia;
181 
182     // Get message with media address configured in given dst
183     itmsg = vector_iterator(call->msgs);
184     while ((msg = vector_iterator_next(&itmsg))) {
185         itmedia = vector_iterator(msg->medias);
186         while ((media = vector_iterator_next(&itmedia))) {
187             if (addressport_equals(dst, media->address)) {
188                 return msg;
189             }
190         }
191     }
192 
193     return NULL;
194 }
195 
196 void
call_update_state(sip_call_t * call,sip_msg_t * msg)197 call_update_state(sip_call_t *call, sip_msg_t *msg)
198 {
199     int reqresp;
200 
201     if (!call_is_invite(call))
202         return;
203 
204     // Get current message Method / Response Code
205     reqresp = msg->reqresp;
206 
207     // If this message is actually a call, get its current state
208     if (call->state) {
209         if (call->state == SIP_CALLSTATE_CALLSETUP) {
210             if (reqresp == SIP_METHOD_ACK && call->invitecseq == msg->cseq) {
211                 // Alice and Bob are talking
212                 call->state = SIP_CALLSTATE_INCALL;
213                 call->cstart_msg = msg;
214             } else if (reqresp == SIP_METHOD_CANCEL) {
215                 // Alice is not in the mood
216                 call->state = SIP_CALLSTATE_CANCELLED;
217             } else if ((reqresp == 480) || (reqresp == 486) || (reqresp == 600 )) {
218                 // Bob is busy
219                 call->state = SIP_CALLSTATE_BUSY;
220             } else if (reqresp > 400 && call->invitecseq == msg->cseq) {
221                 // Bob is not in the mood
222                 call->state = SIP_CALLSTATE_REJECTED;
223             } else if (reqresp == 181 || reqresp == 302 || reqresp == 301) {
224                 // Bob has diversion
225                 call->state = SIP_CALLSTATE_DIVERTED;
226             }
227         } else if (call->state == SIP_CALLSTATE_INCALL) {
228             if (reqresp == SIP_METHOD_BYE) {
229                 // Thanks for all the fish!
230                 call->state = SIP_CALLSTATE_COMPLETED;
231                 call->cend_msg = msg;
232             }
233         } else if (reqresp == SIP_METHOD_INVITE && call->state !=  SIP_CALLSTATE_INCALL) {
234             // Call is being setup (after proper authentication)
235             call->invitecseq = msg->cseq;
236             call->state = SIP_CALLSTATE_CALLSETUP;
237         }
238     } else {
239         // This is actually a call
240         if (reqresp == SIP_METHOD_INVITE) {
241             call->invitecseq = msg->cseq;
242             call->state = SIP_CALLSTATE_CALLSETUP;
243         }
244     }
245 }
246 
247 const char *
call_get_attribute(sip_call_t * call,enum sip_attr_id id,char * value)248 call_get_attribute(sip_call_t *call, enum sip_attr_id id, char *value)
249 {
250     sip_msg_t *first, *last;
251 
252     if (!call)
253         return NULL;
254 
255     switch (id) {
256         case SIP_ATTR_CALLINDEX:
257             sprintf(value, "%d", call->index);
258             break;
259         case SIP_ATTR_CALLID:
260             sprintf(value, "%s", call->callid);
261             break;
262         case SIP_ATTR_XCALLID:
263             sprintf(value, "%s", call->xcallid);
264             break;
265         case SIP_ATTR_MSGCNT:
266             sprintf(value, "%d", vector_count(call->msgs));
267             break;
268         case SIP_ATTR_CALLSTATE:
269             sprintf(value, "%s", call_state_to_str(call->state));
270             break;
271         case SIP_ATTR_TRANSPORT:
272             first = vector_first(call->msgs);
273             sprintf(value, "%s", sip_transport_str(first->packet->type));
274             break;
275         case SIP_ATTR_CONVDUR:
276             timeval_to_duration(msg_get_time(call->cstart_msg), msg_get_time(call->cend_msg), value);
277             break;
278         case SIP_ATTR_TOTALDUR:
279             first = vector_first(call->msgs);
280             last = vector_last(call->msgs);
281             timeval_to_duration(msg_get_time(first), msg_get_time(last), value);
282             break;
283         case SIP_ATTR_REASON_TXT:
284             if (call->reasontxt)
285                 sprintf(value, "%s", call->reasontxt);
286             break;
287         case SIP_ATTR_WARNING:
288             if (call->warning)
289                 sprintf(value, "%d", call->warning);
290             break;
291         default:
292             return msg_get_attribute(vector_first(call->msgs), id, value);
293             break;
294     }
295 
296     return strlen(value) ? value : NULL;
297 }
298 
299 const char *
call_state_to_str(int state)300 call_state_to_str(int state)
301 {
302     switch (state) {
303         case SIP_CALLSTATE_CALLSETUP:
304             return "CALL SETUP";
305         case SIP_CALLSTATE_INCALL:
306             return "IN CALL";
307         case SIP_CALLSTATE_CANCELLED:
308             return "CANCELLED";
309         case SIP_CALLSTATE_REJECTED:
310             return "REJECTED";
311         case SIP_CALLSTATE_BUSY:
312             return "BUSY";
313         case SIP_CALLSTATE_DIVERTED:
314             return "DIVERTED";
315         case SIP_CALLSTATE_COMPLETED:
316             return "COMPLETED";
317     }
318     return "";
319 }
320 
321 int
call_attr_compare(sip_call_t * one,sip_call_t * two,enum sip_attr_id id)322 call_attr_compare(sip_call_t *one, sip_call_t *two, enum sip_attr_id id)
323 {
324     char onevalue[256], twovalue[256];
325     int oneintvalue, twointvalue;
326     int comparetype; /* TODO 0 = string compare, 1 = int comprare */
327 
328     switch (id) {
329         case SIP_ATTR_CALLINDEX:
330             oneintvalue = one->index;
331             twointvalue = two->index;
332             comparetype = 1;
333             break;
334         case SIP_ATTR_MSGCNT:
335             oneintvalue = call_msg_count(one);
336             twointvalue = call_msg_count(two);
337             comparetype = 1;
338             break;
339         default:
340             // Get attribute values
341             memset(onevalue, 0, sizeof(onevalue));
342             memset(twovalue, 0, sizeof(twovalue));
343             call_get_attribute(one, id, onevalue);
344             call_get_attribute(two, id, twovalue);
345             comparetype = 0;
346             break;
347     }
348 
349     switch (comparetype) {
350         case 0:
351             if (strlen(twovalue) == 0 && strlen(onevalue) == 0)
352                 return 0;
353             if (strlen(twovalue) == 0)
354                 return 1;
355             if (strlen(onevalue) == 0)
356                 return -1;
357             return strcmp(onevalue, twovalue);
358         case 1:
359             if (oneintvalue == twointvalue) return 0;
360             if (oneintvalue > twointvalue) return 1;
361             if (oneintvalue < twointvalue) return -1;
362             /* no break */
363         default:
364             return 0;
365     }
366 }
367 
368 void
call_add_xcall(sip_call_t * call,sip_call_t * xcall)369 call_add_xcall(sip_call_t *call, sip_call_t *xcall)
370 {
371     if (!call || !xcall)
372         return;
373 
374     // Mark this call as changed
375     call->changed = true;
376     // Add the xcall to the list
377     vector_append(call->xcalls, xcall);
378 }
379