mirror of https://github.com/wolfSSL/wolfssh.git
more return code checking
parent
f865ad2487
commit
2e1744265b
174
src/internal.c
174
src/internal.c
|
@ -411,16 +411,16 @@ int GrowBuffer(Buffer* buf, uint32_t sz, uint32_t usedSz)
|
||||||
|
|
||||||
void ShrinkBuffer(Buffer* buf, int forcedFree)
|
void ShrinkBuffer(Buffer* buf, int forcedFree)
|
||||||
{
|
{
|
||||||
WLOG(WS_LOG_DEBUG, "Entering %s", __func__);
|
WLOG(WS_LOG_DEBUG, "Entering ShrinkBuffer()");
|
||||||
|
|
||||||
if (buf != NULL) {
|
if (buf != NULL) {
|
||||||
uint32_t usedSz = buf->length - buf->idx;
|
uint32_t usedSz = buf->length - buf->idx;
|
||||||
|
|
||||||
WLOG(WS_LOG_DEBUG, "SB: usedSz = %u, forcedFree = %u", usedSz, forcedFree);
|
WLOG(WS_LOG_DEBUG, "SB: usedSz = %u, forcedFree = %u",
|
||||||
if (!forcedFree && usedSz > STATIC_BUFFER_LEN) {
|
usedSz, forcedFree);
|
||||||
WLOG(WS_LOG_DEBUG, "SB: shifting down");
|
|
||||||
|
if (!forcedFree && usedSz > STATIC_BUFFER_LEN)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (!forcedFree && usedSz) {
|
if (!forcedFree && usedSz) {
|
||||||
WLOG(WS_LOG_DEBUG, "SB: shifting down");
|
WLOG(WS_LOG_DEBUG, "SB: shifting down");
|
||||||
|
@ -437,7 +437,8 @@ void ShrinkBuffer(Buffer* buf, int forcedFree)
|
||||||
buf->length = forcedFree ? 0 : usedSz;
|
buf->length = forcedFree ? 0 : usedSz;
|
||||||
buf->idx = 0;
|
buf->idx = 0;
|
||||||
}
|
}
|
||||||
WLOG(WS_LOG_DEBUG, "Leaving %s", __func__);
|
|
||||||
|
WLOG(WS_LOG_DEBUG, "Leaving ShrinkBuffer()");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -667,6 +668,7 @@ static int GetBoolean(uint8_t* v, uint8_t* buf, uint32_t len, uint32_t* idx)
|
||||||
*idx += BOOLEAN_SZ;
|
*idx += BOOLEAN_SZ;
|
||||||
result = WS_SUCCESS;
|
result = WS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -711,26 +713,37 @@ static int DoNameList(uint8_t* idList, uint32_t* idListSz,
|
||||||
{
|
{
|
||||||
uint8_t idListIdx;
|
uint8_t idListIdx;
|
||||||
uint32_t nameListSz, nameListIdx;
|
uint32_t nameListSz, nameListIdx;
|
||||||
uint32_t begin = *idx;
|
uint32_t begin;
|
||||||
uint8_t* name;
|
uint8_t* name;
|
||||||
uint32_t nameSz;
|
uint32_t nameSz;
|
||||||
|
int ret = WS_SUCCESS;
|
||||||
|
|
||||||
|
WLOG(WS_LOG_DEBUG, "Entering DoNameList()");
|
||||||
|
|
||||||
|
if (idList == NULL || idListSz == NULL ||
|
||||||
|
buf == NULL || len == 0 || idx == NULL) {
|
||||||
|
|
||||||
|
ret = WS_BAD_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This iterates across a name list and finds names that end in either the
|
* This iterates across a name list and finds names that end in either the
|
||||||
* comma delimeter or with the end of the list.
|
* comma delimeter or with the end of the list.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
if (ret == WS_SUCCESS) {
|
||||||
|
begin = *idx;
|
||||||
if (begin >= len || begin + 4 >= len)
|
if (begin >= len || begin + 4 >= len)
|
||||||
return WS_FATAL_ERROR;
|
ret = WS_BUFFER_E;
|
||||||
|
}
|
||||||
|
|
||||||
ato32(buf + begin, &nameListSz);
|
if (ret == WS_SUCCESS)
|
||||||
begin += 4;
|
ret = GetUint32(&nameListSz, buf, len, &begin);
|
||||||
if (begin + nameListSz > len)
|
|
||||||
return WS_FATAL_ERROR;
|
|
||||||
|
|
||||||
/* The strings we want are now in the bounds of the message, and the
|
/* The strings we want are now in the bounds of the message, and the
|
||||||
* length of the list. Find the commas, or end of list, and then decode
|
* length of the list. Find the commas, or end of list, and then decode
|
||||||
* the values. */
|
* the values. */
|
||||||
|
if (ret == WS_SUCCESS) {
|
||||||
name = buf + begin;
|
name = buf + begin;
|
||||||
nameSz = 0;
|
nameSz = 0;
|
||||||
nameListIdx = 0;
|
nameListIdx = 0;
|
||||||
|
@ -749,7 +762,8 @@ static int DoNameList(uint8_t* idList, uint32_t* idListSz,
|
||||||
{
|
{
|
||||||
const char* displayName = IdToName(id);
|
const char* displayName = IdToName(id);
|
||||||
if (displayName) {
|
if (displayName) {
|
||||||
/*WLOG(WS_LOG_DEBUG, "DNL: name ID = %s", displayName);*/
|
/*WLOG(WS_LOG_DEBUG,
|
||||||
|
"DNL: name ID = %s", displayName);*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (id != ID_UNKNOWN)
|
if (id != ID_UNKNOWN)
|
||||||
|
@ -765,8 +779,10 @@ static int DoNameList(uint8_t* idList, uint32_t* idListSz,
|
||||||
begin += nameListSz;
|
begin += nameListSz;
|
||||||
*idListSz = idListIdx;
|
*idListSz = idListIdx;
|
||||||
*idx = begin;
|
*idx = begin;
|
||||||
|
}
|
||||||
|
|
||||||
return WS_SUCCESS;
|
WLOG(WS_LOG_DEBUG, "Leaving DoNameList(), ret = %d", ret);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -855,7 +871,9 @@ static int DoKexInit(WOLFSSH* ssh, uint8_t* buf, uint32_t len, uint32_t* idx)
|
||||||
uint8_t list[3];
|
uint8_t list[3];
|
||||||
uint32_t listSz;
|
uint32_t listSz;
|
||||||
uint32_t skipSz;
|
uint32_t skipSz;
|
||||||
uint32_t begin = *idx;
|
uint32_t begin;
|
||||||
|
|
||||||
|
WLOG(WS_LOG_DEBUG, "Entering DoKexInit()");
|
||||||
|
|
||||||
if (ssh == NULL || buf == NULL || len == 0 || idx == NULL)
|
if (ssh == NULL || buf == NULL || len == 0 || idx == NULL)
|
||||||
ret = WS_BAD_ARGUMENT;
|
ret = WS_BAD_ARGUMENT;
|
||||||
|
@ -867,126 +885,182 @@ static int DoKexInit(WOLFSSH* ssh, uint8_t* buf, uint32_t len, uint32_t* idx)
|
||||||
* is save the actual values.
|
* is save the actual values.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
if (ret == WS_SUCCESS) {
|
||||||
|
begin = *idx;
|
||||||
|
|
||||||
/* Check that the cookie exists inside the message */
|
/* Check that the cookie exists inside the message */
|
||||||
if (begin + COOKIE_SZ > len) {
|
if (begin + COOKIE_SZ > len) {
|
||||||
/* error, out of bounds */
|
/* error, out of bounds */
|
||||||
return WS_FATAL_ERROR;
|
ret = WS_PARSE_E;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
/* Move past the cookie. */
|
/* Move past the cookie. */
|
||||||
begin += COOKIE_SZ;
|
begin += COOKIE_SZ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* KEX Algorithms */
|
/* KEX Algorithms */
|
||||||
|
if (ret == WS_SUCCESS) {
|
||||||
WLOG(WS_LOG_DEBUG, "DKI: KEX Algorithms");
|
WLOG(WS_LOG_DEBUG, "DKI: KEX Algorithms");
|
||||||
listSz = 2;
|
listSz = 2;
|
||||||
DoNameList(list, &listSz, buf, len, &begin);
|
ret = DoNameList(list, &listSz, buf, len, &begin);
|
||||||
|
if (ret == WS_SUCCESS) {
|
||||||
algoId = MatchIdLists(list, listSz, cannedKexAlgo, cannedKexAlgoSz);
|
algoId = MatchIdLists(list, listSz, cannedKexAlgo, cannedKexAlgoSz);
|
||||||
if (algoId == ID_UNKNOWN) {
|
if (algoId == ID_UNKNOWN) {
|
||||||
WLOG(WS_LOG_DEBUG, "Unable to negotiate KEX Algo");
|
WLOG(WS_LOG_DEBUG, "Unable to negotiate KEX Algo");
|
||||||
return WS_INVALID_ALGO_ID;
|
ret = WS_INVALID_ALGO_ID;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ssh->handshake->kexId = algoId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ssh->handshake->kexId = algoId;
|
|
||||||
|
|
||||||
/* Server Host Key Algorithms */
|
/* Server Host Key Algorithms */
|
||||||
|
if (ret == WS_SUCCESS) {
|
||||||
WLOG(WS_LOG_DEBUG, "DKI: Server Host Key Algorithms");
|
WLOG(WS_LOG_DEBUG, "DKI: Server Host Key Algorithms");
|
||||||
listSz = 1;
|
listSz = 1;
|
||||||
DoNameList(list, &listSz, buf, len, &begin);
|
ret = DoNameList(list, &listSz, buf, len, &begin);
|
||||||
|
if (ret == WS_SUCCESS) {
|
||||||
algoId = MatchIdLists(list, listSz, cannedKeyAlgo, cannedKeyAlgoSz);
|
algoId = MatchIdLists(list, listSz, cannedKeyAlgo, cannedKeyAlgoSz);
|
||||||
if (algoId == ID_UNKNOWN) {
|
if (algoId == ID_UNKNOWN) {
|
||||||
WLOG(WS_LOG_DEBUG, "Unable to negotiate Server Host Key Algo");
|
WLOG(WS_LOG_DEBUG, "Unable to negotiate Server Host Key Algo");
|
||||||
return WS_INVALID_ALGO_ID;
|
return WS_INVALID_ALGO_ID;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
ssh->handshake->pubKeyId = algoId;
|
ssh->handshake->pubKeyId = algoId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Enc Algorithms - Client to Server */
|
/* Enc Algorithms - Client to Server */
|
||||||
|
if (ret == WS_SUCCESS) {
|
||||||
WLOG(WS_LOG_DEBUG, "DKI: Enc Algorithms - Client to Server");
|
WLOG(WS_LOG_DEBUG, "DKI: Enc Algorithms - Client to Server");
|
||||||
listSz = 3;
|
listSz = 3;
|
||||||
DoNameList(list, &listSz, buf, len, &begin);
|
ret = DoNameList(list, &listSz, buf, len, &begin);
|
||||||
|
if (ret == WS_SUCCESS) {
|
||||||
algoId = MatchIdLists(list, listSz, cannedEncAlgo, cannedEncAlgoSz);
|
algoId = MatchIdLists(list, listSz, cannedEncAlgo, cannedEncAlgoSz);
|
||||||
if (algoId == ID_UNKNOWN) {
|
if (algoId == ID_UNKNOWN) {
|
||||||
WLOG(WS_LOG_DEBUG, "Unable to negotiate Encryption Algo C2S");
|
WLOG(WS_LOG_DEBUG, "Unable to negotiate Encryption Algo C2S");
|
||||||
return WS_INVALID_ALGO_ID;
|
ret = WS_INVALID_ALGO_ID;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enc Algorithms - Server to Client */
|
/* Enc Algorithms - Server to Client */
|
||||||
|
if (ret == WS_SUCCESS) {
|
||||||
WLOG(WS_LOG_DEBUG, "DKI: Enc Algorithms - Server to Client");
|
WLOG(WS_LOG_DEBUG, "DKI: Enc Algorithms - Server to Client");
|
||||||
listSz = 3;
|
listSz = 3;
|
||||||
DoNameList(list, &listSz, buf, len, &begin);
|
ret = DoNameList(list, &listSz, buf, len, &begin);
|
||||||
if (MatchIdLists(list, listSz, &algoId, 1) == ID_UNKNOWN) {
|
if (MatchIdLists(list, listSz, &algoId, 1) == ID_UNKNOWN) {
|
||||||
WLOG(WS_LOG_DEBUG, "Unable to negotiate Encryption Algo S2C");
|
WLOG(WS_LOG_DEBUG, "Unable to negotiate Encryption Algo S2C");
|
||||||
return WS_INVALID_ALGO_ID;
|
ret = WS_INVALID_ALGO_ID;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
ssh->handshake->encryptId = algoId;
|
ssh->handshake->encryptId = algoId;
|
||||||
ssh->handshake->blockSz = ssh->ivClientSz = ssh->ivServerSz
|
ssh->handshake->blockSz = ssh->ivClientSz = ssh->ivServerSz
|
||||||
= BlockSzForId(algoId);
|
= BlockSzForId(algoId);
|
||||||
ssh->encKeyClientSz = ssh->encKeyServerSz = KeySzForId(algoId);
|
ssh->encKeyClientSz = ssh->encKeyServerSz = KeySzForId(algoId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* MAC Algorithms - Client to Server */
|
/* MAC Algorithms - Client to Server */
|
||||||
|
if (ret == WS_SUCCESS) {
|
||||||
WLOG(WS_LOG_DEBUG, "DKI: MAC Algorithms - Client to Server");
|
WLOG(WS_LOG_DEBUG, "DKI: MAC Algorithms - Client to Server");
|
||||||
listSz = 2;
|
listSz = 2;
|
||||||
DoNameList(list, &listSz, buf, len, &begin);
|
ret = DoNameList(list, &listSz, buf, len, &begin);
|
||||||
|
if (ret == WS_SUCCESS) {
|
||||||
algoId = MatchIdLists(list, listSz, cannedMacAlgo, cannedMacAlgoSz);
|
algoId = MatchIdLists(list, listSz, cannedMacAlgo, cannedMacAlgoSz);
|
||||||
if (algoId == ID_UNKNOWN) {
|
if (algoId == ID_UNKNOWN) {
|
||||||
WLOG(WS_LOG_DEBUG, "Unable to negotiate MAC Algo C2S");
|
WLOG(WS_LOG_DEBUG, "Unable to negotiate MAC Algo C2S");
|
||||||
return WS_INVALID_ALGO_ID;
|
ret = WS_INVALID_ALGO_ID;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MAC Algorithms - Server to Client */
|
/* MAC Algorithms - Server to Client */
|
||||||
|
if (ret == WS_SUCCESS) {
|
||||||
WLOG(WS_LOG_DEBUG, "DKI: MAC Algorithms - Server to Client");
|
WLOG(WS_LOG_DEBUG, "DKI: MAC Algorithms - Server to Client");
|
||||||
listSz = 2;
|
listSz = 2;
|
||||||
DoNameList(list, &listSz, buf, len, &begin);
|
ret = DoNameList(list, &listSz, buf, len, &begin);
|
||||||
|
if (ret == WS_SUCCESS) {
|
||||||
if (MatchIdLists(list, listSz, &algoId, 1) == ID_UNKNOWN) {
|
if (MatchIdLists(list, listSz, &algoId, 1) == ID_UNKNOWN) {
|
||||||
WLOG(WS_LOG_DEBUG, "Unable to negotiate MAC Algo S2C");
|
WLOG(WS_LOG_DEBUG, "Unable to negotiate MAC Algo S2C");
|
||||||
return WS_INVALID_ALGO_ID;
|
ret = WS_INVALID_ALGO_ID;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
ssh->handshake->macId = algoId;
|
ssh->handshake->macId = algoId;
|
||||||
ssh->handshake->macSz = MacSzForId(algoId);
|
ssh->handshake->macSz = MacSzForId(algoId);
|
||||||
ssh->macKeyClientSz = ssh->macKeyServerSz = KeySzForId(algoId);
|
ssh->macKeyClientSz = ssh->macKeyServerSz = KeySzForId(algoId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Compression Algorithms - Client to Server */
|
||||||
|
if (ret == WS_SUCCESS) {
|
||||||
/* The compression algorithm lists should have none as a value. */
|
/* The compression algorithm lists should have none as a value. */
|
||||||
algoId = ID_NONE;
|
algoId = ID_NONE;
|
||||||
|
|
||||||
/* Compression Algorithms - Client to Server */
|
|
||||||
WLOG(WS_LOG_DEBUG, "DKI: Compression Algorithms - Client to Server");
|
WLOG(WS_LOG_DEBUG, "DKI: Compression Algorithms - Client to Server");
|
||||||
listSz = 1;
|
listSz = 1;
|
||||||
DoNameList(list, &listSz, buf, len, &begin);
|
ret = DoNameList(list, &listSz, buf, len, &begin);
|
||||||
|
if (ret == WS_SUCCESS) {
|
||||||
if (MatchIdLists(list, listSz, &algoId, 1) == ID_UNKNOWN) {
|
if (MatchIdLists(list, listSz, &algoId, 1) == ID_UNKNOWN) {
|
||||||
WLOG(WS_LOG_DEBUG, "Unable to negotiate Compression Algo C2S");
|
WLOG(WS_LOG_DEBUG, "Unable to negotiate Compression Algo C2S");
|
||||||
return WS_INVALID_ALGO_ID;
|
ret = WS_INVALID_ALGO_ID;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compression Algorithms - Server to Client */
|
/* Compression Algorithms - Server to Client */
|
||||||
|
if (ret == WS_SUCCESS) {
|
||||||
WLOG(WS_LOG_DEBUG, "DKI: Compression Algorithms - Server to Client");
|
WLOG(WS_LOG_DEBUG, "DKI: Compression Algorithms - Server to Client");
|
||||||
listSz = 1;
|
listSz = 1;
|
||||||
DoNameList(list, &listSz, buf, len, &begin);
|
ret = DoNameList(list, &listSz, buf, len, &begin);
|
||||||
|
if (ret == WS_SUCCESS) {
|
||||||
if (MatchIdLists(list, listSz, &algoId, 1) == ID_UNKNOWN) {
|
if (MatchIdLists(list, listSz, &algoId, 1) == ID_UNKNOWN) {
|
||||||
WLOG(WS_LOG_DEBUG, "Unable to negotiate Compression Algo S2C");
|
WLOG(WS_LOG_DEBUG, "Unable to negotiate Compression Algo S2C");
|
||||||
return WS_INVALID_ALGO_ID;
|
ret = WS_INVALID_ALGO_ID;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Languages - Client to Server, skip */
|
/* Languages - Client to Server, skip */
|
||||||
ato32(buf + begin, &skipSz);
|
if (ret == WS_SUCCESS) {
|
||||||
begin += 4 + skipSz;
|
WLOG(WS_LOG_DEBUG, "DKI: Languages - Client to Server");
|
||||||
|
ret = GetUint32(&skipSz, buf, len, &begin);
|
||||||
|
if (ret == WS_SUCCESS)
|
||||||
|
begin += skipSz;
|
||||||
|
}
|
||||||
|
|
||||||
/* Languages - Server to Client, skip */
|
/* Languages - Server to Client, skip */
|
||||||
ato32(buf + begin, &skipSz);
|
if (ret == WS_SUCCESS) {
|
||||||
begin += 4 + skipSz;
|
WLOG(WS_LOG_DEBUG, "DKI: Languages - Server to Client");
|
||||||
|
ret = GetUint32(&skipSz, buf, len, &begin);
|
||||||
|
if (ret == WS_SUCCESS)
|
||||||
|
begin += skipSz;
|
||||||
|
}
|
||||||
|
|
||||||
/* First KEX Packet Follows */
|
/* First KEX Packet Follows */
|
||||||
ssh->handshake->kexPacketFollows = buf[begin];
|
if (ret == WS_SUCCESS) {
|
||||||
begin += 1;
|
WLOG(WS_LOG_DEBUG, "DKI: KEX Packet Follows");
|
||||||
|
ret = GetBoolean(&ssh->handshake->kexPacketFollows, buf, len, &begin);
|
||||||
|
}
|
||||||
|
|
||||||
/* Skip the "for future use" length. */
|
/* Skip the "for future use" length. */
|
||||||
ato32(buf + begin, &skipSz);
|
if (ret == WS_SUCCESS) {
|
||||||
begin += 4 + skipSz;
|
WLOG(WS_LOG_DEBUG, "DKI: For Future Use");
|
||||||
|
ret = GetUint32(&skipSz, buf, len, &begin);
|
||||||
|
if (ret == WS_SUCCESS)
|
||||||
|
begin += skipSz;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == WS_SUCCESS) {
|
||||||
*idx = begin;
|
*idx = begin;
|
||||||
|
|
||||||
ssh->clientState = CLIENT_KEXINIT_DONE;
|
ssh->clientState = CLIENT_KEXINIT_DONE;
|
||||||
return WS_SUCCESS;
|
}
|
||||||
|
|
||||||
|
WLOG(WS_LOG_DEBUG, "Leaving DoKexInit(), ret = %d", ret);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2080,11 +2154,11 @@ static int DoPacket(WOLFSSH* ssh)
|
||||||
|
|
||||||
case MSGID_KEXINIT:
|
case MSGID_KEXINIT:
|
||||||
{
|
{
|
||||||
uint8_t scratchLen[LENGTH_SZ];
|
uint8_t szFlat[LENGTH_SZ];
|
||||||
|
|
||||||
WLOG(WS_LOG_DEBUG, "Decoding MSGID_KEXINIT");
|
WLOG(WS_LOG_DEBUG, "Decoding MSGID_KEXINIT");
|
||||||
c32toa(payloadSz + sizeof(msg), scratchLen);
|
c32toa(payloadSz + sizeof(msg), szFlat);
|
||||||
wc_ShaUpdate(&ssh->handshake->hash, scratchLen, LENGTH_SZ);
|
wc_ShaUpdate(&ssh->handshake->hash, szFlat, LENGTH_SZ);
|
||||||
wc_ShaUpdate(&ssh->handshake->hash, &msg, sizeof(msg));
|
wc_ShaUpdate(&ssh->handshake->hash, &msg, sizeof(msg));
|
||||||
wc_ShaUpdate(&ssh->handshake->hash, buf + idx, payloadSz);
|
wc_ShaUpdate(&ssh->handshake->hash, buf + idx, payloadSz);
|
||||||
ret = DoKexInit(ssh, buf + idx, payloadSz, &payloadIdx);
|
ret = DoKexInit(ssh, buf + idx, payloadSz, &payloadIdx);
|
||||||
|
|
Loading…
Reference in New Issue