1 /*
2 * Copyright (c) 2004-2006 Maxim Sobolev <sobomax@FreeBSD.org>
3 * Copyright (c) 2006-2007 Sippy Software, Inc., http://www.sippysoft.com
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 */
28
29 #if defined(LINUX_XXX)
30 #undef _GNU_SOURCE
31 #define __FAVOR_BSD
32 #endif
33
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <sys/stat.h>
37 #include <sys/uio.h>
38 #include <netinet/in.h>
39 #include <netinet/ip.h>
40 #include <netinet/ip6.h>
41 #include <netinet/udp.h>
42 #include <fcntl.h>
43 #include <limits.h>
44 #include <netdb.h>
45 #include <stddef.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <unistd.h>
50
51 #include "rtp.h"
52 #include "rtp_packet.h"
53 #include "rtpp_log.h"
54 #include "rtpp_cfg_stable.h"
55 #include "rtpp_ip_chksum.h"
56 #include "rtpp_debug.h"
57 #include "rtpp_defines.h"
58 #include "rtpp_types.h"
59 #include "rtpp_refcnt.h"
60 #include "rtpp_log_obj.h"
61 #include "rtpp_mallocs.h"
62 #include "rtpp_monotime.h"
63 #include "rtpp_network.h"
64 #include "rtpp_record.h"
65 #include "rtpp_record_fin.h"
66 #include "rtpp_record_private.h"
67 #include "rtpp_session.h"
68 #include "rtpp_stream.h"
69 #include "rtpp_time.h"
70 #include "rtpp_pipe.h"
71 #include "rtpp_netaddr.h"
72
73 enum record_mode {MODE_LOCAL_PKT, MODE_REMOTE_RTP, MODE_LOCAL_PCAP}; /* MODE_LOCAL_RTP/MODE_REMOTE_PKT? */
74
75 struct rtpp_record_channel {
76 struct rtpp_record pub;
77 char spath[PATH_MAX + 1];
78 char rpath[PATH_MAX + 1];
79 int fd;
80 int needspool;
81 char rbuf[4096];
82 int rbuf_len;
83 enum record_mode mode;
84 int record_single_file;
85 const char *proto;
86 struct rtpp_log *log;
87 };
88
89 static void rtpp_record_write(struct rtpp_record *, struct rtpp_stream *, struct rtp_packet *);
90 static void rtpp_record_close(struct rtpp_record_channel *);
91 static int get_hdr_size(const struct sockaddr *);
92
93 #define PUB2PVT(pubp) \
94 ((struct rtpp_record_channel *)((char *)(pubp) - offsetof(struct rtpp_record_channel, pub)))
95
96 static int
ropen_remote_ctor_pa(struct rtpp_record_channel * rrc,struct rtpp_log * log,char * rname,int is_rtcp)97 ropen_remote_ctor_pa(struct rtpp_record_channel *rrc, struct rtpp_log *log,
98 char *rname, int is_rtcp)
99 {
100 char *cp, *tmp;
101 int n, port;
102 struct sockaddr_storage raddr;
103
104 tmp = strdup(rname + 4);
105 if (tmp == NULL) {
106 RTPP_ELOG(log, RTPP_LOG_ERR, "can't allocate memory");
107 goto e0;
108 }
109 rrc->mode = MODE_REMOTE_RTP;
110 rrc->needspool = 0;
111 cp = strrchr(tmp, ':');
112 if (cp == NULL) {
113 RTPP_LOG(log, RTPP_LOG_ERR, "remote recording target specification should include port number");
114 goto e1;
115 }
116 *cp = '\0';
117 cp++;
118
119 if (is_rtcp) {
120 /* Handle RTCP (increase target port by 1) */
121 port = atoi(cp);
122 if (port <= 0 || port > 65534) {
123 RTPP_LOG(log, RTPP_LOG_ERR, "invalid port in the remote recording target specification");
124 goto e1;
125 }
126 sprintf(cp, "%d", port + 1);
127 }
128
129 n = resolve(sstosa(&raddr), AF_INET, tmp, cp, AI_PASSIVE);
130 if (n != 0) {
131 RTPP_LOG(log, RTPP_LOG_ERR, "ropen: getaddrinfo: %s", gai_strerror(n));
132 goto e1;
133 }
134 rrc->fd = socket(AF_INET, SOCK_DGRAM, 0);
135 if (rrc->fd == -1) {
136 RTPP_ELOG(log, RTPP_LOG_ERR, "ropen: can't create socket");
137 goto e1;
138 }
139 if (connect(rrc->fd, sstosa(&raddr), SA_LEN(sstosa(&raddr))) == -1) {
140 RTPP_ELOG(log, RTPP_LOG_ERR, "ropen: can't connect socket");
141 goto e2;
142 }
143 free(tmp);
144 return (0);
145
146 e2:
147 close(rrc->fd);
148 e1:
149 free(tmp);
150 e0:
151 return (-1);
152 }
153
154 struct rtpp_record *
rtpp_record_open(struct cfg * cf,struct rtpp_session * sp,char * rname,int orig,int record_type)155 rtpp_record_open(struct cfg *cf, struct rtpp_session *sp, char *rname, int orig,
156 int record_type)
157 {
158 struct rtpp_record_channel *rrc;
159 struct rtpp_refcnt *rcnt;
160 const char *sdir, *suffix1, *suffix2;
161 int rval, remote;
162 pcap_hdr_t pcap_hdr;
163
164 remote = (rname != NULL && strncmp("udp:", rname, 4) == 0) ? 1 : 0;
165
166 rrc = rtpp_rzmalloc(sizeof(*rrc), &rcnt);
167 if (rrc == NULL) {
168 RTPP_ELOG(sp->log, RTPP_LOG_ERR, "can't allocate memory");
169 goto e0;
170 }
171 rrc->pub.rcnt = rcnt;
172
173 rrc->record_single_file = (record_type == RECORD_BOTH) ? 1 : 0;
174 if (rrc->record_single_file != 0) {
175 rrc->proto = "RTP/RTCP";
176 } else {
177 rrc->proto = (record_type == RECORD_RTP) ? "RTP" : "RTCP";
178 }
179 rrc->log = sp->log;
180 CALL_SMETHOD(sp->log->rcnt, incref);
181 rrc->pub.write = &rtpp_record_write;
182 if (remote) {
183 rval = ropen_remote_ctor_pa(rrc, sp->log, rname, (record_type == RECORD_RTCP));
184 if (rval < 0) {
185 goto e2;
186 }
187 CALL_SMETHOD(rrc->pub.rcnt, attach, (rtpp_refcnt_dtor_t)&rtpp_record_close,
188 rrc);
189 return (&rrc->pub);
190 }
191
192 if (cf->stable->rdir == NULL) {
193 RTPP_LOG(sp->log, RTPP_LOG_ERR, "directory for saving local recordings is not configured");
194 goto e2;
195 }
196
197 if (cf->stable->record_pcap != 0) {
198 rrc->mode = MODE_LOCAL_PCAP;
199 } else {
200 rrc->mode = MODE_LOCAL_PKT;
201 }
202
203 if (rrc->record_single_file != 0) {
204 suffix1 = suffix2 = "";
205 } else {
206 suffix1 = (orig != 0) ? ".o" : ".a";
207 suffix2 = (record_type == RECORD_RTP) ? ".rtp" : ".rtcp";
208 }
209 if (cf->stable->sdir == NULL) {
210 sdir = cf->stable->rdir;
211 rrc->needspool = 0;
212 } else {
213 sdir = cf->stable->sdir;
214 rrc->needspool = 1;
215 if (rname == NULL) {
216 sprintf(rrc->rpath, "%s/%s=%s%s%s", cf->stable->rdir, sp->call_id, sp->tag_nomedianum,
217 suffix1, suffix2);
218 } else {
219 sprintf(rrc->rpath, "%s/%s%s", cf->stable->rdir, rname, suffix2);
220 }
221 }
222 if (rname == NULL) {
223 sprintf(rrc->spath, "%s/%s=%s%s%s", sdir, sp->call_id, sp->tag_nomedianum,
224 suffix1, suffix2);
225 } else {
226 sprintf(rrc->spath, "%s/%s%s", sdir, rname, suffix2);
227 }
228 rrc->fd = open(rrc->spath, O_WRONLY | O_CREAT | O_TRUNC, DEFFILEMODE);
229 if (rrc->fd == -1) {
230 RTPP_ELOG(sp->log, RTPP_LOG_ERR, "can't open file %s for writing",
231 rrc->spath);
232 goto e2;
233 }
234
235 if (rrc->mode == MODE_LOCAL_PCAP) {
236 pcap_hdr.magic_number = PCAP_MAGIC;
237 pcap_hdr.version_major = PCAP_VER_MAJR;
238 pcap_hdr.version_minor = PCAP_VER_MINR;
239 pcap_hdr.thiszone = 0;
240 pcap_hdr.sigfigs = 0;
241 pcap_hdr.snaplen = 65535;
242 pcap_hdr.network = PCAP_FORMAT;
243 rval = write(rrc->fd, &pcap_hdr, sizeof(pcap_hdr));
244 if (rval == -1) {
245 RTPP_ELOG(sp->log, RTPP_LOG_ERR, "%s: error writing header",
246 rrc->spath);
247 goto e3;
248 }
249 if (rval < sizeof(pcap_hdr)) {
250 RTPP_LOG(sp->log, RTPP_LOG_ERR, "%s: short write writing header",
251 rrc->spath);
252 goto e3;
253 }
254 }
255
256 CALL_SMETHOD(rrc->pub.rcnt, attach, (rtpp_refcnt_dtor_t)&rtpp_record_close,
257 rrc);
258 return (&rrc->pub);
259
260 e3:
261 close(rrc->fd);
262 e2:
263 CALL_SMETHOD(rrc->log->rcnt, decref);
264 CALL_SMETHOD(rrc->pub.rcnt, decref);
265 free(rrc);
266 e0:
267 return NULL;
268 }
269
270 static int
flush_rbuf(struct rtpp_record_channel * rrc)271 flush_rbuf(struct rtpp_record_channel *rrc)
272 {
273 int rval;
274
275 rval = write(rrc->fd, rrc->rbuf, rrc->rbuf_len);
276 if (rval != -1) {
277 rrc->rbuf_len = 0;
278 return 0;
279 }
280
281 RTPP_ELOG(rrc->log, RTPP_LOG_ERR, "error while recording session (%s)",
282 rrc->proto);
283 /* Prevent futher writing if error happens */
284 close(rrc->fd);
285 rrc->fd = -1;
286 return -1;
287 }
288
289 static int
prepare_pkt_hdr_adhoc(struct rtpp_log * log,struct rtp_packet * packet,struct pkt_hdr_adhoc * hdrp,const struct sockaddr * daddr,struct sockaddr * ldaddr,int ldport,int face)290 prepare_pkt_hdr_adhoc(struct rtpp_log *log, struct rtp_packet *packet,
291 struct pkt_hdr_adhoc *hdrp, const struct sockaddr *daddr, struct sockaddr *ldaddr,
292 int ldport, int face)
293 {
294
295 memset(hdrp, 0, sizeof(*hdrp));
296 hdrp->time = packet->rtime;
297 if (hdrp->time == -1) {
298 RTPP_ELOG(log, RTPP_LOG_ERR, "can't get current time");
299 return -1;
300 }
301 switch (sstosa(&packet->raddr)->sa_family) {
302 case AF_INET:
303 hdrp->addr.in4.sin_family = sstosa(&packet->raddr)->sa_family;
304 hdrp->addr.in4.sin_port = satosin(&packet->raddr)->sin_port;
305 hdrp->addr.in4.sin_addr = satosin(&packet->raddr)->sin_addr;
306 break;
307
308 case AF_INET6:
309 hdrp->addr.in6.sin_family = sstosa(&packet->raddr)->sa_family;
310 hdrp->addr.in6.sin_port = satosin6(&packet->raddr)->sin6_port;
311 hdrp->addr.in6.sin_addr = satosin6(&packet->raddr)->sin6_addr;
312 break;
313
314 default:
315 abort();
316 }
317
318 hdrp->plen = packet->size;
319 return 0;
320 }
321
322 static uint16_t ip_id = 0;
323
324 #if (PCAP_FORMAT != DLT_NULL)
325 static void
fake_ether_addr(const struct sockaddr * addr,uint8_t * eaddr)326 fake_ether_addr(const struct sockaddr *addr, uint8_t *eaddr)
327 {
328 uint8_t *ra;
329 int i;
330
331 switch (addr->sa_family) {
332 case AF_INET:
333 eaddr[0] = eaddr[1] = 0;
334 memcpy(eaddr + 2, &(satosin(addr)->sin_addr), 4);
335 return;
336
337 case AF_INET6:
338 ra = &satosin6(addr)->sin6_addr.s6_addr[0];
339 memcpy(eaddr, ra, 6);
340 for (i = 6; i < sizeof(struct in6_addr); i++) {
341 eaddr[i % 6] ^= ra[i];
342 }
343 return;
344
345 default:
346 break;
347 }
348 abort();
349 }
350 #endif
351
352 static int
prepare_pkt_hdr_pcap(struct rtpp_log * log,struct rtp_packet * packet,union pkt_hdr_pcap * hdrp,const struct sockaddr * daddr,struct sockaddr * ldaddr,int ldport,int face)353 prepare_pkt_hdr_pcap(struct rtpp_log *log, struct rtp_packet *packet,
354 union pkt_hdr_pcap *hdrp, const struct sockaddr *daddr, struct sockaddr *ldaddr,
355 int ldport, int face)
356 {
357 const struct sockaddr *src_addr, *dst_addr;
358 uint16_t src_port, dst_port;
359 pcaprec_hdr_t *php;
360 union {
361 struct ip6_hdr *v6;
362 struct ip *v4;
363 } ipp;
364 struct udphdr *udp;
365 int pcap_size;
366 struct timeval rtimeval;
367 #if (PCAP_FORMAT != DLT_NULL)
368 struct sockaddr_storage tmp_addr;
369 struct layer2_hdr *ether;
370 #endif
371
372 if (packet->rtime == -1) {
373 RTPP_ELOG(log, RTPP_LOG_ERR, "can't get current time");
374 return -1;
375 }
376
377 if (face == 0) {
378 src_addr = sstosa(&(packet->raddr));
379 src_port = getnport(src_addr);
380 dst_addr = packet->laddr;
381 dst_port = htons(packet->lport);
382 } else {
383 src_addr = ldaddr;
384 src_port = htons(ldport);
385 dst_addr = daddr;
386 dst_port = getnport(dst_addr);
387 }
388
389 #if 0
390 if (src_addr->sa_family != AF_INET) {
391 RTPP_ELOG(log, RTPP_LOG_ERR, "only AF_INET pcap format is supported");
392 return -1;
393 }
394 #endif
395
396 memset(hdrp, 0, get_hdr_size(src_addr));
397
398 #if (PCAP_FORMAT == DLT_NULL)
399 if (src_addr->sa_family == AF_INET) {
400 php = &hdrp->null.pcaprec_hdr;
401 hdrp->null.family = src_addr->sa_family;
402 ipp.v4 = &(hdrp->null.udpip.iphdr);
403 udp = &(hdrp->null.udpip.udphdr);
404 pcap_size = sizeof(hdrp->null);
405 } else {
406 php = &hdrp->null_v6.pcaprec_hdr;
407 hdrp->null_v6.family = src_addr->sa_family;
408 ipp.v6 = &(hdrp->null_v6.udpip6.iphdr);
409 udp = &(hdrp->null_v6.udpip6.udphdr);
410 pcap_size = sizeof(hdrp->null_v6);
411 }
412 #else
413 /* Prepare fake ethernet header */
414 if (src_addr->sa_family == AF_INET) {
415 php = &hdrp->en10t.pcaprec_hdr;
416 ether = &hdrp->en10t.ether;
417 ether->type = ETHERTYPE_INET;
418 udp = &(hdrp->en10t.udpip.udphdr);
419 pcap_size = sizeof(hdrp->en10t);
420 ipp.v4 = &(hdrp->en10t.udpip.iphdr);
421 } else {
422 php = &hdrp->en10t_v6.pcaprec_hdr;
423 ether = &hdrp->en10t_v6.ether;
424 ether->type = ETHERTYPE_INET6;
425 udp = &(hdrp->en10t_v6.udpip6.udphdr);
426 pcap_size = sizeof(hdrp->en10t_v6);
427 ipp.v6 = &(hdrp->en10t_v6.udpip6.iphdr);
428 }
429 if (face == 0 && ishostnull(dst_addr) && !ishostnull(src_addr)) {
430 if (local4remote(src_addr, &tmp_addr) == 0) {
431 dst_addr = sstosa(&tmp_addr);
432 }
433 }
434 fake_ether_addr(dst_addr, ether->dhost);
435 if (face != 0 && ishostnull(src_addr) && !ishostnull(dst_addr)) {
436 if (local4remote(dst_addr, &tmp_addr) == 0) {
437 src_addr = sstosa(&tmp_addr);
438 }
439 }
440 fake_ether_addr(src_addr, ether->shost);
441 #endif
442
443 dtime2rtimeval(packet->rtime, &rtimeval);
444 php->ts_sec = SEC(&rtimeval);
445 php->ts_usec = USEC(&rtimeval);
446 php->orig_len = php->incl_len = pcap_size -
447 sizeof(*php) + packet->size;
448
449 /* Prepare fake IP header */
450 if (src_addr->sa_family == AF_INET) {
451 ipp.v4->ip_v = 4;
452 ipp.v4->ip_hl = sizeof(*ipp.v4) >> 2;
453 ipp.v4->ip_len = htons(sizeof(*ipp.v4) + sizeof(*udp) + packet->size);
454 ipp.v4->ip_src = satosin(src_addr)->sin_addr;
455 ipp.v4->ip_dst = satosin(dst_addr)->sin_addr;
456 ipp.v4->ip_p = IPPROTO_UDP;
457 ipp.v4->ip_id = htons(ip_id++);
458 ipp.v4->ip_ttl = 127;
459 ipp.v4->ip_sum = rtpp_in_cksum(ipp.v4, sizeof(*ipp.v4));
460 } else {
461 ipp.v6->ip6_vfc |= IPV6_VERSION;
462 ipp.v6->ip6_hlim = IPV6_DEFHLIM;
463 ipp.v6->ip6_nxt = IPPROTO_UDP;
464 ipp.v6->ip6_src = satosin6(src_addr)->sin6_addr;
465 ipp.v6->ip6_dst = satosin6(dst_addr)->sin6_addr;
466 ipp.v6->ip6_plen = htons(sizeof(*udp) + packet->size);
467 }
468
469 /* Prepare fake UDP header */
470 udp->uh_sport = src_port;
471 udp->uh_dport = dst_port;
472 udp->uh_ulen = htons(sizeof(*udp) + packet->size);
473
474 rtpp_ip_chksum_start();
475 if (src_addr->sa_family == AF_INET) {
476 rtpp_ip_chksum_update(&(ipp.v4->ip_src), sizeof(ipp.v4->ip_src));
477 rtpp_ip_chksum_update(&(ipp.v4->ip_dst), sizeof(ipp.v4->ip_dst));
478 rtpp_ip_chksum_pad_v4();
479 rtpp_ip_chksum_update(&(udp->uh_ulen), sizeof(udp->uh_ulen));
480 } else {
481 uint32_t ulen32;
482
483 rtpp_ip_chksum_update(&ipp.v6->ip6_src, sizeof(ipp.v6->ip6_src));
484 rtpp_ip_chksum_update(&ipp.v6->ip6_dst, sizeof(ipp.v6->ip6_dst));
485 ulen32 = htonl(sizeof(*udp) + packet->size);
486 rtpp_ip_chksum_update(&ulen32, sizeof(ulen32));
487 rtpp_ip_chksum_pad_v6();
488 }
489 rtpp_ip_chksum_update(&(udp->uh_sport), sizeof(udp->uh_sport));
490 rtpp_ip_chksum_update(&(udp->uh_dport), sizeof(udp->uh_dport));
491 rtpp_ip_chksum_update(&(udp->uh_ulen), sizeof(udp->uh_ulen));
492 rtpp_ip_chksum_update_data(packet->data.buf, packet->size);
493 rtpp_ip_chksum_fin(udp->uh_sum);
494
495 return 0;
496 }
497
498 static int
get_hdr_size(const struct sockaddr * raddr)499 get_hdr_size(const struct sockaddr *raddr)
500 {
501 int hdr_size;
502
503 #if (PCAP_FORMAT == DLT_NULL)
504 if (raddr->sa_family == AF_INET) {
505 hdr_size = sizeof(struct pkt_hdr_pcap_null);
506 } else {
507 hdr_size = sizeof(struct pkt_hdr_pcap_null_v6);
508 }
509 #else
510 if (raddr->sa_family == AF_INET) {
511 hdr_size = sizeof(struct pkt_hdr_pcap_en10t);
512 } else {
513 hdr_size = sizeof(struct pkt_hdr_pcap_en10t_v6);
514 }
515 #endif
516 return (hdr_size);
517 }
518
519 static void
rtpp_record_write(struct rtpp_record * self,struct rtpp_stream * stp,struct rtp_packet * packet)520 rtpp_record_write(struct rtpp_record *self, struct rtpp_stream *stp, struct rtp_packet *packet)
521 {
522 struct iovec v[2];
523 union {
524 union pkt_hdr_pcap pcap;
525 struct pkt_hdr_adhoc adhoc;
526 } hdr;
527 int rval, hdr_size;
528 int (*prepare_pkt_hdr)(struct rtpp_log *, struct rtp_packet *, void *,
529 const struct sockaddr *, struct sockaddr *, int, int);
530 const char *proto;
531 struct sockaddr_storage daddr;
532 struct sockaddr *ldaddr;
533 int ldport, face;
534 struct rtpp_record_channel *rrc;
535 struct rtpp_netaddr *rem_addr;
536 size_t dalen;
537
538 rrc = PUB2PVT(self);
539
540 if (rrc->fd == -1)
541 return;
542
543 rem_addr = CALL_SMETHOD(stp, get_rem_addr, 0);
544 if (rem_addr == NULL) {
545 return;
546 }
547 dalen = CALL_SMETHOD(rem_addr, get, sstosa(&daddr), sizeof(daddr));
548 CALL_SMETHOD(rem_addr->rcnt, decref);
549 ldaddr = stp->laddr;
550 ldport = stp->port;
551
552 switch (rrc->mode) {
553 case MODE_REMOTE_RTP:
554 send(rrc->fd, packet->data.buf, packet->size, 0);
555 return;
556
557 case MODE_LOCAL_PKT:
558 hdr_size = sizeof(hdr.adhoc);
559 prepare_pkt_hdr = (void *)&prepare_pkt_hdr_adhoc;
560 break;
561
562 case MODE_LOCAL_PCAP:
563 hdr_size = get_hdr_size(sstosa(&packet->raddr));
564 prepare_pkt_hdr = (void *)&prepare_pkt_hdr_pcap;
565 break;
566
567 default:
568 /* Should not happen */
569 abort();
570 }
571
572 /* Check if the write buffer has necessary space, and flush if not */
573 if ((rrc->rbuf_len + hdr_size + packet->size > sizeof(rrc->rbuf)) && rrc->rbuf_len > 0)
574 if (flush_rbuf(rrc) != 0)
575 return;
576
577 face = (rrc->record_single_file == 0) ? 0 : (stp->pipe_type != PIPE_RTP);
578
579 /* Check if received packet doesn't fit into the buffer, do synchronous write if so */
580 if (rrc->rbuf_len + hdr_size + packet->size > sizeof(rrc->rbuf)) {
581 if (prepare_pkt_hdr(stp->log, packet, (void *)&hdr, sstosa(&daddr), ldaddr, ldport, face) != 0)
582 return;
583
584 v[0].iov_base = (void *)&hdr;
585 v[0].iov_len = hdr_size;
586 v[1].iov_base = packet->data.buf;
587 v[1].iov_len = packet->size;
588
589 rval = writev(rrc->fd, v, 2);
590 if (rval != -1)
591 return;
592
593 proto = CALL_SMETHOD(stp, get_proto);
594 RTPP_ELOG(stp->log, RTPP_LOG_ERR, "error while recording session (%s)",
595 proto);
596 /* Prevent futher writing if error happens */
597 close(rrc->fd);
598 rrc->fd = -1;
599 return;
600 }
601 if (prepare_pkt_hdr(stp->log, packet, (void *)rrc->rbuf + rrc->rbuf_len,
602 sstosa(&daddr), ldaddr, ldport, face) != 0)
603 return;
604 rrc->rbuf_len += hdr_size;
605 memcpy(rrc->rbuf + rrc->rbuf_len, packet->data.buf, packet->size);
606 rrc->rbuf_len += packet->size;
607 }
608
609 static void
rtpp_record_close(struct rtpp_record_channel * rrc)610 rtpp_record_close(struct rtpp_record_channel *rrc)
611 {
612 static int keep = 1;
613
614 rtpp_record_fin(&rrc->pub);
615 if (rrc->mode != MODE_REMOTE_RTP && rrc->rbuf_len > 0)
616 flush_rbuf(rrc);
617
618 if (rrc->fd != -1)
619 close(rrc->fd);
620
621 if (rrc->mode == MODE_REMOTE_RTP)
622 goto done;
623
624 if (keep == 0) {
625 if (unlink(rrc->spath) == -1)
626 RTPP_ELOG(rrc->log, RTPP_LOG_ERR, "can't remove "
627 "session record %s", rrc->spath);
628 } else if (rrc->needspool == 1) {
629 if (rename(rrc->spath, rrc->rpath) == -1)
630 RTPP_ELOG(rrc->log, RTPP_LOG_ERR, "can't move "
631 "session record from spool into permanent storage");
632 }
633 done:
634 CALL_SMETHOD(rrc->log->rcnt, decref);
635
636 free(rrc);
637 }
638