Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions src/ssh.c
Original file line number Diff line number Diff line change
Expand Up @@ -5195,6 +5195,47 @@ static int _ChannelReadExt(WOLFSSH_CHANNEL* channel, byte* buf, word32 bufSz)
}


int wolfSSH_ChannelIdPeek(WOLFSSH* ssh, word32 channelId,
byte* buf, word32 bufSz)
{
WOLFSSH_CHANNEL* channel = NULL;
WOLFSSH_BUFFER* inputBuffer;
word32 avail;

WLOG(WS_LOG_DEBUG, "Entering wolfSSH_ChannelIdPeek(), ID = %u", channelId);

if (ssh == NULL)
return WS_BAD_ARGUMENT;

channel = ChannelFind(ssh, channelId, WS_CHANNEL_ID_SELF);
if (channel == NULL)
return WS_INVALID_CHANID;

inputBuffer = &channel->inputBuffer;
avail = inputBuffer->length - inputBuffer->idx;

/* Report the EOF only once the buffered data is drained. */
if (avail == 0 && channel->eofRxd) {
ssh->error = WS_EOF;
return WS_ERROR;
}

/* The EOF above outranks this: it names the channel. */
if (avail == 0 && ssh->disconnected) {
ssh->error = WS_DISCONNECT;
return WS_FATAL_ERROR;
}

bufSz = min(bufSz, avail);
if (buf != NULL) {
WMEMCPY(buf, inputBuffer->buffer + inputBuffer->idx, bufSz);
}

WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_ChannelIdPeek(), rxd = %u", bufSz);
return (int)bufSz;
}


int wolfSSH_ChannelIdRead(WOLFSSH* ssh, word32 channelId,
byte* buf, word32 bufSz)
{
Expand Down
34 changes: 18 additions & 16 deletions tests/sftp.c
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,9 @@ int wolfSSH_SftpTest(int flag)
int ret = 0;
int argsCount;

const char* args[10];
/* The server thread holds ser.argv, so the client cannot share it. */
const char* argsServer[10];
const char* argsClient[10];
#ifndef USE_WINDOWS_API
char portNumber[8];
#endif
Expand All @@ -496,40 +498,40 @@ int wolfSSH_SftpTest(int flag)
#endif

argsCount = 0;
args[argsCount++] = ".";
args[argsCount++] = "-1";
argsServer[argsCount++] = ".";
argsServer[argsCount++] = "-1";
#ifndef USE_WINDOWS_API
args[argsCount++] = "-p";
args[argsCount++] = "0";
argsServer[argsCount++] = "-p";
argsServer[argsCount++] = "0";
#endif
if (flag)
args[argsCount++] = "-N";
argsServer[argsCount++] = "-N";

ser.argv = (char**)args;
ser.argv = (char**)argsServer;
ser.argc = argsCount;
ser.signal = &ready;
InitTcpReady(ser.signal);
ThreadStart(echoserver_test, (void*)&ser, &serThread);
WaitTcpReady(&ready);

argsCount = 0;
args[argsCount++] = ".";
args[argsCount++] = "-u";
args[argsCount++] = "jill";
args[argsCount++] = "-P";
args[argsCount++] = "upthehill";
argsClient[argsCount++] = ".";
argsClient[argsCount++] = "-u";
argsClient[argsCount++] = "jill";
argsClient[argsCount++] = "-P";
argsClient[argsCount++] = "upthehill";

#ifndef USE_WINDOWS_API
/* use port that server has found */
args[argsCount++] = "-p";
argsClient[argsCount++] = "-p";
snprintf(portNumber, sizeof(portNumber), "%d", ready.port);
args[argsCount++] = portNumber;
argsClient[argsCount++] = portNumber;
#endif

if (flag)
args[argsCount++] = "-N";
argsClient[argsCount++] = "-N";

cli.argv = (char**)args;
cli.argv = (char**)argsClient;
cli.argc = argsCount;
cli.signal = &ready;
cli.sftp_cb = commandCb;
Expand Down
121 changes: 121 additions & 0 deletions tests/unit.c
Original file line number Diff line number Diff line change
Expand Up @@ -10006,6 +10006,122 @@ static int test_stream_read_deferredWindowAdjust(void)
return result;
}

/* wolfSSH_ChannelIdPeek() reports a named channel without consuming it. */
static int test_ChannelIdPeek(void)
{
WOLFSSH_CTX* ctx = NULL;
WOLFSSH* ssh = NULL;
WOLFSSH_CHANNEL* ch = NULL;
int result = 0;
int ret;
byte in[32];
byte out[32];
word32 i;

for (i = 0; i < (word32)sizeof(in); i++) {
in[i] = (byte)(i + 1);
}

ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_SERVER, NULL);
if (ctx == NULL)
return -7050;

ssh = wolfSSH_new(ctx);
if (ssh == NULL) { result = -7051; goto done; }

/* Bad args, before any channel exists. */
if (wolfSSH_ChannelIdPeek(NULL, 0, out, (word32)sizeof(out))
!= WS_BAD_ARGUMENT) {
result = -7052; goto done;
}
if (wolfSSH_ChannelIdPeek(ssh, 99, out, (word32)sizeof(out))
!= WS_INVALID_CHANID) {
result = -7053; goto done;
}

ch = ChannelNew(ssh, ID_CHANTYPE_SESSION,
(word32)sizeof(in), DEFAULT_MAX_PACKET_SZ);
if (ch == NULL) { result = -7054; goto done; }
if (ChannelAppend(ssh, ch) != WS_SUCCESS) {
ChannelDelete(ch, ssh->ctx->heap);
result = -7055;
goto done;
}
ch->openConfirmed = 1;

