Skip to content
Snippets Groups Projects
Commit a1c5e191 authored by Deucе's avatar Deucе :ok_hand_tone4:
Browse files

Add a test client and fix a couple bugs.

parent 85b62571
No related branches found
No related tags found
No related merge requests found
Pipeline #7331 passed
......@@ -32,4 +32,7 @@ target_link_libraries(deuce-ssh_static INTERFACE stdthreads)
target_link_libraries(deuce-ssh_shared PRIVATE ${OPENSSL_CRYPTO_LIBRARIES})
target_link_libraries(deuce-ssh_shared PRIVATE stdthreads)
add_executable(client EXCLUDE_FROM_ALL client.c)
target_link_libraries(client PRIVATE stdthreads deuce-ssh)
install(TARGETS deuce-ssh FILE_SET HEADERS)
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <errno.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <threads.h>
#include "ssh.h"
int sock = -1;
size_t txbufsz;
size_t txbuflen;
uint8_t *txbuf;
atomic_bool *tx_terminate;
cnd_t tx_cnd;
mtx_t tx_mtx;
struct deuce_ssh_session sess;
int
tx_thread(void *arg)
{
while ((tx_terminate == NULL || *tx_terminate == false) && (sock != -1)) {
mtx_lock(&tx_mtx);
if (txbufsz == 0)
cnd_wait(&tx_cnd, &tx_mtx);
mtx_unlock(&tx_mtx);
struct pollfd fd = {
.fd = sock,
.events = POLLOUT | POLLRDHUP,
.revents = 0,
};
if (poll(&fd, 1, 5000) == 1) {
if (fd.revents & POLLOUT) {
mtx_lock(&tx_mtx);
ssize_t sent = send(sock, txbuf, txbuflen, MSG_NOSIGNAL);
if (sent > 0) {
memmove(txbuf, &txbuf[sent], txbuflen - sent);
txbuflen -= sent;
}
else if (sent == -1) {
switch(errno) {
case EAGAIN:
case ENOBUFS:
break;
default:
shutdown(sock, SHUT_WR);
*tx_terminate = true;
break;
}
}
mtx_unlock(&tx_mtx);
}
if (fd.revents & (POLLHUP | POLLRDHUP)) {
shutdown(sock, SHUT_WR);
*tx_terminate = true;
}
}
}
return 0;
}
static int
tx(uint8_t *buf, size_t bufsz, atomic_bool *terminate, void *cbdata)
{
mtx_lock(&tx_mtx);
if (txbuflen + bufsz > txbufsz) {
uint8_t *nb = realloc(txbuf, txbuflen + bufsz);
if (nb == NULL) {
mtx_unlock(&tx_mtx);
return DEUCE_SSH_ERROR_ALLOC;
}
else {
tx_terminate = terminate;
txbuf = nb;
memcpy(&txbuf[txbuflen], buf, bufsz);
txbufsz = txbuflen + bufsz;
if (txbuflen == 0)
cnd_signal(&tx_cnd);
txbuflen += bufsz;
}
}
mtx_unlock(&tx_mtx);
return 0;
}
static int
rx(uint8_t *buf, size_t bufsz, atomic_bool *terminate, void *cbdata)
{
size_t rxlen = 0;
while ((*terminate == false) && (sock != -1) && rxlen < bufsz) {
struct pollfd fd = {
.fd = sock,
.events = POLLIN | POLLRDHUP,
.revents = 0,
};
if (poll(&fd, 1, 5000) == 1) {
if (fd.revents & POLLIN) {
ssize_t received = recv(sock, &buf[rxlen], bufsz - rxlen, MSG_DONTWAIT);
if (received > 0) {
rxlen += received;
}
else if (received == -1) {
switch(errno) {
case EAGAIN:
case EINTR:
break;
default:
shutdown(sock, SHUT_RD);
*terminate = true;
break;
}
}
}
if (fd.revents & (POLLHUP | POLLRDHUP)) {
shutdown(sock, SHUT_RD);
*terminate = true;
}
}
}
return 0;
}
static int
rxline(uint8_t *buf, size_t bufsz, size_t *bytes_received, atomic_bool *terminate, void *cbdata)
{
size_t pos = 0;
bool lastcr = false;
for (;;) {
int res = rx(&buf[pos], 1, terminate, cbdata);
if (res < 0)
return res;
if (buf[pos] == '\r')
lastcr = true;
if (buf[pos] == '\n' && lastcr) {
*bytes_received = pos + 1;
return 0;
}
if (pos + 1 < bufsz)
pos++;
}
}
static int
extra_line(uint8_t *buf, size_t bufsz, void *cbdata)
{
fprintf(stdout, "%.*s\n", (int)bufsz, buf);
return 0;
}
int main(int argc, char **argv)
{
struct sockaddr_in sa = {
.sin_len = sizeof(struct sockaddr_in),
.sin_family = AF_INET,
.sin_port = htons(22),
.sin_addr = htonl(0x7f000001),
};
mtx_init(&tx_mtx, mtx_plain);
cnd_init(&tx_cnd);
sock = socket(PF_INET, SOCK_STREAM, 0);
if (sock == -1)
return 1;
if (connect(sock, (struct sockaddr *)&sa, sa.sin_len) == -1)
return 1;
if (deuce_ssh_transport_set_callbacks(tx, rx, rxline, extra_line) != 0)
return 1;
thrd_t thr;
thrd_create(&thr, tx_thread, NULL);
deuce_ssh_session_init(&sess);
int res;
thrd_join(thr, &res);
}
......@@ -32,7 +32,7 @@ static inline bool
missing_crlf(uint8_t *buf, size_t buflen)
{
assert(buflen >= 2);
return (buf[buflen - 1] == '\n' && buf[buflen - 2] == '\r');
return (buf[buflen - 1] != '\n' || buf[buflen - 2] != '\r');
}
static inline bool
......@@ -48,7 +48,7 @@ is_20(uint8_t *buf, size_t buflen)
{
if (buflen < 8)
return false;
return (buf[4] == '2' && buf[5] != '.' && buf[6] != '0' && buf[7] != '-');
return (buf[4] == '2' && buf[5] == '.' && buf[6] == '0' && buf[7] == '-');
}
static inline void *
......@@ -144,15 +144,21 @@ tx_handshake(void *arg)
memcpy(line, "SSH-2.0-", 8);
sz += 8;
size_t asz = strlen(gconf.software_version);
if (sz + asz + 2 > 255)
return DEUCE_SSH_ERROR_TOOLONG;
memcpy(&line[sz], gconf.software_version, asz);
sz += asz;
if (gconf.version_comment != NULL) {
memcpy(&line[sz], " ", 1);
sz += 1;
asz = strlen(gconf.version_comment);
if (sz + asz + 2 > 255)
return DEUCE_SSH_ERROR_TOOLONG;
memcpy(&line[sz], gconf.version_comment, asz);
sz += asz;
}
memcpy(&line[sz], "\r\n", 2);
sz += 2;
res = gconf.tx(line, sz, &sess->terminate, sess->tx_cbdata);
if (res < 0) {
sess->terminate = true;
......
......@@ -22,6 +22,7 @@ _Static_assert(0, "threads.h support required");
#define DEUCE_SSH_ERROR_TERMINATED -5
#define DEUCE_SSH_ERROR_TOOLATE -6
#define DEUCE_SSH_ERROR_TOOMANY -7
#define DEUCE_SSH_ERROR_TOOLONG -8
typedef struct deuce_ssh_transport_state *deuce_ssh_transport_state_t;
typedef int (*deuce_ssh_transport_io_cb_t)(uint8_t *buf, size_t bufsz, atomic_bool *terminate, void *cbdata);
......@@ -50,4 +51,6 @@ int deuce_ssh_session_init(deuce_ssh_session_t sess);
bool deuce_ssh_session_terminate(deuce_ssh_session_t sess);
void deuce_ssh_session_cleanup(deuce_ssh_session_t sess);
int deuce_ssh_transport_set_callbacks(deuce_ssh_transport_io_cb_t tx, deuce_ssh_transport_io_cb_t rx, deuce_ssh_transport_rxline_cb_t rx_line, deuce_ssh_transport_extra_line_cb_t extra_line_cb);
#endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment