~siretart/libav/trusty-security

« back to all changes in this revision

Viewing changes to avserver.c

  • Committer: Package Import Robot
  • Author(s): Reinhard Tartler
  • Date: 2013-10-22 23:24:08 UTC
  • mfrom: (1.3.36 sid)
  • Revision ID: package-import@ubuntu.com-20131022232408-b8tvvn4pyzri9mi3
Tags: 6:9.10-1ubuntu1
* Build all -extra flavors from this source package, as libav got demoted
  from main to universe, cf LP: #1243235
* Simplify debian/rules to follow exactly the code that debian executes
* New upstream (LP: #1180288) fixes lots of security issues (LP: #1242802)
* Merge from unstable, remaining changes:
  - build-depend on libtiff5-dev rather than libtiff4-dev,
    avoids FTBFS caused by imlib
  - follow the regular debian codepaths

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
#endif
26
26
#include <string.h>
27
27
#include <stdlib.h>
 
28
#include <stdio.h>
28
29
#include "libavformat/avformat.h"
 
30
// FIXME those are internal headers, avserver _really_ shouldn't use them
29
31
#include "libavformat/ffm.h"
30
32
#include "libavformat/network.h"
31
33
#include "libavformat/os_support.h"
32
34
#include "libavformat/rtpdec.h"
33
35
#include "libavformat/rtsp.h"
34
 
// XXX for ffio_open_dyn_packet_buffer, to be removed
35
36
#include "libavformat/avio_internal.h"
 
37
#include "libavformat/internal.h"
 
38
#include "libavformat/url.h"
 
39
 
36
40
#include "libavutil/avstring.h"
37
41
#include "libavutil/lfg.h"
38
42
#include "libavutil/dict.h"
 
43
#include "libavutil/intreadwrite.h"
39
44
#include "libavutil/mathematics.h"
40
45
#include "libavutil/random_seed.h"
41
46
#include "libavutil/parseutils.h"
42
47
#include "libavutil/opt.h"
 
48
#include "libavutil/time.h"
 
49
 
43
50
#include <stdarg.h>
44
51
#include <unistd.h>
45
52
#include <fcntl.h>
48
55
#include <poll.h>
49
56
#endif
50
57
#include <errno.h>
51
 
#include <sys/time.h>
52
58
#include <time.h>
53
59
#include <sys/wait.h>
54
60
#include <signal.h>
296
302
                             HTTPContext *rtsp_c);
297
303
 
298
304
static const char *my_program_name;
299
 
static const char *my_program_dir;
300
305
 
301
306
static const char *config_filename = "/etc/avserver.conf";
302
307
 
303
308
static int avserver_debug;
304
 
static int avserver_daemon;
305
309
static int no_launch;
306
310
static int need_to_start_children;
307
311
 
319
323
 
320
324
static FILE *logfile = NULL;
321
325
 
322
 
void exit_program(int ret)
323
 
{
324
 
    exit(ret);
 
326
static int64_t ffm_read_write_index(int fd)
 
327
{
 
328
    uint8_t buf[8];
 
329
 
 
330
    lseek(fd, 8, SEEK_SET);
 
331
    if (read(fd, buf, 8) != 8)
 
332
        return AVERROR(EIO);
 
333
    return AV_RB64(buf);
 
334
}
 
335
 
 
336
static int ffm_write_write_index(int fd, int64_t pos)
 
337
{
 
338
    uint8_t buf[8];
 
339
    int i;
 
340
 
 
341
    for(i=0;i<8;i++)
 
342
        buf[i] = (pos >> (56 - i * 8)) & 0xff;
 
343
    lseek(fd, 8, SEEK_SET);
 
344
    if (write(fd, buf, 8) != 8)
 
345
        return AVERROR(EIO);
 
346
    return 8;
 
347
}
 
348
 
 
349
static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
 
350
                                int64_t file_size)
 
351
{
 
352
    FFMContext *ffm = s->priv_data;
 
353
    ffm->write_index = pos;
 
354
    ffm->file_size = file_size;
325
355
}
326
356
 
