A new object oriented network api that can be used to replace the one provided by the EthernetInterface library.

Dependents:   NetRelais TCP_Client_Example TCP_Server_Example UDP_Server_Example ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers socket.cpp Source File

socket.cpp

00001 /**
00002  * Copyright (c) 2012, Roy van Dam <roy@vandam-innovations.com>
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright notice, this
00009  *    list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright notice,
00011  *    this list of conditions and the following disclaimer in the documentation
00012  *    and/or other materials provided with the distribution.
00013  *
00014  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00015  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00016  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00017  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
00018  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00019  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00020  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00021  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00022  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00023  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00024  */
00025 
00026 #include "socket.hpp"
00027 using namespace network::tcp;
00028 
00029 int
00030 Socket::open()
00031 {
00032     // Check socket status
00033     if (this->_status != Socket::Closed) {
00034         return -1;
00035     }
00036     
00037     // Open socket
00038     this->_socket = lwip_socket(AF_INET, SOCK_STREAM, 0);
00039     if (this->_socket < 0) {
00040         return -2;
00041     }
00042     
00043     // Update status and return
00044     this->_status = Socket::Open;
00045     return 0;
00046 }
00047 
00048 int
00049 Socket::connect(const char *hostname, int port)
00050 {
00051     ip::Address address;
00052     if (address.fromHostname(hostname) < 0) {
00053         return -1;
00054     }
00055     
00056     return this->connect(address, port);
00057 }
00058 
00059 int
00060 Socket::connect(const std::string hostname, int port)
00061 {
00062     ip::Address address;
00063     if (address.fromHostname(hostname) < 0) {
00064         return -1;
00065     }
00066     
00067     return this->connect(address, port);
00068 }
00069 
00070 int
00071 Socket::connect(const ip::Address &address, int port)
00072 {
00073     ip::Endpoint endpoint(address, port);
00074     return this->connect(endpoint);
00075 }
00076 
00077 int
00078 Socket::connect(ip::Endpoint &endpoint)
00079 {
00080     // Check socket status
00081     if ((this->_status != Socket::Open) &&
00082         (this->_status != Socket::Disconnected))
00083     {
00084         return -1;
00085     }
00086     
00087     // Create native endpoint
00088     struct sockaddr_in native_endpoint;
00089     endpoint.toNative(&native_endpoint);
00090     
00091     // Attempt to connect with remote endpoint.
00092     int result = lwip_connect(this->_socket,
00093         (const struct sockaddr *)&native_endpoint, sizeof(native_endpoint));
00094     
00095     // Check result
00096     if (result < 0) {
00097         return -2;
00098     }
00099     
00100     // Update remote endpoint information.
00101     this->_remote_endpoint = endpoint;
00102     
00103     // Update status and return
00104     this->_status = Socket::Connected;
00105     return 0;
00106 }
00107 
00108 int
00109 Socket::shutdown()
00110 {
00111     // Check socket status
00112     if (this->_status != Socket::Connected) {
00113         return -1;
00114     }
00115     
00116     // Attempt to shutdown the connection.
00117     int result = lwip_shutdown(this->_socket, SHUT_RDWR);
00118     if (result < 0) {
00119         return -2;
00120     }
00121     
00122     // Update status and return
00123     this->_status = Socket::Disconnected;
00124     return 0;
00125 }
00126 
00127 int
00128 Socket::listen(int max_pending)
00129 {
00130     // Check socket status
00131     if (this->_status != Socket::Open) {
00132         return -1;
00133     }
00134     
00135     // Put socket into listening mode.
00136     int result = lwip_listen(this->_socket, max_pending);
00137     if (result < 0) {
00138         return -2;
00139     }
00140     
00141     // Update status and return
00142     this->_status = Socket::Listening;
00143     return 0;
00144 }
00145 
00146 int
00147 Socket::accept(Socket &client)
00148 {
00149     // Check socket status
00150     if (this->_status != Socket::Listening) {
00151         return -1;
00152     }
00153     
00154     // Check client socket status
00155     if (client._status != Socket::Closed) {
00156         return -2;
00157     }
00158     
00159     // Create native endpoint
00160     struct sockaddr_in native_endpoint;
00161     int native_endpoint_size = sizeof(native_endpoint);
00162     std::memset(&native_endpoint, 0, sizeof(native_endpoint));
00163     
00164     // Accept new (pending) connections.
00165     int socket = lwip_accept(this->_socket,
00166         (struct sockaddr*)&native_endpoint, (u32_t *)&native_endpoint_size);
00167     
00168     // Did we succeed?
00169     if (socket < 0) {
00170         return -3;
00171     }
00172     
00173     // Check if we received the endpoint information correctly.
00174     if (native_endpoint_size != sizeof(native_endpoint)) {
00175         printf("Warning: invalid endpoint size received\n\r");
00176     }
00177     
00178     // Populate client socket
00179     client._socket = socket;
00180     client._status = Socket::Connected;
00181     client._remote_endpoint.fromNative(&native_endpoint);
00182     
00183     return 0;
00184 }
00185 
00186 int
00187 Socket::write(Buffer &buffer)
00188 {
00189     return this->write(buffer.data(), buffer.length());
00190 }
00191 
00192 int
00193 Socket::write(void *data, size_t size)
00194 {
00195     // Check data buffer and size
00196     if (data == NULL || size == 0) {
00197         return -1;
00198     }
00199 
00200     // Check socket status
00201     if (this->_status != Socket::Connected) {
00202         return -2;
00203     }
00204     
00205     // Update status
00206     this->_status = Socket::Sending;
00207     
00208     // Try to send the specified amount of bytes.
00209     int bytes_written = lwip_send(this->_socket, data, size, 0);
00210     
00211     // Update status
00212     this->_status = (bytes_written == 0)
00213         ? Socket::Disconnected
00214         : Socket::Connected;
00215     
00216     // Return the result.
00217     return bytes_written;
00218 }
00219 
00220 int
00221 Socket::read(Buffer &buffer)
00222 {
00223     int result = this->read(buffer.data(), buffer.size());
00224     if (result >= 0) {
00225         buffer.length(result);
00226     }
00227     
00228     return result;
00229 }
00230 
00231 int
00232 Socket::read(void *data, size_t max_size)
00233 {
00234     // Check data buffer and size
00235     if (data == NULL || max_size == 0) {
00236         return -1;
00237     }
00238 
00239     // Check socket status
00240     if (this->_status != Socket::Connected) {
00241         return -2;
00242     }
00243     
00244     // Update status
00245     this->_status = Socket::Receiving;
00246     
00247     // Try to read data from the socket.
00248     int bytes_read = lwip_recv(this->_socket, data, max_size, 0);
00249     
00250     // Update status
00251     this->_status = (bytes_read == 0)
00252         ? Socket::Disconnected
00253         : Socket::Connected;
00254             
00255     // Return bytes read
00256     return bytes_read;
00257 }