Greg Steiert / maxim_dev

Dependents:   sensomed

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(0), _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 int TCPSocket::connect(const SocketAddress &address)
00038 {
00039     _lock.lock();
00040     int ret;
00041 
00042     if (!_socket) {
00043         ret = NSAPI_ERROR_NO_SOCKET ;
00044     } else {
00045         ret = _stack->socket_connect(_socket, address);
00046     }
00047 
00048     _lock.unlock();
00049     return ret;
00050 }
00051 
00052 int TCPSocket::connect(const char *host, uint16_t port)
00053 {
00054     SocketAddress address;
00055     int err = _stack->gethostbyname(host, &address);
00056     if (err) {
00057         return NSAPI_ERROR_DNS_FAILURE ;
00058     }
00059 
00060     address.set_port(port);
00061 
00062     // connect is thread safe
00063     return connect(address);
00064 }
00065 
00066 int TCPSocket::send(const void *data, unsigned size)
00067 {
00068     _lock.lock();
00069     int ret;
00070 
00071     // If this assert is hit then there are two threads
00072     // performing a send at the same time which is undefined
00073     // behavior
00074     MBED_ASSERT(!_write_in_progress);
00075     _write_in_progress = true;
00076 
00077     while (true) {
00078         if (!_socket) {
00079             ret = NSAPI_ERROR_NO_SOCKET ;
00080             break;
00081         }
00082 
00083         _pending = 0;
00084         int sent = _stack->socket_send(_socket, data, size);
00085         if ((0 == _timeout) || (NSAPI_ERROR_WOULD_BLOCK  != sent)) {
00086             ret = sent;
00087             break;
00088         } else {
00089             int32_t count;
00090 
00091             // Release lock before blocking so other threads
00092             // accessing this object aren't blocked
00093             _lock.unlock();
00094             count = _write_sem.wait(_timeout);
00095             _lock.lock();
00096 
00097             if (count < 1) {
00098                 // Semaphore wait timed out so break out and return
00099                 ret = NSAPI_ERROR_WOULD_BLOCK ;
00100                 break;
00101             }
00102         }
00103     }
00104 
00105     _write_in_progress = false;
00106     _lock.unlock();
00107     return ret;
00108 }
00109 
00110 int TCPSocket::recv(void *data, unsigned size)
00111 {
00112     _lock.lock();
00113     int ret;
00114 
00115     // If this assert is hit then there are two threads
00116     // performing a recv at the same time which is undefined
00117     // behavior
00118     MBED_ASSERT(!_read_in_progress);
00119     _read_in_progress = true;
00120 
00121     while (true) {
00122         if (!_socket) {
00123             ret = NSAPI_ERROR_NO_SOCKET ;
00124             break;
00125         }
00126 
00127         _pending = 0;
00128         int recv = _stack->socket_recv(_socket, data, size);
00129         if ((0 == _timeout) || (NSAPI_ERROR_WOULD_BLOCK  != recv)) {
00130             ret = recv;
00131             break;
00132         } else {
00133             int32_t count;
00134 
00135             // Release lock before blocking so other threads
00136             // accessing this object aren't blocked
00137             _lock.unlock();
00138             count = _read_sem.wait(_timeout);
00139             _lock.lock();
00140 
00141             if (count < 1) {
00142                 // Semaphore wait timed out so break out and return
00143                 ret = NSAPI_ERROR_WOULD_BLOCK ;
00144                 break;
00145             }
00146         }
00147     }
00148 
00149     _read_in_progress = false;
00150     _lock.unlock();
00151     return ret;
00152 }
00153 
00154 void TCPSocket::event()
00155 {
00156     int32_t wcount = _write_sem.wait(0);
00157     if (wcount <= 1) {
00158         _write_sem.release();
00159     }
00160     int32_t rcount = _read_sem.wait(0);
00161     if (rcount <= 1) {
00162         _read_sem.release();
00163     }
00164 
00165     _pending += 1;
00166     if (_callback && _pending == 1) {
00167         _callback();
00168     }
00169 }