⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sock.c

📁 代码在ti的c67系列单片机上实现了完整的TCPIP协议栈
💻 C
📖 第 1 页 / 共 3 页
字号:
//--------------------------------------------------------------------------
// Ip Stack
//--------------------------------------------------------------------------
// SOCK.C
//
// Object member functions for the Sock device object.
//
// These functions get access to the SOCK object structure and can
// adjust values, but usually call protocol functions for perform
// action.
//
// Author: Michael A. Denio
// Copyright 1999 by Texas Instruments Inc.
//-------------------------------------------------------------------------
#include <stkmain.h>
#include "sock.h"

//--------------------------------------------------------------------
// SockNew()
//
// Creates a socket
//--------------------------------------------------------------------
int SockNew( int Family, int Type, int Protocol, HANDLE hFd, HANDLE *phSock )
{
    SOCK   *ps;
    int    error = 0;

    //
    // Check to see is request makes sense
    //
    // AF_INET, SOCK_DGRAM: must use IPPROTO_UDP
    // AF_INET, SOCK_STREAM: must use IPPROTO_TCP
    // AF_INET, SOCK_RAW: protocol can be anything, including NULL
    //
    if( Family != AF_INET )
        return( EPFNOSUPPORT );

    if( Type == SOCK_DGRAM )
    {
        if( !Protocol )
            Protocol = IPPROTO_UDP;
        else if( Protocol != IPPROTO_UDP)
            return( EPROTOTYPE );
    }
    else if( Type == SOCK_STREAM || Type == SOCK_STREAMNC )
    {
        if( !Protocol )
            Protocol = IPPROTO_TCP;
        else if( Protocol != IPPROTO_TCP )
            return( EPROTOTYPE );
    }
    else if( Type != SOCK_RAW )
        return( ESOCKTNOSUPPORT );

    //
    // If we got here, we have a legal socket request
    //

    // Attempt to allocate space for the socket
    if( !(ps = mmAlloc(sizeof(SOCK))) )
    {
        DbgPrintf(DBG_WARN,"SockNew: OOM");
        ExecLowResource();
        error = ENOMEM;
        goto socknew_done;
    }

    // Initialize what we can
    mmZeroInit( ps, sizeof(SOCK) );     // Most Q's and counts init to Zero
    ps->Type      = HTYPE_SOCK;
    ps->hFd       = hFd;                // Set handle to owning file desc.
    ps->Family    = (uint)Family;       // INET or FILE
    ps->SockType  = (uint)Type;         // STREAM, DGRAM or RAW
    ps->Protocol  = (uint)Protocol;     // IP protocol # or NULL

    ps->IpTtl     = SOCK_TTL_DEFAULT;
    ps->IpTos     = SOCK_TOS_DEFAULT;

    // Init default timeouts
    ps->dwRxTimeout  = SOCK_TIMEIO * 1000;
    ps->dwTxTimeout  = SOCK_TIMEIO * 1000;

    // Allocate Rx socket buffer
    if( Type == SOCK_STREAM )
        ps->hSBRx = SBNew( SOCK_BUFMAX, SOCK_BUFMINRX, SB_MODE_LINEAR );
    else if( Type == SOCK_STREAMNC )
    {
        ps->StateFlags = SS_ATOMICREAD;
        ps->hSBRx = SBNew( SOCK_BUFMAX, SOCK_BUFMINRX, SB_MODE_HYBRID );
    }
    else
    {
        ps->StateFlags = SS_ATOMICREAD | SS_ATOMIC;
        ps->hSBRx = SBNew( SOCK_BUFMAX, SOCK_BUFMINRX, SB_MODE_ATOMIC );
    }
    if( !ps->hSBRx )
    {
        error = ENOMEM;
        goto socknew_error;
    }

    // Finalize Socket Status
    if( Type == SOCK_STREAM || Type == SOCK_STREAMNC )
    {
        ps->StateFlags |= SS_CONNREQUIRED;

        ps->hSBTx = SBNew( SOCK_BUFMAX, SOCK_BUFMINTX, SB_MODE_LINEAR );
        if( !ps->hSBTx )
        {
            error = ENOMEM;
            goto socknew_error;
        }

        // Set the SockProt Type
        ps->SockProt = SOCKPROT_TCP;
    }
    else
    {
        ps->StateFlags |= (SS_ADDR | SS_ATOMICWRITE);

        ps->hSBTx = 0;

        // Set the SockProt Type
        if( Type == SOCK_DGRAM )
            ps->SockProt = SOCKPROT_UDP;
        else
            ps->SockProt = SOCKPROT_RAW;
    }

    // Attach the socket to protocol processing
    if( (error = SockPrAttach( ps )) )
        goto socknew_error;

    *phSock = (HANDLE)ps;

socknew_done:
    // Return
    return( error );

socknew_error:
    ps->Type = 0;

    // Free the Rx and Tx Buffers
    if( ps->hSBRx )
        SBFree( ps->hSBRx );
    if( ps->hSBTx )
        SBFree( ps->hSBTx );

    // Free the socket
    mmFree( ps );

    // Return the error
    return( error );
}