327
357
/* FIXME: make avserver work with IPv6 */
332
362
    if (!ff_inet_aton(hostname, sin_addr)) {
333
363
#if HAVE_GETADDRINFO
334
364
        struct addrinfo *ai, *cur;
335
 
        struct addrinfo hints;
336
 
        memset(&hints, 0, sizeof(hints));
 
365
        struct addrinfo hints = { 0 };
337
366
        hints.ai_family = AF_INET;
338
367
        if (getaddrinfo(hostname, NULL, &hints, &ai))
339
368
            return -1;
485
514
                    close(i);
486
515
 
487
516
                if (!avserver_debug) {
488
 
                    i = open("/dev/null", O_RDWR);
489
 
                    if (i != -1) {
490
 
                        dup2(i, 0);
491
 
                        dup2(i, 1);
492
 
                        dup2(i, 2);
493
 
                        close(i);
494
 
                    }
 
517
                    if (!freopen("/dev/null", "r", stdin))
 
518
                        http_log("failed to redirect STDIN to /dev/null\n;");
 
519
                    if (!freopen("/dev/null", "w", stdout))
 
520
                        http_log("failed to redirect STDOUT to /dev/null\n;");
 
521
                    if (!freopen("/dev/null", "w", stderr))
 
522
                        http_log("failed to redirect STDERR to /dev/null\n;");
495
523
                }
496
524
 
497
 
                /* This is needed to make relative pathnames work */
498
 
                chdir(my_program_dir);
499
 
 
500
525
                signal(SIGPIPE, SIG_DFL);
501
526
 
502
527
                execvp(pathname, feed->child_argv);
769
794
static void new_connection(int server_fd, int is_rtsp)
770
795
{
771
796
    struct sockaddr_in from_addr;
772
 
    int fd, len;
 
797
    socklen_t len;
 
798
    int fd;
773
799
    HTTPContext *c = NULL;
774
800
 
775
801
    len = sizeof(from_addr);
867
893
        }
868
894
        h = c->rtp_handles[i];
869
895
        if (h)
870
 
            url_close(h);
 
896
            ffurl_close(h);
871
897
    }
872
898
 
873
899
    ctx = &c->fmt_ctx;
