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