示例#1
0
文件: udpxy.c 项目: avble/udpxy
/* 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;
}
示例#2
0
文件: serial.c 项目: howard5888/wineT
/******************************************************************
 *		COMM_DeviceIoControl
 *
 *
 */
NTSTATUS COMM_DeviceIoControl(HANDLE hDevice, 
                              HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
                              PVOID UserApcContext, 
                              PIO_STATUS_BLOCK piosb, 
                              ULONG dwIoControlCode,
                              LPVOID lpInBuffer, DWORD nInBufferSize,
                              LPVOID lpOutBuffer, DWORD nOutBufferSize)
{
    DWORD       sz = 0, access = FILE_READ_DATA;
    NTSTATUS    status = STATUS_SUCCESS;
    int         fd = -1;

    TRACE("%p %s %p %ld %p %ld %p\n",
          hDevice, iocode2str(dwIoControlCode), lpInBuffer, nInBufferSize,
          lpOutBuffer, nOutBufferSize, piosb);

    piosb->Information = 0;

    if (dwIoControlCode != IOCTL_SERIAL_GET_TIMEOUTS)
        if ((status = wine_server_handle_to_fd( hDevice, access, &fd, NULL )))
            goto error;

    switch (dwIoControlCode)
    {
    case IOCTL_SERIAL_CLR_DTR:
#ifdef TIOCM_DTR
        if (whack_modem(fd, ~TIOCM_DTR, 0) == -1) status = FILE_GetNtStatus();
#else
        status = STATUS_NOT_SUPPORTED;
#endif
        break;
    case IOCTL_SERIAL_CLR_RTS:
#ifdef TIOCM_RTS
        if (whack_modem(fd, ~TIOCM_RTS, 0) == -1) status = FILE_GetNtStatus();
#else
        status = STATUS_NOT_SUPPORTED;
#endif
        break;
    case IOCTL_SERIAL_GET_BAUD_RATE:
        if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_BAUD_RATE))
        {
            if (!(status = get_baud_rate(fd, (SERIAL_BAUD_RATE*)lpOutBuffer)))
                sz = sizeof(SERIAL_BAUD_RATE);
        }
        else
            status = STATUS_INVALID_PARAMETER;
        break;
    case IOCTL_SERIAL_GET_CHARS:
        if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_CHARS))
        {
            if (!(status = get_special_chars(fd, (SERIAL_CHARS*)lpOutBuffer)))
                sz = sizeof(SERIAL_CHARS);
        }
        else
            status = STATUS_INVALID_PARAMETER;
        break;
     case IOCTL_SERIAL_GET_COMMSTATUS:
        if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_STATUS))
        {
            if (!(status = get_status(fd, (SERIAL_STATUS*)lpOutBuffer)))
                sz = sizeof(SERIAL_STATUS);
        }
        else status = STATUS_INVALID_PARAMETER;
        break;
    case IOCTL_SERIAL_GET_HANDFLOW:
        if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_HANDFLOW))
        {
            if (!(status = get_hand_flow(fd, (SERIAL_HANDFLOW*)lpOutBuffer)))
                sz = sizeof(SERIAL_HANDFLOW);
        }
        else
            status = STATUS_INVALID_PARAMETER;
        break;
    case IOCTL_SERIAL_GET_LINE_CONTROL:
        if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_LINE_CONTROL))
        {
            if (!(status = get_line_control(fd, (SERIAL_LINE_CONTROL*)lpOutBuffer)))
                sz = sizeof(SERIAL_LINE_CONTROL);
        }
        else
            status = STATUS_INVALID_PARAMETER;
        break;
    case IOCTL_SERIAL_GET_MODEMSTATUS:
        if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
        {
            if (!(status = get_modem_status(fd, (DWORD*)lpOutBuffer)))
                sz = sizeof(DWORD);
        }
        else status = STATUS_INVALID_PARAMETER;
        break;
    case IOCTL_SERIAL_GET_TIMEOUTS:
        if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_TIMEOUTS))
        {
            if (!(status = get_timeouts(hDevice, (SERIAL_TIMEOUTS*)lpOutBuffer)))
                sz = sizeof(SERIAL_TIMEOUTS);
        }
        else
            status = STATUS_INVALID_PARAMETER;
        break;
    case IOCTL_SERIAL_GET_WAIT_MASK:
        if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
        {
            if (!(status = get_wait_mask(hDevice, (DWORD*)lpOutBuffer)))
                sz = sizeof(DWORD);
        }
        else
            status = STATUS_INVALID_PARAMETER;
        break;
    case IOCTL_SERIAL_IMMEDIATE_CHAR:
        if (lpInBuffer && nInBufferSize == sizeof(CHAR))
            status = xmit_immediate(hDevice, fd, lpInBuffer);
        else
            status = STATUS_INVALID_PARAMETER;
        break;
    case IOCTL_SERIAL_PURGE:
        if (lpInBuffer && nInBufferSize == sizeof(DWORD))
            status = purge(fd, *(DWORD*)lpInBuffer);
        else
            status = STATUS_INVALID_PARAMETER;
        break;
    case IOCTL_SERIAL_RESET_DEVICE:
        FIXME("Unsupported\n");
        break;
    case IOCTL_SERIAL_SET_BAUD_RATE:
        if (lpInBuffer && nInBufferSize == sizeof(SERIAL_BAUD_RATE))
            status = set_baud_rate(fd, (const SERIAL_BAUD_RATE*)lpInBuffer);
        else
            status = STATUS_INVALID_PARAMETER;
        break;
    case IOCTL_SERIAL_SET_BREAK_OFF:
