BBR 1 Ebene

Committer:
borlanic
Date:
Mon May 14 11:29:06 2018 +0000
Revision:
0:fbdae7e6d805
BBR

Who changed what in which revision?

UserRevisionLine numberNew contents of line
borlanic 0:fbdae7e6d805 1 /* Socket
borlanic 0:fbdae7e6d805 2 * Copyright (c) 2015 ARM Limited
borlanic 0:fbdae7e6d805 3 *
borlanic 0:fbdae7e6d805 4 * Licensed under the Apache License, Version 2.0 (the "License");
borlanic 0:fbdae7e6d805 5 * you may not use this file except in compliance with the License.
borlanic 0:fbdae7e6d805 6 * You may obtain a copy of the License at
borlanic 0:fbdae7e6d805 7 *
borlanic 0:fbdae7e6d805 8 * http://www.apache.org/licenses/LICENSE-2.0
borlanic 0:fbdae7e6d805 9 *
borlanic 0:fbdae7e6d805 10 * Unless required by applicable law or agreed to in writing, software
borlanic 0:fbdae7e6d805 11 * distributed under the License is distributed on an "AS IS" BASIS,
borlanic 0:fbdae7e6d805 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
borlanic 0:fbdae7e6d805 13 * See the License for the specific language governing permissions and
borlanic 0:fbdae7e6d805 14 * limitations under the License.
borlanic 0:fbdae7e6d805 15 */
borlanic 0:fbdae7e6d805 16
borlanic 0:fbdae7e6d805 17 #include "TCPSocket.h"
borlanic 0:fbdae7e6d805 18 #include "Timer.h"
borlanic 0:fbdae7e6d805 19 #include "mbed_assert.h"
borlanic 0:fbdae7e6d805 20
borlanic 0:fbdae7e6d805 21 #define READ_FLAG 0x1u
borlanic 0:fbdae7e6d805 22 #define WRITE_FLAG 0x2u
borlanic 0:fbdae7e6d805 23
borlanic 0:fbdae7e6d805 24 TCPSocket::TCPSocket()
borlanic 0:fbdae7e6d805 25 : _pending(0), _event_flag(),
borlanic 0:fbdae7e6d805 26 _read_in_progress(false), _write_in_progress(false)
borlanic 0:fbdae7e6d805 27 {
borlanic 0:fbdae7e6d805 28 }
borlanic 0:fbdae7e6d805 29
borlanic 0:fbdae7e6d805 30 TCPSocket::~TCPSocket()
borlanic 0:fbdae7e6d805 31 {
borlanic 0:fbdae7e6d805 32 close();
borlanic 0:fbdae7e6d805 33 }
borlanic 0:fbdae7e6d805 34
borlanic 0:fbdae7e6d805 35 nsapi_protocol_t TCPSocket::get_proto()
borlanic 0:fbdae7e6d805 36 {
borlanic 0:fbdae7e6d805 37 return NSAPI_TCP;
borlanic 0:fbdae7e6d805 38 }
borlanic 0:fbdae7e6d805 39
borlanic 0:fbdae7e6d805 40 nsapi_error_t TCPSocket::connect(const SocketAddress &address)
borlanic 0:fbdae7e6d805 41 {
borlanic 0:fbdae7e6d805 42 _lock.lock();
borlanic 0:fbdae7e6d805 43 nsapi_error_t ret;
borlanic 0:fbdae7e6d805 44
borlanic 0:fbdae7e6d805 45 // If this assert is hit then there are two threads
borlanic 0:fbdae7e6d805 46 // performing a send at the same time which is undefined
borlanic 0:fbdae7e6d805 47 // behavior
borlanic 0:fbdae7e6d805 48 MBED_ASSERT(!_write_in_progress);
borlanic 0:fbdae7e6d805 49 _write_in_progress = true;
borlanic 0:fbdae7e6d805 50
borlanic 0:fbdae7e6d805 51 bool blocking_connect_in_progress = false;
borlanic 0:fbdae7e6d805 52
borlanic 0:fbdae7e6d805 53 while (true) {
borlanic 0:fbdae7e6d805 54 if (!_socket) {
borlanic 0:fbdae7e6d805 55 ret = NSAPI_ERROR_NO_SOCKET;
borlanic 0:fbdae7e6d805 56 break;
borlanic 0:fbdae7e6d805 57 }
borlanic 0:fbdae7e6d805 58
borlanic 0:fbdae7e6d805 59 _pending = 0;
borlanic 0:fbdae7e6d805 60 ret = _stack->socket_connect(_socket, address);
borlanic 0:fbdae7e6d805 61 if ((_timeout == 0) || !(ret == NSAPI_ERROR_IN_PROGRESS || ret == NSAPI_ERROR_ALREADY)) {
borlanic 0:fbdae7e6d805 62 break;
borlanic 0:fbdae7e6d805 63 } else {
borlanic 0:fbdae7e6d805 64 blocking_connect_in_progress = true;
borlanic 0:fbdae7e6d805 65
borlanic 0:fbdae7e6d805 66 uint32_t flag;
borlanic 0:fbdae7e6d805 67
borlanic 0:fbdae7e6d805 68 // Release lock before blocking so other threads
borlanic 0:fbdae7e6d805 69 // accessing this object aren't blocked
borlanic 0:fbdae7e6d805 70 _lock.unlock();
borlanic 0:fbdae7e6d805 71 flag = _event_flag.wait_any(WRITE_FLAG, _timeout);
borlanic 0:fbdae7e6d805 72 _lock.lock();
borlanic 0:fbdae7e6d805 73 if (flag & osFlagsError) {
borlanic 0:fbdae7e6d805 74 // Timeout break
borlanic 0:fbdae7e6d805 75 break;
borlanic 0:fbdae7e6d805 76 }
borlanic 0:fbdae7e6d805 77 }
borlanic 0:fbdae7e6d805 78 }
borlanic 0:fbdae7e6d805 79
borlanic 0:fbdae7e6d805 80 _write_in_progress = false;
borlanic 0:fbdae7e6d805 81
borlanic 0:fbdae7e6d805 82 /* Non-blocking connect gives "EISCONN" once done - convert to OK for blocking mode if we became connected during this call */
borlanic 0:fbdae7e6d805 83 if (ret == NSAPI_ERROR_IS_CONNECTED && blocking_connect_in_progress) {
borlanic 0:fbdae7e6d805 84 ret = NSAPI_ERROR_OK;
borlanic 0:fbdae7e6d805 85 }
borlanic 0:fbdae7e6d805 86
borlanic 0:fbdae7e6d805 87 _lock.unlock();
borlanic 0:fbdae7e6d805 88 return ret;
borlanic 0:fbdae7e6d805 89 }
borlanic 0:fbdae7e6d805 90
borlanic 0:fbdae7e6d805 91 nsapi_error_t TCPSocket::connect(const char *host, uint16_t port)
borlanic 0:fbdae7e6d805 92 {
borlanic 0:fbdae7e6d805 93 SocketAddress address;
borlanic 0:fbdae7e6d805 94 nsapi_error_t err = _stack->gethostbyname(host, &address);
borlanic 0:fbdae7e6d805 95 if (err) {
borlanic 0:fbdae7e6d805 96 return NSAPI_ERROR_DNS_FAILURE;
borlanic 0:fbdae7e6d805 97 }
borlanic 0:fbdae7e6d805 98
borlanic 0:fbdae7e6d805 99 address.set_port(port);
borlanic 0:fbdae7e6d805 100
borlanic 0:fbdae7e6d805 101 // connect is thread safe
borlanic 0:fbdae7e6d805 102 return connect(address);
borlanic 0:fbdae7e6d805 103 }
borlanic 0:fbdae7e6d805 104
borlanic 0:fbdae7e6d805 105 nsapi_size_or_error_t TCPSocket::send(const void *data, nsapi_size_t size)
borlanic 0:fbdae7e6d805 106 {
borlanic 0:fbdae7e6d805 107 _lock.lock();
borlanic 0:fbdae7e6d805 108 const uint8_t *data_ptr = static_cast<const uint8_t *>(data);
borlanic 0:fbdae7e6d805 109 nsapi_size_or_error_t ret;
borlanic 0:fbdae7e6d805 110 nsapi_size_t written = 0;
borlanic 0:fbdae7e6d805 111
borlanic 0:fbdae7e6d805 112 // If this assert is hit then there are two threads
borlanic 0:fbdae7e6d805 113 // performing a send at the same time which is undefined
borlanic 0:fbdae7e6d805 114 // behavior
borlanic 0:fbdae7e6d805 115 MBED_ASSERT(!_write_in_progress);
borlanic 0:fbdae7e6d805 116 _write_in_progress = true;
borlanic 0:fbdae7e6d805 117
borlanic 0:fbdae7e6d805 118 // Unlike recv, we should write the whole thing if blocking. POSIX only
borlanic 0:fbdae7e6d805 119 // allows partial as a side-effect of signal handling; it normally tries to
borlanic 0:fbdae7e6d805 120 // write everything if blocking. Without signals we can always write all.
borlanic 0:fbdae7e6d805 121 while (true) {
borlanic 0:fbdae7e6d805 122 if (!_socket) {
borlanic 0:fbdae7e6d805 123 ret = NSAPI_ERROR_NO_SOCKET;
borlanic 0:fbdae7e6d805 124 break;
borlanic 0:fbdae7e6d805 125 }
borlanic 0:fbdae7e6d805 126
borlanic 0:fbdae7e6d805 127 _pending = 0;
borlanic 0:fbdae7e6d805 128 ret = _stack->socket_send(_socket, data_ptr + written, size - written);
borlanic 0:fbdae7e6d805 129 if (ret >= 0) {
borlanic 0:fbdae7e6d805 130 written += ret;
borlanic 0:fbdae7e6d805 131 if (written >= size) {
borlanic 0:fbdae7e6d805 132 break;
borlanic 0:fbdae7e6d805 133 }
borlanic 0:fbdae7e6d805 134 }
borlanic 0:fbdae7e6d805 135 if (_timeout == 0) {
borlanic 0:fbdae7e6d805 136 break;
borlanic 0:fbdae7e6d805 137 } else if (ret == NSAPI_ERROR_WOULD_BLOCK) {
borlanic 0:fbdae7e6d805 138 uint32_t flag;
borlanic 0:fbdae7e6d805 139
borlanic 0:fbdae7e6d805 140 // Release lock before blocking so other threads
borlanic 0:fbdae7e6d805 141 // accessing this object aren't blocked
borlanic 0:fbdae7e6d805 142 _lock.unlock();
borlanic 0:fbdae7e6d805 143 flag = _event_flag.wait_any(WRITE_FLAG, _timeout);
borlanic 0:fbdae7e6d805 144 _lock.lock();
borlanic 0:fbdae7e6d805 145
borlanic 0:fbdae7e6d805 146 if (flag & osFlagsError) {
borlanic 0:fbdae7e6d805 147 // Timeout break
borlanic 0:fbdae7e6d805 148 break;
borlanic 0:fbdae7e6d805 149 }
borlanic 0:fbdae7e6d805 150 } else if (ret < 0) {
borlanic 0:fbdae7e6d805 151 break;
borlanic 0:fbdae7e6d805 152 }
borlanic 0:fbdae7e6d805 153 }
borlanic 0:fbdae7e6d805 154
borlanic 0:fbdae7e6d805 155 _write_in_progress = false;
borlanic 0:fbdae7e6d805 156 _lock.unlock();
borlanic 0:fbdae7e6d805 157 if (ret <= 0 && ret != NSAPI_ERROR_WOULD_BLOCK) {
borlanic 0:fbdae7e6d805 158 return ret;
borlanic 0:fbdae7e6d805 159 } else if (written == 0) {
borlanic 0:fbdae7e6d805 160 return NSAPI_ERROR_WOULD_BLOCK;
borlanic 0:fbdae7e6d805 161 } else {
borlanic 0:fbdae7e6d805 162 return written;
borlanic 0:fbdae7e6d805 163 }
borlanic 0:fbdae7e6d805 164 }
borlanic 0:fbdae7e6d805 165
borlanic 0:fbdae7e6d805 166 nsapi_size_or_error_t TCPSocket::recv(void *data, nsapi_size_t size)
borlanic 0:fbdae7e6d805 167 {
borlanic 0:fbdae7e6d805 168 _lock.lock();
borlanic 0:fbdae7e6d805 169 nsapi_size_or_error_t ret;
borlanic 0:fbdae7e6d805 170
borlanic 0:fbdae7e6d805 171 // If this assert is hit then there are two threads
borlanic 0:fbdae7e6d805 172 // performing a recv at the same time which is undefined
borlanic 0:fbdae7e6d805 173 // behavior
borlanic 0:fbdae7e6d805 174 MBED_ASSERT(!_read_in_progress);
borlanic 0:fbdae7e6d805 175 _read_in_progress = true;
borlanic 0:fbdae7e6d805 176
borlanic 0:fbdae7e6d805 177 while (true) {
borlanic 0:fbdae7e6d805 178 if (!_socket) {
borlanic 0:fbdae7e6d805 179 ret = NSAPI_ERROR_NO_SOCKET;
borlanic 0:fbdae7e6d805 180 break;
borlanic 0:fbdae7e6d805 181 }
borlanic 0:fbdae7e6d805 182
borlanic 0:fbdae7e6d805 183 _pending = 0;
borlanic 0:fbdae7e6d805 184 ret = _stack->socket_recv(_socket, data, size);
borlanic 0:fbdae7e6d805 185 if ((_timeout == 0) || (ret != NSAPI_ERROR_WOULD_BLOCK)) {
borlanic 0:fbdae7e6d805 186 break;
borlanic 0:fbdae7e6d805 187 } else {
borlanic 0:fbdae7e6d805 188 uint32_t flag;
borlanic 0:fbdae7e6d805 189
borlanic 0:fbdae7e6d805 190 // Release lock before blocking so other threads
borlanic 0:fbdae7e6d805 191 // accessing this object aren't blocked
borlanic 0:fbdae7e6d805 192 _lock.unlock();
borlanic 0:fbdae7e6d805 193 flag = _event_flag.wait_any(READ_FLAG, _timeout);
borlanic 0:fbdae7e6d805 194 _lock.lock();
borlanic 0:fbdae7e6d805 195
borlanic 0:fbdae7e6d805 196 if (flag & osFlagsError) {
borlanic 0:fbdae7e6d805 197 // Timeout break
borlanic 0:fbdae7e6d805 198 ret = NSAPI_ERROR_WOULD_BLOCK;
borlanic 0:fbdae7e6d805 199 break;
borlanic 0:fbdae7e6d805 200 }
borlanic 0:fbdae7e6d805 201 }
borlanic 0:fbdae7e6d805 202 }
borlanic 0:fbdae7e6d805 203
borlanic 0:fbdae7e6d805 204 _read_in_progress = false;
borlanic 0:fbdae7e6d805 205 _lock.unlock();
borlanic 0:fbdae7e6d805 206 return ret;
borlanic 0:fbdae7e6d805 207 }
borlanic 0:fbdae7e6d805 208
borlanic 0:fbdae7e6d805 209 void TCPSocket::event()
borlanic 0:fbdae7e6d805 210 {
borlanic 0:fbdae7e6d805 211 _event_flag.set(READ_FLAG|WRITE_FLAG);
borlanic 0:fbdae7e6d805 212
borlanic 0:fbdae7e6d805 213 _pending += 1;
borlanic 0:fbdae7e6d805 214 if (_callback && _pending == 1) {
borlanic 0:fbdae7e6d805 215 _callback();
borlanic 0:fbdae7e6d805 216 }
borlanic 0:fbdae7e6d805 217 }