Beispiel #1
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 )
{
    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_LISTEN)
        {
            HandlePossibleTCPDisconnection(s);

            if(socket->bsdState == SKT_LISTEN)
                return 0;
        }
    }
    else //udp sockets
    {
        if(socket->SocketID != INVALID_UDP_SOCKET)
            UDPClose(socket->SocketID);
    }

    socket->bsdState = SKT_CLOSED;
    return 0; //success
}
Beispiel #2
0
/*****************************************************************************
  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;
}
Beispiel #3
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(UDPIsOpened((UDP_SOCKET)s) != TRUE)
			return SOCKET_ERROR;
		
		if(remoteInfo.IPAddr.Val == IP_ADDR_ANY)
			remoteInfo.IPAddr.Val = 0xFFFFFFFFu;

#if 0
		// 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;
			}
		}
#endif		
		// 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;
}
Beispiel #4
0
/*****************************************************************************
  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);
			
			socket->SocketID = UDPOpenEx(0,UDP_OPEN_SERVER,localPort, 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;
}
Beispiel #5
0
/*****************************************************************************
  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 return value of SOCKET_ERROR (-1)
	indicates an error condition (and errno set accordingly).
    A value of zero indicates socket has been shutdown by the peer.

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

    if( s >= BSD_SOCKET_COUNT )
    {
        errno = EBADF;
        return SOCKET_ERROR;
    }

    socket = &BSDSocketArray[s];

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

        if(HandlePossibleTCPDisconnection(s))
        {
            errno = ECONNRESET;
            return SOCKET_ERROR;
        }

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

        if(UDPIsGetReady(socket->SocketID))
        {
            nBytes =  UDPGetArray(socket->SocketID, (uint8_t*)buf, len);
        }
        else
        {
            nBytes = 0;
        }
        if(nBytes)
        {
            return nBytes;
        }
        errno = EWOULDBLOCK;
        return SOCKET_ERROR;
    }

    return 0;
}
Beispiel #6
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 (and errno set accordingly).

  Remarks:
	None.
  ***************************************************************************/
int sendto( SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen )
{
    struct BSDSocket *socket;
    UDP_SOCKET_DCPT*  udpSkt;
    int size = SOCKET_ERROR;
    NODE_INFO remoteInfo;
    uint16_t wRemotePort;
    struct sockaddr_in local;

    if( s >= BSD_SOCKET_COUNT )
    {
        errno = EBADF;
        return SOCKET_ERROR;
    }

    socket = &BSDSocketArray[s];

    if(socket->bsdState == SKT_CLOSED)
    {
        errno = EBADF;
        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))
            {
                errno = EFAULT;
                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
        udpSkt = UDPSocketDcpt + socket->SocketID;
        if(TCPIP_IPV4_GetDestAddress(udpSkt->pTxPkt).Val != remoteInfo.IPAddr.Val)
        {
            TCPIP_IPV4_SetDestAddress(udpSkt->pTxPkt, remoteInfo.IPAddr.Val);
            if(!ARPIsResolved(UDPSocketGetNet(socket->SocketID), &remoteInfo.IPAddr, &((IPV4_PACKET*)udpSkt->pTxPkt)->remoteMACAddr))
            {
                errno = EINPROGRESS;
                return SOCKET_ERROR;
            }
        }
        // Select the UDP socket and see if we can write to it
        if(UDPIsTxPutReady(socket->SocketID, len))
        {
            // Set the proper remote port
            udpSkt->remotePort = wRemotePort;

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

        if(HandlePossibleTCPDisconnection(s))
        {
            errno = ECONNRESET;
            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, (uint8_t*)buf, len);
        if(size)
            return size;
    }
    errno = EWOULDBLOCK;
    return SOCKET_ERROR;
}
Beispiel #7
0
/*****************************************************************************
  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 (and errno set accordingly).
    For stream based socket, if the connection is not
	established yet, connect returns SOCKET_ERROR and
    errno = EINPROGRESS.

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

    if( s >= BSD_SOCKET_COUNT )
    {
        errno = EBADF;
        return SOCKET_ERROR;
    }

    socket = &BSDSocketArray[s];

    if( socket->bsdState < SKT_CREATED )
    {
        errno = EBADF;
        return SOCKET_ERROR;
    }

    if( (unsigned int)namelen < sizeof(struct sockaddr_in))
    {
        errno = EFAULT;
        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 )
    {
        errno = EINVAL;
        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))
            {
                errno = ECONNREFUSED;
                return SOCKET_ERROR;
            }

            if(!TCPIsConnected(socket->SocketID))
            {
                errno = EINPROGRESS;
                return SOCKET_ERROR;
            }

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

        case SKT_CREATED:
        case SKT_BOUND:
            socket->SocketID = TCPOpenClient(IP_ADDRESS_TYPE_IPV4, remotePort, (IP_MULTI_ADDRESS*)&remoteIP);
            if(socket->SocketID == INVALID_SOCKET)
            {
                errno = ENOBUFS;
                return SOCKET_ERROR;
            }

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

            localAddr.Val = socket->localIP;
            TCPSocketSetNet(socket->SocketID, _TCPIPStackIpAddToNet(&localAddr, true));
            socket->isServer = false;
            socket->bsdState = SKT_IN_PROGRESS;
            errno = EINPROGRESS;
            return SOCKET_ERROR;

        default:
            errno = ECONNRESET;
            return SOCKET_ERROR;
        }
    }
    else
    {
        // If not explicitly bound to a local port, implicitly do the binding
        if(socket->bsdState == SKT_CREATED)
        {
            IPV4_ADDR addrAny = {IP_ADDR_ANY};

            localPort = gAutoPortNumber++;
            if(gAutoPortNumber > 5000u) // reset the port numbers
                gAutoPortNumber = 1024;

            socket->SocketID = UDPOpenServer(IP_ADDRESS_TYPE_IPV4, localPort,  0);
            if(socket->SocketID == INVALID_UDP_SOCKET)
            {
                errno = ENOBUFS;
                return SOCKET_ERROR;
            }
            UDPSocketSetNet(socket->SocketID, _TCPIPStackIpAddToNet(&addrAny, true));
            socket->bsdState = SKT_BOUND;
        }
        if(socket->bsdState != SKT_BOUND)
        {
            errno = EINVAL;
            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
    }

    errno = EINVAL;
    return SOCKET_ERROR;
}