Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

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     _socket_stats.stats_update_proto(this, NSAPI_TCP );
00024 }
00025 
00026 TCPSocket::TCPSocket(TCPSocket *parent, nsapi_socket_t socket, SocketAddress address)
00027 {
00028     _socket = socket;
00029     _stack = parent->_stack;
00030     _factory_allocated = true;
00031     _remote_peer = address;
00032     _socket_stats.stats_new_socket_entry(this);
00033     _event = mbed::Callback<void()>(this, &TCPSocket::event);
00034     _stack->socket_attach(socket, &mbed::Callback<void()>::thunk, &_event);
00035 }
00036 
00037 TCPSocket::~TCPSocket()
00038 {
00039 }
00040 
00041 nsapi_protocol_t TCPSocket::get_proto()
00042 {
00043     return NSAPI_TCP ;
00044 }
00045 
00046 nsapi_error_t TCPSocket::connect(const SocketAddress &address)
00047 {
00048     _lock.lock();
00049     nsapi_error_t ret;
00050 
00051     // If this assert is hit then there are two threads
00052     // performing a send at the same time which is undefined
00053     // behavior
00054     MBED_ASSERT(_writers == 0);
00055     _writers++;
00056 
00057     bool blocking_connect_in_progress = false;
00058 
00059     while (true) {
00060         if (!_socket) {
00061             ret = NSAPI_ERROR_NO_SOCKET ;
00062             break;
00063         }
00064 
00065         core_util_atomic_flag_clear(&_pending);
00066         ret = _stack->socket_connect(_socket, address);
00067         if ((_timeout == 0) || !(ret == NSAPI_ERROR_IN_PROGRESS  || ret == NSAPI_ERROR_ALREADY )) {
00068             _socket_stats.stats_update_socket_state(this, SOCK_CONNECTED);
00069             break;
00070         } else {
00071             blocking_connect_in_progress = true;
00072 
00073             uint32_t flag;
00074 
00075             // Release lock before blocking so other threads
00076             // accessing this object aren't blocked
00077             _lock.unlock();
00078             flag = _event_flag.wait_any(WRITE_FLAG, _timeout);
00079             _lock.lock();
00080             if (flag & osFlagsError) {
00081                 // Timeout break
00082                 break;
00083             }
00084         }
00085     }
00086 
00087     _writers--;
00088     if (!_socket) {
00089         _event_flag.set(FINISHED_FLAG);
00090     }
00091 
00092     /* Non-blocking connect gives "EISCONN" once done - convert to OK for blocking mode if we became connected during this call */
00093     if (ret == NSAPI_ERROR_IS_CONNECTED  && blocking_connect_in_progress) {
00094         _socket_stats.stats_update_socket_state(this, SOCK_CONNECTED);
00095         ret = NSAPI_ERROR_OK ;
00096     }
00097 
00098     if (ret == NSAPI_ERROR_OK  || ret == NSAPI_ERROR_IN_PROGRESS ) {
00099         _remote_peer = address;
00100         _socket_stats.stats_update_peer(this, _remote_peer);
00101     }
00102 
00103     _lock.unlock();
00104     return ret;
00105 }
00106 
00107 nsapi_error_t TCPSocket::connect(const char *host, uint16_t port)
00108 {
00109     SocketAddress address;
00110     if (!_socket) {
00111         return NSAPI_ERROR_NO_SOCKET ;
00112     }
00113     nsapi_error_t err;
00114     if (!strcmp(_interface_name, "")) {
00115         err = _stack->gethostbyname(host, &address);
00116     } else {
00117         err = _stack->gethostbyname(host, &address, NSAPI_UNSPEC , _interface_name);
00118     }
00119     if (err) {
00120         return NSAPI_ERROR_DNS_FAILURE ;
00121     }
00122 
00123     address.set_port(port);
00124 
00125     // connect is thread safe
00126     return connect(address);
00127 }
00128 
00129 nsapi_size_or_error_t TCPSocket::send(const void *data, nsapi_size_t size)
00130 {
00131     _lock.lock();
00132     const uint8_t *data_ptr = static_cast<const uint8_t *>(data);
00133     nsapi_size_or_error_t ret;
00134     nsapi_size_t written = 0;
00135 
00136     // If this assert is hit then there are two threads
00137     // performing a send at the same time which is undefined
00138     // behavior
00139     MBED_ASSERT(_writers == 0);
00140     _writers++;
00141 
00142     // Unlike recv, we should write the whole thing if blocking. POSIX only
00143     // allows partial as a side-effect of signal handling; it normally tries to
00144     // write everything if blocking. Without signals we can always write all.
00145     while (true) {
00146         if (!_socket) {
00147             ret = NSAPI_ERROR_NO_SOCKET ;
00148             break;
00149         }
00150 
00151         core_util_atomic_flag_clear(&_pending);
00152         ret = _stack->socket_send(_socket, data_ptr + written, size - written);
00153         if (ret >= 0) {
00154             written += ret;
00155             if (written >= size) {
00156                 break;
00157             }
00158         }
00159         if (_timeout == 0) {
00160             break;
00161         } else if (ret == NSAPI_ERROR_WOULD_BLOCK ) {
00162             uint32_t flag;
00163 
00164             // Release lock before blocking so other threads
00165             // accessing this object aren't blocked
00166             _lock.unlock();
00167             flag = _event_flag.wait_any(WRITE_FLAG, _timeout);
00168             _lock.lock();
00169 
00170             if (flag & osFlagsError) {
00171                 // Timeout break
00172                 break;
00173             }
00174         } else if (ret < 0) {
00175             break;
00176         }
00177     }
00178 
00179     _writers--;
00180     if (!_socket) {
00181         _event_flag.set(FINISHED_FLAG);
00182     }
00183 
00184     _lock.unlock();
00185     if (ret <= 0 && ret != NSAPI_ERROR_WOULD_BLOCK ) {
00186         return ret;
00187     } else if (written == 0) {
00188         return NSAPI_ERROR_WOULD_BLOCK ;
00189     } else {
00190         _socket_stats.stats_update_sent_bytes(this, written);
00191         return written;
00192     }
00193 }
00194 
00195 nsapi_size_or_error_t TCPSocket::sendto(const SocketAddress &address, const void *data, nsapi_size_t size)
00196 {
00197     (void)address;
00198     return send(data, size);
00199 }
00200 
00201 nsapi_size_or_error_t TCPSocket::recv(void *data, nsapi_size_t size)
00202 {
00203     _lock.lock();
00204     nsapi_size_or_error_t ret;
00205 
00206     // If this assert is hit then there are two threads
00207     // performing a recv at the same time which is undefined
00208     // behavior
00209     MBED_ASSERT(_readers == 0);
00210     _readers++;
00211 
00212     while (true) {
00213         if (!_socket) {
00214             ret = NSAPI_ERROR_NO_SOCKET ;
00215             break;
00216         }
00217 
00218         core_util_atomic_flag_clear(&_pending);
00219         ret = _stack->socket_recv(_socket, data, size);
00220         if ((_timeout == 0) || (ret != NSAPI_ERROR_WOULD_BLOCK )) {
00221             _socket_stats.stats_update_recv_bytes(this, ret);
00222             break;
00223         } else {
00224             uint32_t flag;
00225 
00226             // Release lock before blocking so other threads
00227             // accessing this object aren't blocked
00228             _lock.unlock();
00229             flag = _event_flag.wait_any(READ_FLAG, _timeout);
00230             _lock.lock();
00231 
00232             if (flag & osFlagsError) {
00233                 // Timeout break
00234                 ret = NSAPI_ERROR_WOULD_BLOCK ;
00235                 break;
00236             }
00237         }
00238     }
00239 
00240     _readers--;
00241     if (!_socket) {
00242         _event_flag.set(FINISHED_FLAG);
00243     }
00244 
00245     _lock.unlock();
00246     return ret;
00247 }
00248 
00249 nsapi_size_or_error_t TCPSocket::recvfrom(SocketAddress *address, void *data, nsapi_size_t size)
00250 {
00251     if (address) {
00252         *address = _remote_peer;
00253     }
00254     return recv(data, size);
00255 }
00256 
00257 nsapi_error_t TCPSocket::listen(int backlog)
00258 {
00259     _lock.lock();
00260     nsapi_error_t ret;
00261 
00262     if (!_socket) {
00263         ret = NSAPI_ERROR_NO_SOCKET ;
00264     } else {
00265         ret = _stack->socket_listen(_socket, backlog);
00266         if (NSAPI_ERROR_OK  == ret) {
00267             _socket_stats.stats_update_socket_state(this, SOCK_LISTEN);
00268         }
00269     }
00270 
00271     _lock.unlock();
00272     return ret;
00273 }
00274 
00275 TCPSocket *TCPSocket::accept(nsapi_error_t *error)
00276 {
00277     _lock.lock();
00278     TCPSocket *connection = NULL;
00279     nsapi_error_t ret;
00280 
00281     _readers++;
00282 
00283     while (true) {
00284         if (!_socket) {
00285             ret = NSAPI_ERROR_NO_SOCKET ;
00286             break;
00287         }
00288 
00289         core_util_atomic_flag_clear(&_pending);
00290         void *socket;
00291         SocketAddress address;
00292         ret = _stack->socket_accept(_socket, &socket, &address);
00293 
00294         if (0 == ret) {
00295             connection = new TCPSocket(this, socket, address);
00296             _socket_stats.stats_update_peer(connection, address);
00297             _socket_stats.stats_update_socket_state(connection, SOCK_CONNECTED);
00298             break;
00299         } else if ((_timeout == 0) || (ret != NSAPI_ERROR_WOULD_BLOCK )) {
00300             break;
00301         } else {
00302             uint32_t flag;
00303 
00304             // Release lock before blocking so other threads
00305             // accessing this object aren't blocked
00306             _lock.unlock();
00307             flag = _event_flag.wait_any(READ_FLAG, _timeout);
00308             _lock.lock();
00309 
00310             if (flag & osFlagsError) {
00311                 // Timeout break
00312                 ret = NSAPI_ERROR_WOULD_BLOCK ;
00313                 break;
00314             }
00315         }
00316     }
00317 
00318     _readers--;
00319     if (!_socket) {
00320         _event_flag.set(FINISHED_FLAG);
00321     }
00322     _lock.unlock();
00323     if (error) {
00324         *error = ret;
00325     }
00326     return connection;
00327 }