?lang_form? ?lang_select? ?lang_submit? ?lang_endform?
{HEADER END}
{FILE START}

library

?curdirlinks? - Rev 32

?prevdifflink? - Blame - ?getfile?

/*********************************************************************
 *
 *     Berekely Socket Distribution API Source File
 *
 *********************************************************************
 * FileName:        BerkeleyAPI.c
 * Description:     Berkeley Socket Distribution(BSD) APIs for Microchip TCPIP Stack
 * Processor:       PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F, PIC32
 * Compiler:        Microchip C32 v1.05 or higher
 *                                      Microchip C30 v3.12 or higher
 *                                      Microchip C18 v3.30 or higher
 *                                      HI-TECH PICC-18 PRO 9.63PL2 or higher
 * Company:         Microchip Technology, Inc.
 *
 * Software License Agreement
 *
 * Copyright (C) 2002-2009 Microchip Technology Inc.  All rights
 * reserved.
 *
 * Microchip licenses to you the right to use, modify, copy, and
 * distribute:
 * (i)  the Software when embedded on a Microchip microcontroller or
 *      digital signal controller product ("Device") which is
 *      integrated into Licensee's product; or
 * (ii) ONLY the Software driver source files ENC28J60.c, ENC28J60.h,
 *              ENCX24J600.c and ENCX24J600.h ported to a non-Microchip device
 *              used in conjunction with a Microchip ethernet controller for
 *              the sole purpose of interfacing with the ethernet controller.
 *
 * You should refer to the license agreement accompanying this
 * Software for additional information regarding your rights and
 * obligations.
 *
 * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
 * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
 * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
 * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
 * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
 * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
 * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
 * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
 * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
 *
 * Author               Date            Comment
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Aseem Swalah         4/3/08          Original
 ********************************************************************/

#include "TCPIPConfig.h"

#if defined(STACK_USE_BERKELEY_API)

#include "TCPIP Stack/TCPIP.h"

static BOOL HandlePossibleTCPDisconnection(SOCKET s);


#if defined(__18CXX) && !defined(HI_TECH_C)     
        #pragma udata BSD_uRAM
#endif
static struct BSDSocket  BSDSocketArray[BSD_SOCKET_COUNT];
#if defined(__18CXX) && !defined(HI_TECH_C)     
        #pragma udata
#endif

static WORD gAutoPortNumber = 1024;


/*****************************************************************************
  Function:
        void BerkeleySocketInit(void)

  Summary:
        Initializes the Berkeley socket structure array.

  Description:
        This function initializes the Berkeley socket array. This function should
        be called before any BSD socket call.

  Precondition:
        None.

  Parameters:
        None.

  Returns:
        None

  Remarks:
        None.
  ***************************************************************************/
void BerkeleySocketInit(void)
{
        unsigned int s;
        struct BSDSocket *socket;

        for ( s = 0; s < BSD_SOCKET_COUNT; s++ )
        {
                socket             = (struct BSDSocket *)&BSDSocketArray[s];
                socket->bsdState   = SKT_CLOSED;
        }
}

/*****************************************************************************
  Function:
        SOCKET socket( int af, int type, int protocol )

  Summary:
        This function creates a new Berkeley socket.

  Description:
        This function creates a new BSD socket for the microchip
        TCPIP stack. The return socket descriptor is used for the subsequent
        BSD operations.

  Precondition:
        BerkeleySocketInit function should be called.

  Parameters:
        af - address family - AF_INET.
        type - socket type SOCK_DGRAM or SOCK_STREAM.
        protocol - IP protocol IPPROTO_UDP or IPPROTO_TCP.

  Returns:
        New socket descriptor. INVALID_SOCKET in case of error.

  Remarks:
        None.
  ***************************************************************************/
SOCKET socket( int af, int type, int protocol )
{
        struct BSDSocket *socket = BSDSocketArray;
        SOCKET s;

        if( af != AF_INET )
                return INVALID_SOCKET;

        for( s = 0; s < BSD_SOCKET_COUNT; s++,socket++ )
        {
                if( socket->bsdState != SKT_CLOSED ) //socket in use
                        continue;

                socket->SocketType = type;

                if( type == SOCK_DGRAM && protocol == IPPROTO_UDP )
                {
                        socket->bsdState = SKT_CREATED;
                        return s;
                }
                else if( type == SOCK_STREAM && protocol == IPPROTO_TCP )
                {
                        socket->bsdState = SKT_CREATED;
                        return s;
                }
                else
                        return INVALID_SOCKET;
        }

        return INVALID_SOCKET;
}

