Networking: support nowait connection (Posix)

Thread was used for now.
It's possible to do nonblocking connect & send with io_uring on Linux, but it requires newer kernel and linking to liburing. I don't think it is worth the effort.
This commit is contained in:
李通洲
2022-11-02 17:29:43 +08:00
parent 46ebb52afa
commit 9da7bb3f30
2 changed files with 56 additions and 23 deletions
+10 -3
View File
@@ -3,6 +3,7 @@
#ifndef FF_INCLUDED_common_networking
#define FF_INCLUDED_common_networking
#include "common/thread.h"
#include "util/FFstrbuf.h"
#ifdef _WIN32
@@ -11,10 +12,16 @@
typedef struct FFNetworkingState {
#ifdef _WIN32
uintptr_t sockfd;
OVERLAPPED overlapped;
uintptr_t sockfd;
OVERLAPPED overlapped;
#else
int sockfd;
int sockfd;
FFstrbuf host;
FFstrbuf command;
#ifdef FF_HAVE_THREADS
FFThreadType thread;
#endif
#endif
} FFNetworkingState;
+46 -20
View File
@@ -6,7 +6,7 @@
#include <sys/socket.h>
#include <netdb.h>
bool ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, const char* path, const char* headers)
static void connectAndSend(FFNetworkingState* state)
{
struct addrinfo hints = {
.ai_family = AF_INET,
@@ -15,47 +15,73 @@ bool ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, con
struct addrinfo* addr;
if(getaddrinfo(host, "80", &hints, &addr) != 0)
return false;
if(getaddrinfo(state->host.chars, "80", &hints, &addr) != 0)
goto error;
state->sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if(state->sockfd == -1)
{
freeaddrinfo(addr);
return false;
goto error;
}
if(connect(state->sockfd, addr->ai_addr, addr->ai_addrlen) == -1)
{
close(state->sockfd);
freeaddrinfo(addr);
return false;
goto error;
}
freeaddrinfo(addr);
FFstrbuf command;
ffStrbufInitA(&command, 64);
ffStrbufAppendS(&command, "GET ");
ffStrbufAppendS(&command, path);
ffStrbufAppendS(&command, " HTTP/1.1\nHost: ");
ffStrbufAppendS(&command, host);
ffStrbufAppendS(&command, "\r\n");
ffStrbufAppendS(&command, headers);
ffStrbufAppendS(&command, "\r\n");
if(send(state->sockfd, command.chars, command.length, 0) < 0)
if(send(state->sockfd, state->command.chars, state->command.length, 0) < 0)
{
ffStrbufDestroy(&command);
close(state->sockfd);
return false;
goto error;
}
ffStrbufDestroy(&command);
return true;
goto exit;
error:
state->sockfd = -1;
exit:
ffStrbufDestroy(&state->host);
ffStrbufDestroy(&state->command);
}
FF_THREAD_ENTRY_DECL_WRAPPER(connectAndSend, FFNetworkingState*);
bool ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, const char* path, const char* headers)
{
ffStrbufInitS(&state->host, host);
ffStrbufInitA(&state->command, 64);
ffStrbufAppendS(&state->command, "GET ");
ffStrbufAppendS(&state->command, path);
ffStrbufAppendS(&state->command, " HTTP/1.1\nHost: ");
ffStrbufAppendS(&state->command, host);
ffStrbufAppendS(&state->command, "\r\n");
ffStrbufAppendS(&state->command, headers);
ffStrbufAppendS(&state->command, "\r\n");
#ifdef FF_HAVE_THREADS
state->thread = ffThreadCreate(connectAndSendThreadMain, state);
return state->thread != NULL;
#else
connectAndSend(state);
return state->sockfd != -1;
#endif
}
bool ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer, uint32_t timeout)
{
#ifdef FF_HAVE_THREADS
ffThreadJoin(state->thread);
#endif
if(state->sockfd == -1)
return false;
if(timeout > 0)
{
struct timeval timev;