Esempio n. 1
0
/* main() for udpxrec module
 */
int udpxrec_main( int argc, char* const argv[] )
{
    int rc = 0, ch = 0, custom_log = 0, no_daemon = 0;
    static const char OPTMASK[] = "vb:e:M:p:B:n:m:l:c:R:u:T";
    time_t now = time(NULL);
    char now_buf[ 32 ] = {0}, sel_buf[ 32 ] = {0}, app_finfo[80] = {0};

    extern int optind, optopt;
    extern const char IPv4_ALL[];

    mk_app_info(g_udpxrec_app, g_app_info, sizeof(g_app_info) - 1);

    if( argc < 2 ) {
        usage( argv[0], stderr );
        return ERR_PARAM;
    }

    rc = init_recopt( &g_recopt );
    while( (0 == rc) && (-1 != (ch = getopt( argc, argv, OPTMASK ))) ) {
        switch(ch) {
            case 'T':   no_daemon = 1; break;
            case 'v':   set_verbose( &g_recopt.is_verbose ); break;
            case 'b':
                        if( (time_t)0 != g_recopt.end_time ) {
                            (void) fprintf( stderr, "Cannot specify start-recording "
                                    "time after end-recording time has been set\n" );
                        }

                        rc = a2time( optarg, &g_recopt.bg_time, time(NULL) );
                        if( 0 != rc ) {
                            (void) fprintf( stderr, "Invalid time: [%s]\n", optarg );
                            rc = ERR_PARAM;
                        }
                        else {
                            if( g_recopt.bg_time < now ) {
                                (void)strncpy( now_buf, Zasctime(localtime( &now )),
                                        sizeof(now_buf) );
                                (void)strncpy( sel_buf,
                                        Zasctime(localtime( &g_recopt.bg_time )),
                                        sizeof(sel_buf) );

                                (void) fprintf( stderr,
                                        "Selected %s time is in the past, "
                                        "now=[%s], selected=[%s]\n", "start",
                                        now_buf, sel_buf );
                                rc = ERR_PARAM;
                            }
                        }

                        break;
            case 'e':
                        if( (time_t)0 == g_recopt.bg_time ) {
                            g_recopt.bg_time = time(NULL);
                            (void)fprintf( stderr,
                                    "Start-recording time defaults to now [%s]\n",
                                    Zasctime( localtime( &g_recopt.bg_time ) ) );
                        }

                        rc = a2time( optarg, &g_recopt.end_time, g_recopt.bg_time );
                        if( 0 != rc ) {
                            (void) fprintf( stderr, "Invalid time: [%s]\n", optarg );
                            rc = ERR_PARAM;
                        }
                        else {
                            if( g_recopt.end_time < now ) {
                                (void)strncpy( now_buf, Zasctime(localtime( &now )),
                                        sizeof(now_buf) );
                                (void)strncpy( sel_buf,
                                        Zasctime(localtime( &g_recopt.end_time )),
                                        sizeof(sel_buf) );

                                (void) fprintf( stderr,
                                        "Selected %s time is in the past, "
                                        "now=[%s], selected=[%s]\n", "end",
                                        now_buf, sel_buf );
                                rc = ERR_PARAM;
                            }
                        }
                        break;

            case 'M':
                        rc = a2int64( optarg, &g_recopt.max_fsize );
                        if( 0 != rc ) {
                            (void) fprintf( stderr, "Invalid file size: [%s]\n",
                                    optarg );
                            rc = ERR_PARAM;
                        }
                        break;
            case 'p':
                        g_recopt.pidfile = strdup(optarg);
                        break;

            case 'B':
                        rc = a2size( optarg, &g_recopt.bufsize );
                        if( 0 != rc ) {
                            (void) fprintf( stderr, "Invalid buffer size: [%s]\n",
                                    optarg );
                            rc = ERR_PARAM;
                        }
                        else if( (g_recopt.bufsize < MIN_MCACHE_LEN) ||
                                 (g_recopt.bufsize > MAX_MCACHE_LEN)) {
                            (void) fprintf( stderr,
                                "Buffer size must be in [%ld-%ld] bytes range\n",
                                (long)MIN_MCACHE_LEN, (long)MAX_MCACHE_LEN );
                            rc = ERR_PARAM;
                        }

                        break;
            case 'n':
                      g_recopt.nice_incr = atoi( optarg );
                      if( 0 == g_recopt.nice_incr ) {
                        (void) fprintf( stderr,
                            "Invalid nice-value increment: [%s]\n", optarg );
                        rc = ERR_PARAM;
                      }
                      break;
            case 'm':
                      rc = get_ipv4_address( optarg, g_recopt.mcast_addr,
                              sizeof(g_recopt.mcast_addr) );
                      if( 0 != rc ) {
                        (void) fprintf( stderr, "Invalid multicast address: [%s]\n",
                                        optarg );
                          rc = ERR_PARAM;
                      }
                      break;
            case 'l':
                      g_flog = fopen( optarg, "a" );
                      if( NULL == g_flog ) {
                        rc = errno;
                        (void) fprintf( stderr, "Error opening logfile [%s]: %s\n",
                                optarg, strerror(rc) );
                        rc = ERR_PARAM; break;
                      }

                      Setlinebuf( g_flog );
                      custom_log = 1;
                      break;

            case 'c':
                      rc = get_addrport( optarg, g_recopt.rec_channel,
                                         sizeof( g_recopt.rec_channel ),
                                         &g_recopt.rec_port );
                      if( 0 != rc ) rc = ERR_PARAM;
                      break;

            case 'R':
                      g_recopt.rbuf_msgs = atoi( optarg );
                      if( (g_recopt.rbuf_msgs <= 0) && (-1 != g_recopt.rbuf_msgs) ) {
                        (void) fprintf( stderr,
                                "Invalid rcache size: [%s]\n", optarg );
                        rc = ERR_PARAM;
                      }
                      break;

            case 'u':
                      g_recopt.waitupd_sec = atoi(optarg);
                      if( g_recopt.waitupd_sec <= 0 ) {
                          (void) fprintf( stderr, "Invalid wait-update value [%s] "
                                  "(must be a number > 0)\n", optarg );
                          rc = ERR_PARAM;
                      }
                      break;

            case ':':
                      (void) fprintf( stderr, "Option [-%c] requires an argument\n",
                              optopt );
                      rc = ERR_PARAM; break;
            case '?':
                      (void) fprintf( stderr, "Unrecognized option: [-%c]\n", optopt );
                      rc = ERR_PARAM; break;
            default:
                      usage( argv[0], stderr );
                      rc = ERR_PARAM; break;

        } /* switch */
    } /* while getopt */

    if( 0 == rc ) {
        if( optind >= argc ) {
            (void) fputs( "Missing destination file parameter\n", stderr );
            rc = ERR_PARAM;
        }
        else {
            g_recopt.dstfile = strdup( argv[optind] );
        }

        if( !(g_recopt.max_fsize > 0 || g_recopt.end_time)  ) {
            (void) fputs( "Must specify either max file [-M] size "
                    "or end time [-e]\n", stderr );
            rc = ERR_PARAM;
        }

        if( !g_recopt.rec_channel[0] || !g_recopt.rec_port ) {
            (void) fputs( "Must specify multicast channel to record from\n",
                    stderr );
            rc = ERR_PARAM;
        }
    }

    if( rc ) {
        free_recopt( &g_recopt );
        return rc;
    }

    do {
        if( '\0' == g_recopt.mcast_addr[0] ) {
            (void) strncpy( g_recopt.mcast_addr, IPv4_ALL,
                    sizeof(g_recopt.mcast_addr) - 1 );
        }

        if( !custom_log ) {
            /* in debug mode output goes to stderr, otherwise to /dev/null */
            g_flog = ((uf_TRUE == g_recopt.is_verbose)
                    ? stderr
                    : fopen( "/dev/null", "a" ));
            if( NULL == g_flog ) {
                perror("fopen");
                rc = ERR_INTERNAL; break;
            }
        }

        if( 0 == geteuid() ) {
            if( !no_daemon ) {
                if( stderr == g_flog ) {
                    (void) fprintf( stderr,
                        "Logfile must be specified to run "
                        "in verbose mode in background\n" );
                    rc = ERR_PARAM; break;
                }

                if( NULL == g_recopt.pidfile ) {
                    (void) fprintf( stderr, "pidfile must be specified "
                            "to run as daemon\n" );
                    rc = ERR_PARAM; break;
                }

                if( 0 != (rc = daemonize(0, g_flog)) ) {
                    rc = ERR_INTERNAL; break;
                }
            }

        } /* 0 == geteuid() */

        if( NULL != g_recopt.pidfile ) {
            rc = make_pidfile( g_recopt.pidfile, getpid(), g_flog );
            if( 0 != rc ) break;
        }

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

        if( 0 != (rc = setup_signals()) ) break;

        TRACE( fprint_recopt( g_flog, &g_recopt ) );

        TRACE( printcmdln( g_flog, g_app_info, argc, argv ) );

        if( g_recopt.bg_time ) {
            if( 0 != (rc = verify_channel()) || g_quit )
                break;

            rc = wait_till( g_recopt.bg_time, g_recopt.waitupd_sec );
            if( rc || g_quit ) break;
        }

        rc = record();

        if( NULL != g_recopt.pidfile ) {
            if( -1 == unlink(g_recopt.pidfile) ) {
                mperror( g_flog, errno, "unlink [%s]", g_recopt.pidfile );
            }
        }
    }
    while(0);

    if( g_flog ) {
        (void)tmfprintf( g_flog, "%s is exiting with rc=[%d]\n",
                app_finfo, rc );
    }

    if( g_flog && (stderr != g_flog) ) {
        (void) fclose(g_flog);
    }

    free_recopt( &g_recopt );

    return rc;
}
Esempio n. 2
0
File: udpxy.c Progetto: avble/udpxy
int
udpxy_main( int argc, char* const argv[] )
{
    int rc = 0, ch = 0, port = -1,
        custom_log = 0, no_daemon = 0;

    char ipaddr[IPADDR_STR_SIZE] = "\0",
         mcast_addr[IPADDR_STR_SIZE] = "\0";

    char pidfile[ MAXPATHLEN ] = "\0";
    u_short MIN_MCAST_REFRESH = 0, MAX_MCAST_REFRESH = 0;

/* support for -r -w (file read/write) option is disabled by default;
 * those features are experimental and for dev debugging ONLY
 * */
#ifdef UDPXY_FILEIO
    static const char UDPXY_OPTMASK[] = "TvSa:l:p:m:c:B:n:R:r:w:H:M:";
#else
    static const char UDPXY_OPTMASK[] = "TvSa:l:p:m:c:B:n:R:H:M:";
#endif

    struct sigaction qact, iact, cact, oldact;

    init_app_info();
    (void) get_pidstr( PID_RESET, "S" );

    rc = init_uopt( &g_uopt );
    while( (0 == rc) && (-1 != (ch = getopt(argc, argv, UDPXY_OPTMASK))) ) {
        switch( ch ) {
            case 'v': set_verbose( &g_uopt.is_verbose );
                      break;
            case 'T': no_daemon = 1;
                      break;
            case 'S': g_uopt.cl_tpstat = uf_TRUE;
                      break;
            case 'a':
                      rc = get_ipv4_address( optarg, ipaddr, sizeof(ipaddr) );
                      if( 0 != rc ) {
                        (void) fprintf( stderr, "Invalid address: [%s]\n",
                                        optarg );
                          rc = ERR_PARAM;
                      }
                      break;

            case 'p':
                      port = atoi( optarg );
                      if( port <= 0 ) {
                        (void) fprintf( stderr, "Invalid port number: [%d]\n",
                                        port );
                        rc = ERR_PARAM;
                      }
                      break;

            case 'm':
                      rc = get_ipv4_address( optarg, mcast_addr,
                              sizeof(mcast_addr) );
                      if( 0 != rc ) {
                        (void) fprintf( stderr, "Invalid multicast address: "
                                "[%s]\n", optarg );
                          rc = ERR_PARAM;
                      }
                      break;

            case 'c':
                      g_uopt.max_clients = atoi( optarg );
                      if( (g_uopt.max_clients < MIN_CLIENT_COUNT) ||
                          (g_uopt.max_clients > MAX_CLIENT_COUNT) ) {
                        (void) fprintf( stderr,
                                "Client count should be between %d and %d\n",
                                MIN_CLIENT_COUNT, MAX_CLIENT_COUNT );
                        rc = ERR_PARAM;
                      }
                      break;

            case 'l':
                      g_flog = fopen( optarg, "a" );
                      if( NULL == g_flog ) {
                        rc = errno;
                        (void) fprintf( stderr, "Error opening logfile "
                                "[%s]: %s\n",
                                optarg, strerror(rc) );
                        rc = ERR_PARAM;
                        break;
                      }

                      Setlinebuf( g_flog );
                      custom_log = 1;
                      break;

            case 'B':
                      rc = a2size(optarg, &g_uopt.rbuf_len);
                      if( 0 != rc ) {
                            (void) fprintf( stderr, "Invalid buffer size: [%s]\n",
                                    optarg );
                            exit( ERR_PARAM );
                      }
                      else if( (g_uopt.rbuf_len < MIN_MCACHE_LEN) ||
                          (g_uopt.rbuf_len > MAX_MCACHE_LEN) ) {
                        fprintf(stderr, "Buffer size "
                                "must be within [%ld-%ld] bytes\n",
                                (long)MIN_MCACHE_LEN, (long)MAX_MCACHE_LEN );
                        rc = ERR_PARAM;
                      }
                      break;

            case 'n':
                      g_uopt.nice_incr = atoi( optarg );
                      if( 0 == g_uopt.nice_incr ) {
                        (void) fprintf( stderr,
                            "Invalid nice-value increment: [%s]\n", optarg );
                        rc = ERR_PARAM;
                        break;
                      }
                      break;

            case 'R':
                      g_uopt.rbuf_msgs = atoi( optarg );
                      if( (g_uopt.rbuf_msgs <= 0) && (-1 != g_uopt.rbuf_msgs) ) {
                        (void) fprintf( stderr,
                                "Invalid Rmsgs size: [%s]\n", optarg );
                        rc = ERR_PARAM;
                        break;
                      }
                      break;

            case 'H':
                      g_uopt.dhold_tmout = (time_t)atoi( optarg );
                      if( (0 == g_uopt.dhold_tmout) ||
                          ((g_uopt.dhold_tmout) < 0 && (-1 != g_uopt.dhold_tmout)) ) {
                        (void) fprintf( stderr, "Invalid value for max time "
                                "to hold buffered data: [%s]\n", optarg );
                        rc = ERR_PARAM;
                        break;
                      }
                      break;

    #ifdef UDPXY_FILEIO
            case 'r':
                      if( 0 != access(optarg, R_OK) ) {
                        perror("source file - access");
                        rc = ERR_PARAM;
                        break;
                      }

                      g_uopt.srcfile = strdup( optarg );
                      break;

            case 'w':
                      g_uopt.dstfile = strdup( optarg );
                      break;
    #endif /* UDPXY_FILEIO */
            case 'M':
                      g_uopt.mcast_refresh = (u_short)atoi( optarg );

                      MIN_MCAST_REFRESH = 30;
                      MAX_MCAST_REFRESH = 64000;
                      if( g_uopt.mcast_refresh &&
                         (g_uopt.mcast_refresh < MIN_MCAST_REFRESH ||
                          g_uopt.mcast_refresh > MAX_MCAST_REFRESH )) {
                            (void) fprintf( stderr, 
                                "Invalid multicast refresh period [%d] seconds, "
                                "min=[%d] sec, max=[%d] sec\n",
                                (int)g_uopt.mcast_refresh,
                                (int)MIN_MCAST_REFRESH, (int)MAX_MCAST_REFRESH );
                            rc = ERR_PARAM;
                            break;
                       }
                      break;

            case ':':
                      (void) fprintf( stderr,
                              "Option [-%c] requires an argument\n",
                                    optopt );
                      rc = ERR_PARAM;
                      break;
            case '?':
                      (void) fprintf( stderr,
                              "Unrecognized option: [-%c]\n", optopt );
                      rc = ERR_PARAM;
                      break;

            default:
                     usage( argv[0], stderr );
                     rc = ERR_PARAM;
                     break;
        }
    } /* while getopt */

    if (rc) {
        free_uopt( &g_uopt );
        return rc;
    }

    openlog( g_udpxy_app, LOG_CONS | LOG_PID, LOG_LOCAL0 );

    do {
        if( (argc < 2) || (port <= 0) || (rc != 0) ) {
            usage( argv[0], stderr );
            rc = ERR_PARAM; break;
        }

        if( '\0' == mcast_addr[0] ) {
            (void) strncpy( mcast_addr, IPv4_ALL, sizeof(mcast_addr) - 1 );
        }

        if( !custom_log ) {
            /* in debug mode output goes to stderr, otherwise to /dev/null */
            g_flog = ((uf_TRUE == g_uopt.is_verbose)
                    ? stderr
                    : fopen( "/dev/null", "a" ));
            if( NULL == g_flog ) {
                perror("fopen");
                rc = ERR_INTERNAL; break;
            }
        }

        if( 0 == geteuid() ) {
            if( !no_daemon ) {
                if( stderr == g_flog ) {
                    (void) fprintf( stderr,
                        "Logfile must be specified to run "
                        "in verbose mode in background\n" );
                    rc = ERR_PARAM; break;
                }

                if( 0 != (rc = daemonize(0, g_flog)) ) {
                    rc = ERR_INTERNAL; break;
                }
            }

            rc = set_pidfile( g_udpxy_app, port, pidfile, sizeof(pidfile) );
            if( 0 != rc ) {
                mperror( g_flog, errno, "set_pidfile" );
                rc = ERR_INTERNAL; break;
            }

            if( 0 != (rc = make_pidfile( pidfile, getpid(), g_flog )) )
                break;
        }

        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)) {
            perror("sigaction-quit");
            rc = ERR_INTERNAL; break;
        }

        iact.sa_handler = SIG_IGN;
        sigemptyset(&iact.sa_mask);
        iact.sa_flags = 0;

        if( (sigaction(SIGPIPE, &iact, &oldact) < 0) ) {
            perror("sigaction-ignore");
            rc = ERR_INTERNAL; break;
        }

        cact.sa_handler = handle_sigchld;
        sigemptyset(&cact.sa_mask);
        cact.sa_flags = 0;

        if( sigaction(SIGCHLD, &cact, &oldact) < 0 ) {
            perror("sigaction-sigchld");
            rc = ERR_INTERNAL; break;
        }

        syslog( LOG_NOTICE, "%s is starting\n", g_udpxy_finfo );
        TRACE( printcmdln( g_flog, g_udpxy_finfo, argc, argv ) );

        rc = srv_loop( ipaddr, port, mcast_addr );

        syslog( LOG_NOTICE, "%s is exiting with rc=[%d]\n",
                g_udpxy_finfo, rc);
        TRACE( tmfprintf( g_flog, "%s is exiting with rc=[%d]\n",
                    g_udpxy_app, rc ) );
        TRACE( printcmdln( g_flog, g_udpxy_finfo, argc, argv ) );
    } while(0);

    if( '\0' != pidfile[0] ) {
        if( -1 == unlink(pidfile) ) {
            mperror( g_flog, errno, "unlink [%s]", pidfile );
        }
    }

    if( g_flog && (stderr != g_flog) ) {
        (void) fclose(g_flog);
    }

    closelog();
    free_uopt( &g_uopt );

    return rc;
}