/*****************************************************************************
  Function:
        int bind( SOCKET s, const struct sockaddr* name, int namelen )

  Summary:
        This function assigns a name to the socket descriptor.

  Description:
        The bind function assigns a name to an unnamed socket. The
    name represents the local address of the communication
    endpoint. For sockets of type SOCK_STREAM, the name of the
    remote endpoint is assigned when a connect or accept function
    is executed.

  Precondition:
        socket function should be called.

  Parameters:
        s - Socket descriptor returned from a previous call to socket.
        name - pointer to the sockaddr structure containing the
        local address of the socket.
        namelen - length of the sockaddr structure.

  Returns:
        If bind is successful, a value of 0 is returned. A return
    value of SOCKET_ERROR indicates an error.

  Remarks:
        None.
  ***************************************************************************/
int bind( SOCKET s, const struct sockaddr* name, int namelen )
{
        struct BSDSocket *socket;
        struct sockaddr_in *local_addr;
        WORD lPort;

        if( s >= BSD_SOCKET_COUNT )
                return SOCKET_ERROR;

        socket = &BSDSocketArray[s];

        if( socket->bsdState != SKT_CREATED ) //only work with recently created socket
                return SOCKET_ERROR;

        if( (unsigned int)namelen < sizeof(struct sockaddr_in) )
                return SOCKET_ERROR;

        local_addr = (struct sockaddr_in *)name;

        lPort = local_addr->sin_port;
    if( lPort == 0u ) //pick a port
        {
                lPort = gAutoPortNumber++;
        if(gAutoPortNumber > 5000u) // reset the port numbers
                        gAutoPortNumber = 1024;
        }

        if(socket->SocketType == SOCK_DGRAM)
        {
                socket->SocketID = UDPOpen(lPort, NULL, 0);
                if(socket->SocketID == INVALID_UDP_SOCKET)
                        return SOCKET_ERROR;
        }

        socket->localPort = lPort;
        socket->bsdState  = SKT_BOUND;
        return 0; //success
}

/*****************************************************************************
  Function:
        int listen( SOCKET s, int backlog )

  Summary:
        The listen function sets the specified socket in a listen mode

  Description:
        This function sets the specified socket in a listen
        mode. Calling the listen function indicates that the
        application is ready to accept connection requests arriving
        at a socket of type SOCK_STREAM. The connection request is
        queued (if possible) until accepted with an accept function.
        The backlog parameter defines the maximum number of pending
        connections that may be queued.

  Precondition:
        bind() must have been called on the s socket first.

  Parameters:
        s - Socket identifier returned from a prior socket() call.
        backlog - Maximum number of connection requests that can be queued.  Note 
                that each backlog requires a TCP_PURPOSE_BERKELEY_SERVER type TCP 
                socket to be allocated in the TCPSocketInitializer[] in TCPIPConfig.h.
                Also, ensure that BSD_SOCKET_COUNT (also in TCPIPConfig.h) is greater 
                than the backlog by at least 1 (more if you have other BSD sockets in 
                use).
        
  Returns:
        Returns 0 on success, else return SOCKET_ERROR.

  Remarks:
        None
  ***************************************************************************/
