2016-04-06 13:50:56 +00:00
|
|
|
/* Socket
|
|
|
|
* Copyright (c) 2015 ARM Limited
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "TCPSocket.h"
|
|
|
|
#include "Timer.h"
|
2016-07-19 16:07:39 +00:00
|
|
|
#include "mbed_assert.h"
|
2016-04-06 13:50:56 +00:00
|
|
|
|
2016-06-06 21:35:12 +00:00
|
|
|
TCPSocket::TCPSocket()
|
2016-03-13 12:08:27 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-06-06 21:35:12 +00:00
|
|
|
TCPSocket::~TCPSocket()
|
|
|
|
{
|
|
|
|
close();
|
|
|
|
}
|
|
|
|
|
2016-07-20 20:20:03 +00:00
|
|
|
nsapi_protocol_t TCPSocket::get_proto()
|
2016-03-13 12:08:27 +00:00
|
|
|
{
|
2016-07-20 20:20:03 +00:00
|
|
|
return NSAPI_TCP;
|
2016-04-06 13:50:56 +00:00
|
|
|
}
|
|
|
|
|
2016-10-18 19:48:46 +00:00
|
|
|
nsapi_error_t TCPSocket::connect(const SocketAddress &address)
|
2016-04-06 13:50:56 +00:00
|
|
|
{
|
2016-05-03 20:29:54 +00:00
|
|
|
_lock.lock();
|
2016-10-18 19:48:46 +00:00
|
|
|
nsapi_error_t ret;
|
2016-05-03 20:29:54 +00:00
|
|
|
|
2016-12-16 13:17:35 +00:00
|
|
|
// If this assert is hit then there are two threads
|
|
|
|
// performing a send at the same time which is undefined
|
|
|
|
// behavior
|
2018-06-14 13:58:15 +00:00
|
|
|
MBED_ASSERT(_writers == 0);
|
|
|
|
_writers++;
|
2016-12-16 13:17:35 +00:00
|
|
|
|
|
|
|
bool blocking_connect_in_progress = false;
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
if (!_socket) {
|
|
|
|
ret = NSAPI_ERROR_NO_SOCKET;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
_pending = 0;
|
2016-07-20 02:50:24 +00:00
|
|
|
ret = _stack->socket_connect(_socket, address);
|
2016-12-16 13:17:35 +00:00
|
|
|
if ((_timeout == 0) || !(ret == NSAPI_ERROR_IN_PROGRESS || ret == NSAPI_ERROR_ALREADY)) {
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
blocking_connect_in_progress = true;
|
|
|
|
|
2017-08-28 15:33:50 +00:00
|
|
|
uint32_t flag;
|
2016-12-16 13:17:35 +00:00
|
|
|
|
|
|
|
// Release lock before blocking so other threads
|
|
|
|
// accessing this object aren't blocked
|
|
|
|
_lock.unlock();
|
2017-08-28 15:33:50 +00:00
|
|
|
flag = _event_flag.wait_any(WRITE_FLAG, _timeout);
|
2016-12-16 13:17:35 +00:00
|
|
|
_lock.lock();
|
2017-08-28 15:33:50 +00:00
|
|
|
if (flag & osFlagsError) {
|
|
|
|
// Timeout break
|
2016-12-16 13:17:35 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-14 13:58:15 +00:00
|
|
|
_writers--;
|
|
|
|
if (!_socket) {
|
|
|
|
_event_flag.set(FINISHED_FLAG);
|
|
|
|
}
|
2016-12-16 13:17:35 +00:00
|
|
|
|
|
|
|
/* Non-blocking connect gives "EISCONN" once done - convert to OK for blocking mode if we became connected during this call */
|
|
|
|
if (ret == NSAPI_ERROR_IS_CONNECTED && blocking_connect_in_progress) {
|
|
|
|
ret = NSAPI_ERROR_OK;
|
2016-04-06 13:50:56 +00:00
|
|
|
}
|
|
|
|
|
2018-05-17 20:36:15 +00:00
|
|
|
if (ret == NSAPI_ERROR_OK || ret == NSAPI_ERROR_IN_PROGRESS) {
|
|
|
|
_remote_peer = address;
|
|
|
|
}
|
|
|
|
|
2016-05-03 20:29:54 +00:00
|
|
|
_lock.unlock();
|
|
|
|
return ret;
|
2016-04-06 13:50:56 +00:00
|
|
|
}
|
|
|
|
|
2016-10-18 19:48:46 +00:00
|
|
|
nsapi_error_t TCPSocket::connect(const char *host, uint16_t port)
|
2016-04-06 13:50:56 +00:00
|
|
|
{
|
2016-09-08 14:28:41 +00:00
|
|
|
SocketAddress address;
|
2016-10-18 19:48:46 +00:00
|
|
|
nsapi_error_t err = _stack->gethostbyname(host, &address);
|
2016-09-08 14:28:41 +00:00
|
|
|
if (err) {
|
2016-07-20 02:50:24 +00:00
|
|
|
return NSAPI_ERROR_DNS_FAILURE;
|
2016-04-06 13:50:56 +00:00
|
|
|
}
|
|
|
|
|
2016-09-08 14:28:41 +00:00
|
|
|
address.set_port(port);
|
|
|
|
|
2016-07-20 02:50:24 +00:00
|
|
|
// connect is thread safe
|
|
|
|
return connect(address);
|
2016-04-06 13:50:56 +00:00
|
|
|
}
|
|
|
|
|
2016-10-18 19:48:46 +00:00
|
|
|
nsapi_size_or_error_t TCPSocket::send(const void *data, nsapi_size_t size)
|
2016-04-06 13:50:56 +00:00
|
|
|
{
|
2016-05-03 20:29:54 +00:00
|
|
|
_lock.lock();
|
Make TCPSocket send all data when blocking
Previously, send() was somewhat soft - it only ever made one send
call to the underlying stack, so it would typically take as much data
as would fit in the buffer, and only block if it was unable to write
anything.
This is not the intent of a POSIX socket/filehandle write. It should try
to send everything if blocking, and only send less if interrupted by a
signal:
- If the O_NONBLOCK flag is clear, write() shall block the calling
thread until the data can be accepted.
- If the O_NONBLOCK flag is set, write() shall not block the thread.
If some data can be written without blocking the thread, write()
shall write what it can and return the number of bytes written.
Otherwise, it shall return -1 and set errno to [EAGAIN].
This "send all" behaviour is of slightly limited usefulness in POSIX, as
you still usually have to worry about the interruption possibility:
- If write() is interrupted by a signal before it writes any data, it
shall return -1 with errno set to [EINTR].
- If write() is interrupted by a signal after it successfully writes
some data, it shall return the number of bytes written.
But as mbed OS does not have the possibility of signal interruption, if we
strengthen send to write everything, we can make applications' lives
easier - they can just do "send(large amount)" confident that it will
all go in one call (if no errors).
So, rework to make multiple sends to the underlying stack, blocking as
necessary, until all data is written.
This change does not apply to recv(), which is correct in only blocking until
some data is available:
- If O_NONBLOCK is set, read() shall return -1 and set errno to [EAGAIN].
- If O_NONBLOCK is clear, read() shall block the calling thread until some
data becomes available.
- The use of the O_NONBLOCK flag has no effect if there is some data
available.
2017-11-09 12:30:55 +00:00
|
|
|
const uint8_t *data_ptr = static_cast<const uint8_t *>(data);
|
2016-10-18 19:48:46 +00:00
|
|
|
nsapi_size_or_error_t ret;
|
Make TCPSocket send all data when blocking
Previously, send() was somewhat soft - it only ever made one send
call to the underlying stack, so it would typically take as much data
as would fit in the buffer, and only block if it was unable to write
anything.
This is not the intent of a POSIX socket/filehandle write. It should try
to send everything if blocking, and only send less if interrupted by a
signal:
- If the O_NONBLOCK flag is clear, write() shall block the calling
thread until the data can be accepted.
- If the O_NONBLOCK flag is set, write() shall not block the thread.
If some data can be written without blocking the thread, write()
shall write what it can and return the number of bytes written.
Otherwise, it shall return -1 and set errno to [EAGAIN].
This "send all" behaviour is of slightly limited usefulness in POSIX, as
you still usually have to worry about the interruption possibility:
- If write() is interrupted by a signal before it writes any data, it
shall return -1 with errno set to [EINTR].
- If write() is interrupted by a signal after it successfully writes
some data, it shall return the number of bytes written.
But as mbed OS does not have the possibility of signal interruption, if we
strengthen send to write everything, we can make applications' lives
easier - they can just do "send(large amount)" confident that it will
all go in one call (if no errors).
So, rework to make multiple sends to the underlying stack, blocking as
necessary, until all data is written.
This change does not apply to recv(), which is correct in only blocking until
some data is available:
- If O_NONBLOCK is set, read() shall return -1 and set errno to [EAGAIN].
- If O_NONBLOCK is clear, read() shall block the calling thread until some
data becomes available.
- The use of the O_NONBLOCK flag has no effect if there is some data
available.
2017-11-09 12:30:55 +00:00
|
|
|
nsapi_size_t written = 0;
|
2016-07-20 02:50:24 +00:00
|
|
|
|
2016-07-19 16:07:39 +00:00
|
|
|
// If this assert is hit then there are two threads
|
|
|
|
// performing a send at the same time which is undefined
|
|
|
|
// behavior
|
2018-06-14 13:58:15 +00:00
|
|
|
MBED_ASSERT(_writers == 0);
|
|
|
|
_writers++;
|
2016-04-06 13:50:56 +00:00
|
|
|
|
Make TCPSocket send all data when blocking
Previously, send() was somewhat soft - it only ever made one send
call to the underlying stack, so it would typically take as much data
as would fit in the buffer, and only block if it was unable to write
anything.
This is not the intent of a POSIX socket/filehandle write. It should try
to send everything if blocking, and only send less if interrupted by a
signal:
- If the O_NONBLOCK flag is clear, write() shall block the calling
thread until the data can be accepted.
- If the O_NONBLOCK flag is set, write() shall not block the thread.
If some data can be written without blocking the thread, write()
shall write what it can and return the number of bytes written.
Otherwise, it shall return -1 and set errno to [EAGAIN].
This "send all" behaviour is of slightly limited usefulness in POSIX, as
you still usually have to worry about the interruption possibility:
- If write() is interrupted by a signal before it writes any data, it
shall return -1 with errno set to [EINTR].
- If write() is interrupted by a signal after it successfully writes
some data, it shall return the number of bytes written.
But as mbed OS does not have the possibility of signal interruption, if we
strengthen send to write everything, we can make applications' lives
easier - they can just do "send(large amount)" confident that it will
all go in one call (if no errors).
So, rework to make multiple sends to the underlying stack, blocking as
necessary, until all data is written.
This change does not apply to recv(), which is correct in only blocking until
some data is available:
- If O_NONBLOCK is set, read() shall return -1 and set errno to [EAGAIN].
- If O_NONBLOCK is clear, read() shall block the calling thread until some
data becomes available.
- The use of the O_NONBLOCK flag has no effect if there is some data
available.
2017-11-09 12:30:55 +00:00
|
|
|
// Unlike recv, we should write the whole thing if blocking. POSIX only
|
|
|
|
// allows partial as a side-effect of signal handling; it normally tries to
|
|
|
|
// write everything if blocking. Without signals we can always write all.
|
2016-04-06 13:50:56 +00:00
|
|
|
while (true) {
|
|
|
|
if (!_socket) {
|
2016-05-03 20:29:54 +00:00
|
|
|
ret = NSAPI_ERROR_NO_SOCKET;
|
|
|
|
break;
|
2016-04-06 13:50:56 +00:00
|
|
|
}
|
|
|
|
|
2016-06-06 21:35:12 +00:00
|
|
|
_pending = 0;
|
Make TCPSocket send all data when blocking
Previously, send() was somewhat soft - it only ever made one send
call to the underlying stack, so it would typically take as much data
as would fit in the buffer, and only block if it was unable to write
anything.
This is not the intent of a POSIX socket/filehandle write. It should try
to send everything if blocking, and only send less if interrupted by a
signal:
- If the O_NONBLOCK flag is clear, write() shall block the calling
thread until the data can be accepted.
- If the O_NONBLOCK flag is set, write() shall not block the thread.
If some data can be written without blocking the thread, write()
shall write what it can and return the number of bytes written.
Otherwise, it shall return -1 and set errno to [EAGAIN].
This "send all" behaviour is of slightly limited usefulness in POSIX, as
you still usually have to worry about the interruption possibility:
- If write() is interrupted by a signal before it writes any data, it
shall return -1 with errno set to [EINTR].
- If write() is interrupted by a signal after it successfully writes
some data, it shall return the number of bytes written.
But as mbed OS does not have the possibility of signal interruption, if we
strengthen send to write everything, we can make applications' lives
easier - they can just do "send(large amount)" confident that it will
all go in one call (if no errors).
So, rework to make multiple sends to the underlying stack, blocking as
necessary, until all data is written.
This change does not apply to recv(), which is correct in only blocking until
some data is available:
- If O_NONBLOCK is set, read() shall return -1 and set errno to [EAGAIN].
- If O_NONBLOCK is clear, read() shall block the calling thread until some
data becomes available.
- The use of the O_NONBLOCK flag has no effect if there is some data
available.
2017-11-09 12:30:55 +00:00
|
|
|
ret = _stack->socket_send(_socket, data_ptr + written, size - written);
|
|
|
|
if (ret >= 0) {
|
|
|
|
written += ret;
|
|
|
|
if (written >= size) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (_timeout == 0) {
|
2016-05-03 20:29:54 +00:00
|
|
|
break;
|
Make TCPSocket send all data when blocking
Previously, send() was somewhat soft - it only ever made one send
call to the underlying stack, so it would typically take as much data
as would fit in the buffer, and only block if it was unable to write
anything.
This is not the intent of a POSIX socket/filehandle write. It should try
to send everything if blocking, and only send less if interrupted by a
signal:
- If the O_NONBLOCK flag is clear, write() shall block the calling
thread until the data can be accepted.
- If the O_NONBLOCK flag is set, write() shall not block the thread.
If some data can be written without blocking the thread, write()
shall write what it can and return the number of bytes written.
Otherwise, it shall return -1 and set errno to [EAGAIN].
This "send all" behaviour is of slightly limited usefulness in POSIX, as
you still usually have to worry about the interruption possibility:
- If write() is interrupted by a signal before it writes any data, it
shall return -1 with errno set to [EINTR].
- If write() is interrupted by a signal after it successfully writes
some data, it shall return the number of bytes written.
But as mbed OS does not have the possibility of signal interruption, if we
strengthen send to write everything, we can make applications' lives
easier - they can just do "send(large amount)" confident that it will
all go in one call (if no errors).
So, rework to make multiple sends to the underlying stack, blocking as
necessary, until all data is written.
This change does not apply to recv(), which is correct in only blocking until
some data is available:
- If O_NONBLOCK is set, read() shall return -1 and set errno to [EAGAIN].
- If O_NONBLOCK is clear, read() shall block the calling thread until some
data becomes available.
- The use of the O_NONBLOCK flag has no effect if there is some data
available.
2017-11-09 12:30:55 +00:00
|
|
|
} else if (ret == NSAPI_ERROR_WOULD_BLOCK) {
|
2017-08-28 15:33:50 +00:00
|
|
|
uint32_t flag;
|
2016-05-03 20:29:54 +00:00
|
|
|
|
|
|
|
// Release lock before blocking so other threads
|
|
|
|
// accessing this object aren't blocked
|
|
|
|
_lock.unlock();
|
2017-08-28 15:33:50 +00:00
|
|
|
flag = _event_flag.wait_any(WRITE_FLAG, _timeout);
|
2016-05-03 20:29:54 +00:00
|
|
|
_lock.lock();
|
2016-04-21 00:30:16 +00:00
|
|
|
|
2017-08-28 15:33:50 +00:00
|
|
|
if (flag & osFlagsError) {
|
|
|
|
// Timeout break
|
2016-05-03 20:29:54 +00:00
|
|
|
break;
|
|
|
|
}
|
Make TCPSocket send all data when blocking
Previously, send() was somewhat soft - it only ever made one send
call to the underlying stack, so it would typically take as much data
as would fit in the buffer, and only block if it was unable to write
anything.
This is not the intent of a POSIX socket/filehandle write. It should try
to send everything if blocking, and only send less if interrupted by a
signal:
- If the O_NONBLOCK flag is clear, write() shall block the calling
thread until the data can be accepted.
- If the O_NONBLOCK flag is set, write() shall not block the thread.
If some data can be written without blocking the thread, write()
shall write what it can and return the number of bytes written.
Otherwise, it shall return -1 and set errno to [EAGAIN].
This "send all" behaviour is of slightly limited usefulness in POSIX, as
you still usually have to worry about the interruption possibility:
- If write() is interrupted by a signal before it writes any data, it
shall return -1 with errno set to [EINTR].
- If write() is interrupted by a signal after it successfully writes
some data, it shall return the number of bytes written.
But as mbed OS does not have the possibility of signal interruption, if we
strengthen send to write everything, we can make applications' lives
easier - they can just do "send(large amount)" confident that it will
all go in one call (if no errors).
So, rework to make multiple sends to the underlying stack, blocking as
necessary, until all data is written.
This change does not apply to recv(), which is correct in only blocking until
some data is available:
- If O_NONBLOCK is set, read() shall return -1 and set errno to [EAGAIN].
- If O_NONBLOCK is clear, read() shall block the calling thread until some
data becomes available.
- The use of the O_NONBLOCK flag has no effect if there is some data
available.
2017-11-09 12:30:55 +00:00
|
|
|
} else if (ret < 0) {
|
|
|
|
break;
|
2016-05-03 20:29:54 +00:00
|
|
|
}
|
2016-04-06 13:50:56 +00:00
|
|
|
}
|
2016-05-03 20:29:54 +00:00
|
|
|
|
2018-06-14 13:58:15 +00:00
|
|
|
_writers--;
|
|
|
|
if (!_socket) {
|
|
|
|
_event_flag.set(FINISHED_FLAG);
|
|
|
|
}
|
|
|
|
|
2016-05-03 20:29:54 +00:00
|
|
|
_lock.unlock();
|
Make TCPSocket send all data when blocking
Previously, send() was somewhat soft - it only ever made one send
call to the underlying stack, so it would typically take as much data
as would fit in the buffer, and only block if it was unable to write
anything.
This is not the intent of a POSIX socket/filehandle write. It should try
to send everything if blocking, and only send less if interrupted by a
signal:
- If the O_NONBLOCK flag is clear, write() shall block the calling
thread until the data can be accepted.
- If the O_NONBLOCK flag is set, write() shall not block the thread.
If some data can be written without blocking the thread, write()
shall write what it can and return the number of bytes written.
Otherwise, it shall return -1 and set errno to [EAGAIN].
This "send all" behaviour is of slightly limited usefulness in POSIX, as
you still usually have to worry about the interruption possibility:
- If write() is interrupted by a signal before it writes any data, it
shall return -1 with errno set to [EINTR].
- If write() is interrupted by a signal after it successfully writes
some data, it shall return the number of bytes written.
But as mbed OS does not have the possibility of signal interruption, if we
strengthen send to write everything, we can make applications' lives
easier - they can just do "send(large amount)" confident that it will
all go in one call (if no errors).
So, rework to make multiple sends to the underlying stack, blocking as
necessary, until all data is written.
This change does not apply to recv(), which is correct in only blocking until
some data is available:
- If O_NONBLOCK is set, read() shall return -1 and set errno to [EAGAIN].
- If O_NONBLOCK is clear, read() shall block the calling thread until some
data becomes available.
- The use of the O_NONBLOCK flag has no effect if there is some data
available.
2017-11-09 12:30:55 +00:00
|
|
|
if (ret <= 0 && ret != NSAPI_ERROR_WOULD_BLOCK) {
|
|
|
|
return ret;
|
|
|
|
} else if (written == 0) {
|
|
|
|
return NSAPI_ERROR_WOULD_BLOCK;
|
|
|
|
} else {
|
|
|
|
return written;
|
|
|
|
}
|
2016-04-06 13:50:56 +00:00
|
|
|
}
|
|
|
|
|
2018-05-17 20:36:15 +00:00
|
|
|
nsapi_size_or_error_t TCPSocket::sendto(const SocketAddress &address, const void *data, nsapi_size_t size)
|
|
|
|
{
|
|
|
|
(void)address;
|
|
|
|
return send(data, size);
|
|
|
|
}
|
|
|
|
|
2016-10-18 19:48:46 +00:00
|
|
|
nsapi_size_or_error_t TCPSocket::recv(void *data, nsapi_size_t size)
|
2016-04-06 13:50:56 +00:00
|
|
|
{
|
2016-05-03 20:29:54 +00:00
|
|
|
_lock.lock();
|
2016-10-18 19:48:46 +00:00
|
|
|
nsapi_size_or_error_t ret;
|
2016-07-20 02:50:24 +00:00
|
|
|
|
2016-07-19 16:07:39 +00:00
|
|
|
// If this assert is hit then there are two threads
|
|
|
|
// performing a recv at the same time which is undefined
|
|
|
|
// behavior
|
2018-06-14 13:58:15 +00:00
|
|
|
MBED_ASSERT(_readers == 0);
|
|
|
|
_readers++;
|
2016-04-06 13:50:56 +00:00
|
|
|
|
|
|
|
while (true) {
|
|
|
|
if (!_socket) {
|
2016-05-03 20:29:54 +00:00
|
|
|
ret = NSAPI_ERROR_NO_SOCKET;
|
|
|
|
break;
|
2016-04-06 13:50:56 +00:00
|
|
|
}
|
2016-05-03 20:29:54 +00:00
|
|
|
|
2016-06-06 21:35:12 +00:00
|
|
|
_pending = 0;
|
2016-12-16 13:17:35 +00:00
|
|
|
ret = _stack->socket_recv(_socket, data, size);
|
|
|
|
if ((_timeout == 0) || (ret != NSAPI_ERROR_WOULD_BLOCK)) {
|
2016-05-03 20:29:54 +00:00
|
|
|
break;
|
|
|
|
} else {
|
2017-08-28 15:33:50 +00:00
|
|
|
uint32_t flag;
|
2016-05-03 20:29:54 +00:00
|
|
|
|
|
|
|
// Release lock before blocking so other threads
|
|
|
|
// accessing this object aren't blocked
|
|
|
|
_lock.unlock();
|
2017-08-28 15:33:50 +00:00
|
|
|
flag = _event_flag.wait_any(READ_FLAG, _timeout);
|
2016-05-03 20:29:54 +00:00
|
|
|
_lock.lock();
|
|
|
|
|
2017-08-28 15:33:50 +00:00
|
|
|
if (flag & osFlagsError) {
|
|
|
|
// Timeout break
|
2016-05-03 20:29:54 +00:00
|
|
|
ret = NSAPI_ERROR_WOULD_BLOCK;
|
|
|
|
break;
|
|
|
|
}
|
2016-04-06 13:50:56 +00:00
|
|
|
}
|
2016-05-03 20:29:54 +00:00
|
|
|
}
|
|
|
|
|
2018-06-14 13:58:15 +00:00
|
|
|
_readers--;
|
|
|
|
if (!_socket) {
|
|
|
|
_event_flag.set(FINISHED_FLAG);
|
|
|
|
}
|
|
|
|
|
2016-05-03 20:29:54 +00:00
|
|
|
_lock.unlock();
|
|
|
|
return ret;
|
|
|
|
}
|
2016-04-21 00:30:16 +00:00
|
|
|
|
2018-05-17 20:36:15 +00:00
|
|
|
nsapi_size_or_error_t TCPSocket::recvfrom(SocketAddress *address, void *data, nsapi_size_t size)
|
|
|
|
{
|
|
|
|
if (address) {
|
|
|
|
*address = _remote_peer;
|
|
|
|
}
|
|
|
|
return recv(data, size);
|
|
|
|
}
|
|
|
|
|
2018-06-14 13:58:15 +00:00
|
|
|
nsapi_error_t TCPSocket::listen(int backlog)
|
|
|
|
{
|
|
|
|
_lock.lock();
|
|
|
|
nsapi_error_t ret;
|
|
|
|
|
|
|
|
if (!_socket) {
|
|
|
|
ret = NSAPI_ERROR_NO_SOCKET;
|
|
|
|
} else {
|
|
|
|
ret = _stack->socket_listen(_socket, backlog);
|
|
|
|
}
|
|
|
|
|
|
|
|
_lock.unlock();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
TCPSocket *TCPSocket::accept(nsapi_error_t *error)
|
2016-05-03 20:29:54 +00:00
|
|
|
{
|
2018-06-14 13:58:15 +00:00
|
|
|
_lock.lock();
|
|
|
|
TCPSocket *connection = NULL;
|
2018-06-19 14:57:56 +00:00
|
|
|
nsapi_error_t ret;
|
2018-06-14 13:58:15 +00:00
|
|
|
|
|
|
|
_readers++;
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
if (!_socket) {
|
2018-06-19 14:57:56 +00:00
|
|
|
ret = NSAPI_ERROR_NO_SOCKET;
|
2018-06-14 13:58:15 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
_pending = 0;
|
|
|
|
void *socket;
|
|
|
|
SocketAddress address;
|
2018-06-19 14:57:56 +00:00
|
|
|
ret = _stack->socket_accept(_socket, &socket, &address);
|
2018-06-14 13:58:15 +00:00
|
|
|
|
2018-06-19 14:57:56 +00:00
|
|
|
if (0 == ret) {
|
2018-09-05 09:00:59 +00:00
|
|
|
connection = new TCPSocket();
|
2018-06-14 13:58:15 +00:00
|
|
|
connection->_lock.lock();
|
|
|
|
connection->_factory_allocated = true; // Destroy automatically on close()
|
|
|
|
connection->_remote_peer = address;
|
|
|
|
connection->_stack = _stack;
|
|
|
|
connection->_socket = socket;
|
|
|
|
connection->_event = mbed::Callback<void()>(connection, &TCPSocket::event);
|
|
|
|
_stack->socket_attach(socket, &mbed::Callback<void()>::thunk, &connection->_event);
|
|
|
|
|
|
|
|
connection->_lock.unlock();
|
|
|
|
break;
|
2018-06-19 14:57:56 +00:00
|
|
|
} else if ((_timeout == 0) || (ret != NSAPI_ERROR_WOULD_BLOCK)) {
|
2018-06-14 13:58:15 +00:00
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
uint32_t flag;
|
|
|
|
|
|
|
|
// Release lock before blocking so other threads
|
|
|
|
// accessing this object aren't blocked
|
|
|
|
_lock.unlock();
|
|
|
|
flag = _event_flag.wait_any(READ_FLAG, _timeout);
|
|
|
|
_lock.lock();
|
2016-05-03 20:29:54 +00:00
|
|
|
|
2018-06-14 13:58:15 +00:00
|
|
|
if (flag & osFlagsError) {
|
|
|
|
// Timeout break
|
2018-06-19 14:57:56 +00:00
|
|
|
ret = NSAPI_ERROR_WOULD_BLOCK;
|
2018-06-14 13:58:15 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-06-06 21:35:12 +00:00
|
|
|
}
|
2018-06-14 13:58:15 +00:00
|
|
|
|
|
|
|
_readers--;
|
|
|
|
if (!_socket) {
|
|
|
|
_event_flag.set(FINISHED_FLAG);
|
|
|
|
}
|
|
|
|
_lock.unlock();
|
2018-06-19 14:57:56 +00:00
|
|
|
if (error) {
|
|
|
|
*error = ret;
|
|
|
|
}
|
2018-06-14 13:58:15 +00:00
|
|
|
return connection;
|
2016-04-06 13:50:56 +00:00
|
|
|
}
|