mirror of https://github.com/wolfSSL/wolfssh.git
1. added in the stream send function
2. example uses the new send function 3. added in window size update receipt 4. tweaked the accept state machine to actually finishpull/1/head
parent
6975448d1b
commit
b548720a9a
|
@ -245,13 +245,13 @@ static THREAD_RETURN CYASSL_THREAD server_worker(void* vArgs)
|
|||
{
|
||||
WOLFSSH* ssh = (WOLFSSH*)vArgs;
|
||||
SOCKET_T clientFd = wolfSSH_get_fd(ssh);
|
||||
const char* msgA = "Who's there?!\n";
|
||||
const char* msgB = "Go away!\n";
|
||||
const char* msgA = "Who's there?!\r\n";
|
||||
const char* msgB = "Go away!\r\n";
|
||||
|
||||
if (wolfSSH_accept(ssh) == WS_SUCCESS) {
|
||||
send(clientFd, msgA, strlen(msgA), 0);
|
||||
wolfSSH_stream_send(ssh, (uint8_t*)msgA, (uint32_t)strlen(msgA));
|
||||
sleep(1);
|
||||
send(clientFd, msgB, strlen(msgB), 0);
|
||||
wolfSSH_stream_send(ssh, (uint8_t*)msgB, (uint32_t)strlen(msgB));
|
||||
}
|
||||
close(clientFd);
|
||||
wolfSSH_free(ssh);
|
||||
|
|
150
src/internal.c
150
src/internal.c
|
@ -136,6 +136,9 @@ const char* GetErrorString(int err)
|
|||
case WS_CREATE_MAC_E:
|
||||
return "verify mac error";
|
||||
|
||||
case WS_RESOURCE_E:
|
||||
return "insufficient resources for new channel";
|
||||
|
||||
default:
|
||||
return "Unknown error code";
|
||||
}
|
||||
|
@ -169,7 +172,10 @@ static const NameIdPair NameIdMap[] = {
|
|||
{ ID_SSH_RSA, "ssh-rsa" },
|
||||
|
||||
/* UserAuth IDs */
|
||||
{ ID_USERAUTH_PASSWORD, "password" }
|
||||
{ ID_USERAUTH_PASSWORD, "password" },
|
||||
|
||||
/* Channel Type IDs */
|
||||
{ ID_CHANTYPE_SESSION, "session" }
|
||||
};
|
||||
|
||||
|
||||
|
@ -207,6 +213,33 @@ const char* IdToName(uint8_t id)
|
|||
}
|
||||
|
||||
|
||||
static Channel* ChannelNew(WOLFSSH* ssh, uint8_t channelType,
|
||||
uint32_t peerChannel,
|
||||
uint32_t peerInitialWindowSz,
|
||||
uint32_t peerMaxPacketSz)
|
||||
{
|
||||
Channel *newChannel = NULL;
|
||||
|
||||
WLOG(WS_LOG_DEBUG, "Entering ChannelNew()");
|
||||
|
||||
if (!ssh->channel.inUse) {
|
||||
newChannel = &ssh->channel;
|
||||
newChannel->inUse = 1;
|
||||
newChannel->channelType = channelType;
|
||||
newChannel->channel = ssh->nextChannel++;
|
||||
newChannel->windowSz = DEFAULT_WINDOW_SZ;
|
||||
newChannel->maxPacketSz = DEFAULT_MAX_PACKET_SZ;
|
||||
newChannel->peerChannel = peerChannel;
|
||||
newChannel->peerWindowSz = peerInitialWindowSz;
|
||||
newChannel->peerMaxPacketSz = peerMaxPacketSz;
|
||||
}
|
||||
|
||||
WLOG(WS_LOG_INFO, "Leaving ChannelNew(), ret = %p", newChannel);
|
||||
|
||||
return newChannel;
|
||||
}
|
||||
|
||||
|
||||
int BufferInit(Buffer* buffer, uint32_t size, void* heap)
|
||||
{
|
||||
if (buffer == NULL)
|
||||
|
@ -1273,40 +1306,51 @@ static int DoChannelOpen(WOLFSSH* ssh,
|
|||
uint32_t begin = *idx;
|
||||
uint32_t typeSz;
|
||||
char type[32];
|
||||
uint32_t channel;
|
||||
uint32_t initialWindowSz;
|
||||
uint32_t maxPacketSz;
|
||||
uint8_t typeId;
|
||||
uint32_t peerChannel;
|
||||
uint32_t peerInitialWindowSz;
|
||||
uint32_t peerMaxPacketSz;
|
||||
int ret;
|
||||
Channel* newChannel;
|
||||
|
||||
WLOG(WS_LOG_DEBUG, "Entering DoChannelOpen()");
|
||||
|
||||
(void)ssh;
|
||||
(void)len;
|
||||
|
||||
ret = GetString(type, &typeSz, buf, len, &begin);
|
||||
|
||||
if (ret == WS_SUCCESS)
|
||||
ret = GetUint32(&channel, buf, len, &begin);
|
||||
ret = GetUint32(&peerChannel, buf, len, &begin);
|
||||
|
||||
if (ret == WS_SUCCESS)
|
||||
ret = GetUint32(&initialWindowSz, buf, len, &begin);
|
||||
ret = GetUint32(&peerInitialWindowSz, buf, len, &begin);
|
||||
|
||||
if (ret == WS_SUCCESS)
|
||||
ret = GetUint32(&maxPacketSz, buf, len, &begin);
|
||||
ret = GetUint32(&peerMaxPacketSz, buf, len, &begin);
|
||||
|
||||
if (ret != WS_SUCCESS) {
|
||||
WLOG(WS_LOG_DEBUG, "Leaving DoChannelOpen(), ret = %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
WLOG(WS_LOG_DEBUG, " type = %s", type);
|
||||
WLOG(WS_LOG_DEBUG, " channel = %u", channel);
|
||||
WLOG(WS_LOG_DEBUG, " initialWindowSz = %u", initialWindowSz);
|
||||
WLOG(WS_LOG_DEBUG, " maxPacketSz = %u", maxPacketSz);
|
||||
WLOG(WS_LOG_INFO, " type = %s", type);
|
||||
WLOG(WS_LOG_INFO, " peerChannel = %u", peerChannel);
|
||||
WLOG(WS_LOG_INFO, " peerInitialWindowSz = %u", peerInitialWindowSz);
|
||||
WLOG(WS_LOG_INFO, " peerMaxPacketSz = %u", peerMaxPacketSz);
|
||||
|
||||
*idx = begin;
|
||||
|
||||
ssh->clientState = CLIENT_CHANNEL_REQUEST_DONE;
|
||||
typeId = NameToId(type, typeSz);
|
||||
if (typeId != ID_CHANTYPE_SESSION)
|
||||
return WS_INVALID_CHANTYPE;
|
||||
|
||||
newChannel = ChannelNew(ssh, typeId,
|
||||
peerChannel, peerInitialWindowSz, peerMaxPacketSz);
|
||||
if (newChannel == NULL)
|
||||
return WS_RESOURCE_E;
|
||||
|
||||
ssh->clientState = CLIENT_DONE;
|
||||
newChannel->peerChannel = peerChannel;
|
||||
newChannel->peerWindowSz = peerInitialWindowSz;
|
||||
newChannel->peerMaxPacketSz = peerMaxPacketSz;
|
||||
|
||||
return WS_SUCCESS;
|
||||
}
|
||||
|
@ -1398,6 +1442,36 @@ static int DoChannelRequest(WOLFSSH* ssh,
|
|||
}
|
||||
|
||||
|
||||
static int DoChannelWindowAdjust(WOLFSSH* ssh,
|
||||
uint8_t* buf, uint32_t len, uint32_t* idx)
|
||||
{
|
||||
uint32_t begin = *idx;
|
||||
uint32_t channel, bytesToAdd;
|
||||
int ret;
|
||||
|
||||
WLOG(WS_LOG_DEBUG, "Entering DoChannelWindowAdjust()");
|
||||
|
||||
ret = GetUint32(&channel, buf, len, &begin);
|
||||
if (ret == WS_SUCCESS)
|
||||
ret = GetUint32(&bytesToAdd, buf, len, &begin);
|
||||
|
||||
if (ret != WS_SUCCESS) {
|
||||
WLOG(WS_LOG_DEBUG, "Leaving DoChannelWindowAdjust(), ret = %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
WLOG(WS_LOG_INFO, " channel = %u", channel);
|
||||
WLOG(WS_LOG_INFO, " bytesToAdd = %u", bytesToAdd);
|
||||
WLOG(WS_LOG_INFO, " peerWindowSz = %u", ssh->channel.peerWindowSz);
|
||||
|
||||
ssh->channel.peerWindowSz += bytesToAdd;
|
||||
WLOG(WS_LOG_INFO, " update peerWindowSz = %u", ssh->channel.peerWindowSz);
|
||||
|
||||
WLOG(WS_LOG_DEBUG, "Leaving DoChannelWindowAdjust()");
|
||||
return WS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int DoChannelData(WOLFSSH* ssh,
|
||||
uint8_t* buf, uint32_t len, uint32_t* idx)
|
||||
{
|
||||
|
@ -1416,7 +1490,7 @@ static int DoChannelData(WOLFSSH* ssh,
|
|||
return ret;
|
||||
}
|
||||
|
||||
SendChannelData(ssh, channel, buf + begin, dataSz);
|
||||
SendChannelData(ssh, ssh->channel.peerChannel, buf + begin, dataSz);
|
||||
|
||||
*idx = begin + dataSz;
|
||||
|
||||
|
@ -1505,6 +1579,12 @@ static int DoPacket(WOLFSSH* ssh)
|
|||
idx += payloadIdx;
|
||||
break;
|
||||
|
||||
case MSGID_CHANNEL_WINDOW_ADJUST:
|
||||
WLOG(WS_LOG_DEBUG, "Decoding MSGID_CHANNEL_WINDOW_ADJUST");
|
||||
DoChannelWindowAdjust(ssh, buf + idx, payloadSz, &payloadIdx);
|
||||
idx += payloadIdx;
|
||||
break;
|
||||
|
||||
case MSGID_CHANNEL_DATA:
|
||||
WLOG(WS_LOG_DEBUG, "Decoding MSGID_CHANNEL_DATA");
|
||||
DoChannelData(ssh, buf + idx, payloadSz, &payloadIdx);
|
||||
|
@ -2197,7 +2277,7 @@ int SendNewKeys(WOLFSSH* ssh)
|
|||
idx = ssh->outputBuffer.length;
|
||||
|
||||
output[idx++] = MSGID_NEWKEYS;
|
||||
|
||||
|
||||
ssh->outputBuffer.length = idx;
|
||||
|
||||
BundlePacket(ssh);
|
||||
|
@ -2470,11 +2550,17 @@ int SendChannelOpenConf(WOLFSSH* ssh)
|
|||
{
|
||||
uint8_t* output;
|
||||
uint32_t idx;
|
||||
Channel* channel;
|
||||
|
||||
WLOG(WS_LOG_DEBUG, "Entering SendChannelOpenConf()");
|
||||
|
||||
if (ssh == NULL)
|
||||
if (ssh == NULL) {
|
||||
WLOG(WS_LOG_DEBUG, "Leaving SendChannelOpenConf(), ret = %d",
|
||||
WS_BAD_ARGUMENT);
|
||||
return WS_BAD_ARGUMENT;
|
||||
}
|
||||
|
||||
channel = &ssh->channel;
|
||||
|
||||
PreparePacket(ssh, MSG_ID_SZ + (UINT32_SZ * 4));
|
||||
|
||||
|
@ -2482,13 +2568,13 @@ int SendChannelOpenConf(WOLFSSH* ssh)
|
|||
idx = ssh->outputBuffer.length;
|
||||
|
||||
output[idx++] = MSGID_CHANNEL_OPEN_CONF;
|
||||
c32toa(0, output + idx); /* recipient channel */
|
||||
c32toa(channel->peerChannel, output + idx);
|
||||
idx += UINT32_SZ;
|
||||
c32toa(0, output + idx); /* sender channel */
|
||||
c32toa(channel->channel, output + idx);
|
||||
idx += UINT32_SZ;
|
||||
c32toa(DEFAULT_WINDOW_SZ, output + idx);
|
||||
c32toa(channel->windowSz, output + idx);
|
||||
idx += UINT32_SZ;
|
||||
c32toa(DEFAULT_MAX_PACKET_SZ, output + idx);
|
||||
c32toa(channel->maxPacketSz, output + idx);
|
||||
idx += UINT32_SZ;
|
||||
|
||||
ssh->outputBuffer.length = idx;
|
||||
|
@ -2496,20 +2582,31 @@ int SendChannelOpenConf(WOLFSSH* ssh)
|
|||
BundlePacket(ssh);
|
||||
SendBuffered(ssh);
|
||||
|
||||
WLOG(WS_LOG_DEBUG, "Leaving SendChannelOpenConf()");
|
||||
return WS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int SendChannelData(WOLFSSH* ssh, uint32_t channel,
|
||||
int SendChannelData(WOLFSSH* ssh, uint32_t peerChannel,
|
||||
uint8_t* data, uint32_t dataSz)
|
||||
{
|
||||
uint8_t* output;
|
||||
uint32_t idx;
|
||||
Channel* channel;
|
||||
|
||||
WLOG(WS_LOG_DEBUG, "Entering SendChannelData()");
|
||||
|
||||
if (ssh == NULL)
|
||||
return WS_BAD_ARGUMENT;
|
||||
channel = &ssh->channel;
|
||||
|
||||
if (channel->peerChannel != peerChannel) {
|
||||
WLOG(WS_LOG_DEBUG, "Invalid peer channel");
|
||||
}
|
||||
|
||||
if (channel->peerWindowSz < dataSz) {
|
||||
WLOG(WS_LOG_DEBUG, "Peer window too small");
|
||||
}
|
||||
|
||||
PreparePacket(ssh, MSG_ID_SZ + UINT32_SZ + LENGTH_SZ + dataSz);
|
||||
|
||||
|
@ -2517,7 +2614,7 @@ int SendChannelData(WOLFSSH* ssh, uint32_t channel,
|
|||
idx = ssh->outputBuffer.length;
|
||||
|
||||
output[idx++] = MSGID_CHANNEL_DATA;
|
||||
c32toa(channel, output + idx);
|
||||
c32toa(channel->peerChannel, output + idx);
|
||||
idx += UINT32_SZ;
|
||||
c32toa(dataSz, output + idx);
|
||||
idx += LENGTH_SZ;
|
||||
|
@ -2529,6 +2626,11 @@ int SendChannelData(WOLFSSH* ssh, uint32_t channel,
|
|||
BundlePacket(ssh);
|
||||
SendBuffered(ssh);
|
||||
|
||||
WLOG(WS_LOG_INFO, " dataSz = %u", dataSz);
|
||||
WLOG(WS_LOG_INFO, " peerWindowSz = %u", channel->peerWindowSz);
|
||||
channel->peerWindowSz -= dataSz;
|
||||
WLOG(WS_LOG_INFO, " update peerWindowSz = %u", channel->peerWindowSz);
|
||||
|
||||
WLOG(WS_LOG_DEBUG, "Leaving SendChannelData()");
|
||||
return WS_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -158,7 +158,7 @@ void WLOG(enum wolfSSH_LogLevel level, const char *const fmt, ...)
|
|||
if (logFunction)
|
||||
logFunction(level, msgStr);
|
||||
else
|
||||
fprintf(stderr, "%s: [%s] %s\n", timeStr, GetLogStr(level), msgStr);
|
||||
fprintf(stdout, "%s: [%s] %s\n", timeStr, GetLogStr(level), msgStr);
|
||||
}
|
||||
|
||||
#endif /* DEBUG_WOLFSSH */
|
||||
|
|
36
src/ssh.c
36
src/ssh.c
|
@ -151,6 +151,7 @@ static WOLFSSH* SshInit(WOLFSSH* ssh, WOLFSSH_CTX* ctx)
|
|||
ssh->ioWriteCtx = &ssh->wfd; /* set */
|
||||
ssh->acceptState = ACCEPT_BEGIN;
|
||||
ssh->clientState = CLIENT_BEGIN;
|
||||
ssh->nextChannel = DEFAULT_NEXT_CHANNEL;
|
||||
ssh->blockSz = MIN_BLOCK_SZ;
|
||||
ssh->encryptId = ID_NONE;
|
||||
ssh->macId = ID_NONE;
|
||||
|
@ -401,7 +402,7 @@ int wolfSSH_accept(WOLFSSH* ssh)
|
|||
WLOG(WS_LOG_DEBUG, acceptState, "SERVER_USERAUTH_SENT");
|
||||
|
||||
case ACCEPT_SERVER_USERAUTH_SENT:
|
||||
while (ssh->clientState < CLIENT_CHANNEL_REQUEST_DONE) {
|
||||
while (ssh->clientState < CLIENT_DONE) {
|
||||
if ( (ssh->error = ProcessReply(ssh)) < 0) {
|
||||
WLOG(WS_LOG_DEBUG, acceptError,
|
||||
"SERVER_USERAUTH_SENT", ssh->error);
|
||||
|
@ -419,18 +420,31 @@ int wolfSSH_accept(WOLFSSH* ssh)
|
|||
}
|
||||
ssh->acceptState = ACCEPT_SERVER_CHANNEL_ACCEPT_SENT;
|
||||
WLOG(WS_LOG_DEBUG, acceptState, "SERVER_CHANNEL_ACCEPT_SENT");
|
||||
|
||||
case ACCEPT_SERVER_CHANNEL_ACCEPT_SENT:
|
||||
while (ssh->clientState < CLIENT_DONE) {
|
||||
if ( (ssh->error = ProcessReply(ssh)) < 0) {
|
||||
WLOG(WS_LOG_DEBUG, acceptError,
|
||||
"SERVER_CHANNEL_ACCEPT_SENT", ssh->error);
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return WS_FATAL_ERROR;
|
||||
return WS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int wolfSSH_stream_read(WOLFSSH* ssh, uint8_t* buf, uint32_t bufSz)
|
||||
{
|
||||
int bytesRxd = 0;
|
||||
|
||||
(void)ssh;
|
||||
(void)buf;
|
||||
(void)bufSz;
|
||||
|
||||
return bytesRxd;
|
||||
}
|
||||
|
||||
|
||||
int wolfSSH_stream_send(WOLFSSH* ssh, uint8_t* buf, uint32_t bufSz)
|
||||
{
|
||||
int bytesTxd = 0;
|
||||
|
||||
bytesTxd = SendChannelData(ssh, ssh->channel.peerChannel, buf, bufSz);
|
||||
|
||||
return bytesTxd;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -39,20 +39,20 @@ extern "C" {
|
|||
|
||||
/* main public return values */
|
||||
enum WS_ErrorCodes {
|
||||
WS_SUCCESS = 0, /* function success */
|
||||
WS_FATAL_ERROR = -1, /* general function failure */
|
||||
WS_BAD_ARGUMENT = -2, /* bad function argument */
|
||||
WS_MEMORY_E = -3, /* memory allocation failure */
|
||||
WS_BUFFER_E = -4, /* input/output buffer size error */
|
||||
WS_PARSE_E = -5, /* general parsing error */
|
||||
WS_NOT_COMPILED = -6, /* feature not compiled in */
|
||||
WS_OVERFLOW_E = -7, /* would overflow if continued */
|
||||
WS_BAD_USAGE = -8, /* bad example usage */
|
||||
WS_SUCCESS = 0, /* function success */
|
||||
WS_FATAL_ERROR = -1, /* general function failure */
|
||||
WS_BAD_ARGUMENT = -2, /* bad function argument */
|
||||
WS_MEMORY_E = -3, /* memory allocation failure */
|
||||
WS_BUFFER_E = -4, /* input/output buffer size error */
|
||||
WS_PARSE_E = -5, /* general parsing error */
|
||||
WS_NOT_COMPILED = -6, /* feature not compiled in */
|
||||
WS_OVERFLOW_E = -7, /* would overflow if continued */
|
||||
WS_BAD_USAGE = -8, /* bad example usage */
|
||||
WS_SOCKET_ERROR_E = -9,
|
||||
WS_WANT_READ = -10,
|
||||
WS_WANT_WRITE = -11,
|
||||
WS_RECV_OVERFLOW_E = -12,
|
||||
WS_VERSION_E = -13, /* Peer using wrong version of SSH */
|
||||
WS_VERSION_E = -13, /* Peer using wrong version of SSH */
|
||||
WS_SEND_OOB_READ_E = -14,
|
||||
WS_INPUT_CASE_E = -15,
|
||||
WS_BAD_FILETYPE_E = -16,
|
||||
|
@ -63,7 +63,9 @@ enum WS_ErrorCodes {
|
|||
WS_DECRYPT_E = -21,
|
||||
WS_ENCRYPT_E = -22,
|
||||
WS_VERIFY_MAC_E = -23,
|
||||
WS_CREATE_MAC_E = -24
|
||||
WS_CREATE_MAC_E = -24,
|
||||
WS_RESOURCE_E = -25, /* insufficient resources for new channel */
|
||||
WS_INVALID_CHANTYPE = -26, /* invalid channel type */
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -81,6 +81,9 @@ enum {
|
|||
/* UserAuth IDs */
|
||||
ID_USERAUTH_PASSWORD,
|
||||
|
||||
/* Channel Type IDs */
|
||||
ID_CHANTYPE_SESSION,
|
||||
|
||||
ID_UNKNOWN
|
||||
};
|
||||
|
||||
|
@ -99,6 +102,7 @@ enum {
|
|||
#define UINT32_SZ 4
|
||||
#define DEFAULT_WINDOW_SZ (1024 * 1024)
|
||||
#define DEFAULT_MAX_PACKET_SZ (16 * 1024)
|
||||
#define DEFAULT_NEXT_CHANNEL 13013
|
||||
|
||||
|
||||
WOLFSSH_LOCAL uint8_t NameToId(const char*, uint32_t);
|
||||
|
@ -163,13 +167,14 @@ typedef struct HandshakeInfo {
|
|||
|
||||
|
||||
typedef struct Channel {
|
||||
uint8_t inUse;
|
||||
uint8_t channelType;
|
||||
uint32_t channel;
|
||||
uint32_t windowSz;
|
||||
uint32_t maxPacketSz;
|
||||
uint32_t peerChannel;
|
||||
uint32_t peerWindowSz;
|
||||
uint32_t peerMaxPacketSz;
|
||||
uint32_t channel;
|
||||
uint32_t peerChannel;
|
||||
} Channel;
|
||||
|
||||
|
||||
|
@ -210,6 +215,9 @@ struct WOLFSSH {
|
|||
Ciphers encryptCipher;
|
||||
Ciphers decryptCipher;
|
||||
|
||||
uint32_t nextChannel;
|
||||
Channel channel;
|
||||
|
||||
Buffer inputBuffer;
|
||||
Buffer outputBuffer;
|
||||
RNG* rng;
|
||||
|
@ -291,8 +299,6 @@ enum ClientStates {
|
|||
CLIENT_USING_KEYS,
|
||||
CLIENT_USERAUTH_REQUEST_DONE,
|
||||
CLIENT_USERAUTH_DONE,
|
||||
CLIENT_CHANNEL_REQUEST_DONE,
|
||||
CLIENT_CHANNEL_PTY_OPEN,
|
||||
CLIENT_DONE
|
||||
};
|
||||
|
||||
|
@ -326,6 +332,7 @@ enum WS_MessageIds {
|
|||
|
||||
MSGID_CHANNEL_OPEN = 90,
|
||||
MSGID_CHANNEL_OPEN_CONF = 91,
|
||||
MSGID_CHANNEL_WINDOW_ADJUST = 93,
|
||||
MSGID_CHANNEL_DATA = 94,
|
||||
MSGID_CHANNEL_REQUEST = 98
|
||||
};
|
||||
|
|
|
@ -83,7 +83,9 @@ WOLFSSH_API int wolfSSH_CTX_UseCert_buffer(WOLFSSH_CTX*,
|
|||
WOLFSSH_API int wolfSSH_CTX_UseCaCert_buffer(WOLFSSH_CTX*,
|
||||
const uint8_t*, uint32_t, int);
|
||||
|
||||
WOLFSSH_API int wolfSSH_accept(WOLFSSH* ssh);
|
||||
WOLFSSH_API int wolfSSH_accept(WOLFSSH*);
|
||||
WOLFSSH_API int wolfSSH_stream_read(WOLFSSH*, uint8_t*, uint32_t);
|
||||
WOLFSSH_API int wolfSSH_stream_send(WOLFSSH*, uint8_t*, uint32_t);
|
||||
|
||||
|
||||
enum WS_EndpointTypes {
|
||||
|
|
Loading…
Reference in New Issue