1452
1478
/* parse http request and prepare header */
1453
1479
static int http_parse_request(HTTPContext *c)
1454
1480
{
1455
 
    char *p;
 
1481
    const char *p;
 
1482
    char *p1;
1456
1483
    enum RedirType redir_type;
1457
1484
    char cmd[32];
1458
1485
    char info[1024], filename[1024];
1463
1490
    FFStream *stream;
1464
1491
    int i;
1465
1492
    char ratebuf[32];
1466
 
    char *useragent = 0;
 
1493
    const char *useragent = 0;
1467
1494
 
1468
1495
    p = c->buffer;
1469
 
    get_word(cmd, sizeof(cmd), (const char **)&p);
 
1496
    get_word(cmd, sizeof(cmd), &p);
1470
1497
    av_strlcpy(c->method, cmd, sizeof(c->method));
1471
1498
 
1472
1499
    if (!strcmp(cmd, "GET"))
1476
1503
    else
1477
1504
        return -1;
1478
1505
 
1479
 
    get_word(url, sizeof(url), (const char **)&p);
 
1506
    get_word(url, sizeof(url), &p);
1480
1507
    av_strlcpy(c->url, url, sizeof(c->url));
1481
1508
 
1482
1509
    get_word(protocol, sizeof(protocol), (const char **)&p);
1489
1516
        http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1490
1517
 
1491
1518
    /* find the filename and the optional info string in the request */
1492
 
    p = strchr(url, '?');
1493
 
    if (p) {
1494
 
        av_strlcpy(info, p, sizeof(info));
1495
 
        *p = '\0';
 
1519
    p1 = strchr(url, '?');
 
1520
    if (p1) {
 
1521
        av_strlcpy(info, p1, sizeof(info));
 
1522
        *p1 = '\0';
1496
1523
    } else
1497
1524
        info[0] = '\0';
1498
1525
 
1609
1636
    }
1610
1637
 
1611
1638
    if (redir_type != REDIR_NONE) {
1612
 
        char *hostinfo = 0;
 
1639
        const char *hostinfo = 0;
1613
1640
 
1614
1641
        for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1615
1642
            if (av_strncasecmp(p, "Host:", 5) == 0) {
1687
1714
                    case REDIR_SDP:
1688
1715
                        {
1689
1716
                            uint8_t *sdp_data;
1690
 
                            int sdp_data_size, len;
 
1717
                            int sdp_data_size;
 
1718
                            socklen_t len;
1691
1719
                            struct sockaddr_in my_addr;
1692
1720
 
1693
1721
                            q += snprintf(q, c->buffer_size,
1737
1765
        if (!stream->is_feed) {
1738
1766
            /* However it might be a status report from WMP! Let us log the
1739
1767
             * data as it might come in handy one day. */
1740
 
            char *logline = 0;
 
1768
            const char *logline = 0;
1741
1769
            int client_id = 0;
1742
1770
 
1743
1771
            for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1862
1890
 
1863
1891
static void fmt_bytecount(AVIOContext *pb, int64_t count)
1864
1892
{
1865
 
    static const char *suffix = " kMGTP";
 
1893
    static const char suffix[] = " kMGTP";
1866
1894
    const char *s;
1867
1895
 
1868
1896
    for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
2248
2276
         * Default value from Libav
2249
2277
         * Try to set it use configuration option
2250
2278
         */
2251
 
        c->fmt_ctx.preload   = (int)(0.5*AV_TIME_BASE);
2252
2279
        c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2253
2280
 
2254
2281
        if (avformat_write_header(&c->fmt_ctx, NULL) < 0) {
2367
2394
                        if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2368
2395
                            max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2369
2396
                        else
2370
 
                            max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
 
2397
                            max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2371
2398
                        ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2372
2399
                    } else {
2373
2400
                        ret = avio_open_dyn_buf(&ctx->pb);
2520
2547
                } else {
2521
2548
                    /* send RTP packet directly in UDP */
2522
2549
                    c->buffer_ptr += 4;
2523
 
                    url_write(c->rtp_handles[c->packet_stream_index],
2524
 
                              c->buffer_ptr, len);
 
2550
                    ffurl_write(c->rtp_handles[c->packet_stream_index],
 
2551
                                c->buffer_ptr, len);
2525
2552
                    c->buffer_ptr += len;
2526
2553
                    /* here we continue as we can send several packets per 10 ms slot */
2527
2554
                }
2571
2598
    if (c->stream->truncate) {
2572
2599
        /* truncate feed file */
2573
2600
        ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2574
 
        ftruncate(c->feed_fd, FFM_PACKET_SIZE);
2575
2601
        http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
 
2602
        if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
 
2603
            http_log("Error truncating feed file: %s\n", strerror(errno));
 
2604
            return -1;
 
2605
        }
2576
2606
    } else {
2577
2607
        if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2578
2608
            http_log("Error reading write index from feed file: %s\n", strerror(errno));
2658
2688
        /* a packet has been received : write it in the store, except
2659
2689
           if header */
2660
2690
        if (c->data_count > FFM_PACKET_SIZE) {
2661
 
 
2662
 
            //            printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2663
2691
            /* XXX: use llseek or url_seek */
2664
2692
            lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2665
2693
            if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2820
2848
    char protocol[32];
2821
2849
    char line[1024];
2822
2850
    int len;
2823
 
    RTSPMessageHeader header1, *header = &header1;
 
2851
    RTSPMessageHeader header1 = { 0 }, *header = &header1;
2824
2852
 
2825
2853
    c->buffer_ptr[0] = '\0';
2826
2854
    p = c->buffer;
2846
2874
    }
2847
2875
 
2848
2876
    /* parse each header line */
2849
 
    memset(header, 0, sizeof(*header));
2850
2877
    /* skip to next line */
2851
2878
    while (*p != '\n' && *p != '\0')
2852
2879
        p++;
2962
2989
    char path1[1024];
2963
2990
    const char *path;
2964
2991
    uint8_t *content;
2965
 
    int content_length, len;
 
2992
    int content_length;
 
2993
    socklen_t len;
2966
2994
    struct sockaddr_in my_addr;
2967
2995
 
2968
2996
    /* find which url is asked */
3404
3432
                     "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3405
3433
        }
3406
3434
 
3407
 
        if (url_open(&h, ctx->filename, AVIO_FLAG_WRITE) < 0)
 
3435
        if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3408
3436
            goto fail;
3409
3437
        c->rtp_handles[stream_index] = h;
3410
 
        max_packet_size = url_get_max_packet_size(h);
 
3438
        max_packet_size = h->max_packet_size;
3411
3439
        break;
3412
3440
    case RTSP_LOWER_TRANSPORT_TCP:
3413
3441
        /* RTP/TCP case */
3430
3458
    if (avformat_write_header(ctx, NULL) < 0) {
3431
3459
    fail:
3432
3460
        if (h)
3433
 
            url_close(h);
 
3461
            ffurl_close(h);
3434
3462
        av_free(ctx);
3435
3463
        return -1;
3436
3464
    }
3467
3495
    }
3468
3496
    fst->priv_data = av_mallocz(sizeof(FeedData));
3469
3497
    fst->index = stream->nb_streams;
3470
 
    av_set_pts_info(fst, 33, 1, 90000);
 
3498
    avpriv_set_pts_info(fst, 33, 1, 90000);
3471
3499
    fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3472
3500
    stream->streams[stream->nb_streams++] = fst;
3473
3501
    return fst;
3534
3562
    AVStream *st;
3535
3563
    const uint8_t *p;
3536
3564
 
 
3565
    infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
 
3566
 
3537
3567
    mpeg4_count = 0;
3538
3568
    for(i=0;i<infile->nb_streams;i++) {
3539
3569
        st = infile->streams[i];
3540
 
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
 
3570
        if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3541
3571
            st->codec->extradata_size == 0) {
3542
3572
            mpeg4_count++;
3543
3573
        }
3547
3577
 
3548
3578
    printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3549
3579
    while (mpeg4_count > 0) {
3550
 
        if (av_read_packet(infile, &pkt) < 0)
 
3580
        if (av_read_frame(infile, &pkt) < 0)
3551
3581
            break;
3552
3582
        st = infile->streams[pkt.stream_index];
3553
 
        if (st->codec->codec_id == CODEC_ID_MPEG4 &&
 
3583
        if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3554
3584
            st->codec->extradata_size == 0) {
3555
3585
            av_freep(&st->codec->extradata);
3556
3586
            /* fill extradata with the header */
3864
3894
    memcpy(st->codec, av, sizeof(AVCodecContext));
3865
3895
}
3866
3896
 
3867
 
static enum CodecID opt_audio_codec(const char *arg)
 
3897
static enum AVCodecID opt_audio_codec(const char *arg)
3868
3898
{
3869
3899
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3870
3900
 
3871
3901
    if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3872
 
        return CODEC_ID_NONE;
 
3902
        return AV_CODEC_ID_NONE;
3873
3903
 
3874
3904
    return p->id;
3875
3905
}
3876
3906
 
3877
 
static enum CodecID opt_video_codec(const char *arg)
 
3907
static enum AVCodecID opt_video_codec(const char *arg)
3878
3908
{
3879
3909
    AVCodec *p= avcodec_find_encoder_by_name(arg);
3880
3910
 
3881
3911
    if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
3882
 
        return CODEC_ID_NONE;
 
3912
        return AV_CODEC_ID_NONE;
3883
3913
 
3884
3914
    return p->id;
3885
3915
}
3922
3952
 
3923
3953
static int avserver_opt_preset(const char *arg,
3924
3954
                       AVCodecContext *avctx, int type,
3925
 
                       enum CodecID *audio_id, enum CodecID *video_id)
 
3955
                       enum AVCodecID *audio_id, enum AVCodecID *video_id)
3926
3956
{
3927
3957
    FILE *f=NULL;
3928
3958
    char filename[1000], tmp[1000], tmp2[1000], line[1000];
4004
4034
    FFStream **last_stream, *stream, *redirect;
4005
4035
    FFStream **last_feed, *feed, *s;
4006
4036
    AVCodecContext audio_enc, video_enc;
4007
 
    enum CodecID audio_id, video_id;
 
4037
    enum AVCodecID audio_id, video_id;
4008
4038
 
4009
4039
    f = fopen(filename, "r");
4010
4040
    if (!f) {
4021
4051
    stream = NULL;
4022
4052
    feed = NULL;
4023
4053
    redirect = NULL;
4024
 
    audio_id = CODEC_ID_NONE;
4025
 
    video_id = CODEC_ID_NONE;
 
4054
    audio_id = AV_CODEC_ID_NONE;
 
4055
    video_id = AV_CODEC_ID_NONE;
4026
4056
 
4027
4057
#define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
4028
4058
    for(;;) {
4049
4079
            if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4050
4080
                ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4051
4081
            }
4052
 
        } else if (!av_strcasecmp(cmd, "NoDaemon")) {
4053
 
            avserver_daemon = 0;
4054
4082
        } else if (!av_strcasecmp(cmd, "RTSPPort")) {
4055
4083
            get_arg(arg, sizeof(arg), &p);
4056
4084
            val = atoi(arg);
4214
4242
                stream->fmt = avserver_guess_format(NULL, stream->filename, NULL);
4215
4243
                avcodec_get_context_defaults3(&video_enc, NULL);
4216
4244
                avcodec_get_context_defaults3(&audio_enc, NULL);
4217
 
                audio_id = CODEC_ID_NONE;
4218
 
                video_id = CODEC_ID_NONE;
 
4245
                audio_id = AV_CODEC_ID_NONE;
 
4246
                video_id = AV_CODEC_ID_NONE;
4219
4247
                if (stream->fmt) {
4220
4248
                    audio_id = stream->fmt->audio_codec;
4221
4249
                    video_id = stream->fmt->video_codec;
4297
4325
        } else if (!av_strcasecmp(cmd, "AudioCodec")) {
4298
4326
            get_arg(arg, sizeof(arg), &p);
4299
4327
            audio_id = opt_audio_codec(arg);
4300
 
            if (audio_id == CODEC_ID_NONE) {
 
4328
            if (audio_id == AV_CODEC_ID_NONE) {
4301
4329
                ERROR("Unknown AudioCodec: %s\n", arg);
4302
4330
            }
4303
4331
        } else if (!av_strcasecmp(cmd, "VideoCodec")) {
4304
4332
            get_arg(arg, sizeof(arg), &p);
4305
4333
            video_id = opt_video_codec(arg);
4306
 
            if (video_id == CODEC_ID_NONE) {
 
4334
            if (video_id == AV_CODEC_ID_NONE) {
4307
4335
                ERROR("Unknown VideoCodec: %s\n", arg);
4308
4336
            }
4309
4337
        } else if (!av_strcasecmp(cmd, "MaxTime")) {
4494
4522
            if (stream)
4495
4523
                video_enc.dark_masking = atof(arg);
4496
4524
        } else if (!av_strcasecmp(cmd, "NoVideo")) {
4497
 
            video_id = CODEC_ID_NONE;
 
4525
            video_id = AV_CODEC_ID_NONE;
4498
4526
        } else if (!av_strcasecmp(cmd, "NoAudio")) {
4499
 
            audio_id = CODEC_ID_NONE;
 
4527
            audio_id = AV_CODEC_ID_NONE;
4500
4528
        } else if (!av_strcasecmp(cmd, "ACL")) {
4501
4529
            parse_acl_row(stream, feed, NULL, p, filename, line_num);
4502
4530
        } else if (!av_strcasecmp(cmd, "DynamicACL")) {
4534
4562
                ERROR("No corresponding <Stream> for </Stream>\n");
4535
4563
            } else {
4536
4564
                if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4537
 
                    if (audio_id != CODEC_ID_NONE) {
 
4565
                    if (audio_id != AV_CODEC_ID_NONE) {
4538
4566
                        audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4539
4567
                        audio_enc.codec_id = audio_id;
4540
4568
                        add_codec(stream, &audio_enc);
4541
4569
                    }
4542
 
                    if (video_id != CODEC_ID_NONE) {
 
4570
                    if (video_id != AV_CODEC_ID_NONE) {
4543
4571
                        video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4544
4572
                        video_enc.codec_id = video_id;
4545
4573
                        add_codec(stream, &video_enc);
4623
4651
static void opt_debug(void)
4624
4652
{
4625
4653
    avserver_debug = 1;
4626
 
    avserver_daemon = 0;
4627
4654
    logfilename[0] = '-';
4628
4655
}
4629
4656
 
4630
 
static void show_help(void)
 
4657
void show_help_default(const char *opt, const char *arg)
4631
4658
{
4632
4659
    printf("usage: avserver [options]\n"
4633
4660
           "Hyper fast multi format Audio/Video streaming server\n");
4634
4661
    printf("\n");
4635
 
    show_help_options(options, "Main options:\n", 0, 0);
 
4662
    show_help_options(options, "Main options:", 0, 0, 0);
4636
4663
}
4637
4664
 
4638
4665
static const OptionDef options[] = {
4645
4672
 
4646
4673
int main(int argc, char **argv)
4647
4674
{
4648
 
    struct sigaction sigact;
 
4675
    struct sigaction sigact = { { 0 } };
4649
4676
 
4650
4677
    parse_loglevel(argc, argv, options);
4651
4678
    av_register_all();
4654
4681
    show_banner();
4655
4682
 
4656
4683
    my_program_name = argv[0];
4657
 
    my_program_dir = getcwd(0, 0);
4658
 
    avserver_daemon = 1;
4659
4684
 
4660
4685
    parse_options(NULL, argc, argv, options, NULL);
4661
4686
 
4663
4688
 
4664
4689
    av_lfg_init(&random_state, av_get_random_seed());
4665
4690
 
4666
 
    memset(&sigact, 0, sizeof(sigact));
4667
4691
    sigact.sa_handler = handle_child_exit;
4668
4692
    sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4669
4693
    sigaction(SIGCHLD, &sigact, 0);
4688
4712
 
4689
4713
    compute_bandwidth();
4690
4714
 
4691
 
    /* put the process in background and detach it from its TTY */
4692
 
    if (avserver_daemon) {
4693
 
        int pid;
4694
 
 
4695
 
        pid = fork();
4696
 
        if (pid < 0) {
4697
 
            perror("fork");
4698
 
            exit(1);
4699
 
        } else if (pid > 0) {
4700
 
            /* parent : exit */
4701
 
            exit(0);
4702
 
        } else {
4703
 
            /* child */
4704
 
            setsid();
4705
 
            close(0);
4706
 
            open("/dev/null", O_RDWR);
4707
 
            if (strcmp(logfilename, "-") != 0) {
4708
 
                close(1);
4709
 
                dup(0);
4710
 
            }
4711
 
            close(2);
4712
 
            dup(0);
4713
 
        }
4714
 
    }
4715
 
 
4716
4715
    /* signal init */
4717
4716
    signal(SIGPIPE, SIG_IGN);
4718
4717
 
4719
 
    if (avserver_daemon)
4720
 
        chdir("/");
4721
 
 
4722
4718
    if (http_server() < 0) {
4723
4719
        http_log("Could not start server\n");
4724
4720
        exit(1);