/* Open and empty: zero, not an error. */
ret = wolfSSH_ChannelIdPeek(ssh, ch->channel, out, (word32)sizeof(out));
if (ret != 0) { result = -7056; goto done; }

if (wolfSSH_TestChannelPutData(ch, in, (word32)sizeof(in)) != WS_SUCCESS) {
result = -7057; goto done;
}

/* Whole payload reported and copied out. */
WMEMSET(out, 0, sizeof(out));
ret = wolfSSH_ChannelIdPeek(ssh, ch->channel, out, (word32)sizeof(out));
if (ret != (int)sizeof(in)) { result = -7058; goto done; }
if (WMEMCMP(out, in, sizeof(in)) != 0) { result = -7059; goto done; }

/* Consumed nothing, credited nothing. */
if (ch->inputBuffer.length - ch->inputBuffer.idx != (word32)sizeof(in)) {
result = -7060; goto done;
}
if (ch->windowSz != 0) { result = -7061; goto done; }

/* bufSz caps the count and the bytes written. */
WMEMSET(out, 0, sizeof(out));
ret = wolfSSH_ChannelIdPeek(ssh, ch->channel, out, 8);
if (ret != 8) { result = -7062; goto done; }
if (WMEMCMP(out, in, 8) != 0) { result = -7063; goto done; }
if (out[8] != 0) { result = -7064; goto done; }

/* A NULL buffer asks only for the count. */
ret = wolfSSH_ChannelIdPeek(ssh, ch->channel, NULL, (word32)sizeof(out));
if (ret != (int)sizeof(in)) { result = -7065; goto done; }

/* Still reported mid-rekey, where stream_peek returns WS_REKEYING. */
ssh->isKeying = WOLFSSH_SELF_IS_KEYING;
if (wolfSSH_stream_peek(ssh, out, (word32)sizeof(out)) != WS_REKEYING) {
result = -7066; goto done;
}
ret = wolfSSH_ChannelIdPeek(ssh, ch->channel, out, (word32)sizeof(out));
if (ret != (int)sizeof(in)) { result = -7067; goto done; }
ssh->isKeying = 0;

/* EOF stays hidden until the buffered data is drained. */
ch->eofRxd = 1;
ret = wolfSSH_ChannelIdPeek(ssh, ch->channel, out, (word32)sizeof(out));
if (ret != (int)sizeof(in)) { result = -7068; goto done; }

ret = wolfSSH_ChannelIdRead(ssh, ch->channel, out, (word32)sizeof(out));
if (ret != (int)sizeof(in)) { result = -7069; goto done; }

ssh->error = WS_SUCCESS;
ret = wolfSSH_ChannelIdPeek(ssh, ch->channel, out, (word32)sizeof(out));
if (ret != WS_ERROR) { result = -7070; goto done; }
if (ssh->error != WS_EOF) { result = -7071; goto done; }

/* EOF outranks a disconnect. */
ssh->disconnected = 1;
ssh->error = WS_SUCCESS;
ret = wolfSSH_ChannelIdPeek(ssh, ch->channel, out, (word32)sizeof(out));
if (ret != WS_ERROR) { result = -7072; goto done; }
if (ssh->error != WS_EOF) { result = -7073; goto done; }

/* Without the EOF, the dead session is reported instead. */
ch->eofRxd = 0;
ssh->error = WS_SUCCESS;
ret = wolfSSH_ChannelIdPeek(ssh, ch->channel, out, (word32)sizeof(out));
if (ret != WS_FATAL_ERROR) { result = -7074; goto done; }
if (ssh->error != WS_DISCONNECT) { result = -7075; goto done; }

done:
wolfSSH_free(ssh);
wolfSSH_CTX_free(ctx);
return result;
}

/* wolfSSH_ChannelIdRead() counterpart of
* test_stream_read_deferredWindowAdjust(): callers break out on a non-positive
* read, and this entry point has to retire the owed-flush status itself. */
Expand Down Expand Up @@ -23094,6 +23210,11 @@ int wolfSSH_UnitTest(int argc, char** argv)
printf("ChannelIdRead_deferredWindowAdjust: %s\n",
(unitResult == 0 ? "SUCCESS" : "FAILED"));
testResult = testResult || unitResult;

unitResult = test_ChannelIdPeek();
printf("ChannelIdPeek: %s\n",
(unitResult == 0 ? "SUCCESS" : "FAILED"));
testResult = testResult || unitResult;
#endif /* NO_WOLFSSH_SERVER */

unitResult = test_BuildNameList_emptySrc();
Expand Down
6 changes: 6 additions & 0 deletions wolfssh/ssh.h
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,12 @@ WOLFSSH_API int wolfSSH_global_request(WOLFSSH* ssh, const unsigned char* data,
* wolfSSH_ChannelRead() returns WS_REKEYING. */
WOLFSSH_API int wolfSSH_ChannelIdRead(WOLFSSH* ssh, word32 channelId,
byte* buf, word32 bufSz);
/* Peeks the channel named by channelId, with wolfSSH_stream_peek()'s
* contract, except that it peeks during a rekey the way
* wolfSSH_ChannelIdRead() reads during one. A NULL buf asks only for the
* count, still capped at bufSz. */
WOLFSSH_API int wolfSSH_ChannelIdPeek(WOLFSSH* ssh, word32 channelId,
byte* buf, word32 bufSz);
WOLFSSH_API int wolfSSH_ChannelIdSend(WOLFSSH* ssh, word32 channelId,
byte* buf, word32 bufSz);
WOLFSSH_API int wolfSSH_ChannelIdReadExt(WOLFSSH* ssh, word32 channelId,
Expand Down
Loading