in linux/src/socket_transport_linux.c [443:554]
SOCKET_RECEIVE_RESULT socket_transport_receive(SOCKET_TRANSPORT_HANDLE socket_transport, SOCKET_BUFFER* payload, uint32_t buffer_count, uint32_t* bytes_recv, uint32_t flags, void* data)
{
SOCKET_RECEIVE_RESULT result;
// Codes_SOCKET_TRANSPORT_LINUX_11_038: [ If socket_transport is NULL, socket_transport_receive shall fail and return SOCKET_RECEIVE_INVALID_ARG. ]
if (socket_transport == NULL ||
// Codes_SOCKET_TRANSPORT_LINUX_11_039: [ If payload is NULL, socket_transport_receive shall fail and return SOCKET_RECEIVE_INVALID_ARG. ]
payload == NULL ||
// Codes_SOCKET_TRANSPORT_LINUX_11_040: [ If buffer_count is 0, socket_transport_receive shall fail and return SOCKET_RECEIVE_INVALID_ARG. ]
buffer_count == 0)
{
LogError("Invalid arguments: SOCKET_TRANSPORT_HANDLE socket_transport=%p, const SOCKET_BUFFER* payload=%p, uint32_t buffer_count: %" PRIu32 ", uint32_t flags=%" PRIu32 ", void*, data=%p",
socket_transport, payload, buffer_count, flags, data);
result = SOCKET_RECEIVE_INVALID_ARG;
}
else
{
// Codes_SOCKET_TRANSPORT_LINUX_11_041: [ socket_transport_receive shall call sm_exec_begin. ]
SM_RESULT sm_result = sm_exec_begin(socket_transport->sm);
if (sm_result != SM_EXEC_GRANTED)
{
// Codes_SOCKET_TRANSPORT_LINUX_11_042: [ If sm_exec_begin does not return SM_EXEC_GRANTED, socket_transport_receive shall fail and return SOCKET_RECEIVE_ERROR. ]
LogError("sm_exec_begin failed : %" PRI_MU_ENUM, MU_ENUM_VALUE(SM_RESULT, sm_result));
result = SOCKET_RECEIVE_ERROR;
}
else
{
uint32_t total_recv_size = 0;
for (uint32_t index = 0; index < buffer_count; index++)
{
// Codes_SOCKET_TRANSPORT_LINUX_11_043: [ For each buffer count in payload socket_transport_receive shall call recv with the flags parameter. ]
ssize_t recv_size = recv(socket_transport->socket, payload[index].buffer, payload[index].length, flags);
if (recv_size < 0)
{
// Codes_SOCKET_TRANSPORT_LINUX_11_044: [ If recv a value less then 0, socket_transport_receive shall do the following: ]
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
// Codes_SOCKET_TRANSPORT_LINUX_11_045: [ If errno is EAGAIN or EWOULDBLOCK, socket_transport_receive shall break out of loop and return SOCKET_RECEIVE_WOULD_BLOCK. ]
result = SOCKET_RECEIVE_WOULD_BLOCK;
break;
}
else
{
total_recv_size = 0;
recv_size = 0;
if (errno == ECONNRESET)
{
// Codes_SOCKET_TRANSPORT_LINUX_11_046: [ If errno is ECONNRESET, socket_transport_receive shall break out of the loop and return SOCKET_RECEIVE_SHUTDOWN. ]
result = SOCKET_RECEIVE_SHUTDOWN;
LogError("A reset on the recv socket has been encountered");
}
else
{
// Codes_SOCKET_TRANSPORT_LINUX_11_047: [ else socket_transport_receive shall break out of the looop and return SOCKET_RECEIVE_ERROR. ]
result = SOCKET_RECEIVE_ERROR;
LogErrorNo("failure recv data");
}
break;
}
}
else if (recv_size == 0)
{
// Codes_SOCKET_TRANSPORT_LINUX_11_048: [ If recv returns a 0 value, socket_transport_receive shall break and return SOCKET_RECEIVE_SHUTDOWN. ]
LogError("Socket received 0 bytes, assuming socket is closed");
result = SOCKET_RECEIVE_SHUTDOWN;
break;
}
else
{
// Codes_SOCKET_TRANSPORT_LINUX_11_049: [ Else socket_transport_receive shall do the following: ]
// Codes_SOCKET_TRANSPORT_LINUX_11_050: [ socket_transport_receive shall test that the total recv size will not overflow. ]
if (recv_size > UINT32_MAX ||
UINT32_MAX - total_recv_size < recv_size)
{
// Handle unlikely overflow
LogError("Overflow in computing receive size (total_recv_size=%" PRIu32 " + recv_size=%zi > UINT32_MAX=%" PRIu32 ")",
total_recv_size, recv_size, UINT32_MAX);
result = SOCKET_RECEIVE_ERROR;
break;
}
else
{
// Codes_SOCKET_TRANSPORT_LINUX_11_051: [ socket_transport_receive shall store the received byte size. ]
total_recv_size += recv_size;
if (recv_size <= payload[index].length)
{
#ifdef ENABLE_SOCKET_LOGGING
LogVerbose("Asynchronous receive of %" PRIu32 " bytes completed at %lf", bytes_received, timer_global_get_elapsed_us());
#endif
result = SOCKET_RECEIVE_OK;
}
else
{
// keep receiving data
}
}
}
}
if (result == SOCKET_RECEIVE_OK)
{
// Success
if (bytes_recv != NULL)
{
*bytes_recv = total_recv_size;
}
}
// Codes_SOCKET_TRANSPORT_LINUX_11_053: [ socket_transport_receive shall call sm_exec_end. ]
sm_exec_end(socket_transport->sm);
}
}
return result;
}