Sergey Pastor / 1

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers socket.c Source File

socket.c

Go to the documentation of this file.
00001 /**
00002  * @file socket.c
00003  * @brief Socket API
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneTCP Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00026  * @version 1.7.6
00027  **/
00028 
00029 //Switch to the appropriate trace level
00030 #define TRACE_LEVEL SOCKET_TRACE_LEVEL
00031 
00032 //Dependencies
00033 #include <string.h>
00034 #include "core/net.h"
00035 #include "core/socket.h"
00036 #include "core/raw_socket.h"
00037 #include "core/udp.h"
00038 #include "core/tcp.h"
00039 #include "core/tcp_misc.h"
00040 #include "dns/dns_client.h"
00041 #include "mdns/mdns_client.h"
00042 #include "netbios/nbns_client.h"
00043 #include "debug.h"
00044 
00045 //Socket table
00046 Socket socketTable[SOCKET_MAX_COUNT];
00047 
00048 
00049 /**
00050  * @brief Socket related initialization
00051  * @return Error code
00052  **/
00053 
00054 error_t socketInit(void)
00055 {
00056    uint_t i;
00057    uint_t j;
00058 
00059    //Initialize socket descriptors
00060    memset(socketTable, 0, sizeof(socketTable));
00061 
00062    //Loop through socket descriptors
00063    for(i = 0; i < SOCKET_MAX_COUNT; i++)
00064    {
00065       //Set socket identifier
00066       socketTable[i].descriptor = i;
00067 
00068       //Create an event object to track socket events
00069       if(!osCreateEvent(&socketTable[i].event))
00070       {
00071          //Clean up side effects
00072          for(j = 0; j < i; j++)
00073             osDeleteEvent(&socketTable[j].event);
00074 
00075          //Report an error
00076          return ERROR_OUT_OF_RESOURCES;
00077       }
00078    }
00079 
00080    //Successful initialization
00081    return NO_ERROR;
00082 }
00083 
00084 
00085 /**
00086  * @brief Create a socket (UDP or TCP)
00087  * @param[in] type Type specification for the new socket
00088  * @param[in] protocol Protocol to be used
00089  * @return Handle referencing the new socket
00090  **/
00091 
00092 Socket *socketOpen(uint_t type, uint_t protocol)
00093 {
00094    error_t error;
00095    uint_t i;
00096    uint16_t port;
00097    Socket *socket;
00098    OsEvent event;
00099 
00100    //Initialize socket handle
00101    socket = NULL;
00102 
00103    //Get exclusive access
00104    osAcquireMutex(&netMutex);
00105 
00106 #if (TCP_SUPPORT == ENABLED)
00107    //Connection-oriented socket?
00108    if(type == SOCKET_TYPE_STREAM)
00109    {
00110       //Always use TCP as underlying transport protocol
00111       protocol = SOCKET_IP_PROTO_TCP;
00112       //Get an ephemeral port number
00113       port = tcpGetDynamicPort();
00114       //Continue processing
00115       error = NO_ERROR;
00116    }
00117    else
00118 #endif
00119 #if (UDP_SUPPORT == ENABLED)
00120    //Connectionless socket?
00121    if(type == SOCKET_TYPE_DGRAM)
00122    {
00123       //Always use UDP as underlying transport protocol
00124       protocol = SOCKET_IP_PROTO_UDP;
00125       //Get an ephemeral port number
00126       port = udpGetDynamicPort();
00127       //Continue processing
00128       error = NO_ERROR;
00129    }
00130    else
00131 #endif
00132 #if (RAW_SOCKET_SUPPORT == ENABLED)
00133    //Raw socket?
00134    if(type == SOCKET_TYPE_RAW_IP || type == SOCKET_TYPE_RAW_ETH)
00135    {
00136       //Port numbers are not relevant for raw sockets
00137       port = 0;
00138       //Continue processing
00139       error = NO_ERROR;
00140    }
00141    else
00142 #endif
00143    {
00144       //The socket type is not supported
00145       error = ERROR_INVALID_PARAMETER;
00146    }
00147 
00148    //Check status code
00149    if(!error)
00150    {
00151       //Loop through socket descriptors
00152       for(i = 0; i < SOCKET_MAX_COUNT; i++)
00153       {
00154          //Unused socket found?
00155          if(socketTable[i].type == SOCKET_TYPE_UNUSED)
00156          {
00157             //Save socket handle
00158             socket = &socketTable[i];
00159             //We are done
00160             break;
00161          }
00162       }
00163 
00164 #if (TCP_SUPPORT == ENABLED)
00165       //No more sockets available?
00166       if(socket == NULL)
00167       {
00168          //Kill the oldest connection in the TIME-WAIT state
00169          //whenever the socket table runs out of space
00170          socket = tcpKillOldestConnection();
00171       }
00172 #endif
00173 
00174       //Check whether the current entry is free
00175       if(socket != NULL)
00176       {
00177          //Save socket descriptor
00178          i = socket->descriptor;
00179          //Save event object instance
00180          memcpy(&event, &socket->event, sizeof(OsEvent));
00181 
00182          //Clear associated structure
00183          memset(socket, 0, sizeof(Socket));
00184          //Reuse event objects and avoid recreating them whenever possible
00185          memcpy(&socket->event, &event, sizeof(OsEvent));
00186 
00187          //Save socket characteristics
00188          socket->descriptor = i;
00189          socket->type = type;
00190          socket->protocol = protocol;
00191          socket->localPort = port;
00192          socket->timeout = INFINITE_DELAY;
00193 
00194 #if (TCP_SUPPORT == ENABLED)
00195          socket->txBufferSize = MIN(TCP_DEFAULT_TX_BUFFER_SIZE, TCP_MAX_TX_BUFFER_SIZE);
00196          socket->rxBufferSize = MIN(TCP_DEFAULT_RX_BUFFER_SIZE, TCP_MAX_RX_BUFFER_SIZE);
00197 #endif
00198       }
00199    }
00200 
00201    //Release exclusive access
00202    osReleaseMutex(&netMutex);
00203 
00204    //Return a handle to the freshly created socket
00205    return socket;
00206 }
00207 
00208 
00209 /**
00210  * @brief Set timeout value for blocking operations
00211  * @param[in] socket Handle to a socket
00212  * @param[in] timeout Maximum time to wait
00213  * @return Error code
00214  **/
00215 
00216 error_t socketSetTimeout(Socket *socket, systime_t timeout)
00217 {
00218    //Make sure the socket handle is valid
00219    if(socket == NULL)
00220       return ERROR_INVALID_PARAMETER;
00221 
00222    //Get exclusive access
00223    osAcquireMutex(&netMutex);
00224    //Record timeout value
00225    socket->timeout = timeout;
00226    //Release exclusive access
00227    osReleaseMutex(&netMutex);
00228 
00229    //No error to report
00230    return NO_ERROR;
00231 }
00232 
00233 
00234 /**
00235  * @brief Specify the size of the send buffer
00236  * @param[in] socket Handle to a socket
00237  * @param[in] size Desired buffer size in bytes
00238  * @return Error code
00239  **/
00240 
00241 error_t socketSetTxBufferSize(Socket *socket, size_t size)
00242 {
00243 #if (TCP_SUPPORT == ENABLED)
00244    //Make sure the socket handle is valid
00245    if(socket == NULL)
00246       return ERROR_INVALID_PARAMETER;
00247    //Check parameter value
00248    if(size < 1 || size > TCP_MAX_TX_BUFFER_SIZE)
00249       return ERROR_INVALID_PARAMETER;
00250 
00251    //This function shall be used with connection-oriented socket types
00252    if(socket->type != SOCKET_TYPE_STREAM)
00253       return ERROR_INVALID_SOCKET;
00254    //The buffer size cannot be changed when the connection is established
00255    if(tcpGetState(socket) != TCP_STATE_CLOSED)
00256       return ERROR_INVALID_SOCKET;
00257 
00258    //Use the specified buffer size
00259    socket->txBufferSize = size;
00260    //No error to report
00261    return NO_ERROR;
00262 #else
00263    return ERROR_NOT_IMPLEMENTED;
00264 #endif
00265 }
00266 
00267 
00268 /**
00269  * @brief Specify the size of the receive buffer
00270  * @param[in] socket Handle to a socket
00271  * @param[in] size Desired buffer size in bytes
00272  * @return Error code
00273  **/
00274 
00275 error_t socketSetRxBufferSize(Socket *socket, size_t size)
00276 {
00277 #if (TCP_SUPPORT == ENABLED)
00278    //Make sure the socket handle is valid
00279    if(socket == NULL)
00280       return ERROR_INVALID_PARAMETER;
00281    //Check parameter value
00282    if(size < 1 || size > TCP_MAX_RX_BUFFER_SIZE)
00283       return ERROR_INVALID_PARAMETER;
00284 
00285    //This function shall be used with connection-oriented socket types
00286    if(socket->type != SOCKET_TYPE_STREAM)
00287       return ERROR_INVALID_SOCKET;
00288    //The buffer size cannot be changed when the connection is established
00289    if(tcpGetState(socket) != TCP_STATE_CLOSED)
00290       return ERROR_INVALID_SOCKET;
00291 
00292    //Use the specified buffer size
00293    socket->rxBufferSize = size;
00294    //No error to report
00295    return NO_ERROR;
00296 #else
00297    return ERROR_NOT_IMPLEMENTED;
00298 #endif
00299 }
00300 
00301 
00302 /**
00303  * @brief Bind a socket to a particular network interface
00304  * @param[in] socket Handle to a socket
00305  * @param[in] interface Network interface to be used
00306  * @return Error code
00307  **/
00308 
00309 error_t socketBindToInterface(Socket *socket, NetInterface *interface)
00310 {
00311    //Make sure the socket handle is valid
00312    if(socket == NULL)
00313       return ERROR_INVALID_PARAMETER;
00314 
00315    //Explicitly associate the socket with the specified interface
00316    socket->interface = interface;
00317 
00318    //No error to report
00319    return NO_ERROR;
00320 }
00321 
00322 
00323 /**
00324  * @brief Associate a local address with a socket
00325  * @param[in] socket Handle to a socket
00326  * @param[in] localIpAddr Local address to assign to the bound socket
00327  * @param[in] localPort Local port number to assign to the bound socket
00328  * @return Error code
00329  **/
00330 
00331 error_t socketBind(Socket *socket, const IpAddr *localIpAddr, uint16_t localPort)
00332 {
00333    //Check input parameters
00334    if(!socket || !localIpAddr)
00335       return ERROR_INVALID_PARAMETER;
00336    //Make sure the socket type is correct
00337    if(socket->type != SOCKET_TYPE_STREAM && socket->type != SOCKET_TYPE_DGRAM)
00338       return ERROR_INVALID_SOCKET;
00339 
00340    //Associate the specified IP address and port number
00341    socket->localIpAddr = *localIpAddr;
00342    socket->localPort = localPort;
00343 
00344    //No error to report
00345    return NO_ERROR;
00346 }
00347 
00348 
00349 /**
00350  * @brief Establish a connection to a specified socket
00351  * @param[in] socket Handle to an unconnected socket
00352  * @param[in] remoteIpAddr IP address of the remote host
00353  * @param[in] remotePort Remote port number that will be used to establish the connection
00354  * @return Error code
00355  **/
00356 
00357 error_t socketConnect(Socket *socket, const IpAddr *remoteIpAddr, uint16_t remotePort)
00358 {
00359    error_t error;
00360 
00361    //Check input parameters
00362    if(!socket || !remoteIpAddr)
00363       return ERROR_INVALID_PARAMETER;
00364 
00365 #if (TCP_SUPPORT == ENABLED)
00366    //Connection-oriented socket?
00367    if(socket->type == SOCKET_TYPE_STREAM)
00368    {
00369       //Get exclusive access
00370       osAcquireMutex(&netMutex);
00371 
00372       //Establish TCP connection
00373       error = tcpConnect(socket, remoteIpAddr, remotePort);
00374 
00375       //Release exclusive access
00376       osReleaseMutex(&netMutex);
00377    }
00378    else
00379 #endif
00380    //Connectionless socket?
00381    if(socket->type == SOCKET_TYPE_DGRAM)
00382    {
00383       //Save port number and IP address of the remote host
00384       socket->remoteIpAddr = *remoteIpAddr;
00385       socket->remotePort = remotePort;
00386       //No error to report
00387       error = NO_ERROR;
00388    }
00389    //Raw socket?
00390    else if(socket->type == SOCKET_TYPE_RAW_IP)
00391    {
00392       //Save the IP address of the remote host
00393       socket->remoteIpAddr = *remoteIpAddr;
00394       //No error to report
00395       error = NO_ERROR;
00396    }
00397    //Socket type not supported...
00398    else
00399    {
00400       //Invalid socket type
00401       error = ERROR_INVALID_SOCKET;
00402    }
00403 
00404    //Return status code
00405    return error;
00406 }
00407 
00408 
00409 /**
00410  * @brief Place a socket in the listening state
00411  *
00412  * Place a socket in a state in which it is listening for an incoming connection
00413  *
00414  * @param[in] socket Socket to place in the listening state
00415  * @param[in] backlog backlog The maximum length of the pending connection queue.
00416  *   If this parameter is zero, then the default backlog value is used instead
00417  * @return Error code
00418  **/
00419 
00420 error_t socketListen(Socket *socket, uint_t backlog)
00421 {
00422 #if (TCP_SUPPORT == ENABLED)
00423    error_t error;
00424 
00425    //Make sure the socket handle is valid
00426    if(socket == NULL)
00427       return ERROR_INVALID_PARAMETER;
00428    //This function shall be used with connection-oriented socket types
00429    if(socket->type != SOCKET_TYPE_STREAM)
00430       return ERROR_INVALID_SOCKET;
00431 
00432    //Get exclusive access
00433    osAcquireMutex(&netMutex);
00434 
00435    //Start listening for an incoming connection
00436    error = tcpListen(socket, backlog);
00437 
00438    //Release exclusive access
00439    osReleaseMutex(&netMutex);
00440 
00441    //Return status code
00442    return error;
00443 #else
00444    return ERROR_NOT_IMPLEMENTED;
00445 #endif
00446 }
00447 
00448 
00449 /**
00450  * @brief Permit an incoming connection attempt on a socket
00451  * @param[in] socket Handle to a socket previously placed in a listening state
00452  * @param[out] clientIpAddr IP address of the client
00453  * @param[out] clientPort Port number used by the client
00454  * @return Handle to the socket in which the actual connection is made
00455  **/
00456 
00457 Socket *socketAccept(Socket *socket, IpAddr *clientIpAddr, uint16_t *clientPort)
00458 {
00459 #if (TCP_SUPPORT == ENABLED)
00460    Socket *newSocket;
00461 
00462    //Make sure the socket handle is valid
00463    if(socket == NULL)
00464       return NULL;
00465    //This function shall be used with connection-oriented socket types
00466    if(socket->type != SOCKET_TYPE_STREAM)
00467       return NULL;
00468 
00469    //Accept an incoming connection attempt
00470    newSocket = tcpAccept(socket, clientIpAddr, clientPort);
00471 
00472    //Return a handle to the newly created socket
00473    return newSocket;
00474 #else
00475    return NULL;
00476 #endif
00477 }
00478 
00479 
00480 /**
00481  * @brief Send data to a connected socket
00482  * @param[in] socket Handle that identifies a connected socket
00483  * @param[in] data Pointer to a buffer containing the data to be transmitted
00484  * @param[in] length Number of data bytes to send
00485  * @param[out] written Actual number of bytes written (optional parameter)
00486  * @param[in] flags Set of flags that influences the behavior of this function
00487  * @return Error code
00488  **/
00489 
00490 error_t socketSend(Socket *socket, const void *data,
00491    size_t length, size_t *written, uint_t flags)
00492 {
00493    //Use default remote IP address for connectionless or raw sockets
00494    return socketSendTo(socket, &socket->remoteIpAddr,
00495       socket->remotePort, data, length, written, flags);
00496 }
00497 
00498 
00499 /**
00500  * @brief Send a datagram to a specific destination
00501  * @param[in] socket Handle that identifies a socket
00502  * @param[in] destIpAddr IP address of the target host
00503  * @param[in] destPort Target port number
00504  * @param[in] data Pointer to a buffer containing the data to be transmitted
00505  * @param[in] length Number of data bytes to send
00506  * @param[out] written Actual number of bytes written (optional parameter)
00507  * @param[in] flags Set of flags that influences the behavior of this function
00508  * @return Error code
00509  **/
00510 
00511 error_t socketSendTo(Socket *socket, const IpAddr *destIpAddr, uint16_t destPort,
00512    const void *data, size_t length, size_t *written, uint_t flags)
00513 {
00514    error_t error;
00515 
00516    //No data has been transmitted yet
00517    if(written)
00518       *written = 0;
00519 
00520    //Make sure the socket handle is valid
00521    if(socket == NULL)
00522       return ERROR_INVALID_PARAMETER;
00523 
00524    //Get exclusive access
00525    osAcquireMutex(&netMutex);
00526 
00527 #if (TCP_SUPPORT == ENABLED)
00528    //Connection-oriented socket?
00529    if(socket->type == SOCKET_TYPE_STREAM)
00530    {
00531       //For connection-oriented sockets, target address is ignored
00532       error = tcpSend(socket, data, length, written, flags);
00533    }
00534    else
00535 #endif
00536 #if (UDP_SUPPORT == ENABLED)
00537    //Connectionless socket?
00538    if(socket->type == SOCKET_TYPE_DGRAM)
00539    {
00540       //Send UDP datagram
00541       error = udpSendDatagram(socket, destIpAddr,
00542          destPort, data, length, written);
00543    }
00544    else
00545 #endif
00546 #if (RAW_SOCKET_SUPPORT == ENABLED)
00547    //Raw socket?
00548    if(socket->type == SOCKET_TYPE_RAW_IP)
00549    {
00550       //Send a raw IP packet
00551       error = rawSocketSendIpPacket(socket, destIpAddr, data, length, written);
00552    }
00553    else if(socket->type == SOCKET_TYPE_RAW_ETH)
00554    {
00555       //Send a raw Ethernet packet
00556       error = rawSocketSendEthPacket(socket, data, length, written);
00557    }
00558    else
00559 #endif
00560    //Socket type not supported...
00561    {
00562       //Invalid socket type
00563       error = ERROR_INVALID_SOCKET;
00564    }
00565 
00566    //Release exclusive access
00567    osReleaseMutex(&netMutex);
00568 
00569    //Return status code
00570    return error;
00571 }
00572 
00573 
00574 /**
00575  * @brief Receive data from a connected socket
00576  * @param[in] socket Handle that identifies a connected socket
00577  * @param[out] data Buffer where to store the incoming data
00578  * @param[in] size Maximum number of bytes that can be received
00579  * @param[out] received Number of bytes that have been received
00580  * @param[in] flags Set of flags that influences the behavior of this function
00581  * @return Error code
00582  **/
00583 
00584 error_t socketReceive(Socket *socket, void *data,
00585    size_t size, size_t *received, uint_t flags)
00586 {
00587    //For connection-oriented sockets, source and destination addresses are no use
00588    return socketReceiveEx(socket, NULL, NULL, NULL, data, size, received, flags);
00589 }
00590 
00591 
00592 /**
00593  * @brief Receive a datagram from a connectionless socket
00594  * @param[in] socket Handle that identifies a socket
00595  * @param[out] srcIpAddr Source IP address (optional)
00596  * @param[out] srcPort Source port number (optional)
00597  * @param[out] data Buffer where to store the incoming data
00598  * @param[in] size Maximum number of bytes that can be received
00599  * @param[out] received Number of bytes that have been received
00600  * @param[in] flags Set of flags that influences the behavior of this function
00601  * @return Error code
00602  **/
00603 
00604 error_t socketReceiveFrom(Socket *socket, IpAddr *srcIpAddr, uint16_t *srcPort,
00605    void *data, size_t size, size_t *received, uint_t flags)
00606 {
00607    //Destination address is no use
00608    return socketReceiveEx(socket, srcIpAddr, srcPort, NULL, data, size, received, flags);
00609 }
00610 
00611 
00612 /**
00613  * @brief Receive a datagram
00614  * @param[in] socket Handle that identifies a socket
00615  * @param[out] srcIpAddr Source IP address (optional)
00616  * @param[out] srcPort Source port number (optional)
00617  * @param[out] destIpAddr Destination IP address (optional)
00618  * @param[out] data Buffer where to store the incoming data
00619  * @param[in] size Maximum number of bytes that can be received
00620  * @param[out] received Number of bytes that have been received
00621  * @param[in] flags Set of flags that influences the behavior of this function
00622  * @return Error code
00623  **/
00624 
00625 error_t socketReceiveEx(Socket *socket, IpAddr *srcIpAddr, uint16_t *srcPort,
00626    IpAddr *destIpAddr, void *data, size_t size, size_t *received, uint_t flags)
00627 {
00628    error_t error;
00629 
00630    //Make sure the socket handle is valid
00631    if(socket == NULL)
00632       return ERROR_INVALID_PARAMETER;
00633 
00634    //Get exclusive access
00635    osAcquireMutex(&netMutex);
00636 
00637 #if (TCP_SUPPORT == ENABLED)
00638    //Connection-oriented socket?
00639    if(socket->type == SOCKET_TYPE_STREAM)
00640    {
00641       //Receive data
00642       error = tcpReceive(socket, data, size, received, flags);
00643 
00644       //Output parameters
00645       if(srcIpAddr)
00646          *srcIpAddr = socket->remoteIpAddr;
00647       if(srcPort)
00648          *srcPort = socket->remotePort;
00649       if(destIpAddr)
00650          *destIpAddr = socket->localIpAddr;
00651    }
00652    else
00653 #endif
00654 #if (UDP_SUPPORT == ENABLED)
00655    //Connectionless socket?
00656    if(socket->type == SOCKET_TYPE_DGRAM)
00657    {
00658       //Receive UDP datagram
00659       error = udpReceiveDatagram(socket, srcIpAddr,
00660          srcPort, destIpAddr, data, size, received, flags);
00661    }
00662    else
00663 #endif
00664 #if (RAW_SOCKET_SUPPORT == ENABLED)
00665    //Raw socket?
00666    if(socket->type == SOCKET_TYPE_RAW_IP)
00667    {
00668       //Receive a raw IP packet
00669       error = rawSocketReceiveIpPacket(socket,
00670          srcIpAddr, destIpAddr, data, size, received, flags);
00671    }
00672    else if(socket->type == SOCKET_TYPE_RAW_ETH)
00673    {
00674       //Receive a raw Ethernet packet
00675       error = rawSocketReceiveEthPacket(socket, data, size, received, flags);
00676    }
00677    else
00678 #endif
00679    //Socket type not supported...
00680    {
00681       //No data can be read
00682       *received = 0;
00683       //Invalid socket type
00684       error = ERROR_INVALID_SOCKET;
00685    }
00686 
00687    //Release exclusive access
00688    osReleaseMutex(&netMutex);
00689 
00690    //Return status code
00691    return error;
00692 }
00693 
00694 
00695 /**
00696  * @brief Retrieve the local address for a given socket
00697  * @param[in] socket Handle that identifies a socket
00698  * @param[out] localIpAddr Local IP address (optional)
00699  * @param[out] localPort Local port number (optional)
00700  * @return Error code
00701  **/
00702 
00703 error_t socketGetLocalAddr(Socket *socket, IpAddr *localIpAddr, uint16_t *localPort)
00704 {
00705    //Make sure the socket handle is valid
00706    if(socket == NULL)
00707       return ERROR_INVALID_PARAMETER;
00708 
00709    //Retrieve local IP address
00710    if(localIpAddr != NULL)
00711       *localIpAddr = socket->localIpAddr;
00712 
00713    //Retrieve local port number
00714    if(localPort != NULL)
00715       *localPort = socket->localPort;
00716 
00717    //Successful processing
00718    return NO_ERROR;
00719 }
00720 
00721 
00722 /**
00723  * @brief Retrieve the address of the peer to which a socket is connected
00724  * @param[in] socket Handle that identifies a socket
00725  * @param[out] remoteIpAddr IP address of the remote host (optional)
00726  * @param[out] remotePort Remote port number (optional)
00727  * @return Error code
00728  **/
00729 
00730 error_t socketGetRemoteAddr(Socket *socket, IpAddr *remoteIpAddr, uint16_t *remotePort)
00731 {
00732    //Make sure the socket handle is valid
00733    if(socket == NULL)
00734       return ERROR_INVALID_PARAMETER;
00735 
00736    //Retrieve local IP address
00737    if(remoteIpAddr != NULL)
00738       *remoteIpAddr = socket->remoteIpAddr;
00739 
00740    //Retrieve local port number
00741    if(remotePort != NULL)
00742       *remotePort = socket->remotePort;
00743 
00744    //Successful processing
00745    return NO_ERROR;
00746 }
00747 
00748 
00749 /**
00750  * @brief Disable reception, transmission, or both
00751  *
00752  * Note that socketShutdown() does not close the socket, and resources attached
00753  * to the socket will not be freed until socketClose() is invoked
00754  *
00755  * @param[in] socket Handle to a socket
00756  * @param[in] how Flag that describes what types of operation will no longer be allowed
00757  * @return Error code
00758  **/
00759 
00760 error_t socketShutdown(Socket *socket, uint_t how)
00761 {
00762 #if (TCP_SUPPORT == ENABLED)
00763    error_t error;
00764 
00765    //Make sure the socket handle is valid
00766    if(socket == NULL)
00767       return ERROR_INVALID_PARAMETER;
00768    //Make sure the socket type is correct
00769    if(socket->type != SOCKET_TYPE_STREAM)
00770       return ERROR_INVALID_SOCKET;
00771    //Check flags
00772    if((how != SOCKET_SD_SEND) && (how != SOCKET_SD_RECEIVE) && (how != SOCKET_SD_BOTH))
00773       return ERROR_INVALID_PARAMETER;
00774 
00775    //Get exclusive access
00776    osAcquireMutex(&netMutex);
00777 
00778    //Graceful shutdown
00779    error = tcpShutdown(socket, how);
00780 
00781    //Release exclusive access
00782    osReleaseMutex(&netMutex);
00783 
00784    //Return status code
00785    return error;
00786 #else
00787    return ERROR_NOT_IMPLEMENTED;
00788 #endif
00789 }
00790 
00791 
00792 /**
00793  * @brief Close an existing socket
00794  * @param[in] socket Handle identifying the socket to close
00795  **/
00796 
00797 void socketClose(Socket *socket)
00798 {
00799    //Make sure the socket handle is valid
00800    if(socket == NULL)
00801       return;
00802 
00803    //Get exclusive access
00804    osAcquireMutex(&netMutex);
00805 
00806 #if (TCP_SUPPORT == ENABLED)
00807    //Connection-oriented socket?
00808    if(socket->type == SOCKET_TYPE_STREAM)
00809    {
00810       //Abort the current TCP connection
00811       tcpAbort(socket);
00812    }
00813 #endif
00814 #if (UDP_SUPPORT == ENABLED || RAW_SOCKET_SUPPORT == ENABLED)
00815    //Connectionless socket or raw socket?
00816    if(socket->type == SOCKET_TYPE_DGRAM ||
00817       socket->type == SOCKET_TYPE_RAW_IP ||
00818       socket->type == SOCKET_TYPE_RAW_ETH)
00819    {
00820       //Point to the first item in the receive queue
00821       SocketQueueItem *queueItem = socket->receiveQueue;
00822 
00823       //Purge the receive queue
00824       while(queueItem)
00825       {
00826          //Keep track of the next item in the queue
00827          SocketQueueItem *nextQueueItem = queueItem->next;
00828          //Free previously allocated memory
00829          memPoolFree(queueItem->buffer);
00830          //Point to the next item
00831          queueItem = nextQueueItem;
00832       }
00833 
00834       //Mark the socket as closed
00835       socket->type = SOCKET_TYPE_UNUSED;
00836    }
00837 #endif
00838 
00839    //Release exclusive access
00840    osReleaseMutex(&netMutex);
00841 }
00842 
00843 
00844 /**
00845  * @brief Wait for one of a set of sockets to become ready to perform I/O
00846  *
00847  * The socketPoll function determines the status of one or more sockets,
00848  * waiting if necessary, to perform synchronous I/O
00849  *
00850  * @param[in,out] eventDesc Set of entries specifying the events the user is interested in
00851  * @param[in] size Number of entries in the descriptor set
00852  * @param[in] extEvent External event that can abort the wait if necessary (optional)
00853  * @param[in] timeout Maximum time to wait before returning
00854  * @return Error code
00855  **/
00856 
00857 error_t socketPoll(SocketEventDesc *eventDesc, uint_t size, OsEvent *extEvent, systime_t timeout)
00858 {
00859    uint_t i;
00860    bool_t status;
00861    OsEvent *event;
00862    OsEvent eventObject;
00863 
00864    //Check parameters
00865    if(!eventDesc || !size)
00866       return ERROR_INVALID_PARAMETER;
00867 
00868    //Try to use the supplied event object to receive notifications
00869    if(!extEvent)
00870    {
00871       //Create an event object only if necessary
00872       if(!osCreateEvent(&eventObject))
00873       {
00874          //Report an error
00875          return ERROR_OUT_OF_RESOURCES;
00876       }
00877 
00878       //Reference to the newly created event
00879       event = &eventObject;
00880    }
00881    else
00882    {
00883       //Reference to the external event
00884       event = extEvent;
00885    }
00886 
00887    //Loop through descriptors
00888    for(i = 0; i < size; i++)
00889    {
00890       //Clear event flags
00891       eventDesc[i].eventFlags = 0;
00892       //Subscribe to the requested events
00893       socketRegisterEvents(eventDesc[i].socket, event, eventDesc[i].eventMask);
00894    }
00895 
00896    //Block the current task until an event occurs
00897    status = osWaitForEvent(event, timeout);
00898 
00899    //Any socket event is in the signaled state?
00900    if(status)
00901    {
00902       //Loop through descriptors
00903       for(i = 0; i < size; i++)
00904       {
00905          //Retrieve event flags for the current socket
00906          socketGetEvents(eventDesc[i].socket, &eventDesc[i].eventFlags);
00907          //Clear unnecessary flags
00908          eventDesc[i].eventFlags &= eventDesc[i].eventMask;
00909       }
00910    }
00911 
00912    //Unsubscribe previously registered events
00913    for(i = 0; i < size; i++)
00914       socketUnregisterEvents(eventDesc[i].socket);
00915 
00916    //Reset event object before exiting...
00917    osResetEvent(event);
00918 
00919    //Release previously allocated resources
00920    if(!extEvent)
00921       osDeleteEvent(&eventObject);
00922 
00923    //Return status code
00924    return status ? NO_ERROR : ERROR_TIMEOUT;
00925 }
00926 
00927 
00928 /**
00929  * @brief Subscribe to the specified socket events
00930  * @param[in] socket Handle that identifies a socket
00931  * @param[in] event Event object used to receive notifications
00932  * @param[in] eventMask Logic OR of the requested socket events
00933  * @return Error code
00934  **/
00935 
00936 error_t socketRegisterEvents(Socket *socket, OsEvent *event, uint_t eventMask)
00937 {
00938    //Make sure the socket handle is valid
00939    if(socket == NULL)
00940       return ERROR_INVALID_PARAMETER;
00941 
00942    //Get exclusive access
00943    osAcquireMutex(&netMutex);
00944 
00945    //An user event may have been previously registered...
00946    if(socket->userEvent != NULL)
00947       socket->eventMask |= eventMask;
00948    else
00949       socket->eventMask = eventMask;
00950 
00951    //Suscribe to get notified of events
00952    socket->userEvent = event;
00953 
00954 #if (TCP_SUPPORT == ENABLED)
00955    //Handle TCP specific events
00956    if(socket->type == SOCKET_TYPE_STREAM)
00957    {
00958       tcpUpdateEvents(socket);
00959    }
00960 #endif
00961 #if (UDP_SUPPORT == ENABLED)
00962    //Handle UDP specific events
00963    if(socket->type == SOCKET_TYPE_DGRAM)
00964    {
00965       udpUpdateEvents(socket);
00966    }
00967 #endif
00968 #if (RAW_SOCKET_SUPPORT == ENABLED)
00969    //Handle events that are specific to raw sockets
00970    if(socket->type == SOCKET_TYPE_RAW_IP ||
00971       socket->type == SOCKET_TYPE_RAW_ETH)
00972    {
00973       rawSocketUpdateEvents(socket);
00974    }
00975 #endif
00976 
00977    //Release exclusive access
00978    osReleaseMutex(&netMutex);
00979    //Successful processing
00980    return NO_ERROR;
00981 }
00982 
00983 
00984 /**
00985  * @brief Unsubscribe previously registered events
00986  * @param[in] socket Handle that identifies a socket
00987  * @return Error code
00988  **/
00989 
00990 error_t socketUnregisterEvents(Socket *socket)
00991 {
00992    //Make sure the socket handle is valid
00993    if(socket == NULL)
00994       return ERROR_INVALID_PARAMETER;
00995 
00996    //Get exclusive access
00997    osAcquireMutex(&netMutex);
00998 
00999    //Unsuscribe socket events
01000    socket->userEvent = NULL;
01001 
01002    //Release exclusive access
01003    osReleaseMutex(&netMutex);
01004    //Successful processing
01005    return NO_ERROR;
01006 }
01007 
01008 
01009 /**
01010  * @brief Retrieve event flags for a specified socket
01011  * @param[in] socket Handle that identifies a socket
01012  * @param[out] eventFlags Logic OR of events in the signaled state
01013  * @return Error code
01014  **/
01015 
01016 error_t socketGetEvents(Socket *socket, uint_t *eventFlags)
01017 {
01018    //Make sure the socket handle is valid
01019    if(socket == NULL)
01020    {
01021       //Always return a valid value
01022       *eventFlags = 0;
01023       //Report an error
01024       return ERROR_INVALID_PARAMETER;
01025    }
01026 
01027    //Get exclusive access
01028    osAcquireMutex(&netMutex);
01029 
01030    //Read event flags for the specified socket
01031    *eventFlags = socket->eventFlags;
01032 
01033    //Release exclusive access
01034    osReleaseMutex(&netMutex);
01035    //Successful processing
01036    return NO_ERROR;
01037 }
01038 
01039 
01040 /**
01041  * @brief Resolve a host name into an IP address
01042  * @param[in] interface Underlying network interface (optional parameter)
01043  * @param[in] name Name of the host to be resolved
01044  * @param[out] ipAddr IP address corresponding to the specified host name
01045  * @param[in] flags Set of flags that influences the behavior of this function
01046  * @return Error code
01047  **/
01048 
01049 error_t getHostByName(NetInterface *interface,
01050    const char_t *name, IpAddr *ipAddr, uint_t flags)
01051 {
01052    error_t error;
01053 
01054    //Default address type depends on TCP/IP stack configuration
01055 #if (IPV4_SUPPORT == ENABLED)
01056    HostType type = HOST_TYPE_IPV4;
01057 #elif (IPV6_SUPPORT == ENABLED)
01058    HostType type = HOST_TYPE_IPV6;
01059 #else
01060    HostType type = HOST_TYPE_ANY;
01061 #endif
01062 
01063    //Default name resolution protocol depends on TCP/IP stack configuration
01064 #if (DNS_CLIENT_SUPPORT == ENABLED)
01065    HostnameResolver protocol = HOST_NAME_RESOLVER_DNS;
01066 #elif (MDNS_CLIENT_SUPPORT == ENABLED)
01067    HostnameResolver protocol = HOST_NAME_RESOLVER_MDNS;
01068 #elif (NBNS_CLIENT_SUPPORT == ENABLED)
01069    HostnameResolver protocol = HOST_NAME_RESOLVER_NBNS;
01070 #else
01071    HostnameResolver protocol = HOST_NAME_RESOLVER_ANY;
01072 #endif
01073 
01074    //Check parameters
01075    if(name == NULL || ipAddr == NULL)
01076       return ERROR_INVALID_PARAMETER;
01077 
01078    //Use default network interface?
01079    if(interface == NULL)
01080       interface = netGetDefaultInterface();
01081 
01082    //The specified name can be either an IP or a host name
01083    error = ipStringToAddr(name, ipAddr);
01084 
01085    //Perform name resolution if necessary
01086    if(error)
01087    {
01088       //The user may provide a hint to choose between IPv4 and IPv6
01089       if(flags & HOST_TYPE_IPV4)
01090          type = HOST_TYPE_IPV4;
01091       else if(flags & HOST_TYPE_IPV6)
01092          type = HOST_TYPE_IPV6;
01093 
01094       //The user may provide a hint to to select the desired protocol to be used
01095       if(flags & HOST_NAME_RESOLVER_DNS)
01096       {
01097          //Use DNS to resolve the specified host name
01098          protocol = HOST_NAME_RESOLVER_DNS;
01099       }
01100       else if(flags & HOST_NAME_RESOLVER_MDNS)
01101       {
01102          //Use mDNS to resolve the specified host name
01103          protocol = HOST_NAME_RESOLVER_MDNS;
01104       }
01105       else if(flags & HOST_NAME_RESOLVER_NBNS)
01106       {
01107          //Use NBNS to resolve the specified host name
01108          protocol = HOST_NAME_RESOLVER_NBNS;
01109       }
01110       else
01111       {
01112          //Retrieve the length of the host name to be resolved
01113          size_t n = strlen(name);
01114 
01115          //Select the most suitable protocol
01116          if(n >= 6 && !strcasecmp(name + n - 6, ".local"))
01117          {
01118 #if (MDNS_CLIENT_SUPPORT == ENABLED)
01119             //Use mDNS to resolve the specified host name
01120             protocol = HOST_NAME_RESOLVER_MDNS;
01121 #endif
01122          }
01123          else if(n <= 15 && !strchr(name, '.') && type == HOST_TYPE_IPV4)
01124          {
01125 #if (NBNS_CLIENT_SUPPORT == ENABLED)
01126             //Use NetBIOS Name Service to resolve the specified host name
01127             protocol = HOST_NAME_RESOLVER_NBNS;
01128 #endif
01129          }
01130       }
01131 
01132 #if (DNS_CLIENT_SUPPORT == ENABLED)
01133       //Use DNS protocol?
01134       if(protocol == HOST_NAME_RESOLVER_DNS)
01135       {
01136          //Perform host name resolution
01137          error = dnsResolve(interface, name, type, ipAddr);
01138       }
01139       else
01140 #endif
01141 #if (MDNS_CLIENT_SUPPORT == ENABLED)
01142       //Use mDNS protocol?
01143       if(protocol == HOST_NAME_RESOLVER_MDNS)
01144       {
01145          //Perform host name resolution
01146          error = mdnsClientResolve(interface, name, type, ipAddr);
01147       }
01148       else
01149 #endif
01150 #if (NBNS_CLIENT_SUPPORT == ENABLED && IPV4_SUPPORT == ENABLED)
01151       //Use NetBIOS Name Service protocol?
01152       if(protocol == HOST_NAME_RESOLVER_NBNS)
01153       {
01154          //Perform host name resolution
01155          error = nbnsResolve(interface, name, ipAddr);
01156       }
01157       else
01158 #endif
01159       //Invalid protocol?
01160       {
01161          //Report an error
01162          error = ERROR_INVALID_PARAMETER;
01163       }
01164    }
01165 
01166    //Return status code
01167    return error;
01168 }
01169