int listen( SOCKET s, int backlog )
{
        struct BSDSocket *ps;
        SOCKET clientSockID;
        unsigned int socketcount;
        unsigned char assigned;

        if( s >= BSD_SOCKET_COUNT )
                return SOCKET_ERROR;

        ps = &BSDSocketArray[s];

        if(ps->SocketType != SOCK_STREAM)
                return SOCKET_ERROR;

        if(ps->bsdState == SKT_BSD_LISTEN)
                backlog = ps->backlog;

        if((ps->bsdState != SKT_BOUND) && (ps->bsdState != SKT_BSD_LISTEN))
                return SOCKET_ERROR;

        while(backlog--)
        {
                assigned = 0;
                for(socketcount = 0; socketcount < BSD_SOCKET_COUNT; socketcount++)
                {
                        if(BSDSocketArray[socketcount].bsdState != SKT_CLOSED)
                                continue;

                        clientSockID = TCPOpen(0, TCP_OPEN_SERVER, ps->localPort, TCP_PURPOSE_BERKELEY_SERVER);
                        if(clientSockID == INVALID_SOCKET)
                                return SOCKET_ERROR;
                                
                        // Clear the first reset flag
                        TCPWasReset(clientSockID);

                        assigned = 1;
                        ps->bsdState = SKT_BSD_LISTEN;
                        ps->backlog = backlog;

                        BSDSocketArray[socketcount].SocketID = clientSockID;
                        BSDSocketArray[socketcount].bsdState = SKT_LISTEN;
                        BSDSocketArray[socketcount].isServer = TRUE;
                        BSDSocketArray[socketcount].localPort = ps->localPort;
                        BSDSocketArray[socketcount].SocketType = SOCK_STREAM;
                        break;
                }
                if(!assigned)
                        return SOCKET_ERROR;
        }
        return 0; //Success
}


/*****************************************************************************
  Function:
        SOCKET accept(SOCKET s, struct sockaddr* addr, int* addrlen)

  Summary:
        This function accepts connection requests queued for a listening socket.

  Description:
        The accept function is used to accept connection requests
        queued for a listening socket. If a connection request is
        pending, accept removes the request from the queue, and a new
        socket is created for the connection. The original listening
        socket remains open and continues to queue new connection
        requests. The socket must be a SOCK_STREAM type socket.

  Precondition:
        listen function should be called.

  Parameters:
        s - Socket descriptor returned from a previous call to
        socket. must be bound to a local name and in listening mode.
        addr - Optional pointer to a buffer that receives the address
        of the connecting entity.
        addrlen - Optional pointer to an integer that contains the
        length of the address addr

  Returns:
        If the accept function succeeds, it returns a non-negative
        integer that is a descriptor for the accepted socket.
        Otherwise, the value INVALID_SOCKET is returned.

  Remarks:
        None.
  ***************************************************************************/
SOCKET accept(SOCKET s, struct sockaddr* addr, int* addrlen)
{
        struct BSDSocket *pListenSock;
        SOCKET_INFO *remoteSockInfo;
        struct sockaddr_in *addrRemote;
        unsigned int sockCount;
        TCP_SOCKET hTCP;

        if( s >= BSD_SOCKET_COUNT )
                return INVALID_SOCKET;

        pListenSock = &BSDSocketArray[s]; /* Get the pointer to listening server socket */

        if ( pListenSock->bsdState != SKT_BSD_LISTEN )
                return INVALID_SOCKET;
        if ( pListenSock->SocketType != SOCK_STREAM )
                return INVALID_SOCKET;

        for(sockCount = 0; sockCount < BSD_SOCKET_COUNT; sockCount++)
        {
                if(BSDSocketArray[sockCount].bsdState != SKT_LISTEN)
                        continue;

                if(BSDSocketArray[sockCount].localPort != pListenSock->localPort)
                        continue;

                hTCP = BSDSocketArray[sockCount].SocketID;
                
                // We don't care about connections and disconnections before we can 
                // process them, so clear the reset flag
                TCPWasReset(hTCP);      
                
                if(TCPIsConnected(hTCP))
                {
                        remoteSockInfo = TCPGetRemoteInfo(hTCP);
                        if(addr)
                        {
                                if(addrlen)
                                {
                                        if((unsigned int)*addrlen < sizeof(struct sockaddr_in))
                                                return INVALID_SOCKET;
                                        addrRemote = (struct sockaddr_in *)addr;
                                        addrRemote->sin_addr.S_un.S_addr = remoteSockInfo->remote.IPAddr.Val;
                                        addrRemote->sin_port = remoteSockInfo->remotePort.Val;
                                        *addrlen = sizeof(struct sockaddr_in);
                                }
                        }
                        BSDSocketArray[sockCount].remotePort = remoteSockInfo->remotePort.Val;
                        BSDSocketArray[sockCount].remoteIP   = remoteSockInfo->remote.IPAddr.Val;
                        BSDSocketArray[sockCount].bsdState = SKT_EST;
                        return sockCount;
                }
        }

        return INVALID_SOCKET;
}

