takashi kadono / Mbed OS Nucleo_446

Dependencies:   ssd1331

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers UDPSocket.cpp Source File

UDPSocket.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 "UDPSocket.h"
00018 #include "Timer.h"
00019 #include "mbed_assert.h"
00020 
00021 UDPSocket::UDPSocket()
00022 {
00023 }
00024 
00025 UDPSocket::~UDPSocket()
00026 {
00027     close();
00028 }
00029 
00030 nsapi_protocol_t UDPSocket::get_proto()
00031 {
00032     return NSAPI_UDP ;
00033 }
00034 
00035 nsapi_error_t UDPSocket::connect(const SocketAddress &address)
00036 {
00037     _remote_peer = address;
00038     return NSAPI_ERROR_OK ;
00039 }
00040 
00041 nsapi_size_or_error_t UDPSocket::sendto(const char *host, uint16_t port, const void *data, nsapi_size_t size)
00042 {
00043     SocketAddress address;
00044     nsapi_size_or_error_t err = _stack->gethostbyname(host, &address);
00045     if (err) {
00046         return NSAPI_ERROR_DNS_FAILURE ;
00047     }
00048 
00049     address.set_port(port);
00050 
00051     // sendto is thread safe
00052     return sendto(address, data, size);
00053 }
00054 
00055 nsapi_size_or_error_t UDPSocket::sendto(const SocketAddress &address, const void *data, nsapi_size_t size)
00056 {
00057     _lock.lock();
00058     nsapi_size_or_error_t ret;
00059 
00060     _writers++;
00061 
00062     while (true) {
00063         if (!_socket) {
00064             ret = NSAPI_ERROR_NO_SOCKET ;
00065             break;
00066         }
00067 
00068         _pending = 0;
00069         nsapi_size_or_error_t sent = _stack->socket_sendto(_socket, address, data, size);
00070         if ((0 == _timeout) || (NSAPI_ERROR_WOULD_BLOCK  != sent)) {
00071             ret = sent;
00072             break;
00073         } else {
00074             uint32_t flag;
00075 
00076             // Release lock before blocking so other threads
00077             // accessing this object aren't blocked
00078             _lock.unlock();
00079             flag = _event_flag.wait_any(WRITE_FLAG, _timeout);
00080             _lock.lock();
00081 
00082             if (flag & osFlagsError) {
00083                 // Timeout break
00084                 ret = NSAPI_ERROR_WOULD_BLOCK ;
00085                 break;
00086             }
00087         }
00088     }
00089 
00090     _writers--;
00091     if (!_socket || !_writers) {
00092         _event_flag.set(FINISHED_FLAG);
00093     }
00094     _lock.unlock();
00095     return ret;
00096 }
00097 
00098 nsapi_size_or_error_t UDPSocket::send(const void *data, nsapi_size_t size)
00099 {
00100     if (!_remote_peer) {
00101         return NSAPI_ERROR_NO_ADDRESS ;
00102     }
00103     return sendto(_remote_peer, data, size);
00104 }
00105 
00106 nsapi_size_or_error_t UDPSocket::recvfrom(SocketAddress *address, void *buffer, nsapi_size_t size)
00107 {
00108     _lock.lock();
00109     nsapi_size_or_error_t ret;
00110     SocketAddress ignored;
00111 
00112     if (!address) {
00113         address = &ignored;
00114     }
00115 
00116     _readers++;
00117 
00118     while (true) {
00119         if (!_socket) {
00120             ret = NSAPI_ERROR_NO_SOCKET ;
00121             break;
00122         }
00123 
00124         _pending = 0;
00125         nsapi_size_or_error_t recv = _stack->socket_recvfrom(_socket, address, buffer, size);
00126 
00127         // Filter incomming packets using connected peer address
00128         if (recv >= 0 && _remote_peer && _remote_peer != *address) {
00129             continue;
00130         }
00131 
00132         // Non-blocking sockets always return. Blocking only returns when success or errors other than WOULD_BLOCK
00133         if ((0 == _timeout) || (NSAPI_ERROR_WOULD_BLOCK  != recv)) {
00134             ret = recv;
00135             break;
00136         } else {
00137             uint32_t flag;
00138 
00139             // Release lock before blocking so other threads
00140             // accessing this object aren't blocked
00141             _lock.unlock();
00142             flag = _event_flag.wait_any(READ_FLAG, _timeout);
00143             _lock.lock();
00144 
00145             if (flag & osFlagsError) {
00146                 // Timeout break
00147                 ret = NSAPI_ERROR_WOULD_BLOCK ;
00148                 break;
00149             }
00150         }
00151     }
00152 
00153     _readers--;
00154     if (!_socket || !_readers) {
00155         _event_flag.set(FINISHED_FLAG);
00156     }
00157 
00158     _lock.unlock();
00159     return ret;
00160 }
00161 
00162 nsapi_size_or_error_t UDPSocket::recv(void *buffer, nsapi_size_t size)
00163 {
00164     return recvfrom(NULL, buffer, size);
00165 }
00166 
00167 Socket *UDPSocket::accept(nsapi_error_t *error)
00168 {
00169     if (error) {
00170         *error = NSAPI_ERROR_UNSUPPORTED ;
00171     }
00172     return NULL;
00173 }
00174 
00175 nsapi_error_t UDPSocket::listen(int)
00176 {
00177     return NSAPI_ERROR_UNSUPPORTED ;
00178 }