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:
parent
54c3c39645
commit
7fdbd94e39
@ -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"/>
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
***********************************************************************************************************************************/
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)));
|
||||
}
|
||||
|
@ -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
|
||||
***********************************************************************************************************************************/
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user