//--------------------------------------------------------------------
// SockClose()
//
// Close a socket
//--------------------------------------------------------------------
int SockClose( HANDLE h )
{
    SOCK *ps = (SOCK *)h;
    int  error = 0;

#ifdef _STRONG_CHECKING
    if( ps->Type != HTYPE_SOCK )
    {
        DbgPrintf(DBG_ERROR,"SockClose: HTYPE %04x",ps->Type);
        return( ENOTSOCK );
    }
#endif

    // Abort any incoming connections to a "listening" socket
    if( ps->OptionFlags & SO_ACCEPTCONN )
    {
        SOCK *psTemp;

        while( ps->pPending )
        {
            // Dequeue the socket
            psTemp = ps->pPending;
            ps->pPending = psTemp->pPending;
            psTemp->StateFlags &= ~SS_PENDINGQ;

            // Abort the socket
            SockIntAbort( psTemp );
        }

        while( ps->pReady )
        {
            // Dequeue the socket
            psTemp = ps->pReady;
            ps->pReady = psTemp->pReady;
            psTemp->StateFlags &= ~SS_READYQ;

            // Abort the socket
            SockIntAbort( psTemp );
        }

        ps->ConnTotal = 0;
    }

    // If not connection oriented, we're done
    if( !(ps->StateFlags & SS_CONNREQUIRED) )
        goto close_drop;

    // Disconnect any connections to the connection oriented socket
    if( ps->StateFlags & SS_ISCONNECTED )
    {
        // Flush the input queue (we're not going to be reading)
        SockShutdown( ps, FREAD );

        // If linger is not set, we'll free the socket via our SockNotify
        if( !(ps->OptionFlags & SO_LINGER) )
        {
            ps->StateFlags |= SS_CLOSING;

            // Start Disconnect
            return( SockPrDisconnect( ps ) );
        }

        // Since linger is set, we'll drop the socket now (after linger time)
        ps->StateFlags |= SS_LINGERING;
        error = SockPrDisconnect( ps );
        if( error )
            goto close_drop;

        // Can't linger on non-blocking sockets
        if( ps->StateFlags & SS_NBIO )
            goto close_drop;

        // If no linget time, drop now
        if( !ps->dwLingerTime )
            goto close_drop;

        // Wait for the socket to disconnect
        while( ps->StateFlags & SS_LINGERING )
        {
            // If we ever timeout, break out of this loop
            if( !FDWaitEvent( ps->hFd, FD_EVENT_READ, ps->dwLingerTime ) )
                break;
        }
    }

close_drop:
    SockIntAbort( ps );

    return( error );
}

//--------------------------------------------------------------------
// SockIntAbort()
//
// Close a socket - Called only internally to stack
//--------------------------------------------------------------------
void SockIntAbort( SOCK *ps )
{
    // Detach the socket from protocol processing
    SockPrDetach( ps );

    // DeRef any held route
    if( ps->hRoute )
        RtDeRef( ps->hRoute );

    // Free the Rx and Tx Buffers
    if( ps->hSBRx )
        SBFree( ps->hSBRx );
    if( ps->hSBTx )
        SBFree( ps->hSBTx );

    // Free the sock memory
    mmFree( ps );
}

