Rizky Ardi Maulana / mbed-os
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     : _pending(0), _read_sem(0), _write_sem(0),
00023       _read_in_progress(false), _write_in_progress(false)
00024 {
00025 }
00026 
00027 UDPSocket::~UDPSocket()
00028 {
00029     close();
00030 }
00031 
00032 nsapi_protocol_t UDPSocket::get_proto()
00033 {
00034     return NSAPI_UDP ;
00035 }
00036 
00037 int UDPSocket::sendto(const char *host, uint16_t port, const void *data, unsigned size)
00038 {
00039     SocketAddress address;
00040     int err = _stack->gethostbyname(host, &address);
00041     if (err) {
00042         return NSAPI_ERROR_DNS_FAILURE ;
00043     }
00044 
00045     address.set_port(port);
00046 
00047     // sendto is thread safe
00048     return sendto(address, data, size);
00049 }
00050 
00051 int UDPSocket::sendto(const SocketAddress &address, const void *data, unsigned size)
00052 {
00053     _lock.lock();
00054     int ret;
00055 
00056     // If this assert is hit then there are two threads
00057     // performing a send at the same time which is undefined
00058     // behavior
00059     MBED_ASSERT(!_write_in_progress);
00060     _write_in_progress = true;
00061 
00062     while (true) {
00063         if (!_socket) {
00064             ret = NSAPI_ERROR_NO_SOCKET ;
00065             break;
00066         }
00067 
00068         _pending = 0;
00069         int 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             int32_t count;
00075 
00076             // Release lock before blocking so other threads
00077             // accessing this object aren't blocked
00078             _lock.unlock();
00079             count = _write_sem.wait(_timeout);
00080             _lock.lock();
00081 
00082             if (count < 1) {
00083                 // Semaphore wait timed out so break out and return
00084                 ret = NSAPI_ERROR_WOULD_BLOCK ;
00085                 break;
00086             }
00087         }
00088     }
00089 
00090     _write_in_progress = false;
00091     _lock.unlock();
00092     return ret;
00093 }
00094 
00095 int UDPSocket::recvfrom(SocketAddress *address, void *buffer, unsigned size)
00096 {
00097     _lock.lock();
00098     int ret;
00099 
00100     // If this assert is hit then there are two threads
00101     // performing a recv at the same time which is undefined
00102     // behavior
00103     MBED_ASSERT(!_read_in_progress);
00104     _read_in_progress = true;
00105 
00106     while (true) {
00107         if (!_socket) {
00108             ret = NSAPI_ERROR_NO_SOCKET ;
00109             break;
00110         }
00111 
00112         _pending = 0;
00113         int recv = _stack->socket_recvfrom(_socket, address, buffer, size);
00114         if ((0 == _timeout) || (NSAPI_ERROR_WOULD_BLOCK  != recv)) {
00115             ret = recv;
00116             break;
00117         } else {
00118             int32_t count;
00119 
00120             // Release lock before blocking so other threads
00121             // accessing this object aren't blocked
00122             _lock.unlock();
00123             count = _read_sem.wait(_timeout);
00124             _lock.lock();
00125 
00126             if (count < 1) {
00127                 // Semaphore wait timed out so break out and return
00128                 ret = NSAPI_ERROR_WOULD_BLOCK ;
00129                 break;
00130             }
00131         }
00132     }
00133 
00134     _read_in_progress = false;
00135     _lock.unlock();
00136     return ret;
00137 }
00138 
00139 void UDPSocket::event()
00140 {
00141     int32_t wcount = _write_sem.wait(0);
00142     if (wcount <= 1) {
00143         _write_sem.release();
00144     }
00145     int32_t rcount = _read_sem.wait(0);
00146     if (rcount <= 1) {
00147         _read_sem.release();
00148     }
00149 
00150     _pending += 1;
00151     if (_callback && _pending == 1) {
00152         _callback();
00153     }
00154 }