RTC auf true

Committer:
kevman
Date:
Wed Nov 28 15:10:15 2018 +0000
Revision:
0:38ceb79fef03
RTC modified

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kevman 0:38ceb79fef03 1 /* Socket
kevman 0:38ceb79fef03 2 * Copyright (c) 2015 ARM Limited
kevman 0:38ceb79fef03 3 *
kevman 0:38ceb79fef03 4 * Licensed under the Apache License, Version 2.0 (the "License");
kevman 0:38ceb79fef03 5 * you may not use this file except in compliance with the License.
kevman 0:38ceb79fef03 6 * You may obtain a copy of the License at
kevman 0:38ceb79fef03 7 *
kevman 0:38ceb79fef03 8 * http://www.apache.org/licenses/LICENSE-2.0
kevman 0:38ceb79fef03 9 *
kevman 0:38ceb79fef03 10 * Unless required by applicable law or agreed to in writing, software
kevman 0:38ceb79fef03 11 * distributed under the License is distributed on an "AS IS" BASIS,
kevman 0:38ceb79fef03 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
kevman 0:38ceb79fef03 13 * See the License for the specific language governing permissions and
kevman 0:38ceb79fef03 14 * limitations under the License.
kevman 0:38ceb79fef03 15 */
kevman 0:38ceb79fef03 16
kevman 0:38ceb79fef03 17 #include "TCPSocket.h"
kevman 0:38ceb79fef03 18 #include "Timer.h"
kevman 0:38ceb79fef03 19 #include "mbed_assert.h"
kevman 0:38ceb79fef03 20
kevman 0:38ceb79fef03 21 TCPSocket::TCPSocket()
kevman 0:38ceb79fef03 22 {
kevman 0:38ceb79fef03 23 }
kevman 0:38ceb79fef03 24
kevman 0:38ceb79fef03 25 TCPSocket::TCPSocket(TCPSocket* parent, nsapi_socket_t socket, SocketAddress address)
kevman 0:38ceb79fef03 26 {
kevman 0:38ceb79fef03 27 _socket = socket,
kevman 0:38ceb79fef03 28 _stack = parent->_stack;
kevman 0:38ceb79fef03 29 _factory_allocated = true;
kevman 0:38ceb79fef03 30 _remote_peer = address;
kevman 0:38ceb79fef03 31
kevman 0:38ceb79fef03 32 _event = mbed::Callback<void()>(this, &TCPSocket::event);
kevman 0:38ceb79fef03 33 _stack->socket_attach(socket, &mbed::Callback<void()>::thunk, &_event);
kevman 0:38ceb79fef03 34 }
kevman 0:38ceb79fef03 35
kevman 0:38ceb79fef03 36 TCPSocket::~TCPSocket()
kevman 0:38ceb79fef03 37 {
kevman 0:38ceb79fef03 38 }
kevman 0:38ceb79fef03 39
kevman 0:38ceb79fef03 40 nsapi_protocol_t TCPSocket::get_proto()
kevman 0:38ceb79fef03 41 {
kevman 0:38ceb79fef03 42 return NSAPI_TCP;
kevman 0:38ceb79fef03 43 }
kevman 0:38ceb79fef03 44
kevman 0:38ceb79fef03 45 nsapi_error_t TCPSocket::connect(const SocketAddress &address)
kevman 0:38ceb79fef03 46 {
kevman 0:38ceb79fef03 47 _lock.lock();
kevman 0:38ceb79fef03 48 nsapi_error_t ret;
kevman 0:38ceb79fef03 49
kevman 0:38ceb79fef03 50 // If this assert is hit then there are two threads
kevman 0:38ceb79fef03 51 // performing a send at the same time which is undefined
kevman 0:38ceb79fef03 52 // behavior
kevman 0:38ceb79fef03 53 MBED_ASSERT(_writers == 0);
kevman 0:38ceb79fef03 54 _writers++;
kevman 0:38ceb79fef03 55
kevman 0:38ceb79fef03 56 bool blocking_connect_in_progress = false;
kevman 0:38ceb79fef03 57
kevman 0:38ceb79fef03 58 while (true) {
kevman 0:38ceb79fef03 59 if (!_socket) {
kevman 0:38ceb79fef03 60 ret = NSAPI_ERROR_NO_SOCKET;
kevman 0:38ceb79fef03 61 break;
kevman 0:38ceb79fef03 62 }
kevman 0:38ceb79fef03 63
kevman 0:38ceb79fef03 64 _pending = 0;
kevman 0:38ceb79fef03 65 ret = _stack->socket_connect(_socket, address);
kevman 0:38ceb79fef03 66 if ((_timeout == 0) || !(ret == NSAPI_ERROR_IN_PROGRESS || ret == NSAPI_ERROR_ALREADY)) {
kevman 0:38ceb79fef03 67 break;
kevman 0:38ceb79fef03 68 } else {
kevman 0:38ceb79fef03 69 blocking_connect_in_progress = true;
kevman 0:38ceb79fef03 70
kevman 0:38ceb79fef03 71 uint32_t flag;
kevman 0:38ceb79fef03 72
kevman 0:38ceb79fef03 73 // Release lock before blocking so other threads
kevman 0:38ceb79fef03 74 // accessing this object aren't blocked
kevman 0:38ceb79fef03 75 _lock.unlock();
kevman 0:38ceb79fef03 76 flag = _event_flag.wait_any(WRITE_FLAG, _timeout);
kevman 0:38ceb79fef03 77 _lock.lock();
kevman 0:38ceb79fef03 78 if (flag & osFlagsError) {
kevman 0:38ceb79fef03 79 // Timeout break
kevman 0:38ceb79fef03 80 break;
kevman 0:38ceb79fef03 81 }
kevman 0:38ceb79fef03 82 }
kevman 0:38ceb79fef03 83 }
kevman 0:38ceb79fef03 84
kevman 0:38ceb79fef03 85 _writers--;
kevman 0:38ceb79fef03 86 if (!_socket) {
kevman 0:38ceb79fef03 87 _event_flag.set(FINISHED_FLAG);
kevman 0:38ceb79fef03 88 }
kevman 0:38ceb79fef03 89
kevman 0:38ceb79fef03 90 /* Non-blocking connect gives "EISCONN" once done - convert to OK for blocking mode if we became connected during this call */
kevman 0:38ceb79fef03 91 if (ret == NSAPI_ERROR_IS_CONNECTED && blocking_connect_in_progress) {
kevman 0:38ceb79fef03 92 ret = NSAPI_ERROR_OK;
kevman 0:38ceb79fef03 93 }
kevman 0:38ceb79fef03 94
kevman 0:38ceb79fef03 95 if (ret == NSAPI_ERROR_OK || ret == NSAPI_ERROR_IN_PROGRESS) {
kevman 0:38ceb79fef03 96 _remote_peer = address;
kevman 0:38ceb79fef03 97 }
kevman 0:38ceb79fef03 98
kevman 0:38ceb79fef03 99 _lock.unlock();
kevman 0:38ceb79fef03 100 return ret;
kevman 0:38ceb79fef03 101 }
kevman 0:38ceb79fef03 102
kevman 0:38ceb79fef03 103 nsapi_error_t TCPSocket::connect(const char *host, uint16_t port)
kevman 0:38ceb79fef03 104 {
kevman 0:38ceb79fef03 105 SocketAddress address;
kevman 0:38ceb79fef03 106 nsapi_error_t err = _stack->gethostbyname(host, &address);
kevman 0:38ceb79fef03 107 if (err) {
kevman 0:38ceb79fef03 108 return NSAPI_ERROR_DNS_FAILURE;
kevman 0:38ceb79fef03 109 }
kevman 0:38ceb79fef03 110
kevman 0:38ceb79fef03 111 address.set_port(port);
kevman 0:38ceb79fef03 112
kevman 0:38ceb79fef03 113 // connect is thread safe
kevman 0:38ceb79fef03 114 return connect(address);
kevman 0:38ceb79fef03 115 }
kevman 0:38ceb79fef03 116
kevman 0:38ceb79fef03 117 nsapi_size_or_error_t TCPSocket::send(const void *data, nsapi_size_t size)
kevman 0:38ceb79fef03 118 {
kevman 0:38ceb79fef03 119 _lock.lock();
kevman 0:38ceb79fef03 120 const uint8_t *data_ptr = static_cast<const uint8_t *>(data);
kevman 0:38ceb79fef03 121 nsapi_size_or_error_t ret;
kevman 0:38ceb79fef03 122 nsapi_size_t written = 0;
kevman 0:38ceb79fef03 123
kevman 0:38ceb79fef03 124 // If this assert is hit then there are two threads
kevman 0:38ceb79fef03 125 // performing a send at the same time which is undefined
kevman 0:38ceb79fef03 126 // behavior
kevman 0:38ceb79fef03 127 MBED_ASSERT(_writers == 0);
kevman 0:38ceb79fef03 128 _writers++;
kevman 0:38ceb79fef03 129
kevman 0:38ceb79fef03 130 // Unlike recv, we should write the whole thing if blocking. POSIX only
kevman 0:38ceb79fef03 131 // allows partial as a side-effect of signal handling; it normally tries to
kevman 0:38ceb79fef03 132 // write everything if blocking. Without signals we can always write all.
kevman 0:38ceb79fef03 133 while (true) {
kevman 0:38ceb79fef03 134 if (!_socket) {
kevman 0:38ceb79fef03 135 ret = NSAPI_ERROR_NO_SOCKET;
kevman 0:38ceb79fef03 136 break;
kevman 0:38ceb79fef03 137 }
kevman 0:38ceb79fef03 138
kevman 0:38ceb79fef03 139 _pending = 0;
kevman 0:38ceb79fef03 140 ret = _stack->socket_send(_socket, data_ptr + written, size - written);
kevman 0:38ceb79fef03 141 if (ret >= 0) {
kevman 0:38ceb79fef03 142 written += ret;
kevman 0:38ceb79fef03 143 if (written >= size) {
kevman 0:38ceb79fef03 144 break;
kevman 0:38ceb79fef03 145 }
kevman 0:38ceb79fef03 146 }
kevman 0:38ceb79fef03 147 if (_timeout == 0) {
kevman 0:38ceb79fef03 148 break;
kevman 0:38ceb79fef03 149 } else if (ret == NSAPI_ERROR_WOULD_BLOCK) {
kevman 0:38ceb79fef03 150 uint32_t flag;
kevman 0:38ceb79fef03 151
kevman 0:38ceb79fef03 152 // Release lock before blocking so other threads
kevman 0:38ceb79fef03 153 // accessing this object aren't blocked
kevman 0:38ceb79fef03 154 _lock.unlock();
kevman 0:38ceb79fef03 155 flag = _event_flag.wait_any(WRITE_FLAG, _timeout);
kevman 0:38ceb79fef03 156 _lock.lock();
kevman 0:38ceb79fef03 157
kevman 0:38ceb79fef03 158 if (flag & osFlagsError) {
kevman 0:38ceb79fef03 159 // Timeout break
kevman 0:38ceb79fef03 160 break;
kevman 0:38ceb79fef03 161 }
kevman 0:38ceb79fef03 162 } else if (ret < 0) {
kevman 0:38ceb79fef03 163 break;
kevman 0:38ceb79fef03 164 }
kevman 0:38ceb79fef03 165 }
kevman 0:38ceb79fef03 166
kevman 0:38ceb79fef03 167 _writers--;
kevman 0:38ceb79fef03 168 if (!_socket) {
kevman 0:38ceb79fef03 169 _event_flag.set(FINISHED_FLAG);
kevman 0:38ceb79fef03 170 }
kevman 0:38ceb79fef03 171
kevman 0:38ceb79fef03 172 _lock.unlock();
kevman 0:38ceb79fef03 173 if (ret <= 0 && ret != NSAPI_ERROR_WOULD_BLOCK) {
kevman 0:38ceb79fef03 174 return ret;
kevman 0:38ceb79fef03 175 } else if (written == 0) {
kevman 0:38ceb79fef03 176 return NSAPI_ERROR_WOULD_BLOCK;
kevman 0:38ceb79fef03 177 } else {
kevman 0:38ceb79fef03 178 return written;
kevman 0:38ceb79fef03 179 }
kevman 0:38ceb79fef03 180 }
kevman 0:38ceb79fef03 181
kevman 0:38ceb79fef03 182 nsapi_size_or_error_t TCPSocket::sendto(const SocketAddress &address, const void *data, nsapi_size_t size)
kevman 0:38ceb79fef03 183 {
kevman 0:38ceb79fef03 184 (void)address;
kevman 0:38ceb79fef03 185 return send(data, size);
kevman 0:38ceb79fef03 186 }
kevman 0:38ceb79fef03 187
kevman 0:38ceb79fef03 188 nsapi_size_or_error_t TCPSocket::recv(void *data, nsapi_size_t size)
kevman 0:38ceb79fef03 189 {
kevman 0:38ceb79fef03 190 _lock.lock();
kevman 0:38ceb79fef03 191 nsapi_size_or_error_t ret;
kevman 0:38ceb79fef03 192
kevman 0:38ceb79fef03 193 // If this assert is hit then there are two threads
kevman 0:38ceb79fef03 194 // performing a recv at the same time which is undefined
kevman 0:38ceb79fef03 195 // behavior
kevman 0:38ceb79fef03 196 MBED_ASSERT(_readers == 0);
kevman 0:38ceb79fef03 197 _readers++;
kevman 0:38ceb79fef03 198
kevman 0:38ceb79fef03 199 while (true) {
kevman 0:38ceb79fef03 200 if (!_socket) {
kevman 0:38ceb79fef03 201 ret = NSAPI_ERROR_NO_SOCKET;
kevman 0:38ceb79fef03 202 break;
kevman 0:38ceb79fef03 203 }
kevman 0:38ceb79fef03 204
kevman 0:38ceb79fef03 205 _pending = 0;
kevman 0:38ceb79fef03 206 ret = _stack->socket_recv(_socket, data, size);
kevman 0:38ceb79fef03 207 if ((_timeout == 0) || (ret != NSAPI_ERROR_WOULD_BLOCK)) {
kevman 0:38ceb79fef03 208 break;
kevman 0:38ceb79fef03 209 } else {
kevman 0:38ceb79fef03 210 uint32_t flag;
kevman 0:38ceb79fef03 211
kevman 0:38ceb79fef03 212 // Release lock before blocking so other threads
kevman 0:38ceb79fef03 213 // accessing this object aren't blocked
kevman 0:38ceb79fef03 214 _lock.unlock();
kevman 0:38ceb79fef03 215 flag = _event_flag.wait_any(READ_FLAG, _timeout);
kevman 0:38ceb79fef03 216 _lock.lock();
kevman 0:38ceb79fef03 217
kevman 0:38ceb79fef03 218 if (flag & osFlagsError) {
kevman 0:38ceb79fef03 219 // Timeout break
kevman 0:38ceb79fef03 220 ret = NSAPI_ERROR_WOULD_BLOCK;
kevman 0:38ceb79fef03 221 break;
kevman 0:38ceb79fef03 222 }
kevman 0:38ceb79fef03 223 }
kevman 0:38ceb79fef03 224 }
kevman 0:38ceb79fef03 225
kevman 0:38ceb79fef03 226 _readers--;
kevman 0:38ceb79fef03 227 if (!_socket) {
kevman 0:38ceb79fef03 228 _event_flag.set(FINISHED_FLAG);
kevman 0:38ceb79fef03 229 }
kevman 0:38ceb79fef03 230
kevman 0:38ceb79fef03 231 _lock.unlock();
kevman 0:38ceb79fef03 232 return ret;
kevman 0:38ceb79fef03 233 }
kevman 0:38ceb79fef03 234
kevman 0:38ceb79fef03 235 nsapi_size_or_error_t TCPSocket::recvfrom(SocketAddress *address, void *data, nsapi_size_t size)
kevman 0:38ceb79fef03 236 {
kevman 0:38ceb79fef03 237 if (address) {
kevman 0:38ceb79fef03 238 *address = _remote_peer;
kevman 0:38ceb79fef03 239 }
kevman 0:38ceb79fef03 240 return recv(data, size);
kevman 0:38ceb79fef03 241 }
kevman 0:38ceb79fef03 242
kevman 0:38ceb79fef03 243 nsapi_error_t TCPSocket::listen(int backlog)
kevman 0:38ceb79fef03 244 {
kevman 0:38ceb79fef03 245 _lock.lock();
kevman 0:38ceb79fef03 246 nsapi_error_t ret;
kevman 0:38ceb79fef03 247
kevman 0:38ceb79fef03 248 if (!_socket) {
kevman 0:38ceb79fef03 249 ret = NSAPI_ERROR_NO_SOCKET;
kevman 0:38ceb79fef03 250 } else {
kevman 0:38ceb79fef03 251 ret = _stack->socket_listen(_socket, backlog);
kevman 0:38ceb79fef03 252 }
kevman 0:38ceb79fef03 253
kevman 0:38ceb79fef03 254 _lock.unlock();
kevman 0:38ceb79fef03 255 return ret;
kevman 0:38ceb79fef03 256 }
kevman 0:38ceb79fef03 257
kevman 0:38ceb79fef03 258 TCPSocket *TCPSocket::accept(nsapi_error_t *error)
kevman 0:38ceb79fef03 259 {
kevman 0:38ceb79fef03 260 _lock.lock();
kevman 0:38ceb79fef03 261 TCPSocket *connection = NULL;
kevman 0:38ceb79fef03 262 nsapi_error_t ret;
kevman 0:38ceb79fef03 263
kevman 0:38ceb79fef03 264 _readers++;
kevman 0:38ceb79fef03 265
kevman 0:38ceb79fef03 266 while (true) {
kevman 0:38ceb79fef03 267 if (!_socket) {
kevman 0:38ceb79fef03 268 ret = NSAPI_ERROR_NO_SOCKET;
kevman 0:38ceb79fef03 269 break;
kevman 0:38ceb79fef03 270 }
kevman 0:38ceb79fef03 271
kevman 0:38ceb79fef03 272 _pending = 0;
kevman 0:38ceb79fef03 273 void *socket;
kevman 0:38ceb79fef03 274 SocketAddress address;
kevman 0:38ceb79fef03 275 ret = _stack->socket_accept(_socket, &socket, &address);
kevman 0:38ceb79fef03 276
kevman 0:38ceb79fef03 277 if (0 == ret) {
kevman 0:38ceb79fef03 278 connection = new TCPSocket(this, socket, address);
kevman 0:38ceb79fef03 279 break;
kevman 0:38ceb79fef03 280 } else if ((_timeout == 0) || (ret != NSAPI_ERROR_WOULD_BLOCK)) {
kevman 0:38ceb79fef03 281 break;
kevman 0:38ceb79fef03 282 } else {
kevman 0:38ceb79fef03 283 uint32_t flag;
kevman 0:38ceb79fef03 284
kevman 0:38ceb79fef03 285 // Release lock before blocking so other threads
kevman 0:38ceb79fef03 286 // accessing this object aren't blocked
kevman 0:38ceb79fef03 287 _lock.unlock();
kevman 0:38ceb79fef03 288 flag = _event_flag.wait_any(READ_FLAG, _timeout);
kevman 0:38ceb79fef03 289 _lock.lock();
kevman 0:38ceb79fef03 290
kevman 0:38ceb79fef03 291 if (flag & osFlagsError) {
kevman 0:38ceb79fef03 292 // Timeout break
kevman 0:38ceb79fef03 293 ret = NSAPI_ERROR_WOULD_BLOCK;
kevman 0:38ceb79fef03 294 break;
kevman 0:38ceb79fef03 295 }
kevman 0:38ceb79fef03 296 }
kevman 0:38ceb79fef03 297 }
kevman 0:38ceb79fef03 298
kevman 0:38ceb79fef03 299 _readers--;
kevman 0:38ceb79fef03 300 if (!_socket) {
kevman 0:38ceb79fef03 301 _event_flag.set(FINISHED_FLAG);
kevman 0:38ceb79fef03 302 }
kevman 0:38ceb79fef03 303 _lock.unlock();
kevman 0:38ceb79fef03 304 if (error) {
kevman 0:38ceb79fef03 305 *error = ret;
kevman 0:38ceb79fef03 306 }
kevman 0:38ceb79fef03 307 return connection;
kevman 0:38ceb79fef03 308 }