Kenji Arai / TYBLE16_mbedlized_os5_several_examples_1st

Dependencies:   nRF51_Vdd TextLCD BME280

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers TCPSocket.cpp Source File

TCPSocket.cpp

00001 /* Socket
00002  * Copyright (c) 2015 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include "TCPSocket.h"
00018 #include "Timer.h"
00019 #include "mbed_assert.h"
00020 
00021 TCPSocket::TCPSocket()
00022 {
00023 }
00024 
00025 TCPSocket::TCPSocket(TCPSocket* parent, nsapi_socket_t socket, SocketAddress address)
00026 {
00027     _socket = socket,
00028     _stack = parent->_stack;
00029     _factory_allocated = true;
00030     _remote_peer = address;
00031 
00032     _event = mbed::Callback<void()>(this, &TCPSocket::event);
00033     _stack->socket_attach(socket, &mbed::Callback<void()>::thunk, &_event);
00034 }
00035 
00036 TCPSocket::~TCPSocket()
00037 {
00038 }
00039 
00040 nsapi_protocol_t TCPSocket::get_proto()
00041 {
00042     return NSAPI_TCP ;
00043 }
00044 
00045 nsapi_error_t TCPSocket::connect(const SocketAddress &address)
00046 {
00047     _lock.lock();
00048     nsapi_error_t ret;
00049 
00050     // If this assert is hit then there are two threads
00051     // performing a send at the same time which is undefined
00052     // behavior
00053     MBED_ASSERT(_writers == 0);
00054     _writers++;
00055 
00056     bool blocking_connect_in_progress = false;
00057 
00058     while (true) {
00059         if (!_socket) {
00060             ret = NSAPI_ERROR_NO_SOCKET ;
00061             break;
00062         }
00063 
00064         _pending = 0;
00065         ret = _stack->socket_connect(_socket, address);
00066         if ((_timeout == 0) || !(ret == NSAPI_ERROR_IN_PROGRESS  || ret == NSAPI_ERROR_ALREADY )) {
00067             break;
00068         } else {
00069             blocking_connect_in_progress = true;
00070 
00071             uint32_t flag;
00072 
00073             // Release lock before blocking so other threads
00074             // accessing this object aren't blocked
00075             _lock.unlock();
00076             flag = _event_flag.wait_any(WRITE_FLAG, _timeout);
00077             _lock.lock();
00078             if (flag & osFlagsError) {
00079                 // Timeout break
00080                 break;
00081             }
00082         }
00083     }
00084 
00085     _writers--;
00086     if (!_socket) {
00087         _event_flag.set(FINISHED_FLAG);
00088     }
00089 
00090     /* Non-blocking connect gives "EISCONN" once done - convert to OK for blocking mode if we became connected during this call */
00091     if (ret == NSAPI_ERROR_IS_CONNECTED  && blocking_connect_in_progress) {
00092         ret = NSAPI_ERROR_OK ;
00093     }
00094 
00095     if (ret == NSAPI_ERROR_OK  || ret == NSAPI_ERROR_IN_PROGRESS ) {
00096         _remote_peer = address;
00097     }
00098 
00099     _lock.unlock();
00100     return ret;
00101 }
00102 
00103 nsapi_error_t TCPSocket::connect(const char *host, uint16_t port)
00104 {
00105     SocketAddress address;
00106     nsapi_error_t err = _stack->gethostbyname(host, &address);
00107     if (err) {
00108         return NSAPI_ERROR_DNS_FAILURE ;
00109     }
00110 
00111     address.set_port(port);
00112 
00113     // connect is thread safe
00114     return connect(address);
00115 }
00116 
00117 nsapi_size_or_error_t TCPSocket::send(const void *data, nsapi_size_t size)
00118 {
00119     _lock.lock();
00120     const uint8_t *data_ptr = static_cast<const uint8_t *>(data);
00121     nsapi_size_or_error_t ret;
00122     nsapi_size_t written = 0;
00123 
00124     // If this assert is hit then there are two threads
00125     // performing a send at the same time which is undefined
00126     // behavior
00127     MBED_ASSERT(_writers == 0);
00128     _writers++;
00129 
00130     // Unlike recv, we should write the whole thing if blocking. POSIX only
00131     // allows partial as a side-effect of signal handling; it normally tries to
00132     // write everything if blocking. Without signals we can always write all.
00133     while (true) {
00134         if (!_socket) {
00135             ret = NSAPI_ERROR_NO_SOCKET ;
00136             break;
00137         }
00138 
00139         _pending = 0;
00140         ret = _stack->socket_send(_socket, data_ptr + written, size - written);
00141         if (ret >= 0) {
00142             written += ret;
00143             if (written >= size) {
00144                 break;
00145             }
00146         }
00147         if (_timeout == 0) {
00148             break;
00149         } else if (ret == NSAPI_ERROR_WOULD_BLOCK ) {
00150             uint32_t flag;
00151 
00152             // Release lock before blocking so other threads
00153             // accessing this object aren't blocked
00154             _lock.unlock();
00155             flag = _event_flag.wait_any(WRITE_FLAG, _timeout);
00156             _lock.lock();
00157 
00158             if (flag & osFlagsError) {
00159                 // Timeout break
00160                 break;
00161             }
00162         } else if (ret < 0) {
00163             break;
00164         }
00165     }
00166 
00167     _writers--;
00168     if (!_socket) {
00169         _event_flag.set(FINISHED_FLAG);
00170     }
00171 
00172     _lock.unlock();
00173     if (ret <= 0 && ret != NSAPI_ERROR_WOULD_BLOCK ) {
00174         return ret;
00175     } else if (written == 0) {
00176         return NSAPI_ERROR_WOULD_BLOCK ;
00177     } else {
00178         return written;
00179     }
00180 }
00181 
00182 nsapi_size_or_error_t TCPSocket::sendto(const SocketAddress &address, const void *data, nsapi_size_t size)
00183 {
00184     (void)address;
00185     return send(data, size);
00186 }
00187 
00188 nsapi_size_or_error_t TCPSocket::recv(void *data, nsapi_size_t size)
00189 {
00190     _lock.lock();
00191     nsapi_size_or_error_t ret;
00192 
00193     // If this assert is hit then there are two threads
00194     // performing a recv at the same time which is undefined
00195     // behavior
00196     MBED_ASSERT(_readers == 0);
00197     _readers++;
00198 
00199     while (true) {
00200         if (!_socket) {
00201             ret = NSAPI_ERROR_NO_SOCKET ;
00202             break;
00203         }
00204 
00205         _pending = 0;
00206         ret = _stack->socket_recv(_socket, data, size);
00207         if ((_timeout == 0) || (ret != NSAPI_ERROR_WOULD_BLOCK )) {
00208             break;
00209         } else {
00210             uint32_t flag;
00211 
00212             // Release lock before blocking so other threads
00213             // accessing this object aren't blocked
00214             _lock.unlock();
00215             flag = _event_flag.wait_any(READ_FLAG, _timeout);
00216             _lock.lock();
00217 
00218             if (flag & osFlagsError) {
00219                 // Timeout break
00220                 ret = NSAPI_ERROR_WOULD_BLOCK ;
00221                 break;
00222             }
00223         }
00224     }
00225 
00226     _readers--;
00227     if (!_socket) {
00228         _event_flag.set(FINISHED_FLAG);
00229     }
00230 
00231     _lock.unlock();
00232     return ret;
00233 }
00234 
00235 nsapi_size_or_error_t TCPSocket::recvfrom(SocketAddress *address, void *data, nsapi_size_t size)
00236 {
00237     if (address) {
00238         *address = _remote_peer;
00239     }
00240     return recv(data, size);
00241 }
00242 
00243 nsapi_error_t TCPSocket::listen(int backlog)
00244 {
00245     _lock.lock();
00246     nsapi_error_t ret;
00247 
00248     if (!_socket) {
00249         ret = NSAPI_ERROR_NO_SOCKET ;
00250     } else {
00251         ret = _stack->socket_listen(_socket, backlog);
00252     }
00253 
00254     _lock.unlock();
00255     return ret;
00256 }
00257 
00258 TCPSocket *TCPSocket::accept(nsapi_error_t *error)
00259 {
00260     _lock.lock();
00261     TCPSocket *connection = NULL;
00262     nsapi_error_t ret;
00263 
00264     _readers++;
00265 
00266     while (true) {
00267         if (!_socket) {
00268             ret = NSAPI_ERROR_NO_SOCKET ;
00269             break;
00270         }
00271 
00272         _pending = 0;
00273         void *socket;
00274         SocketAddress address;
00275         ret = _stack->socket_accept(_socket, &socket, &address);
00276 
00277         if (0 == ret) {
00278             connection = new TCPSocket(this, socket, address);
00279             break;
00280         } else if ((_timeout == 0) || (ret != NSAPI_ERROR_WOULD_BLOCK )) {
00281             break;
00282         } else {
00283             uint32_t flag;
00284 
00285             // Release lock before blocking so other threads
00286             // accessing this object aren't blocked
00287             _lock.unlock();
00288             flag = _event_flag.wait_any(READ_FLAG, _timeout);
00289             _lock.lock();
00290 
00291             if (flag & osFlagsError) {
00292                 // Timeout break
00293                 ret = NSAPI_ERROR_WOULD_BLOCK ;
00294                 break;
00295             }
00296         }
00297     }
00298 
00299     _readers--;
00300     if (!_socket) {
00301         _event_flag.set(FINISHED_FLAG);
00302     }
00303     _lock.unlock();
00304     if (error) {
00305         *error = ret;
00306     }
00307     return connection;
00308 }