/*****************************************************************************
  Function:
        int connect( SOCKET s, struct sockaddr* name, int namelen )

  Summary:
        This function connects to the peer communications end point.

  Description:
        The connect function assigns the address of the peer
        communications endpoint. For stream sockets, connection is
        established between the endpoints. For datagram sockets, an
        address filter is established between the endpoints until
        changed with another connect() function.

  Precondition:
        socket function should be called.

  Parameters:
        s - Socket descriptor returned from a previous call to socket.
        name - pointer to the sockaddr structure containing the
        peer address and port number.
        namelen - length of the sockaddr structure.

  Returns:
        If the connect() function succeeds, it returns 0. Otherwise,
        the value SOCKET_ERROR is returned to indicate an error
        condition. For stream based socket, if the connection is not
        established yet, connect returns SOCKET_CNXN_IN_PROGRESS.

  Remarks:
        None.
  ***************************************************************************/
int connect( SOCKET s, struct sockaddr* name, int namelen )
{
        struct BSDSocket *socket;
        struct sockaddr_in *addr;
        DWORD remoteIP;
        WORD remotePort;
        WORD localPort;

        if( s >= BSD_SOCKET_COUNT )
                return SOCKET_ERROR;

        socket = &BSDSocketArray[s];

        if( socket->bsdState < SKT_CREATED )
                return SOCKET_ERROR;

        if( (unsigned int)namelen < sizeof(struct sockaddr_in))
                return SOCKET_ERROR;

        addr = (struct sockaddr_in *)name;
        remotePort      = addr->sin_port;
        remoteIP        = addr->sin_addr.S_un.S_addr;

        if( remoteIP == 0u || remotePort == 0u )
                return SOCKET_ERROR;

        if( socket->SocketType == SOCK_STREAM )
        {
                switch(socket->bsdState)
                {
                case SKT_EST:
                        return 0; // already established

                case SKT_IN_PROGRESS:
                        if(HandlePossibleTCPDisconnection(s))
                                return SOCKET_ERROR;

                        if(!TCPIsConnected(socket->SocketID))
                                return SOCKET_CNXN_IN_PROGRESS;

                        socket->bsdState = SKT_EST;
                        return 0; //success

                case SKT_CREATED:
                case SKT_BOUND:
                        socket->SocketID = TCPOpen(remoteIP, TCP_OPEN_IP_ADDRESS, remotePort, TCP_PURPOSE_BERKELEY_CLIENT);
                        if(socket->SocketID == INVALID_SOCKET)
                                return SOCKET_ERROR;

                        // Clear the first reset flag
                        TCPWasReset(socket->SocketID);

                        socket->isServer = FALSE;
                        socket->bsdState = SKT_IN_PROGRESS;
                        return SOCKET_CNXN_IN_PROGRESS;

                default:
                        return SOCKET_ERROR;
                }
        }
        else
        {
                // If not explicitly bound to a local port, implicitly do the binding
                if(socket->bsdState == SKT_CREATED)
                {
                        localPort = gAutoPortNumber++;
                if(gAutoPortNumber > 5000u) // reset the port numbers
                                gAutoPortNumber = 1024;

                        socket->SocketID = UDPOpen(localPort, NULL, remotePort);
                        if(socket->SocketID == INVALID_UDP_SOCKET)
                                return SOCKET_ERROR;
                        socket->bsdState = SKT_BOUND;
                }
                if(socket->bsdState != SKT_BOUND)
                        return SOCKET_ERROR;

                // UDP: remote port is used as a filter. Need to call connect when using
                // send/recv calls. No need to call 'connect' if using sendto/recvfrom 
                // calls.
                socket->remotePort = remotePort;
                socket->remoteIP = remoteIP;
                return 0; //success
        }
        return SOCKET_ERROR;
}

/*****************************************************************************
  Function:
        int send( SOCKET s, const char* buf, int len, int flags )
        
  Summary:
        The send function is used to send outgoing data on an already
        connected socket.

  Description:
        The send function is used to send outgoing data on an already
        connected socket. This function is used to send a reliable,
        ordered stream of data bytes on a socket of type SOCK_STREAM
        but can also be used to send datagrams on a socket of type SOCK_DGRAM.

  Precondition:
        connect function should be called for TCP and UDP sockets.
        Server side, accept function should be called.

  Parameters:
        s - Socket descriptor returned from a previous call to socket.
        buf - application data buffer containing data to transmit.
        len - length of data in bytes.
        flags - message flags. Currently this field is not supported.

  Returns:
        On success, send returns number of bytes sent. In case of
        error, returns SOCKET_ERROR. a zero indicates no data send.

  Remarks:
        None.
  ***************************************************************************/