#if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
	if (ioctl(fd, TIOCCBRK, 0) == -1)
        {
            TRACE("ioctl failed\n");
            status = FILE_GetNtStatus();
        }
#else
	FIXME("ioctl not available\n");
	status = STATUS_NOT_SUPPORTED;
#endif
        break;
    case IOCTL_SERIAL_SET_BREAK_ON:
#if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
	if (ioctl(fd, TIOCSBRK, 0) == -1)
        {
            TRACE("ioctl failed\n");
            status = FILE_GetNtStatus();
        }
#else
	FIXME("ioctl not available\n");
	status = STATUS_NOT_SUPPORTED;
#endif
        break;
    case IOCTL_SERIAL_SET_CHARS:
        if (lpInBuffer && nInBufferSize == sizeof(SERIAL_CHARS))
            status = set_special_chars(fd, (const SERIAL_CHARS*)lpInBuffer);
        else
            status = STATUS_INVALID_PARAMETER;
        break;
    case IOCTL_SERIAL_SET_DTR:
#ifdef TIOCM_DTR
        if (whack_modem(fd, 0, TIOCM_DTR) == -1) status = FILE_GetNtStatus();
#else
        status = STATUS_NOT_SUPPORTED;
#endif
        break;
    case IOCTL_SERIAL_SET_HANDFLOW:
        if (lpInBuffer && nInBufferSize == sizeof(SERIAL_HANDFLOW))
            status = set_handflow(fd, (const SERIAL_HANDFLOW*)lpInBuffer);
        else
            status = STATUS_INVALID_PARAMETER;
        break;
    case IOCTL_SERIAL_SET_LINE_CONTROL:
        if (lpInBuffer && nInBufferSize == sizeof(SERIAL_LINE_CONTROL))
            status = set_line_control(fd, (const SERIAL_LINE_CONTROL*)lpInBuffer);
        else
            status = STATUS_INVALID_PARAMETER;
        break;
    case IOCTL_SERIAL_SET_QUEUE_SIZE:
        if (lpInBuffer && nInBufferSize == sizeof(SERIAL_QUEUE_SIZE))
            status = set_queue_size(fd, (const SERIAL_QUEUE_SIZE*)lpInBuffer);
        else
            status = STATUS_INVALID_PARAMETER;
        break;
    case IOCTL_SERIAL_SET_RTS:
#ifdef TIOCM_RTS
        if (whack_modem(fd, 0, TIOCM_RTS) == -1) status = FILE_GetNtStatus();
#else
        status = STATUS_NOT_SUPPORTED;
#endif
        break;
    case IOCTL_SERIAL_SET_TIMEOUTS:
        if (lpInBuffer && nInBufferSize == sizeof(SERIAL_TIMEOUTS))
            status = set_timeouts(hDevice, fd, (const SERIAL_TIMEOUTS*)lpInBuffer);
        else
            status = STATUS_INVALID_PARAMETER;
        break;
    case IOCTL_SERIAL_SET_WAIT_MASK:
        if (lpInBuffer && nInBufferSize == sizeof(DWORD))
        {
            status = set_wait_mask(hDevice, *(DWORD*)lpInBuffer);
        }
        else status = STATUS_INVALID_PARAMETER;
        break;
    case IOCTL_SERIAL_SET_XOFF:
        status = set_XOff(fd);
        break;
    case IOCTL_SERIAL_SET_XON:
        status = set_XOn(fd);
        break;
    default:
        FIXME("Unsupported IOCTL %lx (type=%lx access=%lx func=%lx meth=%lx)\n", 
              dwIoControlCode, dwIoControlCode >> 16, (dwIoControlCode >> 14) & 3,
              (dwIoControlCode >> 2) & 0xFFF, dwIoControlCode & 3);
        sz = 0;
        status = STATUS_INVALID_PARAMETER;
        break;
    }
    if (fd != -1) wine_server_release_fd( hDevice, fd );
 error:
    piosb->u.Status = status;
    piosb->Information = sz;
    if (hEvent) NtSetEvent(hEvent, NULL);
    return status;
}