//--------------------------------------------------------------------
// SockCheck()
//
// Check for socket read/write/except status
//--------------------------------------------------------------------
int SockCheck( HANDLE h, int IoType )
{
    SOCK *ps = (SOCK *)h;

#ifdef _STRONG_CHECKING
    if( ps->Type != HTYPE_SOCK )
    {
        DbgPrintf(DBG_ERROR,"SockCheck: HTYPE %04x",ps->Type);
        return( 0 );
    }
#endif

    switch( IoType )
    {
    case SOCK_READ:
        //
        // Return TRUE if readable
        //

        if( ps->OptionFlags & SO_ACCEPTCONN )
        {
            if( ps->pReady || ps->ErrorPending )
                return(1);
        }
        else
        {
            if( SBGetTotal(ps->hSBRx) >= SBGetMin(ps->hSBRx) ||
                    ps->StateFlags & SS_CANTRCVMORE || ps->ErrorPending )
                return(1);
        }
        break;

    case SOCK_WRITE:
        //
        // Return TRUE if writeable
        //

        // Listening sockets can never be written
        // We return 1 so some Bozo won't sleep on it
        // If error pending, then can write (will get error)
        if( (ps->OptionFlags & SO_ACCEPTCONN) || ps->ErrorPending )
            return(1);

        // Verify we're connected
        if( !(ps->StateFlags & SS_CONNREQUIRED) ||
             (ps->StateFlags & SS_ISCONNECTED)  )
        {
            // Writable "connected" cases
            if( (ps->StateFlags & SS_CANTSENDMORE) ||
                    (ps->StateFlags & SS_ATOMICWRITE) ||
                    (SBGetSpace(ps->hSBTx) >= SBGetMin(ps->hSBTx)) )
                return(1);
        }
        break;

    case SOCK_EXCEPT:
        // Return TRUE if OOB data present
        if( ps->StateFlags & SS_OOBACTIVE )
            return(1);
        break;
    }
    return(0);
}


//--------------------------------------------------------------------
// SockShutdown()
//
// Shutdown Socket Connection
//--------------------------------------------------------------------
int SockShutdown( HANDLE h, int how )
{
    SOCK   *ps = (SOCK *)h;

#ifdef _STRONG_CHECKING
    if( ps->Type != HTYPE_SOCK )
    {
        DbgPrintf(DBG_ERROR,"SockShutdown: HTYPE %04x",ps->Type);
        return( ENOTSOCK );
    }
#endif

    // Shutdown Read
    if( how & FREAD )
    {
        ps->StateFlags |= SS_CANTRCVMORE;

        // Perform read flush
        if( ps->hSBRx )
            SBFlush( ps->hSBRx, 1 );

        // Notify the protocol of status change
        SockPrRecv( ps );
    }

    // Shutdown Write
    if( how & FWRITE )
    {
        ps->StateFlags |= SS_CANTSENDMORE;

        // If the socket is connection oriented, we should tell the
        // peer that we're done sending data.
        if( ps->StateFlags & SS_CONNREQUIRED )
            SockPrDisconnect( ps );
    }
    return(0);
}