int send( SOCKET s, const char* buf, int len, int flags )
{
        return sendto(s, buf, len, flags, NULL, 0);
}

/*****************************************************************************
  Function:
        int sendto(SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen)

  Summary:
        This function used to send the data for both connection oriented and connection-less
        sockets.

  Description:
        The sendto function is used to send outgoing data on a socket.
        The destination address is given by to and tolen. Both 
        Datagram and stream sockets are supported.

  Precondition:
        socket function should be called.

  Parameters:
        s - Socket descriptor returned from a previous call to socket.
        buf - application data buffer containing data to transmit.
        len - length of data in bytes.
        flags - message flags. Currently this field is not supported.
        to - Optional pointer to the the sockaddr structure containing the
                destination address.  If NULL, the currently bound remote port and IP 
                address are used as the destination.
        tolen - length of the sockaddr structure.

  Returns:
        On success, sendto returns number of bytes sent. In case of
        error returns SOCKET_ERROR

  Remarks:
        None.
  ***************************************************************************/
int sendto( SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen )
{
        struct BSDSocket *socket;
        int size = SOCKET_ERROR;
        NODE_INFO remoteInfo;
        static DWORD startTick;         // NOTE: startTick really should be a per socket BSDSocket structure member since other BSD calls can interfere with the ARP cycles
        WORD wRemotePort;
        struct sockaddr_in local;

        if( s >= BSD_SOCKET_COUNT )
                return SOCKET_ERROR;

        socket = &BSDSocketArray[s];

        if(socket->bsdState == SKT_CLOSED)
                return SOCKET_ERROR;

        if(socket->SocketType == SOCK_DGRAM) //UDP
        {
                // Decide the destination IP address and port
                remoteInfo.IPAddr.Val = socket->remoteIP;
                wRemotePort = socket->remotePort;
                if(to)
                {
                        if((unsigned int)tolen != sizeof(struct sockaddr_in))
                                return SOCKET_ERROR;
                        wRemotePort = ((struct sockaddr_in*)to)->sin_port;
                        remoteInfo.IPAddr.Val = ((struct sockaddr_in*)to)->sin_addr.s_addr;
                        
                        // Implicitly bind the socket if it isn't already
                        if(socket->bsdState == SKT_CREATED)
                        {
                                memset(&local, 0x00, sizeof(local));
                                if(bind(s, (struct sockaddr*)&local, sizeof(local)) == SOCKET_ERROR)
                                        return SOCKET_ERROR;
                        }
                }
                if(remoteInfo.IPAddr.Val == IP_ADDR_ANY)
                        remoteInfo.IPAddr.Val = 0xFFFFFFFFu;

                // Set the remote IP and MAC address if it is different from what we already have stored in the UDP socket
                if(UDPSocketInfo[socket->SocketID].remoteNode.IPAddr.Val != remoteInfo.IPAddr.Val)
                {
                        if(ARPIsResolved(&remoteInfo.IPAddr, &remoteInfo.MACAddr))
                        {
                                memcpy((void*)&UDPSocketInfo[socket->SocketID].remoteNode, (void*)&remoteInfo, sizeof(remoteInfo));
                        }
                        else
                        {
                                if(TickGet() - startTick > 1*TICK_SECOND)
                                {
                                        ARPResolve(&remoteInfo.IPAddr);
                                        startTick = TickGet();
                                }
                                return SOCKET_ERROR;
                        }
                }
                
                // Select the UDP socket and see if we can write to it
                if(UDPIsPutReady(socket->SocketID))
                {
                        // Set the proper remote port
                        UDPSocketInfo[socket->SocketID].remotePort = wRemotePort;

                        // Write data and send UDP datagram
                        size = UDPPutArray((BYTE*)buf, len);
                        UDPFlush();
                        return size;
                }
        }
        else if(socket->SocketType == SOCK_STREAM) //TCP will only send to the already established socket.
        {
                if(socket->bsdState != SKT_EST)
                        return SOCKET_ERROR;

                if(HandlePossibleTCPDisconnection(s))
                        return SOCKET_ERROR;
                        
                // Handle special case were 0 return value is okay
                if(len == 0)
                        return 0;

                // Write data to the socket. If one or more bytes were written, then 
                // return this value.  Otherwise, fail and return SOCKET_ERROR.
                size = TCPPutArray(socket->SocketID, (BYTE*)buf, len);
                if(size)
                        return size;
        }
        return SOCKET_ERROR;
}

