STM32F7 Ethernet interface for nucleo STM32F767

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