Beispiel #1
0
/* wait till the given time, update wait status
 * every update_sec seconds
 *
 */
static int
wait_till( time_t endtime, int update_sec )
{
    u_int sec2wait = 0;
    u_int unslept = 0;
    time_t now = time(NULL);
    sig_atomic_t quit = 0;

    TRACE( (void)tmfprintf( g_flog, "%s: waiting till time=[%ld], now=[%ld]\n",
                __func__, (long)endtime, (long)now ) );

    if( now >= endtime ) return 0;

    (void) tmfprintf( g_flog, "[%ld] seconds before recording begins\n",
                        (long)(endtime - now) );

    if( (update_sec <= 0) ||
        ((now + update_sec) > endtime) ) {
        unslept = sleep( endtime - now );
    }
    else {
        while( !(quit = must_quit()) && (now < endtime) ) {
            sec2wait = (now + update_sec) <= endtime
                        ? update_sec : (endtime - now);
            update_waitstat( g_flog, endtime );

            TRACE( (void)tmfprintf( g_flog, "Waiting for [%u] more seconds.\n",
                        sec2wait ) );

            unslept = sleep( sec2wait );
            now = time(NULL);
        }
    }

    TRACE( (void)tmfprintf( g_flog, "[%u] seconds unslept, quit=[%d]\n", unslept,
                (long)quit ) );
    return (unslept ? ERR_INTERNAL : 0);
}
Beispiel #2
0
/* record network stream as per spec in opt
 */
static int
record()
{
    int rsock = -1, destfd = -1, rc = 0, wtime_sec = 0;
    struct in_addr raddr;
    struct timeval rtv;
    struct dstream_ctx ds;
    ssize_t nmsgs = 0;
    ssize_t nrcv = -1, lrcv = -1, t_delta = 0;
    int64_t n_total = 0;
    ssize_t nwr = -1, lwr = -1;
    sig_atomic_t quit = 0;
    struct rdata_opt ropt;
    int oflags = 0;

    char* data = NULL;

    static const u_short RSOCK_TIMEOUT  = 5;
    extern const char CMD_UDP[];

    /* NOPs to eliminate warnings in lean version */
    (void)&t_delta; (void)&lrcv;
    t_delta = lrcv = lwr = 0; quit=0;

    check_fragments( NULL, 0, 0, 0, 0, g_flog );