/*****************************************************************************
  Function:
        int recv( SOCKET s, char* buf, int len, int flags )

  Summary:
        The recv() function is used to receive incoming data that has
        been queued for a socket.

  Description:
        The recv() function is used to receive incoming data that has
        been queued for a socket. This function can be used with both 
        datagram and stream socket. If the available data
        is too large to fit in the supplied application buffer buf,
        excess bytes are discarded in case of SOCK_DGRAM type
        sockets.  For SOCK_STREAM types, the data is buffered
        internally so the application can retreive all data by
        multiple calls of recvfrom.

  Precondition:
        connect function should be called for TCP and UDP sockets.
        Server side, accept function should be called.

  Parameters:
        s - Socket descriptor returned from a previous call to socket.
        buf - application data receive buffer.
        len - buffer length in bytes.
        flags - no significance in this implementation

  Returns:
        If recv is successful, the number of bytes copied to
        application buffer buf is returned. A value of zero indicates
        no data available. A return value of SOCKET_ERROR (-1)
        indicates an error condition. A return value of SOCKET_DISCONNECTED
        indicates the connection no longer exists.

  Remarks:
        None.
  ***************************************************************************/
int recv( SOCKET s, char* buf, int len, int flags )
{
        struct BSDSocket *socket;

        if( s >= BSD_SOCKET_COUNT )
                return SOCKET_ERROR;

        socket = &BSDSocketArray[s];

        if(socket->SocketType == SOCK_STREAM) //TCP
        {
                if(socket->bsdState != SKT_EST)
                        return SOCKET_ERROR;

                if(HandlePossibleTCPDisconnection(s))
                        return SOCKET_ERROR;

                return TCPGetArray(socket->SocketID, (BYTE*)buf, len);
        }
        else if(socket->SocketType == SOCK_DGRAM) //UDP
        {
                if(socket->bsdState != SKT_BOUND)
                        return SOCKET_ERROR;

                if(UDPIsGetReady(socket->SocketID))
                        return UDPGetArray((BYTE*)buf, len);
        }

        return 0;
}

/*****************************************************************************
  Function:
        int recvfrom(SOCKET s, char* buf, int len, int flags, struct sockaddr* from, int* fromlen)

  Summary:
        The recvfrom() function is used to receive incoming data that
        has been queued for a socket.

  Description:
        The recvfrom() function is used to receive incoming data that
        has been queued for a socket. This function can be used with
        both datagram and stream type sockets. If the available data
        is too large to fit in the supplied application buffer buf,
        excess bytes are discarded in case of SOCK_DGRAM type
        sockets. For SOCK_STREAM types, the data is buffered
        internally so the application can retreive all data by
        multiple calls of recvfrom.

  Precondition:
        socket function should be called.

  Parameters:
        s - Socket descriptor returned from a previous call to socket.
        buf - application data receive buffer.
        len - buffer length in bytes.
        flags - message flags. Currently this is not supported.
        from - pointer to the sockaddr structure that will be
        filled in with the destination address.
        fromlen - size of buffer pointed by from.

  Returns:
        If recvfrom is successful, the number of bytes copied to
        application buffer buf is returned. A value of zero indicates
        no data available. A return value of SOCKET_ERROR (-1)
        indicates an error condition.

  Remarks:
        None.
  ***************************************************************************/
