Coverage Report

Created: 2023-09-25 06:44

/src/rtpproxy/src/rtpp_record.c
Line
Count
Source (jump to first uncovered line)
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 <pthread.h>
46
#include <stddef.h>
47
#include <stdio.h>
48
#include <stdlib.h>
49
#include <stdint.h>
50
#include <string.h>
51
#include <unistd.h>
52
53
#include "config.h"
54
55
#include "rtp.h"
56
#include "rtpp_time.h"
57
#include "rtp_packet.h"
58
#include "rtpp_log.h"
59
#include "rtpp_cfg.h"
60
#include "rtpp_ip_chksum.h"
61
#include "rtpp_debug.h"
62
#include "rtpp_defines.h"
63
#include "rtpp_types.h"
64
#include "rtpp_refcnt.h"
65
#include "rtpp_log_obj.h"
66
#include "rtpp_mallocs.h"
67
#include "rtpp_network.h"
68
#include "rtpp_record.h"
69
#include "rtpp_record_fin.h"
70
#include "rtpp_record_adhoc.h"
71
#include "rtpp_record_private.h"
72
#include "rtpp_session.h"
73
#include "rtpp_stream.h"
74
#include "rtpp_time.h"
75
#include "rtpp_util.h"
76
#include "rtpp_pipe.h"
77
#include "rtpp_netaddr.h"
78
#include "advanced/pproc_manager.h"
79
80
enum record_mode {MODE_LOCAL_PKT, MODE_REMOTE_RTP, MODE_LOCAL_PCAP}; /* MODE_LOCAL_RTP/MODE_REMOTE_PKT? */
81
82
struct rtpp_record_channel {
83
    struct rtpp_record pub;
84
    pthread_mutex_t lock;
85
    char spath[PATH_MAX + 1];
86
    char rpath[PATH_MAX + 1];
87
    int fd;
88
    int needspool;
89
    char rbuf[4096];
90
    int rbuf_len;
91
    enum record_mode mode;
92
    int record_single_file;
93
    const char *proto;
94
    struct rtpp_log *log;
95
    struct rtpp_timestamp epoch;
96
};
97
98
static void rtpp_record_write(struct rtpp_record *, const struct pkt_proc_ctx *);
99
static void rtpp_record_close(struct rtpp_record_channel *);
100
static int get_hdr_size(const struct sockaddr *);
101
102
#if HAVE_SO_TS_CLOCK
103
#define ARRIVAL_TIME(rp, pp) (rp->epoch.wall + (pp->rtime.mono - rp->epoch.mono))
104
#else
105
0
#define ARRIVAL_TIME(rp, pp) (pp->rtime.wall)
106
#endif
107
108
DEFINE_SMETHODS(rtpp_record,
109
    .pktwrite = &rtpp_record_write
110
);
111
112
static int
113
ropen_remote_ctor_pa(struct rtpp_record_channel *rrc, struct rtpp_log *log,
114
  const char *rname, int is_rtcp)