//--------------------------------------------------------------------
// SockConnect()
//
// Create Socket Connection
//--------------------------------------------------------------------
int SockConnect( HANDLE h, PSA pName )
{
    SOCK   *ps = (SOCK *)h;
    int    error = 0;
    HANDLE hRt;

#ifdef _STRONG_CHECKING
    if( ps->Type != HTYPE_SOCK )
    {
        DbgPrintf(DBG_ERROR,"SockConnect: HTYPE %04x",ps->Type);
        return( ENOTSOCK );
    }
#endif

    // If socket is "accepting", then it can't "connect"
    if( ps->OptionFlags & SO_ACCEPTCONN )
    {
        error = EOPNOTSUPP;
        goto SockConnectDone;
    }

    // We can have only one active connection
    // If connection oriented, we can have only one active connection
    if( ps->StateFlags & (SS_ISCONNECTED | SS_ISCONNECTING) )
    {
        // If connection oriented, we have an error condition
        if( ps->StateFlags & SS_CONNREQUIRED )
        {
            error = EISCONN;
            goto SockConnectDone;
        }
        // Otherwise, we'll disconnect first
        if( error = SockDisconnect( h ) )
            goto SockConnectDone;
    }

    // First create the socket side binding
    //
    // If we aren't bound to an IP, we'll just pick one. We try and pick
    // the IP address of the egress device that matches the Ip network of
    // the destination address.
    //
    // Note: If dwLIP is valid, then the port must also be valid
    //
    if( !ps->dwLIP )
    {
        UINT32 dwIPHost;

        // If the socket has an egress device, then we'll use the
        // IP address of that device
        if( ps->hIFTx )
            dwIPHost = BindIF2IPHost( ps->hIFTx );
        // Else get the IP address that makes the most sense
        else if( !(dwIPHost = BindIFNet2IPHost( 0, pName->sin_addr.s_addr )) )
        {
            // We don't have an IP address on the subnet of the destination,
            // so try finding a route

            // If the destination is a BCAST, we don't use a route. Otherwise;
            // find the next hop for this destination. Search with cloning.
            if( pName->sin_addr.s_addr != INADDR_ANY &&
                pName->sin_addr.s_addr != INADDR_BROADCAST )
            {
                hRt = IPGetRoute( FLG_RTF_CLONE, pName->sin_addr.s_addr, 0 );
                if( hRt )
                {
                    dwIPHost = BindIF2IPHost( RtGetIF(hRt) );
                    RtDeRef(hRt);
                }
            }

            // If all the nice methods failed, fall back and use any
            // IP addr we can get our hands on...
            if( !dwIPHost && !(dwIPHost = BindIF2IPHost( 0 )) )
            {
                // Here we have no IP addresses, plus the user did not
                // specify an egress device. So we don't send out packets
                // with 0.0.0.0 haphazardly, we'll error out instead
                error = ENXIO;
                goto SockConnectDone;
            }
        }

        if( (error = SockPcbBind( h, dwIPHost, 0 )) )
            goto SockConnectDone;
    }

    // Establish the PCB socket connection
    if( (error = SockPcbConnect( h, pName->sin_addr.s_addr, pName->sin_port )) )
        goto SockConnectDone;

    // Make sure these are clear
    ps->StateFlags &= ~(SS_CANTRCVMORE | SS_CANTSENDMORE);

    // Validate a route for this connection
    hRt = SockValidateRoute( ps );

    // Non-Connection oriented socket just "connects"
    if( !(ps->StateFlags & SS_CONNREQUIRED) )
    {
        // Easy case - just set to ISCONNECTED
        ps->StateFlags |= SS_ISCONNECTED;
        goto SockConnectDone;
    }

    // A connection oriented socket will not connect if we didn't find
    // a route.
    if( !hRt )
        return( EHOSTUNREACH );

    // Set ISCONNECTING flag (ISCONNECTED set via SockNotify)
    ps->StateFlags |= SS_ISCONNECTING;

    // Establish the protocol connection
    error = SockPrConnect( ps );

    // If no error and not connected and not non-blocking, we wait
    while( !error && !ps->ErrorPending &&
           !(ps->StateFlags & (SS_NBIO|SS_ISCONNECTED)) )
    {
        // If we ever time out, we have an error
        if( !FDWaitEvent( ps->hFd, FD_EVENT_READ, SOCK_TIMECONNECT*1000 ) )
            error = ETIMEDOUT;
    }

    if( ps->ErrorPending )
    {
        error = ps->ErrorPending;
        ps->ErrorPending = 0;
    }

    if( error )
    {
        ps->StateFlags &= ~SS_ISCONNECTING;
        SockPrDisconnect( ps );
    }

SockConnectDone:
    return( error );
}

//--------------------------------------------------------------------
// SockDisconnect()
//
// Disconnect a Socket
//--------------------------------------------------------------------
int SockDisconnect( HANDLE h )
{
    SOCK *ps = (SOCK *)h;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -