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 nsapi_size_or_error_t ret; 00109 00110 // If this assert is hit then there are two threads 00111 // performing a send at the same time which is undefined 00112 // behavior 00113 MBED_ASSERT(!_write_in_progress); 00114 _write_in_progress = true; 00115 00116 while (true) { 00117 if (!_socket) { 00118 ret = NSAPI_ERROR_NO_SOCKET ; 00119 break; 00120 } 00121 00122 _pending = 0; 00123 ret = _stack->socket_send(_socket, data, size); 00124 if ((_timeout == 0) || (ret != NSAPI_ERROR_WOULD_BLOCK )) { 00125 break; 00126 } else { 00127 uint32_t flag; 00128 00129 // Release lock before blocking so other threads 00130 // accessing this object aren't blocked 00131 _lock.unlock(); 00132 flag = _event_flag.wait_any(WRITE_FLAG, _timeout); 00133 _lock.lock(); 00134 00135 if (flag & osFlagsError) { 00136 // Timeout break 00137 ret = NSAPI_ERROR_WOULD_BLOCK ; 00138 break; 00139 } 00140 } 00141 } 00142 00143 _write_in_progress = false; 00144 _lock.unlock(); 00145 return ret; 00146 } 00147 00148 nsapi_size_or_error_t TCPSocket::recv(void *data, nsapi_size_t size) 00149 { 00150 _lock.lock(); 00151 nsapi_size_or_error_t ret; 00152 00153 // If this assert is hit then there are two threads 00154 // performing a recv at the same time which is undefined 00155 // behavior 00156 MBED_ASSERT(!_read_in_progress); 00157 _read_in_progress = true; 00158 00159 while (true) { 00160 if (!_socket) { 00161 ret = NSAPI_ERROR_NO_SOCKET ; 00162 break; 00163 } 00164 00165 _pending = 0; 00166 ret = _stack->socket_recv(_socket, data, size); 00167 if ((_timeout == 0) || (ret != NSAPI_ERROR_WOULD_BLOCK )) { 00168 break; 00169 } else { 00170 uint32_t flag; 00171 00172 // Release lock before blocking so other threads 00173 // accessing this object aren't blocked 00174 _lock.unlock(); 00175 flag = _event_flag.wait_any(READ_FLAG, _timeout); 00176 _lock.lock(); 00177 00178 if (flag & osFlagsError) { 00179 // Timeout break 00180 ret = NSAPI_ERROR_WOULD_BLOCK ; 00181 break; 00182 } 00183 } 00184 } 00185 00186 _read_in_progress = false; 00187 _lock.unlock(); 00188 return ret; 00189 } 00190 00191 void TCPSocket::event() 00192 { 00193 _event_flag.set(READ_FLAG|WRITE_FLAG); 00194 00195 _pending += 1; 00196 if (_callback && _pending == 1) { 00197 _callback(); 00198 } 00199 }
Generated on Thu Jul 14 2022 14:36:23 by