115
0
{
116
0
    char *cp, *tmp;
117
0
    int n, port;
118
0
    struct sockaddr_storage raddr;
119
120
0
    tmp = strdup(rname + 4);
121
0
    if (tmp == NULL) {
122
0
        RTPP_ELOG(log, RTPP_LOG_ERR, "can't allocate memory");
123
0
        goto e0;
124
0
    }
125
0
    rrc->mode = MODE_REMOTE_RTP;
126
0
    rrc->needspool = 0;
127
0
    cp = strrchr(tmp, ':');
128
0
    if (cp == NULL) {
129
0
        RTPP_LOG(log, RTPP_LOG_ERR, "remote recording target specification should include port number");
130
0
        goto e1;
131
0
    }
132
0
    *cp = '\0';
133
0
    cp++;
134
135
0
    if (is_rtcp) {
136
        /* Handle RTCP (increase target port by 1) */
137
0
        port = atoi(cp);
138
0
        if (port <= 0 || port > 65534) {
139
0
            RTPP_LOG(log, RTPP_LOG_ERR, "invalid port in the remote recording target specification");
140
0
            goto e1;
141
0
        }
142
0
        sprintf(cp, "%d", port + 1);
143
0
    }
144
145
0
    n = resolve(sstosa(&raddr), AF_INET, tmp, cp, AI_PASSIVE);
146
0
    if (n != 0) {
147
0
        RTPP_LOG(log, RTPP_LOG_ERR, "ropen: getaddrinfo: %s", gai_strerror(n));
148
0
        goto e1;
149
0
    }
150
0
    rrc->fd = socket(AF_INET, SOCK_DGRAM, 0);
151
0
    if (rrc->fd == -1) {
152
0
        RTPP_ELOG(log, RTPP_LOG_ERR, "ropen: can't create socket");
153
0
        goto e1;
154
0
    }
155
0
    if (connect(rrc->fd, sstosa(&raddr), SA_LEN(sstosa(&raddr))) == -1) {
156
0
        RTPP_ELOG(log, RTPP_LOG_ERR, "ropen: can't connect socket");
157
0
        goto e2;
158
0
    }
159
0
    free(tmp);
160
0
    return (0);
161
162
0
e2:
163
0
    close(rrc->fd);
164
0
e1:
165
0
    free(tmp);
166
0
e0:
167
0
    return (-1);
168
0
}
169
170
struct rtpp_record *
171
rtpp_record_ctor(const struct rtpp_cfg *cfsp, struct rtpp_session *sp,
172
  const char *rname, int orig, int record_type)
173
0
{
174
0
    struct rtpp_record_channel *rrc;
175
0
    const char *sdir, *suffix1, *suffix2;
176
0
    int rval, remote;
177
0
    pcap_hdr_t pcap_hdr;
178
179
0
    remote = (rname != NULL && strncmp("udp:", rname, 4) == 0) ? 1 : 0;
180
181
0
    rrc = rtpp_rzmalloc(sizeof(*rrc), PVT_RCOFFS(rrc));
182
0
    if (rrc == NULL) {
183
0
  RTPP_ELOG(sp->log, RTPP_LOG_ERR, "can't allocate memory");
184
0
  goto e0;
185
0
    }
186
0
    if (pthread_mutex_init(&rrc->lock, NULL) != 0)
187
0
        goto e1;
188
189
0
    rrc->record_single_file = (record_type == RECORD_BOTH) ? 1 : 0;
190
0
    if (rrc->record_single_file != 0) {
191
0
        rrc->proto = "RTP/RTCP";
192
0
    } else {
193
0
        rrc->proto = (record_type == RECORD_RTP) ? "RTP" : "RTCP";
194
0
    }
195
0
    rrc->log = sp->log;
196
0
    RTPP_OBJ_INCREF(sp->log);
197
#if defined(RTPP_DEBUG)
198
    rrc->pub.smethods = rtpp_record_smethods;
199
#endif
200
0
    if (remote) {
201
0
  rval = ropen_remote_ctor_pa(rrc, sp->log, rname, (record_type == RECORD_RTCP));
202
0
        if (rval < 0) {
203
0
            goto e2;
204
0
        }
205
0
        CALL_SMETHOD(rrc->pub.rcnt, attach, (rtpp_refcnt_dtor_t)&rtpp_record_close,
206
0
          rrc);
207
0
        return (&rrc->pub);
208
0
    }
209
210
0
    if (cfsp->rdir == NULL) {
211
0
  RTPP_LOG(sp->log, RTPP_LOG_ERR, "directory for saving local recordings is not configured");
212
0
        goto e2;
213
0
    }
214
215
0
    if (cfsp->record_pcap != 0) {
216
0
  rrc->mode = MODE_LOCAL_PCAP;
217
0
    } else {
218
0
  rrc->mode = MODE_LOCAL_PKT;
219
0
    }
220
221
0
    if (rrc->record_single_file != 0) {
222
0
        suffix1 = suffix2 = "";
223
0
        if (rrc->mode == MODE_LOCAL_PCAP && rname == NULL) {
224
0
            suffix2 = ".pcap";
225
0
        }
226
0
    } else {
227
0
        suffix1 = (orig != 0) ? ".o" : ".a";
228
0
        suffix2 = (record_type == RECORD_RTP) ? ".rtp" : ".rtcp";
229
0
    }
230
0
    if (cfsp->sdir == NULL) {
231
0
  sdir = cfsp->rdir;
232
0
  rrc->needspool = 0;
233
0
    } else {
234
0
  sdir = cfsp->sdir;
235
0
  rrc->needspool = 1;
236
0
  if (rname == NULL) {
237
0
      sprintf(rrc->rpath, "%s/%.*s=%.*s%s%s", cfsp->rdir, (int)sp->call_id->len,
238
0
              sp->call_id->s, (int)sp->from_tag_nmn->len, sp->from_tag_nmn->s,
239
0
        suffix1, suffix2);
240
0
  } else {
241
0
      sprintf(rrc->rpath, "%s/%s%s", cfsp->rdir, rname, suffix2);
242
0
  }
243
0
    }
244
0
    if (rname == NULL) {
245
0
  sprintf(rrc->spath, "%s/%.*s=%.*s%s%s", sdir, (int)sp->call_id->len,
246
0
          sp->call_id->s, (int)sp->from_tag_nmn->len, sp->from_tag_nmn->s,
247
0
    suffix1, suffix2);
248
0
    } else {
249
0
  sprintf(rrc->spath, "%s/%s%s", sdir, rname, suffix2);
250
0
    }
251
0
    rrc->fd = open(rrc->spath, O_WRONLY | O_CREAT | O_TRUNC, DEFFILEMODE);
252
0
    if (rrc->fd == -1) {
253
0
  RTPP_ELOG(sp->log, RTPP_LOG_ERR, "can't open file %s for writing",
254
0
    rrc->spath);
255
0
        goto e2;
256
0
    }
257
258
0
    if (rrc->mode == MODE_LOCAL_PCAP) {
259
0
  pcap_hdr.magic_number = PCAP_MAGIC;
260
0
  pcap_hdr.version_major = PCAP_VER_MAJR;
261
0
  pcap_hdr.version_minor = PCAP_VER_MINR;
262
0
  pcap_hdr.thiszone = 0;
263
0
  pcap_hdr.sigfigs = 0;
264
0
  pcap_hdr.snaplen = 65535;
265
0
  pcap_hdr.network = PCAP_FORMAT;
266
0
  rval = write(rrc->fd, &pcap_hdr, sizeof(pcap_hdr));
267
0
  if (rval == -1) {
268
0
      RTPP_ELOG(sp->log, RTPP_LOG_ERR, "%s: error writing header",
269
0
        rrc->spath);
270
0
            goto e3;
271
0
  }
272
0
  if (rval < sizeof(pcap_hdr)) {
273
0
      RTPP_LOG(sp->log, RTPP_LOG_ERR, "%s: short write writing header",
274
0
        rrc->spath);
275
0
            goto e3;
276
0
  }
277
0
    }
278
279
0
    CALL_SMETHOD(rrc->pub.rcnt, attach, (rtpp_refcnt_dtor_t)&rtpp_record_close,
280
0
      rrc);
281
0
    return (&rrc->pub);
282
283
0
e3:
284
0
    close(rrc->fd);
285
0
e2:
286
0
    RTPP_OBJ_DECREF(rrc->log);
287
0
    RTPP_OBJ_DECREF(&(rrc->pub));
288
0
    pthread_mutex_destroy(&rrc->lock);
289
0
e1:
290
0
    free(rrc);
291
0
e0:
292
0
    return NULL;
293
0
}
294
295
static int
296
flush_rbuf(struct rtpp_record_channel *rrc)
297
0
{
298
0
    int rval;
299
300
0
    rval = write(rrc->fd, rrc->rbuf, rrc->rbuf_len);
301
0
    if (rval != -1) {
302
0
  rrc->rbuf_len = 0;
303
0
  return 0;
304
0
    }
305
306
0
    RTPP_ELOG(rrc->log, RTPP_LOG_ERR, "error while recording session (%s)",
307
0
      rrc->proto);
308
    /* Prevent futher writing if error happens */
309
0
    close(rrc->fd);
310
0
    rrc->fd = -1;
311
0
    return -1;
312
0
}
313
314
union anyhdr {
315
    union pkt_hdr_pcap pcap;
316
    struct pkt_hdr_adhoc adhoc;
317
};
318
319
struct prepare_pkt_hdr_args {
320
    const struct rtp_packet *packet;
321
    union anyhdr *hdrp;
322
    const struct sockaddr *daddr;
323
    const struct sockaddr *ldaddr;
324
    int ldport;
325
    int face;
326
    double atime_wall;
327
};
328
329
DEFINE_RAW_METHOD(prepare_pkt_hdr, int, const struct prepare_pkt_hdr_args *);
330
331
static int
332
prepare_pkt_hdr_adhoc(const struct prepare_pkt_hdr_args *phap)
333
0
{
334
0
    struct pkt_hdr_adhoc *ap;
335
336
0
    ap = &(phap->hdrp->adhoc);
337
0
    memset(ap, 0, sizeof(*ap));
338
0
    ap->time = phap->atime_wall;
339
0
    switch (sstosa(&phap->packet->raddr)->sa_family) {
340
0
    case AF_INET:
341
0
  ap->addr.in4.sin_family = sstosa(&phap->packet->raddr)->sa_family;
342
0
  ap->addr.in4.sin_port = satosin(&phap->packet->raddr)->sin_port;
343
0
  ap->addr.in4.sin_addr = satosin(&phap->packet->raddr)->sin_addr;
344
0
  break;
345
346
0
    case AF_INET6:
347
0
  ap->addr.in6.sin_family = sstosa(&phap->packet->raddr)->sa_family;
348
0
  ap->addr.in6.sin_port = satosin6(&phap->packet->raddr)->sin6_port;
349
0
  ap->addr.in6.sin_addr = satosin6(&phap->packet->raddr)->sin6_addr;
350
0
  break;
351
352
0
    default:
353
0
  abort();
354
0
    }
355
356
0
    ap->plen = phap->packet->size;
357
0
    return 0;
358
0
}
359
360
static uint16_t ip_id = 0;
361
362
#if (PCAP_FORMAT != DLT_NULL)
363
static void
364
fake_ether_addr(const struct sockaddr *addr, uint8_t *eaddr)
365
0
{
366
0
    uint8_t *ra;
367
0
    int i;
368
369
0
    switch (addr->sa_family) {
370
0
    case AF_INET:
371
0
        eaddr[0] = eaddr[1] = 0;
372
0
        memcpy(eaddr + 2, &(satosin(addr)->sin_addr), 4);
373
0
        return;
374
375
0
    case AF_INET6:
376
0
        ra = &satosin6(addr)->sin6_addr.s6_addr[0];
377
0
        memcpy(eaddr, ra, 6);
378
0
        for (i = 6; i < sizeof(struct in6_addr); i++) {
379
0
            eaddr[i % 6] ^= ra[i];
380
0
        }
381
0
        return;
382
383
0
    default:
384
0
        break;
385
0
    }
386
0
    abort();
387
0
}
388
#endif
389
390
static int
391
prepare_pkt_hdr_pcap(const struct prepare_pkt_hdr_args *phap)
392
0
{
393
0
    const struct sockaddr *src_addr, *dst_addr;
394
0
    uint16_t src_port, dst_port;
395
0
    pcaprec_hdr_t phd;
396
0
    union {
397
0
        struct ip6_hdr *v6;
398
0
        struct ip *v4;
399
0
    } ipp;
400
0
    struct udphdr *udp;
401
0
    int pcap_size;
402
0
    struct timeval rtimeval;
403
0
#if (PCAP_FORMAT != DLT_NULL)
404
0
    struct sockaddr_storage tmp_addr;
405
0
    struct layer2_hdr *ether;
406
0
#endif
407
408
0
    if (phap->face == 0) {
409
0
        src_addr = sstosa(&(phap->packet->raddr));
410
0
        src_port = getnport(src_addr);
411
0
        dst_addr = phap->packet->laddr;
412
0
        dst_port = htons(phap->packet->lport);
413
0
    } else {
414
0
        src_addr = phap->ldaddr;
415
0
        src_port = htons(phap->ldport);
416
0
        dst_addr = phap->daddr;
417
0
        dst_port = getnport(dst_addr);
418
0
    }
419
420
#if 0
421
    if (src_addr->sa_family != AF_INET) {
422
  RTPP_ELOG(phap->log, RTPP_LOG_ERR, "only AF_INET pcap format is supported");
423
  return -1;
424
    }
425
#endif
426
427
0
    union pkt_hdr_pcap *pcp = &(phap->hdrp->pcap);
428
0
    memset(pcp, 0, get_hdr_size(src_addr));
429
0
    memset(&phd, 0, sizeof(phd));
430
431
#if (PCAP_FORMAT == DLT_NULL)
432
    pcap_size = (src_addr->sa_family == AF_INET) ? sizeof(pcp->null) :
433
      sizeof(pcp->null_v6);
434
#else
435
0
    pcap_size = (src_addr->sa_family == AF_INET) ? sizeof(pcp->en10t) :
436
0
       sizeof(pcp->en10t_v6);
437
0
#endif
438
439
0
    dtime2timeval(phap->atime_wall, &rtimeval);
440
441
0
    RTPP_DBG_ASSERT(SEC(&rtimeval) > 0 && SEC(&rtimeval) <= UINT32_MAX);
442
0
    RTPP_DBG_ASSERT(USEC(&rtimeval) < USEC_MAX);
443
444
0
    phd.ts_sec = SEC(&rtimeval);
445
0
    phd.ts_usec = USEC(&rtimeval);
446
0
    phd.orig_len = phd.incl_len = pcap_size -
447
0
      sizeof(phd) + phap->packet->size;
448
449
#if (PCAP_FORMAT == DLT_NULL)
450
    if (src_addr->sa_family == AF_INET) {
451
        memcpy(&pcp->null.pcaprec_hdr, &phd, sizeof(phd));
452
        pcp->null.family = src_addr->sa_family;
453
        ipp.v4 = &(pcp->null.udpip.iphdr);
454
        udp = &(pcp->null.udpip.udphdr);
455
    } else {
456
        memcpy(&pcp->null_v6.pcaprec_hdr, &phd, sizeof(phd));
457
        pcp->null_v6.family = src_addr->sa_family;
458
        ipp.v6 = &(pcp->null_v6.udpip6.iphdr);
459
        udp = &(pcp->null_v6.udpip6.udphdr);
460
    }
461
#else
462
    /* Prepare fake ethernet header */
463
0
    if (src_addr->sa_family == AF_INET) {
464
0
        memcpy(&pcp->en10t.pcaprec_hdr, &phd, sizeof(phd));
465
0
        ether = &pcp->en10t.ether;
466
0
        ether->type = ETHERTYPE_INET;
467
0
        udp = &(pcp->en10t.udpip.udphdr);
468
0
        ipp.v4 = &(pcp->en10t.udpip.iphdr);
469
0
    } else {
470
0
        memcpy(&pcp->en10t_v6.pcaprec_hdr, &phd, sizeof(phd));
471
0
        ether = &pcp->en10t_v6.ether;
472
0
        ether->type = ETHERTYPE_INET6;
473
0
        udp = &(pcp->en10t_v6.udpip6.udphdr);
474
0
        ipp.v6 = &(pcp->en10t_v6.udpip6.iphdr);
475
0
    }
476
0
    if (phap->face == 0 && ishostnull(dst_addr) && !ishostnull(src_addr)) {
477
0
        if (local4remote(src_addr, &tmp_addr) == 0) {
478
0
            dst_addr = sstosa(&tmp_addr);
479
0
        } else {
480
0
            return -1;
481
0
        }
482
0
    }
483
0
    fake_ether_addr(dst_addr, ether->dhost);
484
0
    if (phap->face != 0 && ishostnull(src_addr) && !ishostnull(dst_addr)) {
485
0
        if (local4remote(dst_addr, &tmp_addr) == 0) {
486
0
            src_addr = sstosa(&tmp_addr);
487
0
        } else {
488
0
            return -1;
489
0
        }
490
0
    }
491
0
    fake_ether_addr(src_addr, ether->shost);
492
0
#endif
493
494
    /* Prepare fake IP header */
495
0
    if (src_addr->sa_family == AF_INET) {
496
0
        ipp.v4->ip_v = 4;
497
0
        ipp.v4->ip_hl = sizeof(*ipp.v4) >> 2;
498
0
        ipp.v4->ip_len = htons(sizeof(*ipp.v4) + sizeof(*udp) + phap->packet->size);
499
0
        ipp.v4->ip_src = satosin(src_addr)->sin_addr;
500
0
        ipp.v4->ip_dst = satosin(dst_addr)->sin_addr;
501
0
        ipp.v4->ip_p = IPPROTO_UDP;
502
0
        ipp.v4->ip_id = htons(ip_id++);
503
0
        ipp.v4->ip_ttl = 127;
504
0
        ipp.v4->ip_sum = rtpp_in_cksum(ipp.v4, sizeof(*ipp.v4));
505
0
    } else {
506
0
        ipp.v6->ip6_vfc |= IPV6_VERSION;
507
0
        ipp.v6->ip6_hlim = IPV6_DEFHLIM;
508
0
        ipp.v6->ip6_nxt = IPPROTO_UDP;
509
0
        ipp.v6->ip6_src = satosin6(src_addr)->sin6_addr;
510
0
        ipp.v6->ip6_dst = satosin6(dst_addr)->sin6_addr;
511
0
        ipp.v6->ip6_plen = htons(sizeof(*udp) + phap->packet->size);
512
0
    }
513
514
    /* Prepare fake UDP header */
515
0
    udp->uh_sport = src_port;
516
0
    udp->uh_dport = dst_port;
517
0
    udp->uh_ulen = htons(sizeof(*udp) + phap->packet->size);
518
519
0
    rtpp_ip_chksum_start();
520
0
    if (src_addr->sa_family == AF_INET) {
521
0
        rtpp_ip_chksum_update(&(ipp.v4->ip_src), sizeof(ipp.v4->ip_src));
522
0
        rtpp_ip_chksum_update(&(ipp.v4->ip_dst), sizeof(ipp.v4->ip_dst));
523
0
        rtpp_ip_chksum_pad_v4();
524
0
        rtpp_ip_chksum_update(&(udp->uh_ulen), sizeof(udp->uh_ulen));
525
0
    } else {
526
0
        uint32_t ulen32 = htonl(sizeof(*udp) + phap->packet->size);
527
528
0
        rtpp_ip_chksum_update(&ipp.v6->ip6_src, sizeof(ipp.v6->ip6_src));
529
0
        rtpp_ip_chksum_update(&ipp.v6->ip6_dst, sizeof(ipp.v6->ip6_dst));
530
0
        rtpp_ip_chksum_update(&ulen32, sizeof(ulen32));
531
0
        rtpp_ip_chksum_pad_v6();
532
0
    }
533
0
    rtpp_ip_chksum_update(&(udp->uh_sport), sizeof(udp->uh_sport));
534
0
    rtpp_ip_chksum_update(&(udp->uh_dport), sizeof(udp->uh_dport));
535
0
    rtpp_ip_chksum_update(&(udp->uh_ulen), sizeof(udp->uh_ulen));
536
0
    rtpp_ip_chksum_update_data(phap->packet->data.buf, phap->packet->size);
537
0
    rtpp_ip_chksum_fin(udp->uh_sum);
538
539
0
    return 0;
540
0
}
541
542
static int
543
get_hdr_size(const struct sockaddr *raddr)
544
0
{
545
0
    int hdr_size;
546
547
#if (PCAP_FORMAT == DLT_NULL)
548
    if (raddr->sa_family == AF_INET) {
549
        hdr_size = sizeof(struct pkt_hdr_pcap_null);
550
    } else {
551
        hdr_size = sizeof(struct pkt_hdr_pcap_null_v6);
552
    }
553
#else
554
0
    if (raddr->sa_family == AF_INET) {
555
0
        hdr_size = sizeof(struct pkt_hdr_pcap_en10t);
556
0
    } else {
557
0
        hdr_size = sizeof(struct pkt_hdr_pcap_en10t_v6);
558
0
    }
559
0
#endif
560
0
    return (hdr_size);
561
0
}
562
563
static void
564
rtpp_record_write_locked(struct rtpp_record_channel *rrc, const struct pkt_proc_ctx *pktxp)
565
0
{
566
0
    struct iovec v[2];
567
0
    int rval, hdr_size;
568
0
    prepare_pkt_hdr_t prepare_pkt_hdr;
569
0
    const char *proto;
570
0
    struct sockaddr_storage daddr;
571
0
    struct rtpp_netaddr *rem_addr;
572
0
    struct rtp_packet *packet = pktxp->pktp;
573
0
    struct rtpp_stream *stp = pktxp->strmp_out;
574
575
0
    if (rrc->fd == -1)
576
0
  return;
577
578
0
    rem_addr = CALL_SMETHOD(stp, get_rem_addr, 0);
579
0
    if (rem_addr == NULL) {
580
0
        return;
581
0
    }
582
0
    CALL_SMETHOD(rem_addr, get, sstosa(&daddr), sizeof(daddr));
583
0
    RTPP_OBJ_DECREF(rem_addr);
584
585
0
    if (packet->rtime.wall == -1) {
586
0
        RTPP_ELOG(stp->log, RTPP_LOG_ERR, "can't get current time");
587
0
    }
588
589
0
    if (rrc->epoch.wall == 0) {
590
0
        rrc->epoch = packet->rtime;
591
0
    }
592
593
0
    switch (rrc->mode) {
594
0
    case MODE_REMOTE_RTP:
595
0
  send(rrc->fd, packet->data.buf, packet->size, 0);
596
0
  return;
597
598
0
    case MODE_LOCAL_PKT:
599
0
  hdr_size = sizeof(struct pkt_hdr_adhoc);
600
0
  prepare_pkt_hdr = &prepare_pkt_hdr_adhoc;
601
0
  break;
602
603
0
    case MODE_LOCAL_PCAP:
604
0
        hdr_size = get_hdr_size(sstosa(&packet->raddr));
605
0
  prepare_pkt_hdr = &prepare_pkt_hdr_pcap;
606
0
  break;
607
608
0
    default:
609
        /* Should not happen */
610
0
        abort();
611
0
    }
612
613
    /* Check if the write buffer has necessary space, and flush if not */
614
0
    if ((rrc->rbuf_len + hdr_size + packet->size > sizeof(rrc->rbuf)) && rrc->rbuf_len > 0)
615
0
  if (flush_rbuf(rrc) != 0)
616
0
      return;
617
618
0
    struct prepare_pkt_hdr_args pargs = {
619
0
      .packet = packet,
620
0
      .ldaddr = stp->laddr,
621
0
      .ldport = stp->port,
622
0
      .daddr = sstosa(&daddr),
623
0
      .face = (rrc->record_single_file == 0) ? 0 : (stp->pipe_type != PIPE_RTP),
624
0
      .atime_wall = ARRIVAL_TIME(rrc, packet)
625
0
    };
626
627
    /* Check if received packet doesn't fit into the buffer, do synchronous write  if so */
628
0
    if (rrc->rbuf_len + hdr_size + packet->size > sizeof(rrc->rbuf)) {
629
0
        union anyhdr hdr;
630
0
        pargs.hdrp = &hdr;
631
632
0
  if (prepare_pkt_hdr(&pargs) != 0)
633
0
      return;
634
635
0
  v[0].iov_base = (void *)&hdr;
636
0
  v[0].iov_len = hdr_size;
637
0
  v[1].iov_base = packet->data.buf;
638
0
  v[1].iov_len = packet->size;
639
640
0
  rval = writev(rrc->fd, v, 2);
641
0
  if (rval != -1)
642
0
      return;
643
644
0
        proto = CALL_SMETHOD(stp, get_proto);
645
0
  RTPP_ELOG(stp->log, RTPP_LOG_ERR, "error while recording session (%s)",
646
0
    proto);
647
  /* Prevent futher writing if error happens */
648
0
  close(rrc->fd);
649
0
  rrc->fd = -1;
650
0
  return;
651
0
    }
652
0
    pargs.hdrp = (void *)rrc->rbuf + rrc->rbuf_len;
653
0
    if (prepare_pkt_hdr(&pargs) != 0)
654
0
  return;
655
0
    rrc->rbuf_len += hdr_size;
656
0
    memcpy(rrc->rbuf + rrc->rbuf_len, packet->data.buf, packet->size);
657
0
    rrc->rbuf_len += packet->size;
658
0
}
659
660
static void
661
rtpp_record_write(struct rtpp_record *self, const struct pkt_proc_ctx *pktxp)
662
0
{
663
0
    struct rtpp_record_channel *rrc;
664
665
0
    PUB2PVT(self, rrc);
666
0
    pthread_mutex_lock(&rrc->lock);
667
0
    rtpp_record_write_locked(rrc, pktxp);
668
0
    pthread_mutex_unlock(&rrc->lock);
669
0
}
670
671
static void
672
rtpp_record_close(struct rtpp_record_channel *rrc)
673
0
{
674
0
    static int keep = 1;
675
676
0
    rtpp_record_fin(&rrc->pub);
677
0
    if (rrc->mode != MODE_REMOTE_RTP && rrc->rbuf_len > 0)
678
0
  flush_rbuf(rrc);
679
680
0
    if (rrc->fd != -1)
681
0
  close(rrc->fd);
682
683
0
    if (rrc->mode == MODE_REMOTE_RTP)
684
0
  goto done;
685
686
0
    if (keep == 0) {
687
0
  if (unlink(rrc->spath) == -1)
688
0
      RTPP_ELOG(rrc->log, RTPP_LOG_ERR, "can't remove "
689
0
        "session record %s", rrc->spath);
690
0
    } else if (rrc->needspool == 1) {
691
0
  if (rename(rrc->spath, rrc->rpath) == -1)
692
0
      RTPP_ELOG(rrc->log, RTPP_LOG_ERR, "can't move "
693
0
        "session record from spool into permanent storage");
694
0
    }
695
0
done:
696
0
    RTPP_OBJ_DECREF(rrc->log);
697
0
    pthread_mutex_destroy(&rrc->lock);
698
0
    free(rrc);
699
0
}