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