int recvfrom( SOCKET s, char* buf, int len, int flags, struct sockaddr* from, int* fromlen )
{
        struct BSDSocket *socket;
        struct sockaddr_in *rem_addr;
        SOCKET_INFO *remoteSockInfo;

        socket = &BSDSocketArray[s];
        rem_addr = (struct sockaddr_in *)from;

        if(socket->SocketType == SOCK_DGRAM) //UDP
        {
                // If this BSD socket doesn't have a Microchip UDP socket associated 
                // with it yet, then no data can be received and we must not use the 
                // socket->SocketID parameter, which isn't set yet.
                if(socket->bsdState != SKT_BOUND)
                        return 0;
                
                if(UDPIsGetReady(socket->SocketID))
                {
                        // Capture sender information (can change packet to packet)
                        if(from && fromlen)
                        {
                                if((unsigned int)*fromlen >= sizeof(struct sockaddr_in))
                                {
                                        rem_addr->sin_addr.S_un.S_addr = UDPSocketInfo[socket->SocketID].remoteNode.IPAddr.Val;
                                        rem_addr->sin_port = UDPSocketInfo[socket->SocketID].remotePort;
                                        *fromlen = sizeof(struct sockaddr_in);
                                }
                        }

                        return UDPGetArray((BYTE*)buf, len);
                }
        }
        else  //TCP recieve from already connected socket.
        {
                if(from && fromlen)
                {
                        // Capture sender information (will always match socket connection information)
                        if((unsigned int)*fromlen >= sizeof(struct sockaddr_in))
                        {
                                remoteSockInfo = TCPGetRemoteInfo(socket->SocketID);
                                rem_addr->sin_addr.S_un.S_addr = remoteSockInfo->remote.IPAddr.Val;
                                rem_addr->sin_port = remoteSockInfo->remotePort.Val;
                                *fromlen = sizeof(struct sockaddr_in);
                        }
                }
                return recv(s, buf, len, 0);
        }
        return 0;
}

/*****************************************************************************
  Function:
        int gethostname(char* name, int namelen )

  Summary:
        Returns the standard host name for the system.

  Description:
        This function returns the standard host name of the system which is 
        calling this function.  The returned name is null-terminated.

  Precondition:
        None.

  Parameters:
        name - Pointer to a buffer that receives the local host name.
        namelen - size of the name array.

  Returns:
        Success will return a value of 0. 
        If name is too short to hold the host name or any other error occurs, 
        SOCKET_ERROR (-1) will be returned.  On error, *name will be unmodified 
        and no null terminator will be generated.

  Remarks:
        None.
  ***************************************************************************/
int gethostname(char* name, int namelen)
{
        WORD wSourceLen;
        WORD w;
        BYTE v;

        wSourceLen = sizeof(AppConfig.NetBIOSName);
        for(w = 0; w < wSourceLen; w++)
        {
                v = AppConfig.NetBIOSName[w];
                if((v == ' ') || (v == 0u))
                        break;
        }
        wSourceLen = w;
        if(namelen < (int)wSourceLen + 1)
                return SOCKET_ERROR;

        memcpy((void*)name, (void*)AppConfig.NetBIOSName, wSourceLen);
        name[wSourceLen] = 0;

        return 0;
}

/*****************************************************************************
  Function:
        int closesocket( SOCKET s )
        
  Summary:
        The closesocket function closes an existing socket.

  Description:
        The closesocket function closes an existing socket.  
        This function releases the socket descriptor s.  
        Any data buffered at the socket is discarded.  If the 
        socket s is no longer needed, closesocket() must be 
        called in order to release all resources associated with s.

  Precondition:
        None.

  Parameters:
        s - Socket descriptor returned from a previous call to socket

  Returns:
        If closesocket is successful, a value of 0 is returned. 
        A return value of SOCKET_ERROR (-1) indicates an error.

  Remarks:
        None.
  ***************************************************************************/
