mbed-os for GR-LYCHEE

Dependents:   mbed-os-example-blinky-gr-lychee GR-Boads_Camera_sample GR-Boards_Audio_Recoder GR-Boads_Camera_DisplayApp ... more

Committer:
dkato
Date:
Fri Feb 02 05:42:23 2018 +0000
Revision:
0:f782d9c66c49
mbed-os for GR-LYCHEE

Who changed what in which revision?

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