    /* init */
    do {
        data = malloc( g_recopt.bufsize );
        if( NULL == data ) {
            mperror(g_flog, errno, "%s: cannot allocate [%ld] bytes",
                    __func__, (long)g_recopt.bufsize );
            rc = ERR_INTERNAL;
            break;
        }

        rc = subscribe( &rsock, &raddr );
        if( 0 != rc ) break;

        rtv.tv_sec = RSOCK_TIMEOUT;
        rtv.tv_usec = 0;

        rc = setsockopt( rsock, SOL_SOCKET, SO_RCVTIMEO, &rtv, sizeof(rtv) );
        if( -1 == rc ) {
            mperror(g_flog, errno, "%s: setsockopt - SO_RCVTIMEO",
                    __func__);
            rc = ERR_INTERNAL;
            break;
        }

        oflags = O_CREAT | O_TRUNC | O_WRONLY |
                 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
        # if defined(O_LARGEFILE)
            /* O_LARGEFILE is not defined under FreeBSD ??-7.1 */
            oflags |= O_LARGEFILE;
        # endif
        destfd = open( g_recopt.dstfile, oflags,
                (mode_t)(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
        if( -1 == destfd ) {
            mperror( g_flog, errno, "%s: cannot create destination file [%s]",
                     __func__, g_recopt.dstfile );
            rc = ERR_INTERNAL;
            break;
        }

        rc = calc_buf_settings( &nmsgs, NULL );
        if (0 != rc) return -1;

        if( nmsgs < (ssize_t)1 ) {
            (void) tmfprintf( g_flog, "Buffer for inbound data is too small [%ld] bytes; "
                    "the minimum size is [%ld] bytes\n",
                    (long)g_recopt.bufsize, (long)ETHERNET_MTU );
            rc = ERR_PARAM;
            break;
        }

        TRACE( (void)tmfprintf( g_flog, "Inbound buffer set to "
                        "[%d] messages\n", nmsgs ) );

        rc = init_dstream_ctx( &ds, CMD_UDP, NULL, nmsgs );
        if( 0 != rc ) return -1;

        (void) set_nice( g_recopt.nice_incr, g_flog );

        /* set up alarm to break main loop */
        if( 0 != g_recopt.end_time ) {
            wtime_sec = (int)difftime( g_recopt.end_time, time(NULL) );
            assert( wtime_sec >= 0 );

            (void) alarm( wtime_sec );

            (void)tmfprintf( g_flog, "Recording will end in [%d] seconds\n",
                    wtime_sec );
        }
    } while(0);

    /* record loop */
    ropt.max_frgs = g_recopt.rbuf_msgs;
    ropt.buf_tmout = -1;

    for( n_total = 0; (0 == rc) && !(quit = must_quit()); ) {
        nrcv = read_data( &ds, rsock, data, g_recopt.bufsize, &ropt );
        if( -1 == nrcv ) { rc = ERR_INTERNAL; break; }

        if( 0 == n_total ) {
            (void) tmfprintf( g_flog, "Recording to file=[%s] started.\n",
                    g_recopt.dstfile );
        }

        TRACE( check_fragments( "received new", g_recopt.bufsize,
                    lrcv, nrcv, t_delta, g_flog ) );
        lrcv = nrcv;

        if( nrcv > 0 ) {
            if( g_recopt.max_fsize &&
                ((n_total + nrcv) >= g_recopt.max_fsize) ) {
                break;
            }

            nwr = write_data( &ds, data, nrcv, destfd );
            if( -1 == nwr ) { rc = ERR_INTERNAL; break; }

            n_total += (size_t)nwr;
            /*
            TRACE( tmfprintf( g_flog, "Wrote [%ld] to file, total=[%ld]\n",
                        (long)nwr, (long)n_total ) );
            */

            TRACE( check_fragments( "wrote to file",
                    nrcv, lwr, nwr, t_delta, g_flog ) );
            lwr = nwr;
        }

        if( ds.flags & F_SCATTERED ) reset_pkt_registry( &ds );

    } /* record loop */

    (void) tmfprintf( g_flog, "Recording to file=[%s] stopped at filesize=[%lu] bytes\n",
                      g_recopt.dstfile, (u_long)n_total );

    /* CLEANUP
     */
    (void) alarm(0);

    TRACE( (void)tmfprintf( g_flog, "Exited record loop: wrote [%lu] bytes to file [%s], "
                    "rc=[%d], alarm=[%ld], quit=[%ld]\n",
                    (u_long)n_total, g_recopt.dstfile, rc, g_alarm, (long)quit ) );

    free_dstream_ctx( &ds );
    if( data ) free( data );

    close_mcast_listener( rsock, &raddr );
    if( destfd >= 0 ) (void) close( destfd );

    if( quit )
        TRACE( (void)tmfprintf( g_flog, "%s process must quit\n",
                        g_udpxrec_app ) );

    return rc;
}
Beispiel #3
0
/* relay traffic from source to destination socket
 *
 */
static int
relay_traffic( int ssockfd, int dsockfd, struct server_ctx* ctx,
               int dfilefd, const struct in_addr* mifaddr )
{
    volatile sig_atomic_t quit = 0;

    int rc = 0;
    ssize_t nmsgs = -1;
    ssize_t nrcv = 0, nsent = 0, nwr = 0,
            lrcv = 0, lsent = 0;
    char*  data = NULL;
    size_t data_len = g_uopt.rbuf_len;
    struct rdata_opt ropt;
    time_t pause_time = 0, rfr_tm = time(NULL);
    sigset_t ubset;

    const int ALLOW_PAUSES = get_flagval( "UDPXY_ALLOW_PAUSES", 0 );
    const ssize_t MAX_PAUSE_MSEC =
        get_sizeval( "UDPXY_PAUSE_MSEC", 1000);

    /* permissible variation in data-packet size */
    static const ssize_t t_delta = 0x20;

    struct dstream_ctx ds;

    static const int SET_PID = 1;
    struct tps_data tps;

    assert( ctx && mifaddr && MAX_PAUSE_MSEC > 0 );

    (void) sigemptyset (&ubset);
    sigaddset (&ubset, SIGINT);
    sigaddset (&ubset, SIGQUIT);
    sigaddset (&ubset, SIGTERM);

    /* restore the ability to receive *quit* signals */
    rc = sigprocmask (SIG_UNBLOCK, &ubset, NULL);
    if (0 != rc) {
        mperror (g_flog, errno, "%s: sigprocmask", __func__);
        return -1;
    }

    /* NOPs to eliminate warnings in lean version */
    (void)&lrcv; (void)&lsent; (void)&t_delta;

    check_fragments( NULL, 0, 0, 0, 0, g_flog );

    /* INIT
     */

    rc = calc_buf_settings( &nmsgs, NULL );
    if (0 != rc) return -1;

    TRACE( (void)tmfprintf( g_flog, "Data buffer will hold up to "
                        "[%d] messages\n", nmsgs ) );

    rc = init_dstream_ctx( &ds, ctx->cmd, g_uopt.srcfile, nmsgs );
    if( 0 != rc ) return -1;

    (void) set_nice( g_uopt.nice_incr, g_flog );

    do {
        if( NULL == g_uopt.srcfile ) {
            rc = set_timeouts( ssockfd, dsockfd,
                               ctx->rcv_tmout, 0,
                               ctx->snd_tmout, 0 );
            if( 0 != rc ) break;
        }

        if( dsockfd > 0 ) {
            rc = sync_dsockbuf_len( ssockfd, dsockfd );
            if( 0 != rc ) break;

            rc = send_http_response( dsockfd, 200, "OK" );
            if( 0 != rc ) break;

            /* timeshift: to detect PAUSE make destination
            * socket non-blocking, otherwise make it blocking
            * (since it might have been set unblocking earlier)
            */
            rc = set_nblock( dsockfd, (ALLOW_PAUSES ? 1 : 0) );
            if( 0 != rc ) break;
        }

        data = malloc(data_len);
        if( NULL == data ) {
            mperror( g_flog, errno, "%s: malloc", __func__ );
            break;
        }

        if( g_uopt.cl_tpstat )
            tpstat_init( &tps, SET_PID );
    } while(0);

    TRACE( (void)tmfprintf( g_flog, "Relaying traffic from socket[%d] "
            "to socket[%d], buffer size=[%d], Rmsgs=[%d], pauses=[%d]\n",
            ssockfd, dsockfd, data_len, g_uopt.rbuf_msgs, ALLOW_PAUSES) );

    /* RELAY LOOP
     */
    ropt.max_frgs = g_uopt.rbuf_msgs;
    ropt.buf_tmout = g_uopt.dhold_tmout;

    pause_time = 0;

    while( (0 == rc) && !(quit = must_quit()) ) {
        if( g_uopt.mcast_refresh > 0 ) {
            check_mcast_refresh( ssockfd, &rfr_tm, mifaddr );
        }

        nrcv = read_data( &ds, ssockfd, data, data_len, &ropt );
        if( -1 == nrcv ) break;

        TRACE( check_fragments( "received new", data_len,
                    lrcv, nrcv, t_delta, g_flog ) );
        lrcv = nrcv;

        if( dsockfd && (nrcv > 0) ) {
            nsent = write_data( &ds, data, nrcv, dsockfd );
            if( -1 == nsent ) break;

            if ( nsent < 0 ) {
                if ( !ALLOW_PAUSES ) break;
                if ( 0 != pause_detect( nsent, MAX_PAUSE_MSEC, &pause_time ) )
                    break;
            }

            TRACE( check_fragments("sent", nrcv,
                        lsent, nsent, t_delta, g_flog) );
            lsent = nsent;
        }

        if( (dfilefd > 0) && (nrcv > 0) ) {
            nwr = write_data( &ds, data, nrcv, dfilefd );
            if( -1 == nwr )
                break;
            TRACE( check_fragments( "wrote to file",
                    nrcv, lsent, nwr, t_delta, g_flog ) );
            lsent = nwr;
        }

        if( ds.flags & F_SCATTERED ) reset_pkt_registry( &ds );

        if( uf_TRUE == g_uopt.cl_tpstat )
            tpstat_update( ctx, &tps, nsent );

    } /* end of RELAY LOOP */

    /* CLEANUP
     */
    TRACE( (void)tmfprintf( g_flog, "Exited relay loop: received=[%ld], "
        "sent=[%ld], quit=[%ld]\n", (long)nrcv, (long)nsent, (long)quit ) );

    free_dstream_ctx( &ds );
    if( NULL != data ) free( data );

    if( 0 != (quit = must_quit()) ) {
        TRACE( (void)tmfprintf( g_flog, "Child process=[%d] must quit\n",
                    getpid()) );
    }

    return rc;
}
Beispiel #4
0
int
main( int argc, char* const argv[] )
{
    const char app[] = "mcprobe";
    int msockfd = 0, rc = 0, tries = -1;
    const char *mifaddr, *addrport;
    struct sigaction qact, oldact;

    if( argc < 3 ) {
        (void) fprintf( stderr,
                "Usage: %s mcast_ifc_addr channel_ip:port\n"
                "Example:\n"
                "\t mcprobe 192.168.1.1 224.0.2.26:1234\n\n"
                "(C) 2008-2013 by Pavel V. Cherenkov, licensed under GNU GPLv3\n\n",
                app );
        return 1;
    }

    g_flog = stdout;

    mifaddr = argv[1];
    addrport = argv[2];

    qact.sa_handler = handle_quitsigs;
    sigemptyset(&qact.sa_mask);
    qact.sa_flags = 0;

    if( (sigaction(SIGTERM, &qact, &oldact) < 0) ||
        (sigaction(SIGQUIT, &qact, &oldact) < 0) ||
        (sigaction(SIGINT,  &qact, &oldact) < 0) ||
        (sigaction(SIGPIPE, &qact, &oldact) < 0)) {
        perror("sigaction-quit");

        return 2;
    }


#define LEN_64K (64 * 1024)
    msockfd = setup_mcast_socket( mifaddr, addrport, LEN_64K );
    if( msockfd < 1 )
        return msockfd;

#define TMOUT_SEC 2
    rc = set_rtmout( msockfd, TMOUT_SEC, 0 );

#define RENEW_TRIES 3
    for( tries = RENEW_TRIES; (0 == rc) && (tries >= 0); ) {
        rc = read_msock( msockfd );

        if( 0 != rc ) {
            if( RC_TIMEOUT == rc && (tries > 0) ) {
                rc = renew_mcast_subscr( msockfd, mifaddr );
                if( 0 != rc ) break;
                --tries;
            }
        } /* 0 != rc */

        if( must_quit() )
            break;
    }

    close_mcast_socket( msockfd, mifaddr );
    return rc;
}
Beispiel #5
0
static int
read_msock( int msockfd )
{
    char buf[ ETHERNET_MTU ];
    struct timeval tvb, tva, dtv,
                   min_dtv, max_dtv;
    time_t ltm, tmnow;
    char str_tmnow[ 32 ];

    int rc = 0;
    ssize_t nread = -1, sum_read = 0, bytesec;
    size_t packets = (size_t)0, len;

    assert( msockfd > 0 );
    ltm = tmnow = time(NULL);

    TRACE( (void)fprintf( g_flog, "%s started\n", __func__ ) );

    timerclear( &min_dtv );
    timerclear( &max_dtv );

    for( packets = (size_t)0; !must_quit(); ++packets ) {
        (void) gettimeofday( &tva, NULL );
        nread = read( msockfd, buf, sizeof(buf) );

        (void) gettimeofday( &tvb, NULL );

        if( tvb.tv_usec >= tva.tv_usec ) {
            dtv.tv_usec = tvb.tv_usec - tva.tv_usec;
            dtv.tv_sec = tvb.tv_sec - tva.tv_sec;
        }
        else {
            dtv.tv_usec = tvb.tv_usec - tva.tv_usec + 1000000;
            dtv.tv_sec = tvb.tv_sec - tva.tv_sec - 1;
        }

        if( !timerisset( &max_dtv ) ) {
            min_dtv = max_dtv = dtv;
            /* TRACE( (void)fprintf( g_flog, "Reading ...\n" ) ); */
        }

        if( tvalcmp( &dtv, &min_dtv ) < 0 ) min_dtv = dtv;
        if( tvalcmp( &dtv, &max_dtv ) > 0 ) max_dtv = dtv;

        if( nread >= 0 )
            sum_read += nread;

#define REPORT_PERIOD_SEC 2
        tmnow = time(NULL);
        if( difftime( tmnow, ltm ) > (double)REPORT_PERIOD_SEC )
        {
            strncpy( str_tmnow, ctime(&tmnow), sizeof(str_tmnow) - 1 );
            str_tmnow[ sizeof(str_tmnow) - 1 ] = 0;
            len = strlen( str_tmnow );
            if( '\n' == str_tmnow[ len - 1 ] )
                str_tmnow[ len - 1 ] = 0;

            bytesec = sum_read / REPORT_PERIOD_SEC;

            (void) fprintf( g_flog, "%s - packets: %ld, bytes: %ld speed: %.2f K/sec "
                    "min: %lds.%ldms max: %lds.%ldms last: %lds.%ldms\n",
                    str_tmnow, (long)packets, (long)sum_read,
                    ((double)bytesec / 1024),
                    (long)min_dtv.tv_sec, (long)(min_dtv.tv_usec / 1000),
                    (long)max_dtv.tv_sec, (long)(max_dtv.tv_usec / 1000),
                    (long)dtv.tv_sec, (long)(dtv.tv_usec / 1000) );

            ltm = tmnow;
            packets = sum_read = (size_t)0;
            timerclear( &max_dtv );
            timerclear( &min_dtv );
        }

        if( nread <= 0 ) {
            if( EINTR == errno ) {
                (void) fprintf( g_flog, "\nINTERRUPT!\n" );
                break;
            }
            else if( EAGAIN == errno ) {
                (void) fprintf( g_flog, "\nTIME-OUT!\n" );
                rc = RC_TIMEOUT;
                break;
            }

            rc = -1;
            break;
        }

    } /* for */

    TRACE( (void)fprintf( g_flog, "%s finished\n", __func__ ) );
    return rc;
}
Beispiel #6
0
/* process client requests */
int
srv_loop( const char* ipaddr, int port,
             const char* mcast_addr )
{
    int                 rc, maxfd, err, nrdy, i;
    fd_set              rset;
    struct timeval      tmout, idle_tmout, *ptmout = NULL;
    tmfd_t              *asock = NULL;
    size_t              n = 0, nasock = 0, max_nasock = LQ_BACKLOG;
    sigset_t            oset, bset;

    static const long IDLE_TMOUT_SEC = 30;

    assert( (port > 0) && mcast_addr && ipaddr );

    (void)tmfprintf( g_flog, "Server is starting up, max clients = [%u]\n",
                        g_uopt.max_clients );
    asock = calloc (max_nasock, sizeof(*asock));
    if (!asock) {
        mperror (g_flog, ENOMEM, "%s: calloc", __func__);
        return ERR_INTERNAL;
    }

    init_server_ctx( &g_srv, g_uopt.max_clients,
            (ipaddr[0] ? ipaddr : "0.0.0.0") , (uint16_t)port, mcast_addr );

    g_srv.rcv_tmout = (u_short)g_uopt.rcv_tmout;
    g_srv.snd_tmout = RLY_SOCK_TIMEOUT;

    /* NB: server socket is non-blocking! */
    if( 0 != (rc = setup_listener( ipaddr, port, &g_srv.lsockfd,
            g_uopt.lq_backlog )) ) {
        return rc;
    }

    sigemptyset (&bset);
    sigaddset (&bset, SIGINT);
    sigaddset (&bset, SIGQUIT);
    sigaddset (&bset, SIGCHLD);
    sigaddset (&bset, SIGTERM);

    (void) sigprocmask (SIG_BLOCK, &bset, &oset);

    TRACE( (void)tmfprintf( g_flog, "Entering server loop [%s]\n",
        SLOOP_TAG) );
    while (1) {
        FD_ZERO( &rset );
        FD_SET( g_srv.lsockfd, &rset );
        FD_SET( g_srv.cpipe[0], &rset );

        maxfd = (g_srv.lsockfd > g_srv.cpipe[0] ) ? g_srv.lsockfd : g_srv.cpipe[0];
        for (i = 0; (size_t)i < nasock; ++i) {
            assert (asock[i].fd >= 0);
            FD_SET (asock[i].fd, &rset);
            if (asock[i].fd > maxfd) maxfd = asock[i].fd;
        }

        /* if there are accepted sockets - apply specified time-out
         */
        tmout.tv_sec = g_uopt.ssel_tmout;
        tmout.tv_usec = 0;

        idle_tmout.tv_sec = IDLE_TMOUT_SEC;
        idle_tmout.tv_usec = 0;

        /* enforce *idle* select(2) timeout to alleviate signal contention */
        ptmout = ((nasock > 0) && (g_uopt.ssel_tmout > 0)) ? &tmout : &idle_tmout;

        TRACE( (void)tmfprintf( g_flog, "Waiting for input from [%ld] fd's, "
            "%s timeout\n", (long)(2 + nasock), (ptmout ? "with" : "NO")));

        if (ptmout && ptmout->tv_sec) {
            TRACE( (void)tmfprintf (g_flog, "select() timeout set to "
            "[%ld] seconds\n", ptmout->tv_sec) );
        }

        (void) sigprocmask (SIG_UNBLOCK, &bset, NULL);
        if( must_quit() ) {
            TRACE( (void)tmfputs( "Must quit now\n", g_flog ) );
            rc = 0; break;
        }

        nrdy = select (maxfd + 1, &rset, NULL, NULL, ptmout);
        err = errno;
        (void) sigprocmask (SIG_BLOCK, &bset, NULL);

        if( must_quit() ) {
            TRACE( (void)tmfputs( "Must quit now\n", g_flog ) );
            rc = 0; break;
        }
        wait_terminated( &g_srv );

        if( nrdy < 0 ) {
            if (EINTR == err) {
                TRACE( (void)tmfputs ("INTERRUPTED, yet "
                        "will continue.\n", g_flog)  );
                rc = 0; continue;
            }

            mperror( g_flog, err, "%s: select", __func__ );
            break;
        }

        TRACE( (void)tmfprintf (g_flog, "Got %ld requests\n", (long)nrdy) );
        if (0 == nrdy) {    /* time-out */
            tmout_requests (asock, &nasock);
            rc = 0; continue;
        }

        if( FD_ISSET(g_srv.cpipe[0], &rset) ) {
            (void) tpstat_read( &g_srv );
            if (--nrdy <= 0) continue;
        }

        if ((0 < nasock) &&
                 (0 < (nrdy - (FD_ISSET(g_srv.lsockfd, &rset) ? 1 : 0)))) {
            process_requests (asock, &nasock, &rset, &g_srv);
            /* n now contains # (yet) unprocessed accepted sockets */
        }

        if (FD_ISSET(g_srv.lsockfd, &rset)) {
            if (nasock >= max_nasock) {
                (void) tmfprintf (g_flog, "Cannot accept sockets beyond "
                    "the limit [%ld/%ld], skipping\n",
                    (long)nasock, (long)max_nasock);
            }
            else {
                n = max_nasock - nasock; /* append asock */
                accept_requests (g_srv.lsockfd, &(asock[nasock]), &n);
                nasock += n;
            }
        }
    } /* server loop */

    TRACE( (void)tmfprintf( g_flog, "Exited server loop [%s]\n", SLOOP_TAG) );

    for (i = 0; (size_t)i < nasock; ++i) {
        if (asock[i].fd > 0) (void) close (asock[i].fd);
    }
    free (asock);

    /* receive additional (blocked signals) */
    (void) sigprocmask (SIG_SETMASK, &oset, NULL);
    wait_terminated( &g_srv );
    terminate_all_clients( &g_srv );
    wait_all( &g_srv );

    if (0 != close( g_srv.lsockfd )) {
        mperror (g_flog, errno, "server socket close");
    }

    free_server_ctx( &g_srv );

    (void)tmfprintf( g_flog, "Server exits with rc=[%d]\n", rc );
    return rc;
}