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.
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 20:52:59 by
1.7.2