mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-03-03 14:52:21 +02:00
Add IoClient and IoSession interfaces.
These interfaces allow the HttpClient and HttpSession objects to work with protocols other than TLS, .e.g. plain sockets. This is necessary to allow standard HTTP -- right now only HTTPS is allowed, i.e. HTTP over TLS. For now only TlsClient and TlsSession have been converted to the new interfaces. SocketClient and SocketSession will also need to be converted but first sckSessionReadyRead() and sckSessionReadyWrite() need to be moved into the IoRead and IoWrite interfaces, since they are not a good fit for IoSession.
This commit is contained in:
parent
9b7fd1a894
commit
111d33c123
@ -74,6 +74,19 @@
|
||||
<p>Improve TLS error reporting.</p>
|
||||
</release-item>
|
||||
</release-improvement-list>
|
||||
|
||||
<release-development-list>
|
||||
<release-item>
|
||||
<commit subject="Add IoClient and IoSession interfaces."/>
|
||||
|
||||
<release-item-contributor-list>
|
||||
<release-item-reviewer id="stephen.frost"/>
|
||||
<release-item-reviewer id="cynthia.shang"/>
|
||||
</release-item-contributor-list>
|
||||
|
||||
<p>Allow <code>HttpClient</code>/<code>HttpSession</code> to work on plain sockets.</p>
|
||||
</release-item>
|
||||
</release-development-list>
|
||||
</release-core-list>
|
||||
|
||||
<release-doc-list>
|
||||
|
@ -66,6 +66,7 @@ SRCS = \
|
||||
common/fork.c \
|
||||
common/io/bufferRead.c \
|
||||
common/io/bufferWrite.c \
|
||||
common/io/client.c \
|
||||
common/io/fdRead.c \
|
||||
common/io/fdWrite.c \
|
||||
common/io/filter/buffer.c \
|
||||
@ -82,6 +83,7 @@ SRCS = \
|
||||
common/io/http/session.c \
|
||||
common/io/io.c \
|
||||
common/io/read.c \
|
||||
common/io/session.c \
|
||||
common/io/socket/client.c \
|
||||
common/io/socket/common.c \
|
||||
common/io/socket/session.c \
|
||||
|
69
src/common/io/client.c
Normal file
69
src/common/io/client.c
Normal file
@ -0,0 +1,69 @@
|
||||
/***********************************************************************************************************************************
|
||||
Io Client Interface
|
||||
***********************************************************************************************************************************/
|
||||
#include "build.auto.h"
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/io/client.intern.h"
|
||||
#include "common/log.h"
|
||||
#include "common/memContext.h"
|
||||
#include "common/type/object.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Object type
|
||||
***********************************************************************************************************************************/
|
||||
struct IoClient
|
||||
{
|
||||
MemContext *memContext; // Mem context
|
||||
void *driver; // Driver object
|
||||
const IoClientInterface *interface; // Driver interface
|
||||
};
|
||||
|
||||
OBJECT_DEFINE_FREE(IO_CLIENT);
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
IoClient *
|
||||
ioClientNew(void *driver, const IoClientInterface *interface)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelTrace)
|
||||
FUNCTION_LOG_PARAM_P(VOID, driver);
|
||||
FUNCTION_LOG_PARAM(IO_CLIENT_INTERFACE, interface);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(driver != NULL);
|
||||
ASSERT(interface != NULL);
|
||||
ASSERT(interface->type != NULL);
|
||||
ASSERT(interface->open != NULL);
|
||||
ASSERT(interface->toLog != NULL);
|
||||
|
||||
IoClient *this = memNew(sizeof(IoClient));
|
||||
|
||||
*this = (IoClient)
|
||||
{
|
||||
.memContext = memContextCurrent(),
|
||||
.driver = driver,
|
||||
.interface = interface,
|
||||
};
|
||||
|
||||
FUNCTION_LOG_RETURN(IO_CLIENT, this);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
IoSession *
|
||||
ioClientOpen(IoClient *this)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelTrace);
|
||||
FUNCTION_LOG_PARAM(IO_CLIENT, this);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(this != NULL);
|
||||
|
||||
FUNCTION_LOG_RETURN(IO_SESSION, this->interface->open(this->driver));
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
String *
|
||||
ioClientToLog(const IoClient *this)
|
||||
{
|
||||
return strNewFmt("{type: %s, driver: %s}", strZ(*this->interface->type), strZ(this->interface->toLog(this->driver)));
|
||||
}
|
41
src/common/io/client.h
Normal file
41
src/common/io/client.h
Normal file
@ -0,0 +1,41 @@
|
||||
/***********************************************************************************************************************************
|
||||
Io Client Interface
|
||||
|
||||
Create sessions for protocol clients. For example, a TLS client can be created with tlsClientNew() and then new TLS sessions can be
|
||||
opened with ioClientOpen().
|
||||
***********************************************************************************************************************************/
|
||||
#ifndef COMMON_IO_CLIENT_H
|
||||
#define COMMON_IO_CLIENT_H
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Object type
|
||||
***********************************************************************************************************************************/
|
||||
#define IO_CLIENT_TYPE IoClient
|
||||
#define IO_CLIENT_PREFIX ioClient
|
||||
|
||||
typedef struct IoClient IoClient;
|
||||
|
||||
#include "common/io/session.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Functions
|
||||
***********************************************************************************************************************************/
|
||||
// Open session
|
||||
IoSession *ioClientOpen(IoClient *this);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Destructor
|
||||
***********************************************************************************************************************************/
|
||||
void ioClientFree(IoClient *this);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Macros for function logging
|
||||
***********************************************************************************************************************************/
|
||||
String *ioClientToLog(const IoClient *this);
|
||||
|
||||
#define FUNCTION_LOG_IO_CLIENT_TYPE \
|
||||
IoClient *
|
||||
#define FUNCTION_LOG_IO_CLIENT_FORMAT(value, buffer, bufferSize) \
|
||||
FUNCTION_LOG_STRING_OBJECT_FORMAT(value, ioClientToLog, buffer, bufferSize)
|
||||
|
||||
#endif
|
38
src/common/io/client.intern.h
Normal file
38
src/common/io/client.intern.h
Normal file
@ -0,0 +1,38 @@
|
||||
/***********************************************************************************************************************************
|
||||
Io Client Interface Internal
|
||||
***********************************************************************************************************************************/
|
||||
#ifndef COMMON_IO_CLIENT_INTERN_H
|
||||
#define COMMON_IO_CLIENT_INTERN_H
|
||||
|
||||
#include "common/io/client.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Interface
|
||||
***********************************************************************************************************************************/
|
||||
typedef struct IoClientInterface
|
||||
{
|
||||
// Type used to identify the client. This is stored as a pointer to a String pointer so it can be used with an existing String
|
||||
// constant (e.g. created with STRING_EXTERN()) without needing to be copied.
|
||||
const String *const *type;
|
||||
|
||||
// Open a session
|
||||
IoSession *(*open)(void *driver);
|
||||
|
||||
// Driver log function
|
||||
String *(*toLog)(const void *driver);
|
||||
} IoClientInterface;
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Constructors
|
||||
***********************************************************************************************************************************/
|
||||
IoClient *ioClientNew(void *driver, const IoClientInterface *interface);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Macros for function logging
|
||||
***********************************************************************************************************************************/
|
||||
#define FUNCTION_LOG_IO_CLIENT_INTERFACE_TYPE \
|
||||
IoClientInterface *
|
||||
#define FUNCTION_LOG_IO_CLIENT_INTERFACE_FORMAT(value, buffer, bufferSize) \
|
||||
objToLog(&value, "IoClientInterface", buffer, bufferSize)
|
||||
|
||||
#endif
|
@ -4,8 +4,8 @@ HTTP Client
|
||||
#include "build.auto.h"
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/io/client.h"
|
||||
#include "common/io/http/client.h"
|
||||
#include "common/io/tls/client.h"
|
||||
#include "common/log.h"
|
||||
#include "common/type/object.h"
|
||||
|
||||
@ -21,7 +21,7 @@ struct HttpClient
|
||||
{
|
||||
MemContext *memContext; // Mem context
|
||||
TimeMSec timeout; // Request timeout
|
||||
TlsClient *tlsClient; // TLS client
|
||||
IoClient *ioClient; // Io client (e.g. TLS or socket client)
|
||||
|
||||
List *sessionReuseList; // List of HTTP sessions that can be reused
|
||||
};
|
||||
@ -30,19 +30,14 @@ OBJECT_DEFINE_GET(Timeout, const, HTTP_CLIENT, TimeMSec, timeout);
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
HttpClient *
|
||||
httpClientNew(
|
||||
const String *host, unsigned int port, TimeMSec timeout, bool verifyPeer, const String *caFile, const String *caPath)
|
||||
httpClientNew(IoClient *ioClient, TimeMSec timeout)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug)
|
||||
FUNCTION_LOG_PARAM(STRING, host);
|
||||
FUNCTION_LOG_PARAM(UINT, port);
|
||||
FUNCTION_LOG_PARAM(IO_CLIENT, ioClient);
|
||||
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(host != NULL);
|
||||
ASSERT(ioClient != NULL);
|
||||
|
||||
HttpClient *this = NULL;
|
||||
|
||||
@ -54,7 +49,7 @@ httpClientNew(
|
||||
{
|
||||
.memContext = MEM_CONTEXT_NEW(),
|
||||
.timeout = timeout,
|
||||
.tlsClient = tlsClientNew(sckClientNew(host, port, timeout), timeout, verifyPeer, caFile, caPath),
|
||||
.ioClient = ioClient,
|
||||
.sessionReuseList = lstNewP(sizeof(HttpSession *)),
|
||||
};
|
||||
|
||||
@ -90,7 +85,7 @@ httpClientOpen(HttpClient *this)
|
||||
// Else create a new session
|
||||
else
|
||||
{
|
||||
result = httpSessionNew(this, tlsClientOpen(this->tlsClient));
|
||||
result = httpSessionNew(this, ioClientOpen(this->ioClient));
|
||||
httpClientStat.session++;
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ Object type
|
||||
|
||||
typedef struct HttpClient HttpClient;
|
||||
|
||||
#include "common/io/client.h"
|
||||
#include "common/io/http/session.h"
|
||||
#include "common/time.h"
|
||||
|
||||
@ -33,7 +34,7 @@ Statistics
|
||||
typedef struct HttpClientStat
|
||||
{
|
||||
uint64_t object; // Objects created
|
||||
uint64_t session; // TLS sessions created
|
||||
uint64_t session; // Sessions created
|
||||
uint64_t request; // Requests (i.e. calls to httpRequestNew())
|
||||
uint64_t retry; // Request retries
|
||||
uint64_t close; // Closes forced by server
|
||||
@ -44,8 +45,7 @@ extern HttpClientStat httpClientStat;
|
||||
/***********************************************************************************************************************************
|
||||
Constructors
|
||||
***********************************************************************************************************************************/
|
||||
HttpClient *httpClientNew(
|
||||
const String *host, unsigned int port, TimeMSec timeout, bool verifyPeer, const String *caFile, const String *caPath);
|
||||
HttpClient *httpClientNew(IoClient *ioClient, TimeMSec timeout);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Functions
|
||||
|
@ -10,7 +10,6 @@ HTTP Response
|
||||
#include "common/io/http/response.h"
|
||||
#include "common/io/io.h"
|
||||
#include "common/io/read.intern.h"
|
||||
#include "common/io/tls/client.h"
|
||||
#include "common/log.h"
|
||||
#include "common/type/object.h"
|
||||
#include "common/wait.h"
|
||||
|
@ -17,7 +17,7 @@ struct HttpSession
|
||||
{
|
||||
MemContext *memContext; // Mem context
|
||||
HttpClient *httpClient; // HTTP client
|
||||
TlsSession *tlsSession; // TLS session
|
||||
IoSession *ioSession; // IO session
|
||||
};
|
||||
|
||||
OBJECT_DEFINE_MOVE(HTTP_SESSION);
|
||||
@ -25,15 +25,15 @@ OBJECT_DEFINE_FREE(HTTP_SESSION);
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
HttpSession *
|
||||
httpSessionNew(HttpClient *httpClient, TlsSession *tlsSession)
|
||||
httpSessionNew(HttpClient *httpClient, IoSession *ioSession)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug)
|
||||
FUNCTION_LOG_PARAM(HTTP_CLIENT, httpClient);
|
||||
FUNCTION_LOG_PARAM(TLS_SESSION, tlsSession);
|
||||
FUNCTION_LOG_PARAM(IO_SESSION, ioSession);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(httpClient != NULL);
|
||||
ASSERT(tlsSession != NULL);
|
||||
ASSERT(ioSession != NULL);
|
||||
|
||||
HttpSession *this = NULL;
|
||||
|
||||
@ -45,7 +45,7 @@ httpSessionNew(HttpClient *httpClient, TlsSession *tlsSession)
|
||||
{
|
||||
.memContext = MEM_CONTEXT_NEW(),
|
||||
.httpClient = httpClient,
|
||||
.tlsSession = tlsSessionMove(tlsSession, memContextCurrent()),
|
||||
.ioSession = ioSessionMove(ioSession, memContextCurrent()),
|
||||
};
|
||||
}
|
||||
MEM_CONTEXT_NEW_END();
|
||||
@ -78,7 +78,7 @@ httpSessionIoRead(HttpSession *this)
|
||||
|
||||
ASSERT(this != NULL);
|
||||
|
||||
FUNCTION_TEST_RETURN(tlsSessionIoRead(this->tlsSession));
|
||||
FUNCTION_TEST_RETURN(ioSessionIoRead(this->ioSession));
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
@ -91,5 +91,5 @@ httpSessionIoWrite(HttpSession *this)
|
||||
|
||||
ASSERT(this != NULL);
|
||||
|
||||
FUNCTION_TEST_RETURN(tlsSessionIoWrite(this->tlsSession));
|
||||
FUNCTION_TEST_RETURN(ioSessionIoWrite(this->ioSession));
|
||||
}
|
||||
|
@ -16,13 +16,13 @@ typedef struct HttpSession HttpSession;
|
||||
|
||||
#include "common/io/read.h"
|
||||
#include "common/io/http/client.h"
|
||||
#include "common/io/tls/session.h"
|
||||
#include "common/io/session.h"
|
||||
#include "common/io/write.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Constructors
|
||||
***********************************************************************************************************************************/
|
||||
HttpSession *httpSessionNew(HttpClient *client, TlsSession *session);
|
||||
HttpSession *httpSessionNew(HttpClient *client, IoSession *session);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Functions
|
||||
|
100
src/common/io/session.c
Normal file
100
src/common/io/session.c
Normal file
@ -0,0 +1,100 @@
|
||||
/***********************************************************************************************************************************
|
||||
Io Session Interface
|
||||
***********************************************************************************************************************************/
|
||||
#include "build.auto.h"
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/io/session.intern.h"
|
||||
#include "common/log.h"
|
||||
#include "common/memContext.h"
|
||||
#include "common/type/object.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Object type
|
||||
***********************************************************************************************************************************/
|
||||
struct IoSession
|
||||
{
|
||||
MemContext *memContext; // Mem context
|
||||
void *driver; // Driver object
|
||||
const IoSessionInterface *interface; // Driver interface
|
||||
};
|
||||
|
||||
OBJECT_DEFINE_MOVE(IO_SESSION);
|
||||
OBJECT_DEFINE_FREE(IO_SESSION);
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
IoSession *
|
||||
ioSessionNew(void *driver, const IoSessionInterface *interface)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelTrace)
|
||||
FUNCTION_LOG_PARAM_P(VOID, driver);
|
||||
FUNCTION_LOG_PARAM(IO_SESSION_INTERFACE, interface);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(driver != NULL);
|
||||
ASSERT(interface != NULL);
|
||||
ASSERT(interface->type != NULL);
|
||||
ASSERT(interface->close != NULL);
|
||||
ASSERT(interface->ioRead != NULL);
|
||||
ASSERT(interface->ioWrite != NULL);
|
||||
ASSERT(interface->toLog != NULL);
|
||||
|
||||
IoSession *this = memNew(sizeof(IoSession));
|
||||
|
||||
*this = (IoSession)
|
||||
{
|
||||
.memContext = memContextCurrent(),
|
||||
.driver = driver,
|
||||
.interface = interface,
|
||||
};
|
||||
|
||||
FUNCTION_LOG_RETURN(IO_SESSION, this);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
void
|
||||
ioSessionClose(IoSession *this)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelTrace);
|
||||
FUNCTION_LOG_PARAM(IO_SESSION, this);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(this != NULL);
|
||||
|
||||
this->interface->close(this->driver);
|
||||
|
||||
FUNCTION_LOG_RETURN_VOID();
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
IoRead *
|
||||
ioSessionIoRead(IoSession *this)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(IO_SESSION, this);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(this != NULL);
|
||||
|
||||
FUNCTION_TEST_RETURN(this->interface->ioRead(this->driver));
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
IoWrite *
|
||||
ioSessionIoWrite(IoSession *this)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(IO_SESSION, this);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(this != NULL);
|
||||
|
||||
FUNCTION_TEST_RETURN(this->interface->ioWrite(this->driver));
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
String *
|
||||
ioSessionToLog(const IoSession *this)
|
||||
{
|
||||
return strNewFmt("{type: %s, driver: %s}", strZ(*this->interface->type), strZ(this->interface->toLog(this->driver)));
|
||||
}
|
54
src/common/io/session.h
Normal file
54
src/common/io/session.h
Normal file
@ -0,0 +1,54 @@
|
||||
/***********************************************************************************************************************************
|
||||
Io Session Interface
|
||||
|
||||
Provides access to IoRead and IoWrite interfaces for interacting with the session returned by ioClientOpen(). Sessions should always
|
||||
be closed when work with them is done but they also contain destructors to do cleanup if there is an error.
|
||||
***********************************************************************************************************************************/
|
||||
#ifndef COMMON_IO_SESSION_H
|
||||
#define COMMON_IO_SESSION_H
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Object type
|
||||
***********************************************************************************************************************************/
|
||||
#define IO_SESSION_TYPE IoSession
|
||||
#define IO_SESSION_PREFIX ioSession
|
||||
|
||||
typedef struct IoSession IoSession;
|
||||
|
||||
#include "common/io/read.h"
|
||||
#include "common/io/write.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Functions
|
||||
***********************************************************************************************************************************/
|
||||
// Close the session
|
||||
void ioSessionClose(IoSession *this);
|
||||
|
||||
// Move to a new parent mem context
|
||||
IoSession *ioSessionMove(IoSession *this, MemContext *parentNew);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Getters/Setters
|
||||
***********************************************************************************************************************************/
|
||||
// Read interface
|
||||
IoRead *ioSessionIoRead(IoSession *this);
|
||||
|
||||
// Write interface
|
||||
IoWrite *ioSessionIoWrite(IoSession *this);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Destructor
|
||||
***********************************************************************************************************************************/
|
||||
void ioSessionFree(IoSession *this);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Macros for function logging
|
||||
***********************************************************************************************************************************/
|
||||
String *ioSessionToLog(const IoSession *this);
|
||||
|
||||
#define FUNCTION_LOG_IO_SESSION_TYPE \
|
||||
IoSession *
|
||||
#define FUNCTION_LOG_IO_SESSION_FORMAT(value, buffer, bufferSize) \
|
||||
FUNCTION_LOG_STRING_OBJECT_FORMAT(value, ioSessionToLog, buffer, bufferSize)
|
||||
|
||||
#endif
|
44
src/common/io/session.intern.h
Normal file
44
src/common/io/session.intern.h
Normal file
@ -0,0 +1,44 @@
|
||||
/***********************************************************************************************************************************
|
||||
Io Session Interface Internal
|
||||
***********************************************************************************************************************************/
|
||||
#ifndef COMMON_IO_SESSION_INTERN_H
|
||||
#define COMMON_IO_SESSION_INTERN_H
|
||||
|
||||
#include "common/io/session.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Interface
|
||||
***********************************************************************************************************************************/
|
||||
typedef struct IoSessionInterface
|
||||
{
|
||||
// Type used to identify the session. This is stored as a pointer to a String pointer so it can be used with an existing String
|
||||
// constant (e.g. created with STRING_EXTERN()) without needing to be copied.
|
||||
const String *const *type;
|
||||
|
||||
// Close the session
|
||||
void (*close)(void *driver);
|
||||
|
||||
// IoRead interface for the session
|
||||
IoRead *(*ioRead)(void *driver);
|
||||
|
||||
// IoWrite interface for the session
|
||||
IoWrite *(*ioWrite)(void *driver);
|
||||
|
||||
// Driver log function
|
||||
String *(*toLog)(const void *driver);
|
||||
} IoSessionInterface;
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Constructors
|
||||
***********************************************************************************************************************************/
|
||||
IoSession *ioSessionNew(void *driver, const IoSessionInterface *interface);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Macros for function logging
|
||||
***********************************************************************************************************************************/
|
||||
#define FUNCTION_LOG_IO_SESSION_INTERFACE_TYPE \
|
||||
IoSessionInterface *
|
||||
#define FUNCTION_LOG_IO_SESSION_INTERFACE_FORMAT(value, buffer, bufferSize) \
|
||||
objToLog(&value, "IoSessionInterface", buffer, bufferSize)
|
||||
|
||||
#endif
|
@ -11,13 +11,19 @@ TLS Client
|
||||
#include "common/crypto/common.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/log.h"
|
||||
#include "common/io/client.intern.h"
|
||||
#include "common/io/io.h"
|
||||
#include "common/io/tls/client.h"
|
||||
#include "common/io/tls/session.intern.h"
|
||||
#include "common/io/tls/session.h"
|
||||
#include "common/memContext.h"
|
||||
#include "common/type/object.h"
|
||||
#include "common/wait.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Io client type
|
||||
***********************************************************************************************************************************/
|
||||
STRING_EXTERN(IO_CLIENT_TLS_TYPE_STR, IO_CLIENT_TLS_TYPE);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Statistics
|
||||
***********************************************************************************************************************************/
|
||||
@ -26,7 +32,10 @@ static TlsClientStat tlsClientStatLocal;
|
||||
/***********************************************************************************************************************************
|
||||
Object type
|
||||
***********************************************************************************************************************************/
|
||||
struct TlsClient
|
||||
#define TLS_CLIENT_TYPE TlsClient
|
||||
#define TLS_CLIENT_PREFIX tlsClient
|
||||
|
||||
typedef struct TlsClient
|
||||
{
|
||||
MemContext *memContext; // Mem context
|
||||
TimeMSec timeout; // Timeout for any i/o operation (connect, read, etc.)
|
||||
@ -34,9 +43,26 @@ struct TlsClient
|
||||
SocketClient *socketClient; // Socket client
|
||||
|
||||
SSL_CTX *context; // TLS context
|
||||
};
|
||||
} TlsClient;
|
||||
|
||||
OBJECT_DEFINE_FREE(TLS_CLIENT);
|
||||
/***********************************************************************************************************************************
|
||||
Macros for function logging
|
||||
***********************************************************************************************************************************/
|
||||
static String *
|
||||
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,
|
||||
cvtBoolToConstZ(this->verifyPeer));
|
||||
}
|
||||
|
||||
#define FUNCTION_LOG_TLS_CLIENT_TYPE \
|
||||
TlsClient *
|
||||
#define FUNCTION_LOG_TLS_CLIENT_FORMAT(value, buffer, bufferSize) \
|
||||
FUNCTION_LOG_STRING_OBJECT_FORMAT(value, tlsClientToLog, buffer, bufferSize)
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Free connection
|
||||
@ -47,78 +73,6 @@ OBJECT_DEFINE_FREE_RESOURCE_BEGIN(TLS_CLIENT, LOG, logLevelTrace)
|
||||
}
|
||||
OBJECT_DEFINE_FREE_RESOURCE_END(LOG);
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
TlsClient *
|
||||
tlsClientNew(SocketClient *socket, TimeMSec timeout, bool verifyPeer, const String *caFile, const String *caPath)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug)
|
||||
FUNCTION_LOG_PARAM(SOCKET_CLIENT, socket);
|
||||
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);
|
||||
|
||||
TlsClient *this = NULL;
|
||||
|
||||
MEM_CONTEXT_NEW_BEGIN("TlsClient")
|
||||
{
|
||||
this = memNew(sizeof(TlsClient));
|
||||
|
||||
*this = (TlsClient)
|
||||
{
|
||||
.memContext = MEM_CONTEXT_NEW(),
|
||||
.socketClient = sckClientMove(socket, MEM_CONTEXT_NEW()),
|
||||
.timeout = timeout,
|
||||
.verifyPeer = verifyPeer,
|
||||
};
|
||||
|
||||
// Setup TLS context
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
cryptoInit();
|
||||
|
||||
// Select the TLS method to use. To maintain compatibility with older versions of OpenSSL we need to use an SSL method,
|
||||
// but SSL versions will be excluded in SSL_CTX_set_options().
|
||||
const SSL_METHOD *method = SSLv23_method();
|
||||
cryptoError(method == NULL, "unable to load TLS method");
|
||||
|
||||
// Create the TLS context
|
||||
this->context = SSL_CTX_new(method);
|
||||
cryptoError(this->context == NULL, "unable to create TLS context");
|
||||
|
||||
memContextCallbackSet(this->memContext, tlsClientFreeResource, this);
|
||||
|
||||
// Exclude SSL versions to only allow TLS and also disable compression
|
||||
SSL_CTX_set_options(this->context, (long)(SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION));
|
||||
|
||||
// Disable auto-retry to prevent SSL_read() from hanging
|
||||
SSL_CTX_clear_mode(this->context, SSL_MODE_AUTO_RETRY);
|
||||
|
||||
// Set location of CA certificates if the server certificate will be verified
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
if (this->verifyPeer)
|
||||
{
|
||||
// If the user specified a location
|
||||
if (caFile != NULL || caPath != NULL) // {vm_covered}
|
||||
{
|
||||
cryptoError( // {vm_covered}
|
||||
SSL_CTX_load_verify_locations(this->context, strZNull(caFile), strZNull(caPath)) != 1, // {vm_covered}
|
||||
"unable to set user-defined CA certificate location"); // {vm_covered}
|
||||
}
|
||||
// Else use the defaults
|
||||
else
|
||||
cryptoError(SSL_CTX_set_default_verify_paths(this->context) != 1, "unable to set default CA certificate location");
|
||||
}
|
||||
|
||||
tlsClientStatLocal.object++;
|
||||
}
|
||||
MEM_CONTEXT_NEW_END();
|
||||
|
||||
FUNCTION_LOG_RETURN(TLS_CLIENT, this);
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Convert an ASN1 string used in certificates to a String
|
||||
***********************************************************************************************************************************/
|
||||
@ -259,16 +213,18 @@ tlsClientHostVerify(const String *host, X509 *certificate)
|
||||
/***********************************************************************************************************************************
|
||||
Open connection if this is a new client or if the connection was closed by the server
|
||||
***********************************************************************************************************************************/
|
||||
TlsSession *
|
||||
tlsClientOpen(TlsClient *this)
|
||||
static IoSession *
|
||||
tlsClientOpen(THIS_VOID)
|
||||
{
|
||||
THIS(TlsClient);
|
||||
|
||||
FUNCTION_LOG_BEGIN(logLevelTrace)
|
||||
FUNCTION_LOG_PARAM(TLS_CLIENT, this);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(this != NULL);
|
||||
|
||||
TlsSession *result = NULL;
|
||||
IoSession *result = NULL;
|
||||
SSL *session = NULL;
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
@ -317,7 +273,7 @@ tlsClientOpen(TlsClient *this)
|
||||
}
|
||||
while (retry);
|
||||
|
||||
tlsSessionMove(result, memContextPrior());
|
||||
ioSessionMove(result, memContextPrior());
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
|
||||
@ -351,7 +307,92 @@ tlsClientOpen(TlsClient *this)
|
||||
}
|
||||
}
|
||||
|
||||
FUNCTION_LOG_RETURN(TLS_SESSION, result);
|
||||
FUNCTION_LOG_RETURN(IO_SESSION, result);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
static const IoClientInterface tlsClientInterface =
|
||||
{
|
||||
.type = &IO_CLIENT_TLS_TYPE_STR,
|
||||
.open = tlsClientOpen,
|
||||
.toLog = tlsClientToLog,
|
||||
};
|
||||
|
||||
IoClient *
|
||||
tlsClientNew(SocketClient *socket, TimeMSec timeout, bool verifyPeer, const String *caFile, const String *caPath)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug)
|
||||
FUNCTION_LOG_PARAM(SOCKET_CLIENT, socket);
|
||||
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);
|
||||
|
||||
IoClient *this = NULL;
|
||||
|
||||
MEM_CONTEXT_NEW_BEGIN("TlsClient")
|
||||
{
|
||||
TlsClient *driver = memNew(sizeof(TlsClient));
|
||||
|
||||
*driver = (TlsClient)
|
||||
{
|
||||
.memContext = MEM_CONTEXT_NEW(),
|
||||
.socketClient = sckClientMove(socket, MEM_CONTEXT_NEW()),
|
||||
.timeout = timeout,
|
||||
.verifyPeer = verifyPeer,
|
||||
};
|
||||
|
||||
// Setup TLS context
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
cryptoInit();
|
||||
|
||||
// Select the TLS method to use. To maintain compatibility with older versions of OpenSSL we need to use an SSL method,
|
||||
// but SSL versions will be excluded in SSL_CTX_set_options().
|
||||
const SSL_METHOD *method = SSLv23_method();
|
||||
cryptoError(method == NULL, "unable to load TLS method");
|
||||
|
||||
// Create the TLS context
|
||||
driver->context = SSL_CTX_new(method);
|
||||
cryptoError(driver->context == NULL, "unable to create TLS context");
|
||||
|
||||
memContextCallbackSet(driver->memContext, tlsClientFreeResource, driver);
|
||||
|
||||
// Exclude SSL versions to only allow TLS and also disable compression
|
||||
SSL_CTX_set_options(driver->context, (long)(SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION));
|
||||
|
||||
// Disable auto-retry to prevent SSL_read() from hanging
|
||||
SSL_CTX_clear_mode(driver->context, SSL_MODE_AUTO_RETRY);
|
||||
|
||||
// Set location of CA certificates if the server certificate will be verified
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
if (driver->verifyPeer)
|
||||
{
|
||||
// If the user specified a location
|
||||
if (caFile != NULL || caPath != NULL) // {vm_covered}
|
||||
{
|
||||
cryptoError( // {vm_covered}
|
||||
SSL_CTX_load_verify_locations(driver->context, strZNull(caFile), strZNull(caPath)) != 1, // {vm_covered}
|
||||
"unable to set user-defined CA certificate location"); // {vm_covered}
|
||||
}
|
||||
// Else use the defaults
|
||||
else
|
||||
{
|
||||
cryptoError(
|
||||
SSL_CTX_set_default_verify_paths(driver->context) != 1, "unable to set default CA certificate location");
|
||||
}
|
||||
}
|
||||
|
||||
tlsClientStatLocal.object++;
|
||||
|
||||
// Create client interface
|
||||
this = ioClientNew(driver, &tlsClientInterface);
|
||||
}
|
||||
MEM_CONTEXT_NEW_END();
|
||||
|
||||
FUNCTION_LOG_RETURN(IO_CLIENT, this);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
|
@ -4,21 +4,19 @@ TLS Client
|
||||
A simple, secure TLS client intended to allow access to services that are exposed via HTTPS. We call it TLS instead of SSL because
|
||||
SSL methods are disabled so only TLS connections are allowed.
|
||||
|
||||
This object is intended to be used for multiple TLS sessions so tlsClientOpen() can be called each time a new session is needed.
|
||||
This object is intended to be used for multiple TLS sessions so ioClientOpen() can be called each time a new session is needed.
|
||||
***********************************************************************************************************************************/
|
||||
#ifndef COMMON_IO_TLS_CLIENT_H
|
||||
#define COMMON_IO_TLS_CLIENT_H
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Object type
|
||||
***********************************************************************************************************************************/
|
||||
#define TLS_CLIENT_TYPE TlsClient
|
||||
#define TLS_CLIENT_PREFIX tlsClient
|
||||
|
||||
typedef struct TlsClient TlsClient;
|
||||
|
||||
#include "common/io/client.h"
|
||||
#include "common/io/socket/client.h"
|
||||
#include "common/io/tls/session.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Io client type
|
||||
***********************************************************************************************************************************/
|
||||
#define IO_CLIENT_TLS_TYPE "tls"
|
||||
STRING_DECLARE(IO_CLIENT_TLS_TYPE_STR);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Statistics
|
||||
@ -33,28 +31,12 @@ typedef struct TlsClientStat
|
||||
/***********************************************************************************************************************************
|
||||
Constructors
|
||||
***********************************************************************************************************************************/
|
||||
TlsClient *tlsClientNew(SocketClient *socket, TimeMSec timeout, bool verifyPeer, const String *caFile, const String *caPath);
|
||||
IoClient *tlsClientNew(SocketClient *socket, TimeMSec timeout, bool verifyPeer, const String *caFile, const String *caPath);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Functions
|
||||
***********************************************************************************************************************************/
|
||||
// Open tls session
|
||||
TlsSession *tlsClientOpen(TlsClient *this);
|
||||
|
||||
// Statistics as a formatted string
|
||||
String *tlsClientStatStr(void);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Destructor
|
||||
***********************************************************************************************************************************/
|
||||
void tlsClientFree(TlsClient *this);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Macros for function logging
|
||||
***********************************************************************************************************************************/
|
||||
#define FUNCTION_LOG_TLS_CLIENT_TYPE \
|
||||
TlsClient *
|
||||
#define FUNCTION_LOG_TLS_CLIENT_FORMAT(value, buffer, bufferSize) \
|
||||
objToLog(value, "TlsClient", buffer, bufferSize)
|
||||
|
||||
#endif
|
||||
|
@ -9,7 +9,10 @@ TLS Session
|
||||
#include "common/debug.h"
|
||||
#include "common/io/io.h"
|
||||
#include "common/io/read.intern.h"
|
||||
#include "common/io/tls/session.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"
|
||||
#include "common/log.h"
|
||||
#include "common/memContext.h"
|
||||
@ -18,23 +21,39 @@ TLS Session
|
||||
/***********************************************************************************************************************************
|
||||
Object type
|
||||
***********************************************************************************************************************************/
|
||||
struct TlsSession
|
||||
#define TLS_SESSION_TYPE TlsSession
|
||||
#define TLS_SESSION_PREFIX tlsSession
|
||||
|
||||
typedef struct TlsSession
|
||||
{
|
||||
MemContext *memContext; // Mem context
|
||||
SocketSession *socketSession; // Socket session
|
||||
SSL *session; // TLS session on the socket
|
||||
TimeMSec timeout; // Timeout for any i/o operation (connect, read, etc.)
|
||||
bool shutdownOnClose; // Shutdown the TLS connection when closing the socket
|
||||
|
||||
IoRead *read; // Read interface
|
||||
IoWrite *write; // Write interface
|
||||
};
|
||||
} TlsSession;
|
||||
|
||||
OBJECT_DEFINE_MOVE(TLS_SESSION);
|
||||
/***********************************************************************************************************************************
|
||||
Macros for function logging
|
||||
***********************************************************************************************************************************/
|
||||
static String *
|
||||
tlsSessionToLog(const THIS_VOID)
|
||||
{
|
||||
THIS(const TlsSession);
|
||||
|
||||
OBJECT_DEFINE_GET(IoRead, , TLS_SESSION, IoRead *, read);
|
||||
OBJECT_DEFINE_GET(IoWrite, , TLS_SESSION, IoWrite *, write);
|
||||
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));
|
||||
}
|
||||
|
||||
OBJECT_DEFINE_FREE(TLS_SESSION);
|
||||
#define FUNCTION_LOG_TLS_SESSION_TYPE \
|
||||
TlsSession *
|
||||
#define FUNCTION_LOG_TLS_SESSION_FORMAT(value, buffer, bufferSize) \
|
||||
FUNCTION_LOG_STRING_OBJECT_FORMAT(value, tlsSessionToLog, buffer, bufferSize)
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Free connection
|
||||
@ -46,12 +65,13 @@ OBJECT_DEFINE_FREE_RESOURCE_BEGIN(TLS_SESSION, LOG, logLevelTrace)
|
||||
OBJECT_DEFINE_FREE_RESOURCE_END(LOG);
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
void
|
||||
tlsSessionClose(TlsSession *this, bool shutdown)
|
||||
static void
|
||||
tlsSessionClose(THIS_VOID)
|
||||
{
|
||||
THIS(TlsSession);
|
||||
|
||||
FUNCTION_LOG_BEGIN(logLevelTrace);
|
||||
FUNCTION_LOG_PARAM(TLS_SESSION, this);
|
||||
FUNCTION_LOG_PARAM(BOOL, shutdown);
|
||||
FUNCTION_LOG_END();
|
||||
|
||||
ASSERT(this != NULL);
|
||||
@ -60,7 +80,7 @@ tlsSessionClose(TlsSession *this, bool shutdown)
|
||||
if (this->session != NULL)
|
||||
{
|
||||
// Shutdown on request
|
||||
if (shutdown)
|
||||
if (this->shutdownOnClose)
|
||||
SSL_shutdown(this->session);
|
||||
|
||||
// Free the socket session
|
||||
@ -109,7 +129,8 @@ tlsSessionResultProcess(TlsSession *this, int errorTls, long unsigned int errorT
|
||||
if (!closeOk)
|
||||
THROW(ProtocolError, "unexpected TLS eof");
|
||||
|
||||
tlsSessionClose(this, false);
|
||||
this->shutdownOnClose = false;
|
||||
tlsSessionClose(this);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -272,7 +293,46 @@ tlsSessionEof(THIS_VOID)
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
TlsSession *
|
||||
static IoRead *
|
||||
tlsSessionIoRead(THIS_VOID)
|
||||
{
|
||||
THIS(TlsSession);
|
||||
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(TLS_SESSION, this);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(this != NULL);
|
||||
|
||||
FUNCTION_TEST_RETURN(this->read);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
static IoWrite *
|
||||
tlsSessionIoWrite(THIS_VOID)
|
||||
{
|
||||
THIS(TlsSession);
|
||||
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(TLS_SESSION, this);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(this != NULL);
|
||||
|
||||
FUNCTION_TEST_RETURN(this->write);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
static const IoSessionInterface tlsSessionInterface =
|
||||
{
|
||||
.type = &IO_CLIENT_TLS_TYPE_STR,
|
||||
.close = tlsSessionClose,
|
||||
.ioRead = tlsSessionIoRead,
|
||||
.ioWrite = tlsSessionIoWrite,
|
||||
.toLog = tlsSessionToLog,
|
||||
};
|
||||
|
||||
IoSession *
|
||||
tlsSessionNew(SSL *session, SocketSession *socketSession, TimeMSec timeout)
|
||||
{
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug)
|
||||
@ -284,26 +344,27 @@ tlsSessionNew(SSL *session, SocketSession *socketSession, TimeMSec timeout)
|
||||
ASSERT(session != NULL);
|
||||
ASSERT(socketSession != NULL);
|
||||
|
||||
TlsSession *this = NULL;
|
||||
IoSession *this = NULL;
|
||||
|
||||
MEM_CONTEXT_NEW_BEGIN("TlsSession")
|
||||
{
|
||||
this = memNew(sizeof(TlsSession));
|
||||
TlsSession *driver = memNew(sizeof(TlsSession));
|
||||
|
||||
*this = (TlsSession)
|
||||
*driver = (TlsSession)
|
||||
{
|
||||
.memContext = MEM_CONTEXT_NEW(),
|
||||
.session = session,
|
||||
.socketSession = sckSessionMove(socketSession, MEM_CONTEXT_NEW()),
|
||||
.timeout = timeout,
|
||||
.shutdownOnClose = true,
|
||||
};
|
||||
|
||||
// Ensure session is freed
|
||||
memContextCallbackSet(this->memContext, tlsSessionFreeResource, this);
|
||||
memContextCallbackSet(driver->memContext, tlsSessionFreeResource, driver);
|
||||
|
||||
// Assign socket to TLS session
|
||||
cryptoError(
|
||||
SSL_set_fd(this->session, sckSessionFd(this->socketSession)) != 1, "unable to add socket to TLS session");
|
||||
SSL_set_fd(driver->session, sckSessionFd(driver->socketSession)) != 1, "unable to add socket to TLS session");
|
||||
|
||||
// Negotiate TLS session. The error queue must be cleared before this operation.
|
||||
int result = 0;
|
||||
@ -312,19 +373,22 @@ tlsSessionNew(SSL *session, SocketSession *socketSession, TimeMSec timeout)
|
||||
{
|
||||
ERR_clear_error();
|
||||
|
||||
if (sckSessionType(this->socketSession) == sckSessionTypeClient)
|
||||
result = tlsSessionResult(this, SSL_connect(this->session), false);
|
||||
if (sckSessionType(driver->socketSession) == sckSessionTypeClient)
|
||||
result = tlsSessionResult(driver, SSL_connect(driver->session), false);
|
||||
else
|
||||
result = tlsSessionResult(this, SSL_accept(this->session), false);
|
||||
result = tlsSessionResult(driver, SSL_accept(driver->session), false);
|
||||
}
|
||||
|
||||
// Create read and write interfaces
|
||||
this->write = ioWriteNewP(this, .write = tlsSessionWrite);
|
||||
ioWriteOpen(this->write);
|
||||
this->read = ioReadNewP(this, .block = true, .eof = tlsSessionEof, .read = tlsSessionRead);
|
||||
ioReadOpen(this->read);
|
||||
driver->write = ioWriteNewP(driver, .write = tlsSessionWrite);
|
||||
ioWriteOpen(driver->write);
|
||||
driver->read = ioReadNewP(driver, .block = true, .eof = tlsSessionEof, .read = tlsSessionRead);
|
||||
ioReadOpen(driver->read);
|
||||
|
||||
// Create session interface
|
||||
this = ioSessionNew(driver, &tlsSessionInterface);
|
||||
}
|
||||
MEM_CONTEXT_NEW_END();
|
||||
|
||||
FUNCTION_LOG_RETURN(TLS_SESSION, this);
|
||||
FUNCTION_LOG_RETURN(IO_SESSION, this);
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
/***********************************************************************************************************************************
|
||||
TLS Session
|
||||
|
||||
TLS sessions are created by calling tlsClientOpen().
|
||||
TLS sessions are created by calling ioClientOpen().
|
||||
|
||||
TLS sessions are generally reused so the user must be prepared to retry their transaction on a read/write error if the server closes
|
||||
the session before it is reused. If this behavior is not desirable then tlsSessionFree()/tlsClientOpen() can be called to get a new
|
||||
the session before it is reused. If this behavior is not desirable then ioSessionFree()/ioClientOpen() can be called to get a new
|
||||
session.
|
||||
***********************************************************************************************************************************/
|
||||
#ifndef COMMON_IO_TLS_SESSION_H
|
||||
@ -13,45 +13,16 @@ session.
|
||||
/***********************************************************************************************************************************
|
||||
Object type
|
||||
***********************************************************************************************************************************/
|
||||
#define TLS_SESSION_TYPE TlsSession
|
||||
#define TLS_SESSION_PREFIX tlsSession
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
typedef struct TlsSession TlsSession;
|
||||
|
||||
#include "common/io/read.h"
|
||||
#include "common/io/session.h"
|
||||
#include "common/io/socket/session.h"
|
||||
#include "common/io/write.h"
|
||||
#include "common/time.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Functions
|
||||
Constructors
|
||||
***********************************************************************************************************************************/
|
||||
// Close the session. Shutdown should not be attempted after an error, which means the client never has the oppottunity to do a
|
||||
// shutdown since the connection is held open until it is disconnected by the server.
|
||||
void tlsSessionClose(TlsSession *this, bool shutdown);
|
||||
|
||||
// Move to a new parent mem context
|
||||
TlsSession *tlsSessionMove(TlsSession *this, MemContext *parentNew);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Getters/Setters
|
||||
***********************************************************************************************************************************/
|
||||
// Read interface
|
||||
IoRead *tlsSessionIoRead(TlsSession *this);
|
||||
|
||||
// Write interface
|
||||
IoWrite *tlsSessionIoWrite(TlsSession *this);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Destructor
|
||||
***********************************************************************************************************************************/
|
||||
void tlsSessionFree(TlsSession *this);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Macros for function logging
|
||||
***********************************************************************************************************************************/
|
||||
#define FUNCTION_LOG_TLS_SESSION_TYPE \
|
||||
TlsSession *
|
||||
#define FUNCTION_LOG_TLS_SESSION_FORMAT(value, buffer, bufferSize) \
|
||||
objToLog(value, "TlsSession", buffer, bufferSize)
|
||||
// Only called by TLS client/server code
|
||||
IoSession *tlsSessionNew(SSL *session, SocketSession *socketSession, TimeMSec timeout);
|
||||
|
||||
#endif
|
||||
|
@ -1,17 +0,0 @@
|
||||
/***********************************************************************************************************************************
|
||||
TLS Session Internal
|
||||
***********************************************************************************************************************************/
|
||||
#ifndef COMMON_IO_TLS_SESSION_INTERN_H
|
||||
#define COMMON_IO_TLS_SESSION_INTERN_H
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include "common/io/tls/session.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Constructors
|
||||
***********************************************************************************************************************************/
|
||||
// Only called by TLS client/server code
|
||||
TlsSession *tlsSessionNew(SSL *session, SocketSession *socketSession, 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/tls/client.h"
|
||||
#include "common/log.h"
|
||||
#include "common/memContext.h"
|
||||
#include "common/regExp.h"
|
||||
@ -739,7 +740,8 @@ storageAzureNew(
|
||||
driver->sasKey = httpQueryNewStr(key);
|
||||
|
||||
// Create the http client used to service requests
|
||||
driver->httpClient = httpClientNew(driver->host, port, timeout, verifyPeer, caFile, caPath);
|
||||
driver->httpClient = httpClientNew(
|
||||
tlsClientNew(sckClientNew(driver->host, port, timeout), 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/tls/client.h"
|
||||
#include "common/log.h"
|
||||
#include "common/memContext.h"
|
||||
#include "common/regExp.h"
|
||||
@ -851,7 +852,10 @@ storageS3New(
|
||||
};
|
||||
|
||||
// Create the HTTP client used to service requests
|
||||
driver->httpClient = httpClientNew(host == NULL ? driver->bucketEndpoint : host, port, timeout, verifyPeer, caFile, caPath);
|
||||
driver->httpClient = httpClientNew(
|
||||
tlsClientNew(
|
||||
sckClientNew(host == NULL ? driver->bucketEndpoint : host, port, timeout), timeout, verifyPeer, caFile, caPath),
|
||||
timeout);
|
||||
|
||||
// Create list of redacted headers
|
||||
driver->headerRedactList = strLstNew();
|
||||
|
@ -915,10 +915,6 @@ src/common/io/tls/session.h:
|
||||
class: core
|
||||
type: c/h
|
||||
|
||||
src/common/io/tls/session.intern.h:
|
||||
class: core
|
||||
type: c/h
|
||||
|
||||
src/common/io/write.c:
|
||||
class: core
|
||||
type: c
|
||||
|
@ -242,6 +242,8 @@ unit:
|
||||
total: 5
|
||||
|
||||
coverage:
|
||||
common/io/client: full
|
||||
common/io/session: full
|
||||
common/io/tls/client: full
|
||||
common/io/tls/session: full
|
||||
common/io/socket/client: full
|
||||
|
@ -12,7 +12,7 @@ TLS Test Harness
|
||||
#include "common/crypto/common.h"
|
||||
#include "common/error.h"
|
||||
#include "common/io/socket/session.h"
|
||||
#include "common/io/tls/session.intern.h"
|
||||
#include "common/io/tls/session.h"
|
||||
#include "common/log.h"
|
||||
#include "common/type/buffer.h"
|
||||
#include "common/type/json.h"
|
||||
@ -271,7 +271,7 @@ void hrnTlsServerRunParam(IoRead *read, const String *certificate, const String
|
||||
THROW_SYS_ERROR(AssertError, "unable to listen on socket");
|
||||
|
||||
// Loop until no more commands
|
||||
TlsSession *serverSession = NULL;
|
||||
IoSession *serverSession = NULL;
|
||||
bool done = false;
|
||||
|
||||
do
|
||||
@ -283,8 +283,7 @@ void hrnTlsServerRunParam(IoRead *read, const String *certificate, const String
|
||||
{
|
||||
case hrnTlsCmdAbort:
|
||||
{
|
||||
tlsSessionClose(serverSession, false);
|
||||
tlsSessionFree(serverSession);
|
||||
ioSessionFree(serverSession);
|
||||
serverSession = NULL;
|
||||
|
||||
break;
|
||||
@ -313,8 +312,8 @@ void hrnTlsServerRunParam(IoRead *read, const String *certificate, const String
|
||||
if (serverSession == NULL)
|
||||
THROW(AssertError, "TLS session is already closed");
|
||||
|
||||
tlsSessionClose(serverSession, true);
|
||||
tlsSessionFree(serverSession);
|
||||
ioSessionClose(serverSession);
|
||||
ioSessionFree(serverSession);
|
||||
serverSession = NULL;
|
||||
|
||||
break;
|
||||
@ -332,7 +331,7 @@ void hrnTlsServerRunParam(IoRead *read, const String *certificate, const String
|
||||
const String *expected = varStr(data);
|
||||
Buffer *buffer = bufNew(strSize(expected));
|
||||
|
||||
ioRead(tlsSessionIoRead(serverSession), buffer);
|
||||
ioRead(ioSessionIoRead(serverSession), buffer);
|
||||
|
||||
// Treat any ? characters as wildcards so variable elements (e.g. auth hashes) can be ignored
|
||||
String *actual = strNewBuf(buffer);
|
||||
@ -352,8 +351,8 @@ void hrnTlsServerRunParam(IoRead *read, const String *certificate, const String
|
||||
|
||||
case hrnTlsCmdReply:
|
||||
{
|
||||
ioWrite(tlsSessionIoWrite(serverSession), BUFSTR(varStr(data)));
|
||||
ioWriteFlush(tlsSessionIoWrite(serverSession));
|
||||
ioWrite(ioSessionIoWrite(serverSession), BUFSTR(varStr(data)));
|
||||
ioWriteFlush(ioSessionIoWrite(serverSession));
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ testRun(void)
|
||||
|
||||
cfgOptionSet(cfgOptLogTimestamp, cfgSourceParam, varNewBool(true));
|
||||
|
||||
httpClientNew(strNew("BOGUS"), 443, 1000, true, NULL, NULL);
|
||||
httpClientNew(tlsClientNew(sckClientNew(STRDEF("BOGUS"), 443, 1000), 1000, true, NULL, NULL), 1000);
|
||||
|
||||
harnessLogLevelSet(logLevelDetail);
|
||||
|
||||
|
@ -5,6 +5,7 @@ Test HTTP
|
||||
|
||||
#include "common/io/fdRead.h"
|
||||
#include "common/io/fdWrite.h"
|
||||
#include "common/io/tls/client.h"
|
||||
|
||||
#include "common/harnessFork.h"
|
||||
#include "common/harnessTls.h"
|
||||
@ -176,7 +177,9 @@ testRun(void)
|
||||
TEST_RESULT_STR(httpClientStatStr(), NULL, "no stats yet");
|
||||
|
||||
TEST_ASSIGN(
|
||||
client, httpClientNew(strNew("localhost"), hrnTlsServerPort(), 500, testContainer(), NULL, NULL),
|
||||
client,
|
||||
httpClientNew(
|
||||
tlsClientNew(sckClientNew(strNew("localhost"), hrnTlsServerPort(), 500), 500, testContainer(), NULL, NULL), 500),
|
||||
"new client");
|
||||
|
||||
TEST_ERROR_FMT(
|
||||
@ -204,7 +207,10 @@ testRun(void)
|
||||
ioBufferSizeSet(35);
|
||||
|
||||
TEST_ASSIGN(
|
||||
client, httpClientNew(hrnTlsServerHost(), hrnTlsServerPort(), 5000, testContainer(), NULL, NULL),
|
||||
client,
|
||||
httpClientNew(
|
||||
tlsClientNew(sckClientNew(hrnTlsServerHost(), hrnTlsServerPort(), 5000), 5000, testContainer(), NULL, NULL),
|
||||
5000),
|
||||
"new client");
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
|
@ -211,7 +211,7 @@ testRun(void)
|
||||
// *****************************************************************************************************************************
|
||||
if (testBegin("TlsClient verification"))
|
||||
{
|
||||
TlsClient *client = NULL;
|
||||
IoClient *client = NULL;
|
||||
|
||||
// Connection errors
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
@ -219,20 +219,20 @@ testRun(void)
|
||||
client, tlsClientNew(sckClientNew(strNew("99.99.99.99.99"), hrnTlsServerPort(), 0), 0, true, NULL, NULL),
|
||||
"new client");
|
||||
TEST_ERROR(
|
||||
tlsClientOpen(client), HostConnectError, "unable to get address for '99.99.99.99.99': [-2] Name or service not known");
|
||||
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),
|
||||
"new client");
|
||||
TEST_ERROR_FMT(
|
||||
tlsClientOpen(client), HostConnectError, "unable to connect to 'localhost:%u': [111] Connection refused",
|
||||
ioClientOpen(client), HostConnectError, "unable to connect to 'localhost:%u': [111] Connection refused",
|
||||
hrnTlsServerPort());
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("bogus client cert/path");
|
||||
|
||||
TEST_ERROR(
|
||||
tlsClientOpen(
|
||||
ioClientOpen(
|
||||
tlsClientNew(
|
||||
sckClientNew(strNew("localhost"), hrnTlsServerPort(), 5000), 0, true, strNew("bogus.crt"), strNew("/bogus"))),
|
||||
CryptoError, "unable to set user-defined CA certificate location: [33558530] No such file or directory");
|
||||
@ -273,7 +273,7 @@ testRun(void)
|
||||
hrnTlsServerClose();
|
||||
|
||||
TEST_ERROR_FMT(
|
||||
tlsClientOpen(
|
||||
ioClientOpen(
|
||||
tlsClientNew(
|
||||
sckClientNew(strNew("localhost"), hrnTlsServerPort(), 5000), 0, true, NULL, strNew("/bogus"))),
|
||||
CryptoError,
|
||||
@ -287,7 +287,7 @@ testRun(void)
|
||||
hrnTlsServerClose();
|
||||
|
||||
TEST_RESULT_VOID(
|
||||
tlsClientOpen(
|
||||
ioClientOpen(
|
||||
tlsClientNew(
|
||||
sckClientNew(strNew("test.pgbackrest.org"), hrnTlsServerPort(), 5000), 0, true,
|
||||
strNewFmt("%s/" TEST_CERTIFICATE_PREFIX "-ca.crt", testRepoPath()), NULL)),
|
||||
@ -300,7 +300,7 @@ testRun(void)
|
||||
hrnTlsServerClose();
|
||||
|
||||
TEST_RESULT_VOID(
|
||||
tlsClientOpen(
|
||||
ioClientOpen(
|
||||
tlsClientNew(
|
||||
sckClientNew(strNew("host.test2.pgbackrest.org"), hrnTlsServerPort(), 5000), 0, true,
|
||||
strNewFmt("%s/" TEST_CERTIFICATE_PREFIX "-ca.crt", testRepoPath()), NULL)),
|
||||
@ -313,7 +313,7 @@ testRun(void)
|
||||
hrnTlsServerClose();
|
||||
|
||||
TEST_ERROR(
|
||||
tlsClientOpen(
|
||||
ioClientOpen(
|
||||
tlsClientNew(
|
||||
sckClientNew(strNew("test3.pgbackrest.org"), hrnTlsServerPort(), 5000), 0, true,
|
||||
strNewFmt("%s/" TEST_CERTIFICATE_PREFIX "-ca.crt", testRepoPath()), NULL)),
|
||||
@ -327,7 +327,7 @@ testRun(void)
|
||||
hrnTlsServerClose();
|
||||
|
||||
TEST_ERROR_FMT(
|
||||
tlsClientOpen(
|
||||
ioClientOpen(
|
||||
tlsClientNew(
|
||||
sckClientNew(strNew("localhost"), hrnTlsServerPort(), 5000), 0, true,
|
||||
strNewFmt("%s/" TEST_CERTIFICATE_PREFIX ".crt", testRepoPath()),
|
||||
@ -343,7 +343,7 @@ testRun(void)
|
||||
hrnTlsServerClose();
|
||||
|
||||
TEST_RESULT_VOID(
|
||||
tlsClientOpen(
|
||||
ioClientOpen(
|
||||
tlsClientNew(sckClientNew(strNew("localhost"), hrnTlsServerPort(), 5000), 0, false, NULL, NULL)),
|
||||
"open connection");
|
||||
|
||||
@ -359,8 +359,8 @@ testRun(void)
|
||||
// *****************************************************************************************************************************
|
||||
if (testBegin("TlsClient general usage"))
|
||||
{
|
||||
TlsClient *client = NULL;
|
||||
TlsSession *session = NULL;
|
||||
IoClient *client = NULL;
|
||||
IoSession *session = NULL;
|
||||
|
||||
// Reset statistics
|
||||
sckClientStatLocal = (SocketClientStat){0};
|
||||
@ -389,7 +389,8 @@ testRun(void)
|
||||
|
||||
hrnTlsServerAccept();
|
||||
|
||||
TEST_ASSIGN(session, tlsClientOpen(client), "open client");
|
||||
TEST_ASSIGN(session, ioClientOpen(client), "open client");
|
||||
TlsSession *tlsSession = (TlsSession *)session->driver;
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("socket read/write ready");
|
||||
@ -406,22 +407,22 @@ testRun(void)
|
||||
TEST_ERROR(
|
||||
sckReadyRetry(-1, EINVAL, true, &timeout, 0), KernelError, "unable to poll socket: [22] Invalid argument");
|
||||
|
||||
TEST_RESULT_BOOL(sckReadyRead(session->socketSession->fd, 0), false, "socket is not read ready");
|
||||
TEST_RESULT_BOOL(sckReadyWrite(session->socketSession->fd, 100), true, "socket is write ready");
|
||||
TEST_RESULT_VOID(sckSessionReadyWrite(session->socketSession), "socket session is write ready");
|
||||
TEST_RESULT_BOOL(sckReadyRead(tlsSession->socketSession->fd, 0), false, "socket is not read ready");
|
||||
TEST_RESULT_BOOL(sckReadyWrite(tlsSession->socketSession->fd, 100), true, "socket is write ready");
|
||||
TEST_RESULT_VOID(sckSessionReadyWrite(tlsSession->socketSession), "socket session is write ready");
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("uncovered errors");
|
||||
|
||||
TEST_RESULT_INT(tlsSessionResultProcess(session, SSL_ERROR_WANT_WRITE, 0, 0, false), 0, "write ready");
|
||||
TEST_RESULT_INT(tlsSessionResultProcess(tlsSession, SSL_ERROR_WANT_WRITE, 0, 0, false), 0, "write ready");
|
||||
TEST_ERROR(
|
||||
tlsSessionResultProcess(session, SSL_ERROR_WANT_X509_LOOKUP, 336031996, 0, false), ServiceError,
|
||||
tlsSessionResultProcess(tlsSession, SSL_ERROR_WANT_X509_LOOKUP, 336031996, 0, false), ServiceError,
|
||||
"TLS error [4:336031996] unknown protocol");
|
||||
TEST_ERROR(
|
||||
tlsSessionResultProcess(session, SSL_ERROR_WANT_X509_LOOKUP, 0, 0, false), ServiceError,
|
||||
tlsSessionResultProcess(tlsSession, SSL_ERROR_WANT_X509_LOOKUP, 0, 0, false), ServiceError,
|
||||
"TLS error [4:0] no details available");
|
||||
TEST_ERROR(
|
||||
tlsSessionResultProcess(session, SSL_ERROR_ZERO_RETURN, 0, 0, false), ProtocolError, "unexpected TLS eof");
|
||||
tlsSessionResultProcess(tlsSession, SSL_ERROR_ZERO_RETURN, 0, 0, false), ProtocolError, "unexpected TLS eof");
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("first protocol exchange");
|
||||
@ -430,11 +431,11 @@ testRun(void)
|
||||
hrnTlsServerReplyZ("something:0\n");
|
||||
|
||||
const Buffer *input = BUFSTRDEF("some protocol info");
|
||||
TEST_RESULT_VOID(ioWrite(tlsSessionIoWrite(session), input), "write input");
|
||||
ioWriteFlush(tlsSessionIoWrite(session));
|
||||
TEST_RESULT_VOID(ioWrite(ioSessionIoWrite(session), input), "write input");
|
||||
ioWriteFlush(ioSessionIoWrite(session));
|
||||
|
||||
TEST_RESULT_STR_Z(ioReadLine(tlsSessionIoRead(session)), "something:0", "read line");
|
||||
TEST_RESULT_BOOL(ioReadEof(tlsSessionIoRead(session)), false, "check eof = false");
|
||||
TEST_RESULT_STR_Z(ioReadLine(ioSessionIoRead(session)), "something:0", "read line");
|
||||
TEST_RESULT_BOOL(ioReadEof(ioSessionIoRead(session)), false, "check eof = false");
|
||||
|
||||
hrnTlsServerSleep(100);
|
||||
hrnTlsServerReplyZ("some ");
|
||||
@ -443,14 +444,14 @@ testRun(void)
|
||||
hrnTlsServerReplyZ("contentAND MORE");
|
||||
|
||||
Buffer *output = bufNew(12);
|
||||
TEST_RESULT_UINT(ioRead(tlsSessionIoRead(session), output), 12, "read output");
|
||||
TEST_RESULT_UINT(ioRead(ioSessionIoRead(session), output), 12, "read output");
|
||||
TEST_RESULT_STR_Z(strNewBuf(output), "some content", "check output");
|
||||
TEST_RESULT_BOOL(ioReadEof(tlsSessionIoRead(session)), false, "check eof = false");
|
||||
TEST_RESULT_BOOL(ioReadEof(ioSessionIoRead(session)), false, "check eof = false");
|
||||
|
||||
output = bufNew(8);
|
||||
TEST_RESULT_UINT(ioRead(tlsSessionIoRead(session), output), 8, "read output");
|
||||
TEST_RESULT_UINT(ioRead(ioSessionIoRead(session), output), 8, "read output");
|
||||
TEST_RESULT_STR_Z(strNewBuf(output), "AND MORE", "check output");
|
||||
TEST_RESULT_BOOL(ioReadEof(tlsSessionIoRead(session)), false, "check eof = false");
|
||||
TEST_RESULT_BOOL(ioReadEof(ioSessionIoRead(session)), false, "check eof = false");
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("read eof");
|
||||
@ -458,11 +459,11 @@ testRun(void)
|
||||
hrnTlsServerSleep(500);
|
||||
|
||||
output = bufNew(12);
|
||||
session->socketSession->timeout = 100;
|
||||
tlsSession->socketSession->timeout = 100;
|
||||
TEST_ERROR_FMT(
|
||||
ioRead(tlsSessionIoRead(session), output), ProtocolError,
|
||||
ioRead(ioSessionIoRead(session), output), ProtocolError,
|
||||
"timeout after 100ms waiting for read from '%s:%u'", strZ(hrnTlsServerHost()), hrnTlsServerPort());
|
||||
session->socketSession->timeout = 5000;
|
||||
tlsSession->socketSession->timeout = 5000;
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("second protocol exchange");
|
||||
@ -473,19 +474,19 @@ testRun(void)
|
||||
hrnTlsServerClose();
|
||||
|
||||
input = BUFSTRDEF("more protocol info");
|
||||
TEST_RESULT_VOID(ioWrite(tlsSessionIoWrite(session), input), "write input");
|
||||
ioWriteFlush(tlsSessionIoWrite(session));
|
||||
TEST_RESULT_VOID(ioWrite(ioSessionIoWrite(session), input), "write input");
|
||||
ioWriteFlush(ioSessionIoWrite(session));
|
||||
|
||||
output = bufNew(12);
|
||||
TEST_RESULT_UINT(ioRead(tlsSessionIoRead(session), output), 12, "read output");
|
||||
TEST_RESULT_UINT(ioRead(ioSessionIoRead(session), output), 12, "read output");
|
||||
TEST_RESULT_STR_Z(strNewBuf(output), "0123456789AB", "check output");
|
||||
TEST_RESULT_BOOL(ioReadEof(tlsSessionIoRead(session)), false, "check eof = false");
|
||||
TEST_RESULT_BOOL(ioReadEof(ioSessionIoRead(session)), false, "check eof = false");
|
||||
|
||||
output = bufNew(12);
|
||||
TEST_RESULT_UINT(ioRead(tlsSessionIoRead(session), output), 0, "read no output after eof");
|
||||
TEST_RESULT_BOOL(ioReadEof(tlsSessionIoRead(session)), true, "check eof = true");
|
||||
TEST_RESULT_UINT(ioRead(ioSessionIoRead(session), output), 0, "read no output after eof");
|
||||
TEST_RESULT_BOOL(ioReadEof(ioSessionIoRead(session)), true, "check eof = true");
|
||||
|
||||
TEST_RESULT_VOID(tlsSessionClose(session, false), "close again");
|
||||
TEST_RESULT_VOID(ioSessionClose(session), "close again");
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("aborted connection before read complete (blocking socket)");
|
||||
@ -495,16 +496,16 @@ testRun(void)
|
||||
hrnTlsServerAbort();
|
||||
|
||||
socketLocal.block = true;
|
||||
TEST_ASSIGN(session, tlsClientOpen(client), "open client again (was closed by server)");
|
||||
TEST_ASSIGN(session, ioClientOpen(client), "open client again (was closed by server)");
|
||||
socketLocal.block = false;
|
||||
|
||||
output = bufNew(13);
|
||||
TEST_ERROR(ioRead(tlsSessionIoRead(session), output), KernelError, "TLS syscall error");
|
||||
TEST_ERROR(ioRead(ioSessionIoRead(session), output), KernelError, "TLS syscall error");
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("close connection");
|
||||
|
||||
TEST_RESULT_VOID(tlsClientFree(client), "free client");
|
||||
TEST_RESULT_VOID(ioClientFree(client), "free client");
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
hrnTlsClientEnd();
|
||||
|
Loading…
x
Reference in New Issue
Block a user