From 7fdbd94e39ff6a97d00f1aa4a40c02c0b7b2ef4c Mon Sep 17 00:00:00 2001 From: David Steele Date: Mon, 10 Aug 2020 16:03:38 -0400 Subject: [PATCH] Implement IoClient/IoSession interfaces for SocketClient/SocketSession. Following up on 111d33c, implement the new interfaces for socket client/session. Now HTTP objects can be used over TLS or plain sockets. This required adding ioSessionFd() and ioSessionRole() to provide the functionality of sckSessionFd() and sckSessionType(). sckClientHost() and sckClientPort don't make sense in a generic interface so they were replaced with ioSessionName(). --- doc/xml/release.xml | 1 + src/command/command.c | 1 + src/common/io/client.c | 15 +++ src/common/io/client.h | 9 ++ src/common/io/client.intern.h | 3 + src/common/io/session.c | 31 ++++- src/common/io/session.h | 15 +++ src/common/io/session.intern.h | 6 + src/common/io/socket/client.c | 140 ++++++++++++++-------- src/common/io/socket/client.h | 48 ++------ src/common/io/socket/session.c | 163 +++++++++++++++++++++----- src/common/io/socket/session.h | 63 +--------- src/common/io/tls/client.c | 52 +++++--- src/common/io/tls/client.h | 4 +- src/common/io/tls/session.c | 57 +++++---- src/common/io/tls/session.h | 3 +- src/storage/azure/storage.c | 3 +- src/storage/s3/storage.c | 8 +- test/src/common/harnessTls.c | 2 +- test/src/module/command/commandTest.c | 2 +- test/src/module/common/ioHttpTest.c | 9 +- test/src/module/common/ioTlsTest.c | 59 ++++++---- test/src/module/storage/s3Test.c | 8 +- 23 files changed, 443 insertions(+), 259 deletions(-) diff --git a/doc/xml/release.xml b/doc/xml/release.xml index ad91f46da..3a9d05fa3 100644 --- a/doc/xml/release.xml +++ b/doc/xml/release.xml @@ -88,6 +88,7 @@ + diff --git a/src/command/command.c b/src/command/command.c index b6e8d3770..4e9b0e164 100644 --- a/src/command/command.c +++ b/src/command/command.c @@ -8,6 +8,7 @@ Common Command Routines #include "common/debug.h" #include "common/io/http/client.h" +#include "common/io/socket/client.h" #include "common/io/tls/client.h" #include "common/log.h" #include "common/memContext.h" diff --git a/src/common/io/client.c b/src/common/io/client.c index 4367c697a..b6516b89d 100644 --- a/src/common/io/client.c +++ b/src/common/io/client.c @@ -19,6 +19,7 @@ struct IoClient const IoClientInterface *interface; // Driver interface }; +OBJECT_DEFINE_MOVE(IO_CLIENT); OBJECT_DEFINE_FREE(IO_CLIENT); /**********************************************************************************************************************************/ @@ -33,6 +34,7 @@ ioClientNew(void *driver, const IoClientInterface *interface) ASSERT(driver != NULL); ASSERT(interface != NULL); ASSERT(interface->type != NULL); + ASSERT(interface->name != NULL); ASSERT(interface->open != NULL); ASSERT(interface->toLog != NULL); @@ -61,6 +63,19 @@ ioClientOpen(IoClient *this) FUNCTION_LOG_RETURN(IO_SESSION, this->interface->open(this->driver)); } +/**********************************************************************************************************************************/ +const String * +ioClientName(IoClient *this) +{ + FUNCTION_LOG_BEGIN(logLevelTrace); + FUNCTION_LOG_PARAM(IO_CLIENT, this); + FUNCTION_LOG_END(); + + ASSERT(this != NULL); + + FUNCTION_LOG_RETURN_CONST(STRING, this->interface->name(this->driver)); +} + /**********************************************************************************************************************************/ String * ioClientToLog(const IoClient *this) diff --git a/src/common/io/client.h b/src/common/io/client.h index 70c622ce1..290d39d6e 100644 --- a/src/common/io/client.h +++ b/src/common/io/client.h @@ -20,9 +20,18 @@ typedef struct IoClient IoClient; /*********************************************************************************************************************************** Functions ***********************************************************************************************************************************/ +// Move to a new parent mem context +IoClient *ioClientMove(IoClient *this, MemContext *parentNew); + // Open session IoSession *ioClientOpen(IoClient *this); +/*********************************************************************************************************************************** +Getters/Setters +***********************************************************************************************************************************/ +// Name that identifies the client +const String *ioClientName(IoClient *this); + /*********************************************************************************************************************************** Destructor ***********************************************************************************************************************************/ diff --git a/src/common/io/client.intern.h b/src/common/io/client.intern.h index 63f1e5ea0..5517b5ab0 100644 --- a/src/common/io/client.intern.h +++ b/src/common/io/client.intern.h @@ -15,6 +15,9 @@ typedef struct IoClientInterface // constant (e.g. created with STRING_EXTERN()) without needing to be copied. const String *const *type; + // Client name, usually host:port or some other unique indentifier + const String *(*name)(void *driver); + // Open a session IoSession *(*open)(void *driver); diff --git a/src/common/io/session.c b/src/common/io/session.c index 3cd20fe80..1a69dd1ca 100644 --- a/src/common/io/session.c +++ b/src/common/io/session.c @@ -37,6 +37,7 @@ ioSessionNew(void *driver, const IoSessionInterface *interface) ASSERT(interface->close != NULL); ASSERT(interface->ioRead != NULL); ASSERT(interface->ioWrite != NULL); + ASSERT(interface->role != NULL); ASSERT(interface->toLog != NULL); IoSession *this = memNew(sizeof(IoSession)); @@ -66,6 +67,19 @@ ioSessionClose(IoSession *this) FUNCTION_LOG_RETURN_VOID(); } +/**********************************************************************************************************************************/ +int +ioSessionFd(IoSession *this) +{ + FUNCTION_TEST_BEGIN(); + FUNCTION_TEST_PARAM(IO_SESSION, this); + FUNCTION_TEST_END(); + + ASSERT(this != NULL); + + FUNCTION_TEST_RETURN(this->interface->fd == NULL ? -1 : this->interface->fd(this->driver)); +} + /**********************************************************************************************************************************/ IoRead * ioSessionIoRead(IoSession *this) @@ -92,9 +106,24 @@ ioSessionIoWrite(IoSession *this) FUNCTION_TEST_RETURN(this->interface->ioWrite(this->driver)); } +/**********************************************************************************************************************************/ +IoSessionRole +ioSessionRole(const IoSession *this) +{ + FUNCTION_TEST_BEGIN(); + FUNCTION_TEST_PARAM(IO_SESSION, this); + FUNCTION_TEST_END(); + + ASSERT(this != NULL); + + FUNCTION_TEST_RETURN(this->interface->role(this->driver)); +} + /**********************************************************************************************************************************/ String * ioSessionToLog(const IoSession *this) { - return strNewFmt("{type: %s, driver: %s}", strZ(*this->interface->type), strZ(this->interface->toLog(this->driver))); + return strNewFmt( + "{type: %s, role: %s, driver: %s}", strZ(*this->interface->type), + ioSessionRole(this) == ioSessionRoleClient ? "client" : "server", strZ(this->interface->toLog(this->driver))); } diff --git a/src/common/io/session.h b/src/common/io/session.h index a3ecc4489..7030ccb4a 100644 --- a/src/common/io/session.h +++ b/src/common/io/session.h @@ -18,6 +18,15 @@ typedef struct IoSession IoSession; #include "common/io/read.h" #include "common/io/write.h" +/*********************************************************************************************************************************** +Session roles +***********************************************************************************************************************************/ +typedef enum +{ + ioSessionRoleClient, // Client session + ioSessionRoleServer, // Server session +} IoSessionRole; + /*********************************************************************************************************************************** Functions ***********************************************************************************************************************************/ @@ -30,12 +39,18 @@ IoSession *ioSessionMove(IoSession *this, MemContext *parentNew); /*********************************************************************************************************************************** Getters/Setters ***********************************************************************************************************************************/ +// Session file descriptor, -1 if none +int ioSessionFd(IoSession *this); + // Read interface IoRead *ioSessionIoRead(IoSession *this); // Write interface IoWrite *ioSessionIoWrite(IoSession *this); +// Session role +IoSessionRole ioSessionRole(const IoSession *this); + /*********************************************************************************************************************************** Destructor ***********************************************************************************************************************************/ diff --git a/src/common/io/session.intern.h b/src/common/io/session.intern.h index bc7b1d255..0ff3c0163 100644 --- a/src/common/io/session.intern.h +++ b/src/common/io/session.intern.h @@ -18,12 +18,18 @@ typedef struct IoSessionInterface // Close the session void (*close)(void *driver); + // Session file descriptor, if any + int (*fd)(void *driver); + // IoRead interface for the session IoRead *(*ioRead)(void *driver); // IoWrite interface for the session IoWrite *(*ioWrite)(void *driver); + // Session role + IoSessionRole (*role)(const void *driver); + // Driver log function String *(*toLog)(const void *driver); } IoSessionInterface; diff --git a/src/common/io/socket/client.c b/src/common/io/socket/client.c index d055f5634..7db0650e2 100644 --- a/src/common/io/socket/client.c +++ b/src/common/io/socket/client.c @@ -10,6 +10,7 @@ Socket Client #include "common/debug.h" #include "common/log.h" +#include "common/io/client.intern.h" #include "common/io/socket/client.h" #include "common/io/socket/common.h" #include "common/io/socket/session.h" @@ -17,6 +18,11 @@ Socket Client #include "common/type/object.h" #include "common/wait.h" +/*********************************************************************************************************************************** +Io client type +***********************************************************************************************************************************/ +STRING_EXTERN(IO_CLIENT_SOCKET_TYPE_STR, IO_CLIENT_SOCKET_TYPE); + /*********************************************************************************************************************************** Statistics ***********************************************************************************************************************************/ @@ -25,63 +31,47 @@ static SocketClientStat sckClientStatLocal; /*********************************************************************************************************************************** Object type ***********************************************************************************************************************************/ -struct SocketClient +#define SOCKET_CLIENT_TYPE SocketClient +#define SOCKET_CLIENT_PREFIX sckClient + +typedef struct SocketClient { MemContext *memContext; // Mem context String *host; // Hostname or IP address unsigned int port; // Port to connect to host on + String *name; // Socket name (host:port) TimeMSec timeout; // Timeout for any i/o operation (connect, read, etc.) -}; +} SocketClient; -OBJECT_DEFINE_MOVE(SOCKET_CLIENT); - -OBJECT_DEFINE_GET(Host, const, SOCKET_CLIENT, const String *, host); -OBJECT_DEFINE_GET(Port, const, SOCKET_CLIENT, unsigned int, port); - -/**********************************************************************************************************************************/ -SocketClient * -sckClientNew(const String *host, unsigned int port, TimeMSec timeout) +/*********************************************************************************************************************************** +Macros for function logging +***********************************************************************************************************************************/ +static String * +sckClientToLog(const THIS_VOID) { - FUNCTION_LOG_BEGIN(logLevelDebug) - FUNCTION_LOG_PARAM(STRING, host); - FUNCTION_LOG_PARAM(UINT, port); - FUNCTION_LOG_PARAM(TIME_MSEC, timeout); - FUNCTION_LOG_END(); + THIS(const SocketClient); - ASSERT(host != NULL); - - SocketClient *this = NULL; - - MEM_CONTEXT_NEW_BEGIN("SocketClient") - { - this = memNew(sizeof(SocketClient)); - - *this = (SocketClient) - { - .memContext = MEM_CONTEXT_NEW(), - .host = strDup(host), - .port = port, - .timeout = timeout, - }; - - sckClientStatLocal.object++; - } - MEM_CONTEXT_NEW_END(); - - FUNCTION_LOG_RETURN(SOCKET_CLIENT, this); + return strNewFmt("{host: %s, port: %u, timeout: %" PRIu64 "}", strZ(this->host), this->port, this->timeout); } +#define FUNCTION_LOG_SOCKET_CLIENT_TYPE \ + SocketClient * +#define FUNCTION_LOG_SOCKET_CLIENT_FORMAT(value, buffer, bufferSize) \ + FUNCTION_LOG_STRING_OBJECT_FORMAT(value, sckClientToLog, buffer, bufferSize) + /**********************************************************************************************************************************/ -SocketSession * -sckClientOpen(SocketClient *this) +static IoSession * +sckClientOpen(THIS_VOID) { - FUNCTION_LOG_BEGIN(logLevelTrace) + THIS(SocketClient); + + FUNCTION_LOG_BEGIN(logLevelTrace); FUNCTION_LOG_PARAM(SOCKET_CLIENT, this); FUNCTION_LOG_END(); ASSERT(this != NULL); - SocketSession *result = NULL; + IoSession *result = NULL; MEM_CONTEXT_TEMP_BEGIN() { @@ -137,7 +127,7 @@ sckClientOpen(SocketClient *this) // Create the session MEM_CONTEXT_PRIOR_BEGIN() { - result = sckSessionNew(sckSessionTypeClient, fd, this->host, this->port, this->timeout); + result = sckSessionNew(ioSessionRoleClient, fd, this->host, this->port, this->timeout); } MEM_CONTEXT_PRIOR_END(); } @@ -165,7 +155,66 @@ sckClientOpen(SocketClient *this) } MEM_CONTEXT_TEMP_END(); - FUNCTION_LOG_RETURN(SOCKET_SESSION, result); + FUNCTION_LOG_RETURN(IO_SESSION, result); +} + +/**********************************************************************************************************************************/ +static const String * +sckClientName(THIS_VOID) +{ + THIS(SocketClient); + + FUNCTION_TEST_BEGIN(); + FUNCTION_TEST_PARAM(SOCKET_CLIENT, this); + FUNCTION_TEST_END(); + + ASSERT(this != NULL); + + FUNCTION_TEST_RETURN(this->name); +} + +/**********************************************************************************************************************************/ +static const IoClientInterface sckClientInterface = +{ + .type = &IO_CLIENT_SOCKET_TYPE_STR, + .name = sckClientName, + .open = sckClientOpen, + .toLog = sckClientToLog, +}; + +IoClient * +sckClientNew(const String *host, unsigned int port, TimeMSec timeout) +{ + FUNCTION_LOG_BEGIN(logLevelDebug) + FUNCTION_LOG_PARAM(STRING, host); + FUNCTION_LOG_PARAM(UINT, port); + FUNCTION_LOG_PARAM(TIME_MSEC, timeout); + FUNCTION_LOG_END(); + + ASSERT(host != NULL); + + IoClient *this = NULL; + + MEM_CONTEXT_NEW_BEGIN("SocketClient") + { + SocketClient *driver = memNew(sizeof(SocketClient)); + + *driver = (SocketClient) + { + .memContext = MEM_CONTEXT_NEW(), + .host = strDup(host), + .port = port, + .name = strNewFmt("%s:%u", strZ(host), port), + .timeout = timeout, + }; + + sckClientStatLocal.object++; + + this = ioClientNew(driver, &sckClientInterface); + } + MEM_CONTEXT_NEW_END(); + + FUNCTION_LOG_RETURN(IO_CLIENT, this); } /**********************************************************************************************************************************/ @@ -185,10 +234,3 @@ sckClientStatStr(void) FUNCTION_TEST_RETURN(result); } - -/**********************************************************************************************************************************/ -String * -sckClientToLog(const SocketClient *this) -{ - return strNewFmt("{host: %s, port: %u, timeout: %" PRIu64 "}", strZ(this->host), this->port, this->timeout); -} diff --git a/src/common/io/socket/client.h b/src/common/io/socket/client.h index 3b820e5a6..369bc7902 100644 --- a/src/common/io/socket/client.h +++ b/src/common/io/socket/client.h @@ -2,25 +2,18 @@ Socket Client A simple socket client intended to allow access to services that are exposed via a socket. - -Currently this is not a full-featured client and is only intended to isolate socket functionality from the tls code. ***********************************************************************************************************************************/ #ifndef COMMON_IO_SOCKET_CLIENT_H #define COMMON_IO_SOCKET_CLIENT_H -/*********************************************************************************************************************************** -Object type -***********************************************************************************************************************************/ -#define SOCKET_CLIENT_TYPE SocketClient -#define SOCKET_CLIENT_PREFIX sckClient - -typedef struct SocketClient SocketClient; - -#include "common/io/read.h" -#include "common/io/socket/session.h" -#include "common/io/write.h" +#include "common/io/client.h" #include "common/time.h" -#include "common/type/string.h" + +/*********************************************************************************************************************************** +Io client type +***********************************************************************************************************************************/ +#define IO_CLIENT_SOCKET_TYPE "socket" + STRING_DECLARE(IO_CLIENT_SOCKET_TYPE_STR); /*********************************************************************************************************************************** Statistics @@ -35,37 +28,12 @@ typedef struct SocketClientStat /*********************************************************************************************************************************** Constructors ***********************************************************************************************************************************/ -SocketClient *sckClientNew(const String *host, unsigned int port, TimeMSec timeout); +IoClient *sckClientNew(const String *host, unsigned int port, TimeMSec timeout); /*********************************************************************************************************************************** Functions ***********************************************************************************************************************************/ -// Open the connection -SocketSession *sckClientOpen(SocketClient *this); - -// Move to a new parent mem context -SocketClient *sckClientMove(SocketClient *this, MemContext *parentNew); - // Statistics as a formatted string String *sckClientStatStr(void); -/*********************************************************************************************************************************** -Getters/Setters -***********************************************************************************************************************************/ -// Socket host -const String *sckClientHost(const SocketClient *this); - -// Socket port -unsigned int sckClientPort(const SocketClient *this); - -/*********************************************************************************************************************************** -Macros for function logging -***********************************************************************************************************************************/ -String *sckClientToLog(const SocketClient *this); - -#define FUNCTION_LOG_SOCKET_CLIENT_TYPE \ - SocketClient * -#define FUNCTION_LOG_SOCKET_CLIENT_FORMAT(value, buffer, bufferSize) \ - FUNCTION_LOG_STRING_OBJECT_FORMAT(value, sckClientToLog, buffer, bufferSize) - #endif diff --git a/src/common/io/socket/session.c b/src/common/io/socket/session.c index 11f1d4a2d..8b072d372 100644 --- a/src/common/io/socket/session.c +++ b/src/common/io/socket/session.c @@ -10,18 +10,20 @@ Socket Session #include "common/io/fdRead.h" #include "common/io/fdWrite.h" #include "common/io/socket/client.h" -#include "common/io/socket/common.h" +#include "common/io/session.intern.h" #include "common/memContext.h" #include "common/type/object.h" -#include "common/wait.h" /*********************************************************************************************************************************** Object type ***********************************************************************************************************************************/ -struct SocketSession +#define SOCKET_SESSION_TYPE SocketSession +#define SOCKET_SESSION_PREFIX sckSession + +typedef struct SocketSession { MemContext *memContext; // Mem context - SocketSessionType type; // Type (server or client) + IoSessionRole role; // Role (server or client) int fd; // File descriptor String *host; // Hostname or IP address unsigned int port; // Port to connect to host on @@ -29,16 +31,23 @@ struct SocketSession IoRead *read; // IoRead interface to the file descriptor IoWrite *write; // IoWrite interface to the file descriptor -}; +} SocketSession; -OBJECT_DEFINE_MOVE(SOCKET_SESSION); +/*********************************************************************************************************************************** +Macros for function logging +***********************************************************************************************************************************/ +static String * +sckSessionToLog(const THIS_VOID) +{ + THIS(const SocketSession); -OBJECT_DEFINE_GET(Fd, , SOCKET_SESSION, int, fd); -OBJECT_DEFINE_GET(IoRead, , SOCKET_SESSION, IoRead *, read); -OBJECT_DEFINE_GET(IoWrite, , SOCKET_SESSION, IoWrite *, write); -OBJECT_DEFINE_GET(Type, const, SOCKET_SESSION, SocketSessionType, type); + return strNewFmt("{fd %d, host: %s, port: %u, timeout: %" PRIu64 "}", this->fd, strZ(this->host), this->port, this->timeout); +} -OBJECT_DEFINE_FREE(SOCKET_SESSION); +#define FUNCTION_LOG_SOCKET_SESSION_TYPE \ + SocketSession * +#define FUNCTION_LOG_SOCKET_SESSION_FORMAT(value, buffer, bufferSize) \ + FUNCTION_LOG_STRING_OBJECT_FORMAT(value, sckSessionToLog, buffer, bufferSize) /*********************************************************************************************************************************** Free connection @@ -50,11 +59,108 @@ OBJECT_DEFINE_FREE_RESOURCE_BEGIN(SOCKET_SESSION, LOG, logLevelTrace) OBJECT_DEFINE_FREE_RESOURCE_END(LOG); /**********************************************************************************************************************************/ -SocketSession * -sckSessionNew(SocketSessionType type, int fd, const String *host, unsigned int port, TimeMSec timeout) +static void +sckSessionClose(THIS_VOID) +{ + THIS(SocketSession); + + FUNCTION_LOG_BEGIN(logLevelTrace); + FUNCTION_LOG_PARAM(SOCKET_SESSION, this); + FUNCTION_LOG_END(); + + ASSERT(this != NULL); + + // If not already closed + if (this->fd != -1) + { + // Clear the callback to close the socket + memContextCallbackClear(this->memContext); + + // Close the socket + close(this->fd); + this->fd = -1; + } + + FUNCTION_LOG_RETURN_VOID(); +} + +/**********************************************************************************************************************************/ +static int +sckSessionFd(THIS_VOID) +{ + THIS(SocketSession); + + FUNCTION_TEST_BEGIN(); + FUNCTION_TEST_PARAM(SOCKET_SESSION, this); + FUNCTION_TEST_END(); + + ASSERT(this != NULL); + + FUNCTION_TEST_RETURN(this->fd); +} + +/**********************************************************************************************************************************/ +static IoRead * +sckSessionIoRead(THIS_VOID) +{ + THIS(SocketSession); + + FUNCTION_TEST_BEGIN(); + FUNCTION_TEST_PARAM(SOCKET_SESSION, this); + FUNCTION_TEST_END(); + + ASSERT(this != NULL); + + FUNCTION_TEST_RETURN(this->read); +} + +/**********************************************************************************************************************************/ +static IoWrite * +sckSessionIoWrite(THIS_VOID) +{ + THIS(SocketSession); + + FUNCTION_TEST_BEGIN(); + FUNCTION_TEST_PARAM(SOCKET_SESSION, this); + FUNCTION_TEST_END(); + + ASSERT(this != NULL); + + FUNCTION_TEST_RETURN(this->write); +} + +/**********************************************************************************************************************************/ +static IoSessionRole +sckSessionRole(const THIS_VOID) +{ + THIS(const SocketSession); + + FUNCTION_TEST_BEGIN(); + FUNCTION_TEST_PARAM(SOCKET_SESSION, this); + FUNCTION_TEST_END(); + + ASSERT(this != NULL); + + FUNCTION_TEST_RETURN(this->role); +} + +/**********************************************************************************************************************************/ +static const IoSessionInterface sckSessionInterface = +{ + .type = &IO_CLIENT_SOCKET_TYPE_STR, + .close = sckSessionClose, + .fd = sckSessionFd, + .ioRead = sckSessionIoRead, + .ioWrite = sckSessionIoWrite, + .role = sckSessionRole, + .toLog = sckSessionToLog, +}; + +IoSession * +sckSessionNew(IoSessionRole role, int fd, const String *host, unsigned int port, TimeMSec timeout) { FUNCTION_LOG_BEGIN(logLevelDebug) - FUNCTION_LOG_PARAM(ENUM, type); + FUNCTION_LOG_PARAM(ENUM, role); FUNCTION_LOG_PARAM(INT, fd); FUNCTION_LOG_PARAM(STRING, host); FUNCTION_LOG_PARAM(UINT, port); @@ -64,18 +170,18 @@ sckSessionNew(SocketSessionType type, int fd, const String *host, unsigned int p ASSERT(fd != -1); ASSERT(host != NULL); - SocketSession *this = NULL; + IoSession *this = NULL; MEM_CONTEXT_NEW_BEGIN("SocketSession") { - this = memNew(sizeof(SocketSession)); + SocketSession *driver = memNew(sizeof(SocketSession)); String *name = strNewFmt("%s:%u", strZ(host), port); - *this = (SocketSession) + *driver = (SocketSession) { .memContext = MEM_CONTEXT_NEW(), - .type = type, + .role = role, .fd = fd, .host = strDup(host), .port = port, @@ -84,19 +190,18 @@ sckSessionNew(SocketSessionType type, int fd, const String *host, unsigned int p .write = ioFdWriteNew(name, fd, timeout), }; - memContextCallbackSet(this->memContext, sckSessionFreeResource, this); strFree(name); + + // Open read/write io + ioReadOpen(driver->read); + ioWriteOpen(driver->write); + + // Ensure file descriptor is closed + memContextCallbackSet(driver->memContext, sckSessionFreeResource, driver); + + this = ioSessionNew(driver, &sckSessionInterface); } MEM_CONTEXT_NEW_END(); - FUNCTION_LOG_RETURN(SOCKET_SESSION, this); -} - -/**********************************************************************************************************************************/ -String * -sckSessionToLog(const SocketSession *this) -{ - return strNewFmt( - "{type: %s, fd %d, host: %s, port: %u, timeout: %" PRIu64 "}", this->type == sckSessionTypeClient ? "client" : "server", - this->fd, strZ(this->host), this->port, this->timeout); + FUNCTION_LOG_RETURN(IO_SESSION, this); } diff --git a/src/common/io/socket/session.h b/src/common/io/socket/session.h index 5e647632f..94192ecba 100644 --- a/src/common/io/socket/session.h +++ b/src/common/io/socket/session.h @@ -2,76 +2,17 @@ Socket Session A simple socket session intended to allow access to services that are exposed via a socket. - -Currently this is not a full-featured session and is only intended to isolate socket functionality from the tls code. ***********************************************************************************************************************************/ #ifndef COMMON_IO_SOCKET_SESSION_H #define COMMON_IO_SOCKET_SESSION_H -/*********************************************************************************************************************************** -Test result operations -***********************************************************************************************************************************/ -typedef enum -{ - sckSessionTypeClient, - sckSessionTypeServer, -} SocketSessionType; - -/*********************************************************************************************************************************** -Object type -***********************************************************************************************************************************/ -#define SOCKET_SESSION_TYPE SocketSession -#define SOCKET_SESSION_PREFIX sckSession - -typedef struct SocketSession SocketSession; - -#include "common/io/read.h" -#include "common/io/write.h" +#include "common/io/session.h" #include "common/time.h" -#include "common/type/string.h" /*********************************************************************************************************************************** Constructors ***********************************************************************************************************************************/ -SocketSession *sckSessionNew(SocketSessionType type, int fd, const String *host, unsigned int port, TimeMSec timeout); +IoSession *sckSessionNew(IoSessionRole role, int fd, const String *host, unsigned int port, TimeMSec timeout); -/*********************************************************************************************************************************** -Getters/Setters -***********************************************************************************************************************************/ -// Read interface -IoRead *sckSessionIoRead(SocketSession *this); - -// Write interface -IoWrite *sckSessionIoWrite(SocketSession *this); - -/*********************************************************************************************************************************** -Functions -***********************************************************************************************************************************/ -// Move to a new parent mem context -SocketSession *sckSessionMove(SocketSession *this, MemContext *parentNew); - -/*********************************************************************************************************************************** -Getters/Setters -***********************************************************************************************************************************/ -// Socket file descriptor -int sckSessionFd(SocketSession *this); - -// Socket type -SocketSessionType sckSessionType(const SocketSession *this); - -/*********************************************************************************************************************************** -Destructor -***********************************************************************************************************************************/ -void sckSessionFree(SocketSession *this); - -/*********************************************************************************************************************************** -Macros for function logging -***********************************************************************************************************************************/ -String *sckSessionToLog(const SocketSession *this); - -#define FUNCTION_LOG_SOCKET_SESSION_TYPE \ - SocketSession * -#define FUNCTION_LOG_SOCKET_SESSION_FORMAT(value, buffer, bufferSize) \ - FUNCTION_LOG_STRING_OBJECT_FORMAT(value, sckSessionToLog, buffer, bufferSize) #endif diff --git a/src/common/io/tls/client.c b/src/common/io/tls/client.c index 9cedac06c..46db3cf4b 100644 --- a/src/common/io/tls/client.c +++ b/src/common/io/tls/client.c @@ -38,9 +38,10 @@ Object type typedef struct TlsClient { MemContext *memContext; // Mem context + const String *host; // Host to use for peer verification TimeMSec timeout; // Timeout for any i/o operation (connect, read, etc.) bool verifyPeer; // Should the peer (server) certificate be verified? - SocketClient *socketClient; // Socket client + IoClient *ioClient; // Underlying client (usually a SocketClient) SSL_CTX *context; // TLS context } TlsClient; @@ -54,8 +55,8 @@ tlsClientToLog(const THIS_VOID) THIS(const TlsClient); return strNewFmt( - "{socketClient: %s, timeout: %" PRIu64", verifyPeer: %s}", - memContextFreeing(this->memContext) ? NULL_Z : strZ(sckClientToLog(this->socketClient)), this->timeout, + "{ioClient: %s, timeout: %" PRIu64", verifyPeer: %s}", + memContextFreeing(this->memContext) ? NULL_Z : strZ(ioClientToLog(this->ioClient)), this->timeout, cvtBoolToConstZ(this->verifyPeer)); } @@ -239,20 +240,18 @@ tlsClientOpen(THIS_VOID) TRY_BEGIN() { - // Open the socket session first since this is mostly likely to fail - SocketSession *socketSession = sckClientOpen(this->socketClient); + // Open the underlying session first since this is mostly likely to fail + IoSession *ioSession = ioClientOpen(this->ioClient); // Create internal TLS session. If there is a failure before the TlsSession object is created there may be a leak // of the TLS session but this is likely to result in program termination so it doesn't seem worth coding for. cryptoError((session = SSL_new(this->context)) == NULL, "unable to create TLS session"); // Set server host name used for validation - cryptoError( - SSL_set_tlsext_host_name(session, strZ(sckClientHost(this->socketClient))) != 1, - "unable to set TLS host name"); + cryptoError(SSL_set_tlsext_host_name(session, strZ(this->host)) != 1, "unable to set TLS host name"); // Create the TLS session - result = tlsSessionNew(session, socketSession, this->timeout); + result = tlsSessionNew(session, ioSession, this->timeout); } CATCH_ANY() { @@ -288,14 +287,13 @@ tlsClientOpen(THIS_VOID) if (verifyResult != X509_V_OK) // {vm_covered} { THROW_FMT( // {vm_covered} - CryptoError, "unable to verify certificate presented by '%s:%u': [%ld] %s", // {vm_covered} - strZ(sckClientHost(this->socketClient)), sckClientPort(this->socketClient), verifyResult, // {vm_covered} - X509_verify_cert_error_string(verifyResult)); // {vm_covered} + CryptoError, "unable to verify certificate presented by '%s': [%ld] %s", // {vm_covered} + strZ(ioClientName(this->ioClient)), verifyResult, X509_verify_cert_error_string(verifyResult)); // {vm_covered} } // Verify that the hostname appears in the certificate X509 *certificate = SSL_get_peer_certificate(session); // {vm_covered} - bool nameResult = tlsClientHostVerify(sckClientHost(this->socketClient), certificate); // {vm_covered} + bool nameResult = tlsClientHostVerify(this->host, certificate); // {vm_covered} X509_free(certificate); // {vm_covered} if (!nameResult) // {vm_covered} @@ -303,33 +301,50 @@ tlsClientOpen(THIS_VOID) THROW_FMT( // {vm_covered} CryptoError, // {vm_covered} "unable to find hostname '%s' in certificate common name or subject alternative names", // {vm_covered} - strZ(sckClientHost(this->socketClient))); // {vm_covered} + strZ(this->host)); // {vm_covered} } } FUNCTION_LOG_RETURN(IO_SESSION, result); } +/**********************************************************************************************************************************/ +static const String * +tlsClientName(THIS_VOID) +{ + THIS(TlsClient); + + FUNCTION_TEST_BEGIN(); + FUNCTION_TEST_PARAM(TLS_CLIENT, this); + FUNCTION_TEST_END(); + + ASSERT(this != NULL); + + FUNCTION_TEST_RETURN(ioClientName(this->ioClient)); +} + /**********************************************************************************************************************************/ static const IoClientInterface tlsClientInterface = { .type = &IO_CLIENT_TLS_TYPE_STR, + .name = tlsClientName, .open = tlsClientOpen, .toLog = tlsClientToLog, }; IoClient * -tlsClientNew(SocketClient *socket, TimeMSec timeout, bool verifyPeer, const String *caFile, const String *caPath) +tlsClientNew(IoClient *ioClient, const String *host, TimeMSec timeout, bool verifyPeer, const String *caFile, const String *caPath) { FUNCTION_LOG_BEGIN(logLevelDebug) - FUNCTION_LOG_PARAM(SOCKET_CLIENT, socket); + FUNCTION_LOG_PARAM(IO_CLIENT, ioClient); + FUNCTION_LOG_PARAM(STRING, host); FUNCTION_LOG_PARAM(TIME_MSEC, timeout); FUNCTION_LOG_PARAM(BOOL, verifyPeer); FUNCTION_LOG_PARAM(STRING, caFile); FUNCTION_LOG_PARAM(STRING, caPath); FUNCTION_LOG_END(); - ASSERT(socket != NULL); + ASSERT(ioClient != NULL); IoClient *this = NULL; @@ -340,7 +355,8 @@ tlsClientNew(SocketClient *socket, TimeMSec timeout, bool verifyPeer, const Stri *driver = (TlsClient) { .memContext = MEM_CONTEXT_NEW(), - .socketClient = sckClientMove(socket, MEM_CONTEXT_NEW()), + .ioClient = ioClientMove(ioClient, MEM_CONTEXT_NEW()), + .host = strDup(host), .timeout = timeout, .verifyPeer = verifyPeer, }; diff --git a/src/common/io/tls/client.h b/src/common/io/tls/client.h index 3c841188a..82cec0a1e 100644 --- a/src/common/io/tls/client.h +++ b/src/common/io/tls/client.h @@ -10,7 +10,6 @@ This object is intended to be used for multiple TLS sessions so ioClientOpen() c #define COMMON_IO_TLS_CLIENT_H #include "common/io/client.h" -#include "common/io/socket/client.h" /*********************************************************************************************************************************** Io client type @@ -31,7 +30,8 @@ typedef struct TlsClientStat /*********************************************************************************************************************************** Constructors ***********************************************************************************************************************************/ -IoClient *tlsClientNew(SocketClient *socket, TimeMSec timeout, bool verifyPeer, const String *caFile, const String *caPath); +IoClient *tlsClientNew( + IoClient *ioClient, const String *host, TimeMSec timeout, bool verifyPeer, const String *caFile, const String *caPath); /*********************************************************************************************************************************** Functions diff --git a/src/common/io/tls/session.c b/src/common/io/tls/session.c index ec2188c1b..31b24003e 100644 --- a/src/common/io/tls/session.c +++ b/src/common/io/tls/session.c @@ -10,7 +10,6 @@ TLS Session #include "common/io/io.h" #include "common/io/read.intern.h" #include "common/io/session.intern.h" -#include "common/io/socket/session.h" #include "common/io/tls/client.h" #include "common/io/tls/session.h" #include "common/io/write.intern.h" @@ -27,10 +26,10 @@ Object type typedef struct TlsSession { MemContext *memContext; // Mem context - SocketSession *socketSession; // Socket session - SSL *session; // TLS session on the socket + IoSession *ioSession; // Io session + SSL *session; // TLS session on the file descriptor TimeMSec timeout; // Timeout for any i/o operation (connect, read, etc.) - bool shutdownOnClose; // Shutdown the TLS connection when closing the socket + bool shutdownOnClose; // Shutdown the TLS connection when closing the session IoRead *read; // Read interface IoWrite *write; // Write interface @@ -45,9 +44,9 @@ tlsSessionToLog(const THIS_VOID) THIS(const TlsSession); return strNewFmt( - "{socketSession: %s, timeout: %" PRIu64", shutdownOnClose: %s}", - this->socketSession == NULL || memContextFreeing(this->memContext) ? NULL_Z : strZ(sckSessionToLog(this->socketSession)), - this->timeout, cvtBoolToConstZ(this->shutdownOnClose)); + "{ioSession: %s, timeout: %" PRIu64", shutdownOnClose: %s}", + memContextFreeing(this->memContext) ? NULL_Z : strZ(ioSessionToLog(this->ioSession)), this->timeout, + cvtBoolToConstZ(this->shutdownOnClose)); } #define FUNCTION_LOG_TLS_SESSION_TYPE \ @@ -83,9 +82,8 @@ tlsSessionClose(THIS_VOID) if (this->shutdownOnClose) SSL_shutdown(this->session); - // Free the socket session - sckSessionFree(this->socketSession); - this->socketSession = NULL; + // Close the io session + ioSessionClose(this->ioSession); // Free the TLS session memContextCallbackClear(this->memContext); @@ -137,7 +135,7 @@ tlsSessionResultProcess(TlsSession *this, int errorTls, long unsigned int errorT // Try again after waiting for read ready case SSL_ERROR_WANT_READ: { - ioReadReadyP(sckSessionIoRead(this->socketSession), .error = true); + ioReadReadyP(ioSessionIoRead(this->ioSession), .error = true); result = 0; break; } @@ -145,7 +143,7 @@ tlsSessionResultProcess(TlsSession *this, int errorTls, long unsigned int errorT // Try again after waiting for write ready case SSL_ERROR_WANT_WRITE: { - ioWriteReadyP(sckSessionIoWrite(this->socketSession), .error = true); + ioWriteReadyP(ioSessionIoWrite(this->ioSession), .error = true); result = 0; break; } @@ -219,9 +217,9 @@ tlsSessionRead(THIS_VOID, Buffer *buffer, bool block) // If blocking read keep reading until buffer is full do { - // If no TLS data pending then check the socket to reduce blocking + // If no TLS data pending then check the io to reduce blocking if (!SSL_pending(this->session)) - ioReadReadyP(sckSessionIoRead(this->socketSession), .error = true); + ioReadReadyP(ioSessionIoRead(this->ioSession), .error = true); // Read and handle errors. The error queue must be cleared before this operation. ERR_clear_error(); @@ -322,6 +320,21 @@ tlsSessionIoWrite(THIS_VOID) FUNCTION_TEST_RETURN(this->write); } +/**********************************************************************************************************************************/ +static IoSessionRole +tlsSessionRole(const THIS_VOID) +{ + THIS(const TlsSession); + + FUNCTION_TEST_BEGIN(); + FUNCTION_TEST_PARAM(TLS_SESSION, this); + FUNCTION_TEST_END(); + + ASSERT(this != NULL); + + FUNCTION_TEST_RETURN(ioSessionRole(this->ioSession)); +} + /**********************************************************************************************************************************/ static const IoSessionInterface tlsSessionInterface = { @@ -329,20 +342,21 @@ static const IoSessionInterface tlsSessionInterface = .close = tlsSessionClose, .ioRead = tlsSessionIoRead, .ioWrite = tlsSessionIoWrite, + .role = tlsSessionRole, .toLog = tlsSessionToLog, }; IoSession * -tlsSessionNew(SSL *session, SocketSession *socketSession, TimeMSec timeout) +tlsSessionNew(SSL *session, IoSession *ioSession, TimeMSec timeout) { FUNCTION_LOG_BEGIN(logLevelDebug) FUNCTION_LOG_PARAM_P(VOID, session); - FUNCTION_LOG_PARAM(SOCKET_SESSION, socketSession); + FUNCTION_LOG_PARAM(IO_SESSION, ioSession); FUNCTION_LOG_PARAM(TIME_MSEC, timeout); FUNCTION_LOG_END(); ASSERT(session != NULL); - ASSERT(socketSession != NULL); + ASSERT(ioSession != NULL); IoSession *this = NULL; @@ -354,7 +368,7 @@ tlsSessionNew(SSL *session, SocketSession *socketSession, TimeMSec timeout) { .memContext = MEM_CONTEXT_NEW(), .session = session, - .socketSession = sckSessionMove(socketSession, MEM_CONTEXT_NEW()), + .ioSession = ioSessionMove(ioSession, MEM_CONTEXT_NEW()), .timeout = timeout, .shutdownOnClose = true, }; @@ -362,9 +376,8 @@ tlsSessionNew(SSL *session, SocketSession *socketSession, TimeMSec timeout) // Ensure session is freed memContextCallbackSet(driver->memContext, tlsSessionFreeResource, driver); - // Assign socket to TLS session - cryptoError( - SSL_set_fd(driver->session, sckSessionFd(driver->socketSession)) != 1, "unable to add socket to TLS session"); + // Assign file descriptor to TLS session + cryptoError(SSL_set_fd(driver->session, ioSessionFd(driver->ioSession)) != 1, "unable to add fd to TLS session"); // Negotiate TLS session. The error queue must be cleared before this operation. int result = 0; @@ -373,7 +386,7 @@ tlsSessionNew(SSL *session, SocketSession *socketSession, TimeMSec timeout) { ERR_clear_error(); - if (sckSessionType(driver->socketSession) == sckSessionTypeClient) + if (ioSessionRole(driver->ioSession) == ioSessionRoleClient) result = tlsSessionResult(driver, SSL_connect(driver->session), false); else result = tlsSessionResult(driver, SSL_accept(driver->session), false); diff --git a/src/common/io/tls/session.h b/src/common/io/tls/session.h index 7f339d055..52f1d4cee 100644 --- a/src/common/io/tls/session.h +++ b/src/common/io/tls/session.h @@ -16,13 +16,12 @@ Object type #include #include "common/io/session.h" -#include "common/io/socket/session.h" #include "common/time.h" /*********************************************************************************************************************************** Constructors ***********************************************************************************************************************************/ // Only called by TLS client/server code -IoSession *tlsSessionNew(SSL *session, SocketSession *socketSession, TimeMSec timeout); +IoSession *tlsSessionNew(SSL *session, IoSession *ioSession, TimeMSec timeout); #endif diff --git a/src/storage/azure/storage.c b/src/storage/azure/storage.c index f08d985f0..7485c96e8 100644 --- a/src/storage/azure/storage.c +++ b/src/storage/azure/storage.c @@ -11,6 +11,7 @@ Azure Storage #include "common/debug.h" #include "common/io/http/client.h" #include "common/io/http/common.h" +#include "common/io/socket/client.h" #include "common/io/tls/client.h" #include "common/log.h" #include "common/memContext.h" @@ -741,7 +742,7 @@ storageAzureNew( // Create the http client used to service requests driver->httpClient = httpClientNew( - tlsClientNew(sckClientNew(driver->host, port, timeout), timeout, verifyPeer, caFile, caPath), timeout); + tlsClientNew(sckClientNew(driver->host, port, timeout), driver->host, timeout, verifyPeer, caFile, caPath), timeout); // Create list of redacted headers driver->headerRedactList = strLstNew(); diff --git a/src/storage/s3/storage.c b/src/storage/s3/storage.c index ef98345b4..682e8f5ae 100644 --- a/src/storage/s3/storage.c +++ b/src/storage/s3/storage.c @@ -10,6 +10,7 @@ S3 Storage #include "common/debug.h" #include "common/io/http/client.h" #include "common/io/http/common.h" +#include "common/io/socket/client.h" #include "common/io/tls/client.h" #include "common/log.h" #include "common/memContext.h" @@ -857,10 +858,11 @@ storageS3New( }; // Create the HTTP client used to service requests + if (host == NULL) + host = driver->bucketEndpoint; + driver->httpClient = httpClientNew( - tlsClientNew( - sckClientNew(host == NULL ? driver->bucketEndpoint : host, port, timeout), timeout, verifyPeer, caFile, caPath), - timeout); + tlsClientNew(sckClientNew(host, port, timeout), host, timeout, verifyPeer, caFile, caPath), timeout); // Create list of redacted headers driver->headerRedactList = strLstNew(); diff --git a/test/src/common/harnessTls.c b/test/src/common/harnessTls.c index 220a5452f..148116531 100644 --- a/test/src/common/harnessTls.c +++ b/test/src/common/harnessTls.c @@ -302,7 +302,7 @@ void hrnTlsServerRunParam(IoRead *read, const String *certificate, const String SSL *testClientSSL = SSL_new(serverContext); serverSession = tlsSessionNew( - testClientSSL, sckSessionNew(sckSessionTypeServer, testClientSocket, STRDEF("client"), 0, 5000), 5000); + testClientSSL, sckSessionNew(ioSessionRoleServer, testClientSocket, STRDEF("client"), 0, 5000), 5000); break; } diff --git a/test/src/module/command/commandTest.c b/test/src/module/command/commandTest.c index d351a684c..0476ceafc 100644 --- a/test/src/module/command/commandTest.c +++ b/test/src/module/command/commandTest.c @@ -121,7 +121,7 @@ testRun(void) cfgOptionSet(cfgOptLogTimestamp, cfgSourceParam, varNewBool(true)); - httpClientNew(tlsClientNew(sckClientNew(STRDEF("BOGUS"), 443, 1000), 1000, true, NULL, NULL), 1000); + httpClientNew(tlsClientNew(sckClientNew(STRDEF("BOGUS"), 443, 1000), STRDEF("BOGUS"), 1000, true, NULL, NULL), 1000); harnessLogLevelSet(logLevelDetail); diff --git a/test/src/module/common/ioHttpTest.c b/test/src/module/common/ioHttpTest.c index 8f5ee8bc3..f6a02d30d 100644 --- a/test/src/module/common/ioHttpTest.c +++ b/test/src/module/common/ioHttpTest.c @@ -6,6 +6,7 @@ Test HTTP #include "common/io/fdRead.h" #include "common/io/fdWrite.h" #include "common/io/tls/client.h" +#include "common/io/socket/client.h" #include "common/harnessFork.h" #include "common/harnessTls.h" @@ -179,7 +180,9 @@ testRun(void) TEST_ASSIGN( client, httpClientNew( - tlsClientNew(sckClientNew(strNew("localhost"), hrnTlsServerPort(), 500), 500, testContainer(), NULL, NULL), 500), + tlsClientNew( + sckClientNew(strNew("localhost"), hrnTlsServerPort(), 500), strNew("X"), 500, testContainer(), NULL, NULL), + 500), "new client"); TEST_ERROR_FMT( @@ -209,7 +212,9 @@ testRun(void) TEST_ASSIGN( client, httpClientNew( - tlsClientNew(sckClientNew(hrnTlsServerHost(), hrnTlsServerPort(), 5000), 5000, testContainer(), NULL, NULL), + tlsClientNew( + sckClientNew(hrnTlsServerHost(), hrnTlsServerPort(), 5000), hrnTlsServerHost(), 5000, testContainer(), + NULL, NULL), 5000), "new client"); diff --git a/test/src/module/common/ioTlsTest.c b/test/src/module/common/ioTlsTest.c index 878e1321e..1a3d9dff6 100644 --- a/test/src/module/common/ioTlsTest.c +++ b/test/src/module/common/ioTlsTest.c @@ -140,24 +140,26 @@ testRun(void) CHECK(connect(fd, hostBadAddress->ai_addr, hostBadAddress->ai_addrlen) == -1); // Create socket session and wait for timeout - SocketSession *session = NULL; - TEST_ASSIGN(session, sckSessionNew(sckSessionTypeClient, fd, strNew(hostBad), 7777, 100), "new socket"); + IoSession *session = NULL; + TEST_ASSIGN(session, sckSessionNew(ioSessionRoleClient, fd, strNew(hostBad), 7777, 100), "new socket"); TEST_ERROR( - ioWriteReadyP(sckSessionIoWrite(session), .error = true), FileWriteError, + ioWriteReadyP(ioSessionIoWrite(session), .error = true), FileWriteError, "timeout after 100ms waiting for write to '172.31.255.255:7777'"); - TEST_RESULT_VOID(sckSessionFree(session), "free socket session"); + TEST_RESULT_VOID(ioSessionClose(session), "close socket session"); + TEST_RESULT_VOID(ioSessionClose(session), "close socket session again"); + TEST_RESULT_VOID(ioSessionFree(session), "free socket session"); // --------------------------------------------------------------------------------------------------------------------- TEST_TITLE("unable to connect to blocking socket"); - SocketClient *socketClient = sckClientNew(STR(hostLocal), 7777, 0); - TEST_RESULT_UINT(sckClientPort(socketClient), 7777, " check port"); + IoClient *socketClient = sckClientNew(STR(hostLocal), 7777, 0); + TEST_RESULT_STR_Z(ioClientName(socketClient), "127.0.0.1:7777", " check name"); socketLocal.block = true; TEST_ERROR( - sckClientOpen(socketClient), HostConnectError, "unable to connect to '127.0.0.1:7777': [111] Connection refused"); + ioClientOpen(socketClient), HostConnectError, "unable to connect to '127.0.0.1:7777': [111] Connection refused"); socketLocal.block = false; // --------------------------------------------------------------------------------------------------------------------- @@ -180,16 +182,16 @@ testRun(void) // ***************************************************************************************************************************** if (testBegin("SocketClient")) { - SocketClient *client = NULL; + IoClient *client = NULL; TEST_ASSIGN(client, sckClientNew(strNew("localhost"), hrnTlsServerPort(), 100), "new client"); TEST_ERROR_FMT( - sckClientOpen(client), HostConnectError, "unable to connect to 'localhost:%u': [111] Connection refused", + ioClientOpen(client), HostConnectError, "unable to connect to 'localhost:%u': [111] Connection refused", hrnTlsServerPort()); // This address should not be in use in a test environment -- if it is the test will fail TEST_ASSIGN(client, sckClientNew(strNew("172.31.255.255"), hrnTlsServerPort(), 100), "new client"); - TEST_ERROR_FMT(sckClientOpen(client), HostConnectError, "timeout connecting to '172.31.255.255:%u'", hrnTlsServerPort()); + TEST_ERROR_FMT(ioClientOpen(client), HostConnectError, "timeout connecting to '172.31.255.255:%u'", hrnTlsServerPort()); } // Additional coverage not provided by testing with actual certificates @@ -217,13 +219,14 @@ testRun(void) // Connection errors // ------------------------------------------------------------------------------------------------------------------------- TEST_ASSIGN( - client, tlsClientNew(sckClientNew(strNew("99.99.99.99.99"), hrnTlsServerPort(), 0), 0, true, NULL, NULL), + client, tlsClientNew(sckClientNew(strNew("99.99.99.99.99"), 7777, 0), strNew("X"), 0, true, NULL, NULL), "new client"); + TEST_RESULT_STR_Z(ioClientName(client), "99.99.99.99.99:7777", " check name"); TEST_ERROR( ioClientOpen(client), HostConnectError, "unable to get address for '99.99.99.99.99': [-2] Name or service not known"); TEST_ASSIGN( - client, tlsClientNew(sckClientNew(strNew("localhost"), hrnTlsServerPort(), 100), 100, true, NULL, NULL), + client, tlsClientNew(sckClientNew(strNew("localhost"), hrnTlsServerPort(), 100), strNew("X"), 100, true, NULL, NULL), "new client"); TEST_ERROR_FMT( ioClientOpen(client), HostConnectError, "unable to connect to 'localhost:%u': [111] Connection refused", @@ -235,7 +238,9 @@ testRun(void) TEST_ERROR( ioClientOpen( tlsClientNew( - sckClientNew(strNew("localhost"), hrnTlsServerPort(), 5000), 0, true, strNew("bogus.crt"), strNew("/bogus"))), + sckClientNew( + strNew("localhost"), hrnTlsServerPort(), 5000), strNew("X"), 0, true, strNew("bogus.crt"), + strNew("/bogus"))), CryptoError, "unable to set user-defined CA certificate location: [33558530] No such file or directory"); // Certificate location and validation errors @@ -276,7 +281,8 @@ testRun(void) TEST_ERROR_FMT( ioClientOpen( tlsClientNew( - sckClientNew(strNew("localhost"), hrnTlsServerPort(), 5000), 0, true, NULL, strNew("/bogus"))), + sckClientNew(strNew("localhost"), hrnTlsServerPort(), 5000), strNew("X"), 0, true, NULL, + strNew("/bogus"))), CryptoError, "unable to verify certificate presented by 'localhost:%u': [20] unable to get local issuer certificate", hrnTlsServerPort()); @@ -290,8 +296,8 @@ testRun(void) TEST_RESULT_VOID( ioClientOpen( tlsClientNew( - sckClientNew(strNew("test.pgbackrest.org"), hrnTlsServerPort(), 5000), 0, true, - strNewFmt("%s/" TEST_CERTIFICATE_PREFIX "-ca.crt", testRepoPath()), NULL)), + sckClientNew(strNew("test.pgbackrest.org"), hrnTlsServerPort(), 5000), strNew("test.pgbackrest.org"), + 0, true, strNewFmt("%s/" TEST_CERTIFICATE_PREFIX "-ca.crt", testRepoPath()), NULL)), "open connection"); // ----------------------------------------------------------------------------------------------------------------- @@ -303,7 +309,8 @@ testRun(void) TEST_RESULT_VOID( ioClientOpen( tlsClientNew( - sckClientNew(strNew("host.test2.pgbackrest.org"), hrnTlsServerPort(), 5000), 0, true, + sckClientNew(strNew("host.test2.pgbackrest.org"), hrnTlsServerPort(), 5000), + strNew("host.test2.pgbackrest.org"), 0, true, strNewFmt("%s/" TEST_CERTIFICATE_PREFIX "-ca.crt", testRepoPath()), NULL)), "open connection"); @@ -316,7 +323,8 @@ testRun(void) TEST_ERROR( ioClientOpen( tlsClientNew( - sckClientNew(strNew("test3.pgbackrest.org"), hrnTlsServerPort(), 5000), 0, true, + sckClientNew(strNew("test3.pgbackrest.org"), hrnTlsServerPort(), 5000), + strNew("test3.pgbackrest.org"), 0, true, strNewFmt("%s/" TEST_CERTIFICATE_PREFIX "-ca.crt", testRepoPath()), NULL)), CryptoError, "unable to find hostname 'test3.pgbackrest.org' in certificate common name or subject alternative names"); @@ -330,7 +338,7 @@ testRun(void) TEST_ERROR_FMT( ioClientOpen( tlsClientNew( - sckClientNew(strNew("localhost"), hrnTlsServerPort(), 5000), 0, true, + sckClientNew(strNew("localhost"), hrnTlsServerPort(), 5000), strNew("X"), 0, true, strNewFmt("%s/" TEST_CERTIFICATE_PREFIX ".crt", testRepoPath()), NULL)), CryptoError, @@ -345,7 +353,8 @@ testRun(void) TEST_RESULT_VOID( ioClientOpen( - tlsClientNew(sckClientNew(strNew("localhost"), hrnTlsServerPort(), 5000), 0, false, NULL, NULL)), + tlsClientNew( + sckClientNew(strNew("localhost"), hrnTlsServerPort(), 5000), strNew("X"), 0, false, NULL, NULL)), "open connection"); // ----------------------------------------------------------------------------------------------------------------- @@ -385,7 +394,9 @@ testRun(void) TEST_ASSIGN( client, - tlsClientNew(sckClientNew(hrnTlsServerHost(), hrnTlsServerPort(), 5000), 0, testContainer(), NULL, NULL), + tlsClientNew( + sckClientNew(hrnTlsServerHost(), hrnTlsServerPort(), 5000), hrnTlsServerHost(), 0, testContainer(), NULL, + NULL), "new client"); hrnTlsServerAccept(); @@ -393,6 +404,8 @@ testRun(void) TEST_ASSIGN(session, ioClientOpen(client), "open client"); TlsSession *tlsSession = (TlsSession *)session->driver; + TEST_RESULT_INT(ioSessionFd(session), -1, "no fd for tls session"); + // ----------------------------------------------------------------------------------------------------------------- TEST_TITLE("uncovered errors"); @@ -441,11 +454,11 @@ testRun(void) hrnTlsServerSleep(500); output = bufNew(12); - ((IoFdRead *)tlsSession->socketSession->read->driver)->timeout = 100; + ((IoFdRead *)((SocketSession *)tlsSession->ioSession->driver)->read->driver)->timeout = 100; TEST_ERROR_FMT( ioRead(ioSessionIoRead(session), output), FileReadError, "timeout after 100ms waiting for read from '%s:%u'", strZ(hrnTlsServerHost()), hrnTlsServerPort()); - ((IoFdRead *)tlsSession->socketSession->read->driver)->timeout = 5000; + ((IoFdRead *)((SocketSession *)tlsSession->ioSession->driver)->read->driver)->timeout = 5000; // ----------------------------------------------------------------------------------------------------------------- TEST_TITLE("second protocol exchange"); diff --git a/test/src/module/storage/s3Test.c b/test/src/module/storage/s3Test.c index 19186adee..418ca979b 100644 --- a/test/src/module/storage/s3Test.c +++ b/test/src/module/storage/s3Test.c @@ -213,8 +213,8 @@ testRun(void) TEST_RESULT_STR( httpClientToLog(driver->httpClient), strNewFmt( - "{ioClient: {type: tls, driver: {socketClient: {host: bucket.s3.amazonaws.com, port: 443, timeout: 60000}" - ", timeout: 60000, verifyPeer: %s}}, reusable: 0, timeout: 60000}", + "{ioClient: {type: tls, driver: {ioClient: {type: socket, driver: {host: bucket.s3.amazonaws.com, port: 443" + ", timeout: 60000}}, timeout: 60000, verifyPeer: %s}}, reusable: 0, timeout: 60000}", cvtBoolToConstZ(testContainer())), "check http client"); @@ -281,8 +281,8 @@ testRun(void) TEST_RESULT_STR( httpClientToLog(driver->httpClient), strNewFmt( - "{ioClient: {type: tls, driver: {socketClient: {host: bucket.custom.endpoint, port: 333, timeout: 60000}" - ", timeout: 60000, verifyPeer: %s}}, reusable: 0, timeout: 60000}", + "{ioClient: {type: tls, driver: {ioClient: {type: socket, driver: {host: bucket.custom.endpoint, port: 333" + ", timeout: 60000}}, timeout: 60000, verifyPeer: %s}}, reusable: 0, timeout: 60000}", cvtBoolToConstZ(testContainer())), "check http client");