1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-07-15 01:04:37 +02:00

Fix leaks in protocol module.

These leaks were not a big deal individually and there are generally few protocol objects created, but the leaks ended up in mem contexts that persist for most of execution. It makes sense to keep long-lived contexts as tidy as possible.
This commit is contained in:
David Steele
2022-04-26 11:59:21 -04:00
parent 78e912a932
commit a56fa0eb45

View File

@ -171,7 +171,11 @@ protocolLocalParam(ProtocolStorageType protocolStorageType, unsigned int hostIdx
// Disable output to stdout since it is used by the protocol // Disable output to stdout since it is used by the protocol
kvPut(optionReplace, VARSTRDEF(CFGOPT_LOG_LEVEL_CONSOLE), VARSTRDEF("off")); kvPut(optionReplace, VARSTRDEF(CFGOPT_LOG_LEVEL_CONSOLE), VARSTRDEF("off"));
result = strLstMove(cfgExecParam(cfgCommand(), cfgCmdRoleLocal, optionReplace, true, false), memContextPrior()); MEM_CONTEXT_PRIOR_BEGIN()
{
result = cfgExecParam(cfgCommand(), cfgCmdRoleLocal, optionReplace, true, false);
}
MEM_CONTEXT_PRIOR_END();
} }
MEM_CONTEXT_TEMP_END(); MEM_CONTEXT_TEMP_END();
@ -193,19 +197,34 @@ protocolLocalExec(
ASSERT(helper != NULL); ASSERT(helper != NULL);
// Execute the protocol command MEM_CONTEXT_TEMP_BEGIN()
helper->exec = execNew( {
cfgExe(), protocolLocalParam(protocolStorageType, hostIdx, processId), // Execute the protocol command
strNewFmt(PROTOCOL_SERVICE_LOCAL "-%u process", processId), cfgOptionUInt64(cfgOptProtocolTimeout)); const String *name = strNewFmt(PROTOCOL_SERVICE_LOCAL "-%u process", processId);
execOpen(helper->exec); const StringList *const param = protocolLocalParam(protocolStorageType, hostIdx, processId);
// Create protocol object MEM_CONTEXT_PRIOR_BEGIN()
helper->client = protocolClientNew( {
strNewFmt(PROTOCOL_SERVICE_LOCAL "-%u protocol", processId), helper->exec = execNew(cfgExe(), param, name, cfgOptionUInt64(cfgOptProtocolTimeout));
PROTOCOL_SERVICE_LOCAL_STR, execIoRead(helper->exec), execIoWrite(helper->exec)); }
MEM_CONTEXT_PRIOR_END();
// Move client to exec context so they are freed together execOpen(helper->exec);
protocolClientMove(helper->client, execMemContext(helper->exec));
// Create protocol object
name = strNewFmt(PROTOCOL_SERVICE_LOCAL "-%u protocol", processId);
MEM_CONTEXT_PRIOR_BEGIN()
{
helper->client = protocolClientNew(
name, PROTOCOL_SERVICE_LOCAL_STR, execIoRead(helper->exec), execIoWrite(helper->exec));
}
MEM_CONTEXT_PRIOR_END();
// Move client to exec context so they are freed together
protocolClientMove(helper->client, execMemContext(helper->exec));
}
MEM_CONTEXT_TEMP_END();
FUNCTION_TEST_RETURN_VOID(); FUNCTION_TEST_RETURN_VOID();
} }
@ -332,29 +351,39 @@ protocolServerAuthorize(const String *authListStr, const String *const stanza)
ASSERT(authListStr != NULL); ASSERT(authListStr != NULL);
// Empty list is not valid. ??? It would be better if this were done during config parsing. bool result = false;
authListStr = strTrim(strDup(authListStr));
if (strEmpty(authListStr)) MEM_CONTEXT_TEMP_BEGIN()
THROW(OptionInvalidValueError, "'" CFGOPT_TLS_SERVER_AUTH "' option must have a value");
// If * then all stanzas are authorized
if (strEqZ(authListStr, "*"))
FUNCTION_TEST_RETURN(BOOL, true);
// Check the list of stanzas for a match with the specified stanza. Each entry will need to be trimmed before comparing.
if (stanza != NULL)
{ {
StringList *authList = strLstNewSplitZ(authListStr, COMMA_Z); // Empty list is not valid. ??? It would be better if this were done during config parsing.
authListStr = strTrim(strDup(authListStr));
for (unsigned int authListIdx = 0; authListIdx < strLstSize(authList); authListIdx++) if (strEmpty(authListStr))
THROW(OptionInvalidValueError, "'" CFGOPT_TLS_SERVER_AUTH "' option must have a value");
// If * then all stanzas are authorized
if (strEqZ(authListStr, "*"))
{ {
if (strEq(strTrim(strLstGet(authList, authListIdx)), stanza)) result = true;
FUNCTION_TEST_RETURN(BOOL, true); }
// Else check the stanza list for a match with the specified stanza. Each entry will need to be trimmed before comparing.
else if (stanza != NULL)
{
StringList *authList = strLstNewSplitZ(authListStr, COMMA_Z);
for (unsigned int authListIdx = 0; authListIdx < strLstSize(authList); authListIdx++)
{
if (strEq(strTrim(strLstGet(authList, authListIdx)), stanza))
{
result = true;
break;
}
}
} }
} }
MEM_CONTEXT_TEMP_END();
FUNCTION_TEST_RETURN(BOOL, false); FUNCTION_TEST_RETURN(BOOL, result);
} }
ProtocolServer * ProtocolServer *
@ -443,127 +472,139 @@ protocolRemoteParam(ProtocolStorageType protocolStorageType, unsigned int hostId
FUNCTION_LOG_PARAM(UINT, hostIdx); FUNCTION_LOG_PARAM(UINT, hostIdx);
FUNCTION_LOG_END(); FUNCTION_LOG_END();
// Is this a repo remote? StringList *result = NULL;
bool isRepo = protocolStorageType == protocolStorageTypeRepo;
// Option replacements MEM_CONTEXT_TEMP_BEGIN()
KeyValue *optionReplace = kvNew();
// Replace config options with the host versions
unsigned int optConfig = isRepo ? cfgOptRepoHostConfig : cfgOptPgHostConfig;
kvPut(
optionReplace, VARSTRDEF(CFGOPT_CONFIG),
cfgOptionIdxSource(optConfig, hostIdx) != cfgSourceDefault ? VARSTR(cfgOptionIdxStr(optConfig, hostIdx)) : NULL);
unsigned int optConfigIncludePath = isRepo ? cfgOptRepoHostConfigIncludePath : cfgOptPgHostConfigIncludePath;
kvPut(
optionReplace, VARSTRDEF(CFGOPT_CONFIG_INCLUDE_PATH),
cfgOptionIdxSource(optConfigIncludePath, hostIdx) != cfgSourceDefault ?
VARSTR(cfgOptionIdxStr(optConfigIncludePath, hostIdx)) : NULL);
unsigned int optConfigPath = isRepo ? cfgOptRepoHostConfigPath : cfgOptPgHostConfigPath;
kvPut(
optionReplace, VARSTRDEF(CFGOPT_CONFIG_PATH),
cfgOptionIdxSource(optConfigPath, hostIdx) != cfgSourceDefault ? VARSTR(cfgOptionIdxStr(optConfigPath, hostIdx)) : NULL);
// Update/remove repo/pg options that are sent to the remote
for (ConfigOption optionId = 0; optionId < CFG_OPTION_TOTAL; optionId++)
{ {
// Skip options that are not part of a group // Is this a repo remote?
if (!cfgOptionGroup(optionId)) bool isRepo = protocolStorageType == protocolStorageTypeRepo;
continue;
bool remove = false; // Option replacements
bool skipHostZero = false; KeyValue *optionReplace = kvNew();
// Remove repo options that are not needed on the remote // Replace config options with the host versions
if (cfgOptionGroupId(optionId) == cfgOptGrpRepo) unsigned int optConfig = isRepo ? cfgOptRepoHostConfig : cfgOptPgHostConfig;
kvPut(
optionReplace, VARSTRDEF(CFGOPT_CONFIG),
cfgOptionIdxSource(optConfig, hostIdx) != cfgSourceDefault ? VARSTR(cfgOptionIdxStr(optConfig, hostIdx)) : NULL);
unsigned int optConfigIncludePath = isRepo ? cfgOptRepoHostConfigIncludePath : cfgOptPgHostConfigIncludePath;
kvPut(
optionReplace, VARSTRDEF(CFGOPT_CONFIG_INCLUDE_PATH),
cfgOptionIdxSource(optConfigIncludePath, hostIdx) != cfgSourceDefault ?
VARSTR(cfgOptionIdxStr(optConfigIncludePath, hostIdx)) : NULL);
unsigned int optConfigPath = isRepo ? cfgOptRepoHostConfigPath : cfgOptPgHostConfigPath;
kvPut(
optionReplace, VARSTRDEF(CFGOPT_CONFIG_PATH),
cfgOptionIdxSource(optConfigPath, hostIdx) != cfgSourceDefault ? VARSTR(cfgOptionIdxStr(optConfigPath, hostIdx)) : NULL);
// Update/remove repo/pg options that are sent to the remote
for (ConfigOption optionId = 0; optionId < CFG_OPTION_TOTAL; optionId++)
{ {
// If remote type is pg then remove all repo options since they will not be used // Skip options that are not part of a group
if (protocolStorageType == protocolStorageTypePg) if (!cfgOptionGroup(optionId))
continue;
bool remove = false;
bool skipHostZero = false;
// Remove repo options that are not needed on the remote
if (cfgOptionGroupId(optionId) == cfgOptGrpRepo)
{ {
remove = true; // If remote type is pg then remove all repo options since they will not be used
if (protocolStorageType == protocolStorageTypePg)
{
remove = true;
}
// Else remove repo options for indexes that are not being passed to the repo. This prevents the remote from getting
// partial info about a repo, which could cause an error during validation.
else
{
for (unsigned int optionIdx = 0; optionIdx < cfgOptionIdxTotal(optionId); optionIdx++)
{
if (cfgOptionIdxTest(optionId, optionIdx) && optionIdx != hostIdx)
kvPut(optionReplace, VARSTRZ(cfgOptionIdxName(optionId, optionIdx)), NULL);
}
}
} }
// Else remove repo options for indexes that are not being passed to the repo. This prevents the remote from getting // Remove pg options that are not needed on the remote
// partial info about a repo, which could cause an error during validation.
else else
{ {
ASSERT(cfgOptionGroupId(optionId) == cfgOptGrpPg);
// Remove unrequired/defaulted pg options when the remote type is repo since they won't be used
if (protocolStorageType == protocolStorageTypeRepo)
{
remove = !cfgParseOptionRequired(cfgCommand(), optionId) || cfgParseOptionDefault(cfgCommand(), optionId) != NULL;
}
// Move pg options to host index 0 (key 1) so they will be in the default index on the remote host
else
{
if (hostIdx != 0)
{
kvPut(
optionReplace, VARSTRZ(cfgOptionIdxName(optionId, 0)),
cfgOptionIdxSource(optionId, hostIdx) != cfgSourceDefault ? cfgOptionIdxVar(optionId, hostIdx) : NULL);
}
remove = true;
skipHostZero = true;
}
}
// Remove options that have been marked for removal if they are not already null or invalid. This is more efficient because
// cfgExecParam() won't have to search through as large a list looking for overrides.
if (remove)
{
// Loop through option indexes
for (unsigned int optionIdx = 0; optionIdx < cfgOptionIdxTotal(optionId); optionIdx++) for (unsigned int optionIdx = 0; optionIdx < cfgOptionIdxTotal(optionId); optionIdx++)
{ {
if (cfgOptionIdxTest(optionId, optionIdx) && optionIdx != hostIdx) if (cfgOptionIdxTest(optionId, optionIdx) && !(skipHostZero && optionIdx == 0))
kvPut(optionReplace, VARSTRZ(cfgOptionIdxName(optionId, optionIdx)), NULL); kvPut(optionReplace, VARSTRZ(cfgOptionIdxName(optionId, optionIdx)), NULL);
} }
} }
} }
// Remove pg options that are not needed on the remote
else // Set repo default so the remote only operates on a single repo
if (protocolStorageType == protocolStorageTypeRepo)
kvPut(optionReplace, VARSTRDEF(CFGOPT_REPO), VARUINT(cfgOptionGroupIdxToKey(cfgOptGrpRepo, hostIdx)));
// Add the process id if not set. This means that the remote is being started from the main process and should always get a
// process id of 0.
if (!cfgOptionTest(cfgOptProcess))
kvPut(optionReplace, VARSTRDEF(CFGOPT_PROCESS), VARINT(0));
// Don't pass log-path or lock-path since these are host specific
kvPut(optionReplace, VARSTRDEF(CFGOPT_LOG_PATH), NULL);
kvPut(optionReplace, VARSTRDEF(CFGOPT_LOCK_PATH), NULL);
// Only enable file logging on the remote when requested
kvPut(
optionReplace, VARSTRDEF(CFGOPT_LOG_LEVEL_FILE),
cfgOptionBool(cfgOptLogSubprocess) ? VARUINT64(cfgOptionStrId(cfgOptLogLevelFile)) : VARSTRDEF("off"));
// Always output errors on stderr for debugging purposes
kvPut(optionReplace, VARSTRDEF(CFGOPT_LOG_LEVEL_STDERR), VARSTRDEF("error"));
// Disable output to stdout since it is used by the protocol
kvPut(optionReplace, VARSTRDEF(CFGOPT_LOG_LEVEL_CONSOLE), VARSTRDEF("off"));
// Add the remote type
kvPut(optionReplace, VARSTRDEF(CFGOPT_REMOTE_TYPE), VARSTR(strIdToStr(protocolStorageType)));
MEM_CONTEXT_PRIOR_BEGIN()
{ {
ASSERT(cfgOptionGroupId(optionId) == cfgOptGrpPg); result = cfgExecParam(cfgCommand(), cfgCmdRoleRemote, optionReplace, false, true);
// Remove unrequired/defaulted pg options when the remote type is repo since they won't be used
if (protocolStorageType == protocolStorageTypeRepo)
{
remove = !cfgParseOptionRequired(cfgCommand(), optionId) || cfgParseOptionDefault(cfgCommand(), optionId) != NULL;
}
// Move pg options to host index 0 (key 1) so they will be in the default index on the remote host
else
{
if (hostIdx != 0)
{
kvPut(
optionReplace, VARSTRZ(cfgOptionIdxName(optionId, 0)),
cfgOptionIdxSource(optionId, hostIdx) != cfgSourceDefault ? cfgOptionIdxVar(optionId, hostIdx) : NULL);
}
remove = true;
skipHostZero = true;
}
}
// Remove options that have been marked for removal if they are not already null or invalid. This is more efficient because
// cfgExecParam() won't have to search through as large a list looking for overrides.
if (remove)
{
// Loop through option indexes
for (unsigned int optionIdx = 0; optionIdx < cfgOptionIdxTotal(optionId); optionIdx++)
{
if (cfgOptionIdxTest(optionId, optionIdx) && !(skipHostZero && optionIdx == 0))
kvPut(optionReplace, VARSTRZ(cfgOptionIdxName(optionId, optionIdx)), NULL);
}
} }
MEM_CONTEXT_PRIOR_END();
} }
MEM_CONTEXT_TEMP_END();
// Set repo default so the remote only operates on a single repo FUNCTION_LOG_RETURN(STRING_LIST, result);
if (protocolStorageType == protocolStorageTypeRepo)
kvPut(optionReplace, VARSTRDEF(CFGOPT_REPO), VARUINT(cfgOptionGroupIdxToKey(cfgOptGrpRepo, hostIdx)));
// Add the process id if not set. This means that the remote is being started from the main process and should always get a
// process id of 0.
if (!cfgOptionTest(cfgOptProcess))
kvPut(optionReplace, VARSTRDEF(CFGOPT_PROCESS), VARINT(0));
// Don't pass log-path or lock-path since these are host specific
kvPut(optionReplace, VARSTRDEF(CFGOPT_LOG_PATH), NULL);
kvPut(optionReplace, VARSTRDEF(CFGOPT_LOCK_PATH), NULL);
// Only enable file logging on the remote when requested
kvPut(
optionReplace, VARSTRDEF(CFGOPT_LOG_LEVEL_FILE),
cfgOptionBool(cfgOptLogSubprocess) ? VARUINT64(cfgOptionStrId(cfgOptLogLevelFile)) : VARSTRDEF("off"));
// Always output errors on stderr for debugging purposes
kvPut(optionReplace, VARSTRDEF(CFGOPT_LOG_LEVEL_STDERR), VARSTRDEF("error"));
// Disable output to stdout since it is used by the protocol
kvPut(optionReplace, VARSTRDEF(CFGOPT_LOG_LEVEL_CONSOLE), VARSTRDEF("off"));
// Add the remote type
kvPut(optionReplace, VARSTRDEF(CFGOPT_REMOTE_TYPE), VARSTR(strIdToStr(protocolStorageType)));
FUNCTION_LOG_RETURN(STRING_LIST, cfgExecParam(cfgCommand(), cfgCmdRoleRemote, optionReplace, false, true));
} }
// Helper to add SSH parameters when executing the remote via SSH // Helper to add SSH parameters when executing the remote via SSH
@ -575,7 +616,7 @@ protocolRemoteParamSsh(const ProtocolStorageType protocolStorageType, const unsi
FUNCTION_LOG_PARAM(UINT, hostIdx); FUNCTION_LOG_PARAM(UINT, hostIdx);
FUNCTION_LOG_END(); FUNCTION_LOG_END();
StringList *result = NULL; StringList *result = strLstNew();
MEM_CONTEXT_TEMP_BEGIN() MEM_CONTEXT_TEMP_BEGIN()
{ {
@ -583,7 +624,6 @@ protocolRemoteParamSsh(const ProtocolStorageType protocolStorageType, const unsi
bool isRepo = protocolStorageType == protocolStorageTypeRepo; bool isRepo = protocolStorageType == protocolStorageTypeRepo;
// Fixed parameters for ssh command // Fixed parameters for ssh command
result = strLstNew();
strLstAddZ(result, "-o"); strLstAddZ(result, "-o");
strLstAddZ(result, "LogLevel=error"); strLstAddZ(result, "LogLevel=error");
strLstAddZ(result, "-o"); strLstAddZ(result, "-o");
@ -610,9 +650,6 @@ protocolRemoteParamSsh(const ProtocolStorageType protocolStorageType, const unsi
strLstInsert(paramList, 0, cfgOptionIdxStr(isRepo ? cfgOptRepoHostCmd : cfgOptPgHostCmd, hostIdx)); strLstInsert(paramList, 0, cfgOptionIdxStr(isRepo ? cfgOptRepoHostCmd : cfgOptPgHostCmd, hostIdx));
strLstAdd(result, strLstJoin(paramList, " ")); strLstAdd(result, strLstJoin(paramList, " "));
// Move to prior context
strLstMove(result, memContextPrior());
} }
MEM_CONTEXT_TEMP_END(); MEM_CONTEXT_TEMP_END();
@ -635,84 +672,104 @@ protocolRemoteExec(
ASSERT(helper != NULL); ASSERT(helper != NULL);
// Get remote info MEM_CONTEXT_TEMP_BEGIN()
const bool isRepo = protocolStorageType == protocolStorageTypeRepo;
const StringId remoteType = cfgOptionIdxStrId(isRepo ? cfgOptRepoHostType : cfgOptPgHostType, hostIdx);
const String *const host = cfgOptionIdxStr(isRepo ? cfgOptRepoHost : cfgOptPgHost, hostIdx);
// Handle remote types
IoRead *read;
IoWrite *write;
switch (remoteType)
{ {
// SSH remote // Get remote info
case CFGOPTVAL_REPO_HOST_TYPE_SSH: const bool isRepo = protocolStorageType == protocolStorageTypeRepo;
const StringId remoteType = cfgOptionIdxStrId(isRepo ? cfgOptRepoHostType : cfgOptPgHostType, hostIdx);
const String *const host = cfgOptionIdxStr(isRepo ? cfgOptRepoHost : cfgOptPgHost, hostIdx);
// Handle remote types
IoRead *read;
IoWrite *write;
switch (remoteType)
{ {
// Exec SSH // SSH remote
helper->exec = execNew( case CFGOPTVAL_REPO_HOST_TYPE_SSH:
cfgOptionStr(cfgOptCmdSsh), protocolRemoteParamSsh(protocolStorageType, hostIdx), {
strNewFmt(PROTOCOL_SERVICE_REMOTE "-%u process on '%s'", processId, strZ(host)), // Exec SSH
cfgOptionUInt64(cfgOptProtocolTimeout)); const String *const name = strNewFmt(PROTOCOL_SERVICE_REMOTE "-%u process on '%s'", processId, strZ(host));
execOpen(helper->exec); const StringList *const param = protocolRemoteParamSsh(protocolStorageType, hostIdx);
read = execIoRead(helper->exec); MEM_CONTEXT_PRIOR_BEGIN()
write = execIoWrite(helper->exec); {
helper->exec = execNew(cfgOptionStr(cfgOptCmdSsh), param, name, cfgOptionUInt64(cfgOptProtocolTimeout));
}
MEM_CONTEXT_PRIOR_END();
break; execOpen(helper->exec);
read = execIoRead(helper->exec);
write = execIoWrite(helper->exec);
break;
}
// TLS remote
default:
{
ASSERT(remoteType == CFGOPTVAL_REPO_HOST_TYPE_TLS);
// Negotiate TLS
MEM_CONTEXT_PRIOR_BEGIN()
{
helper->ioClient = tlsClientNewP(
sckClientNew(
host, cfgOptionIdxUInt(isRepo ? cfgOptRepoHostPort : cfgOptPgHostPort, hostIdx),
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionUInt64(cfgOptProtocolTimeout)),
host, cfgOptionUInt64(cfgOptIoTimeout), cfgOptionUInt64(cfgOptProtocolTimeout), true,
.caFile = cfgOptionIdxStrNull(isRepo ? cfgOptRepoHostCaFile : cfgOptPgHostCaFile, hostIdx),
.caPath = cfgOptionIdxStrNull(isRepo ? cfgOptRepoHostCaPath : cfgOptPgHostCaPath, hostIdx),
.certFile = cfgOptionIdxStr(isRepo ? cfgOptRepoHostCertFile : cfgOptPgHostCertFile, hostIdx),
.keyFile = cfgOptionIdxStr(isRepo ? cfgOptRepoHostKeyFile : cfgOptPgHostKeyFile, hostIdx));
helper->ioSession = ioClientOpen(helper->ioClient);
}
MEM_CONTEXT_PRIOR_END();
read = ioSessionIoReadP(helper->ioSession);
write = ioSessionIoWrite(helper->ioSession);
break;
}
} }
// TLS remote // Create protocol object
default: const String *const name = strNewFmt(
PROTOCOL_SERVICE_REMOTE "-%u %s protocol on '%s'", processId, strZ(strIdToStr(remoteType)), strZ(host));
MEM_CONTEXT_PRIOR_BEGIN()
{ {
ASSERT(remoteType == CFGOPTVAL_REPO_HOST_TYPE_TLS); helper->client = protocolClientNew(name, PROTOCOL_SERVICE_REMOTE_STR, read, write);
}
MEM_CONTEXT_PRIOR_END();
// Negotiate TLS // Remote initialization
helper->ioClient = tlsClientNewP( switch (remoteType)
sckClientNew( {
host, cfgOptionIdxUInt(isRepo ? cfgOptRepoHostPort : cfgOptPgHostPort, hostIdx), // SSH remote
cfgOptionUInt64(cfgOptIoTimeout), cfgOptionUInt64(cfgOptProtocolTimeout)), case CFGOPTVAL_REPO_HOST_TYPE_SSH:
host, cfgOptionUInt64(cfgOptIoTimeout), cfgOptionUInt64(cfgOptProtocolTimeout), true, // Move client to exec context so they are freed together
.caFile = cfgOptionIdxStrNull(isRepo ? cfgOptRepoHostCaFile : cfgOptPgHostCaFile, hostIdx), protocolClientMove(helper->client, execMemContext(helper->exec));
.caPath = cfgOptionIdxStrNull(isRepo ? cfgOptRepoHostCaPath : cfgOptPgHostCaPath, hostIdx), break;
.certFile = cfgOptionIdxStr(isRepo ? cfgOptRepoHostCertFile : cfgOptPgHostCertFile, hostIdx),
.keyFile = cfgOptionIdxStr(isRepo ? cfgOptRepoHostKeyFile : cfgOptPgHostKeyFile, hostIdx));
helper->ioSession = ioClientOpen(helper->ioClient);
read = ioSessionIoReadP(helper->ioSession); // TLS remote
write = ioSessionIoWrite(helper->ioSession); default:
{
ASSERT(remoteType == CFGOPTVAL_REPO_HOST_TYPE_TLS);
break; // Pass parameters to server
} ProtocolCommand *const command = protocolCommandNew(PROTOCOL_COMMAND_CONFIG);
} pckWriteStrLstP(protocolCommandParam(command), protocolRemoteParam(protocolStorageType, hostIdx));
protocolClientExecute(helper->client, command, false);
// Create protocol object protocolCommandFree(command);
helper->client = protocolClientNew(
strNewFmt(PROTOCOL_SERVICE_REMOTE "-%u %s protocol on '%s'", processId, strZ(strIdToStr(remoteType)), strZ(host)), break;
PROTOCOL_SERVICE_REMOTE_STR, read, write); }
// Remote initialization
switch (remoteType)
{
// SSH remote
case CFGOPTVAL_REPO_HOST_TYPE_SSH:
// Move client to exec context so they are freed together
protocolClientMove(helper->client, execMemContext(helper->exec));
break;
// TLS remote
default:
{
ASSERT(remoteType == CFGOPTVAL_REPO_HOST_TYPE_TLS);
// Pass parameters to server
ProtocolCommand *command = protocolCommandNew(PROTOCOL_COMMAND_CONFIG);
pckWriteStrLstP(protocolCommandParam(command), protocolRemoteParam(protocolStorageType, hostIdx));
protocolClientExecute(helper->client, command, false);
break;
} }
} }
MEM_CONTEXT_TEMP_END();
FUNCTION_TEST_RETURN_VOID(); FUNCTION_TEST_RETURN_VOID();
} }