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