ON Semiconductor / mbed-os

Dependents:   mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers TCPSocket.cpp Source File

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