Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: nRF51_Vdd TextLCD BME280
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 }
Generated on Tue Jul 12 2022 15:16:01 by
