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 #define READ_FLAG 0x1u 00022 #define WRITE_FLAG 0x2u 00023 00024 TCPSocket::TCPSocket() 00025 : _pending(0), _event_flag(), 00026 _read_in_progress(false), _write_in_progress(false) 00027 { 00028 } 00029 00030 TCPSocket::~TCPSocket() 00031 { 00032 close(); 00033 } 00034 00035 nsapi_protocol_t TCPSocket::get_proto() 00036 { 00037 return NSAPI_TCP ; 00038 } 00039 00040 nsapi_error_t TCPSocket::connect(const SocketAddress &address) 00041 { 00042 _lock.lock(); 00043 nsapi_error_t ret; 00044 00045 // If this assert is hit then there are two threads 00046 // performing a send at the same time which is undefined 00047 // behavior 00048 MBED_ASSERT(!_write_in_progress); 00049 _write_in_progress = true; 00050 00051 bool blocking_connect_in_progress = false; 00052 00053 while (true) { 00054 if (!_socket) { 00055 ret = NSAPI_ERROR_NO_SOCKET ; 00056 break; 00057 } 00058 00059 _pending = 0; 00060 ret = _stack->socket_connect(_socket, address); 00061 if ((_timeout == 0) || !(ret == NSAPI_ERROR_IN_PROGRESS || ret == NSAPI_ERROR_ALREADY )) { 00062 break; 00063 } else { 00064 blocking_connect_in_progress = true; 00065 00066 uint32_t flag; 00067 00068 // Release lock before blocking so other threads 00069 // accessing this object aren't blocked 00070 _lock.unlock(); 00071 flag = _event_flag.wait_any(WRITE_FLAG, _timeout); 00072 _lock.lock(); 00073 if (flag & osFlagsError) { 00074 // Timeout break 00075 break; 00076 } 00077 } 00078 } 00079 00080 _write_in_progress = false; 00081 00082 /* Non-blocking connect gives "EISCONN" once done - convert to OK for blocking mode if we became connected during this call */ 00083 if (ret == NSAPI_ERROR_IS_CONNECTED && blocking_connect_in_progress) { 00084 ret = NSAPI_ERROR_OK ; 00085 } 00086 00087 _lock.unlock(); 00088 return ret; 00089 } 00090 00091 nsapi_error_t TCPSocket::connect(const char *host, uint16_t port) 00092 { 00093 SocketAddress address; 00094 nsapi_error_t err = _stack->gethostbyname(host, &address); 00095 if (err) { 00096 return NSAPI_ERROR_DNS_FAILURE ; 00097 } 00098 00099 address.set_port(port); 00100 00101 // connect is thread safe 00102 return connect(address); 00103 } 00104 00105 nsapi_size_or_error_t TCPSocket::send(const void *data, nsapi_size_t size) 00106 { 00107 _lock.lock(); 00108 const uint8_t *data_ptr = static_cast<const uint8_t *>(data); 00109 nsapi_size_or_error_t ret; 00110 nsapi_size_t written = 0; 00111 00112 // If this assert is hit then there are two threads 00113 // performing a send at the same time which is undefined 00114 // behavior 00115 MBED_ASSERT(!_write_in_progress); 00116 _write_in_progress = true; 00117 00118 // Unlike recv, we should write the whole thing if blocking. POSIX only 00119 // allows partial as a side-effect of signal handling; it normally tries to 00120 // write everything if blocking. Without signals we can always write all. 00121 while (true) { 00122 if (!_socket) { 00123 ret = NSAPI_ERROR_NO_SOCKET ; 00124 break; 00125 } 00126 00127 _pending = 0; 00128 ret = _stack->socket_send(_socket, data_ptr + written, size - written); 00129 if (ret >= 0) { 00130 written += ret; 00131 if (written >= size) { 00132 break; 00133 } 00134 } 00135 if (_timeout == 0) { 00136 break; 00137 } else if (ret == NSAPI_ERROR_WOULD_BLOCK ) { 00138 uint32_t flag; 00139 00140 // Release lock before blocking so other threads 00141 // accessing this object aren't blocked 00142 _lock.unlock(); 00143 flag = _event_flag.wait_any(WRITE_FLAG, _timeout); 00144 _lock.lock(); 00145 00146 if (flag & osFlagsError) { 00147 // Timeout break 00148 break; 00149 } 00150 } else if (ret < 0) { 00151 break; 00152 } 00153 } 00154 00155 _write_in_progress = false; 00156 _lock.unlock(); 00157 if (ret <= 0 && ret != NSAPI_ERROR_WOULD_BLOCK ) { 00158 return ret; 00159 } else if (written == 0) { 00160 return NSAPI_ERROR_WOULD_BLOCK ; 00161 } else { 00162 return written; 00163 } 00164 } 00165 00166 nsapi_size_or_error_t TCPSocket::recv(void *data, nsapi_size_t size) 00167 { 00168 _lock.lock(); 00169 nsapi_size_or_error_t ret; 00170 00171 // If this assert is hit then there are two threads 00172 // performing a recv at the same time which is undefined 00173 // behavior 00174 MBED_ASSERT(!_read_in_progress); 00175 _read_in_progress = true; 00176 00177 while (true) { 00178 if (!_socket) { 00179 ret = NSAPI_ERROR_NO_SOCKET ; 00180 break; 00181 } 00182 00183 _pending = 0; 00184 ret = _stack->socket_recv(_socket, data, size); 00185 if ((_timeout == 0) || (ret != NSAPI_ERROR_WOULD_BLOCK )) { 00186 break; 00187 } else { 00188 uint32_t flag; 00189 00190 // Release lock before blocking so other threads 00191 // accessing this object aren't blocked 00192 _lock.unlock(); 00193 flag = _event_flag.wait_any(READ_FLAG, _timeout); 00194 _lock.lock(); 00195 00196 if (flag & osFlagsError) { 00197 // Timeout break 00198 ret = NSAPI_ERROR_WOULD_BLOCK ; 00199 break; 00200 } 00201 } 00202 } 00203 00204 _read_in_progress = false; 00205 _lock.unlock(); 00206 return ret; 00207 } 00208 00209 void TCPSocket::event() 00210 { 00211 _event_flag.set(READ_FLAG|WRITE_FLAG); 00212 00213 _pending += 1; 00214 if (_callback && _pending == 1) { 00215 _callback(); 00216 } 00217 }
Generated on Tue Jul 12 2022 18:18:51 by
