1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-01-18 04:58:51 +02:00

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().
This commit is contained in:
David Steele 2020-08-10 16:03:38 -04:00 committed by GitHub
parent 54c3c39645
commit 7fdbd94e39
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 443 additions and 259 deletions

View File

@ -88,6 +88,7 @@
<release-item>
<commit subject="Add IoClient and IoSession interfaces."/>
<commit subject="Move file descriptor read/write ready into IoRead/IoWrite."/>
<commit subject="Implement IoClient/IoSession interfaces for SocketClient/SocketSession."/>
<release-item-contributor-list>
<release-item-reviewer id="stephen.frost"/>

View File

@ -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"

View File

@ -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)

View File

@ -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
***********************************************************************************************************************************/

View File

@ -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);

View File

@ -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)));
}

View File

@ -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
***********************************************************************************************************************************/

View File

@ -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;

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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,
};

View File

@ -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

View File

@ -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);

View File

@ -16,13 +16,12 @@ Object type
#include <openssl/ssl.h>
#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

View File

@ -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();

View File

@ -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();

View File

@ -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;
}

View File

@ -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);

View File

@ -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");

View File

@ -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");

View File

@ -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");