int closesocket( SOCKET s )
{       
        BYTE i;
        struct BSDSocket *socket;

        if( s >= BSD_SOCKET_COUNT )
                return SOCKET_ERROR;

        socket = &BSDSocketArray[s];

        if(socket->bsdState == SKT_CLOSED)
                return 0;       // Nothing to do, so return success

        if(socket->SocketType == SOCK_STREAM)
        {
                if(socket->bsdState == SKT_BSD_LISTEN)
                {
                        // This is a listerner handle, so when we close it we also should 
                        // close all TCP sockets that were opened for backlog processing 
                        // but didn't actually get connected
                        for(i = 0; i < sizeof(BSDSocketArray)/sizeof(BSDSocketArray[0]); i++)
                        {
                                if(BSDSocketArray[i].bsdState != SKT_LISTEN)
                                        continue;
                                if(BSDSocketArray[i].localPort == socket->localPort)
                                {
                                        TCPClose(BSDSocketArray[i].SocketID);
                                        BSDSocketArray[i].bsdState = SKT_CLOSED;
                                }
                        }
                }
                else if(socket->bsdState >= SKT_LISTEN)
                {
                        // For server sockets, if the parent listening socket is still open, 
                        // then return this socket to the queue for future backlog processing.
                        if(socket->isServer)
                        {
                                for(i = 0; i < sizeof(BSDSocketArray)/sizeof(BSDSocketArray[0]); i++)
                                {
                                        if(BSDSocketArray[i].bsdState != SKT_BSD_LISTEN)
                                                continue;
                                        if(BSDSocketArray[i].localPort == socket->localPort)
                                        {
                                                TCPDisconnect(socket->SocketID);
                                                
                                                // Listener socket is still open, so just return to the 
                                                // listening state so that the user must call accept() again to 
                                                // reuse this BSD socket
                                                socket->bsdState = SKT_LISTEN;
                                                return 0;
                                        }
                                }
                                // If we get down here, then the parent listener socket has 
                                // apparently already been closed, so this socket can not be 
                                // reused.  Close it complete.
                                TCPClose(socket->SocketID);
                        }
                        else if(socket->bsdState != SKT_DISCONNECTED)   // this is a client socket that isn't already disconnected
                        {
                                TCPClose(socket->SocketID);
                        }
                }
        }
        else //udp sockets
        {
                if(socket->bsdState == SKT_BOUND)
                        UDPClose(socket->SocketID);
        }

        socket->bsdState = SKT_CLOSED;
        return 0; //success
}


/*****************************************************************************
  Function:
        static BOOL HandlePossibleTCPDisconnection(SOCKET s)
        
  Summary:
        Internal function that checks for asynchronous TCP connection state 
        changes and resynchs the BSD socket descriptor state to match. 

  Description:
        Internal function that checks for asynchronous TCP connection state 
        changes and resynchs the BSD socket descriptor state to match. 

  Precondition:
        None

  Parameters:
        s - TCP type socket descriptor returned from a previous call to socket.  
            This socket must be in the SKT_LISTEN, SKT_IN_PROGRESS, SKT_EST, or 
            SKT_DISCONNECTED states.

  Returns:
        TRUE - Socket is disconnected
        FALSE - Socket is 

  ***************************************************************************/
static BOOL HandlePossibleTCPDisconnection(SOCKET s)
{
        struct BSDSocket *socket;
        BYTE i;
        BOOL bSocketWasReset;

        socket = &BSDSocketArray[s];

        // Nothing to do if disconnection has already been handled
        if(socket->bsdState == SKT_DISCONNECTED)
                return TRUE;    

        // Find out if a disconnect has occurred
        bSocketWasReset = TCPWasReset(socket->SocketID);

        // For server sockets, if the parent listening socket is still open, 
        // then return this socket to the queue for future backlog processing.
        if(socket->isServer)
        {
                for(i = 0; i < sizeof(BSDSocketArray)/sizeof(BSDSocketArray[0]); i++)
                {
                        if(BSDSocketArray[i].bsdState != SKT_BSD_LISTEN)
                                continue;
                        if(BSDSocketArray[i].localPort == socket->localPort)
                        {
                                // Nothing to do if a disconnect has not occurred
                                if(!bSocketWasReset)
                                        return FALSE;

                                // Listener socket is still open, so just return to the 
                                // listening state so that the user must call accept() again to 
                                // reuse this BSD socket
                                socket->bsdState = SKT_LISTEN;
                                return TRUE;
                        }
                }
        }
                        
        // If we get down here and the socket was reset, then this socket 
        // should be closed so that no more clients can connect to it.  However, 
        // we can't go to the BSD SKT_CLOSED state directly since the user still 
        // has to call closesocket() with this s SOCKET descriptor first.
        if(bSocketWasReset)
        {
                TCPClose(socket->SocketID);
                socket->bsdState = SKT_DISCONNECTED;
                return TRUE;
        }
        
        return FALSE;
}

#endif //STACK_USE_BERKELEY_API

{FILE END}
{FOOTER START}

Powered by WebSVN v2.8.3