aos/usr/netcat/main.c
2022-06-02 20:42:11 +02:00

164 lines
4.8 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <aos/aos.h>
#include <aos/waitset_chan.h>
#include <aos/aos_rpc.h>
#include <aos/ump_binding.h>
#include <aos/ump_chan.h>
#include <aos/ump_net.h>
#include <aos/ump_net_client.h>
#include <netutil/ip.h>
#define BUF_SIZE (1500 - 20 - 8)
struct send_buf {
struct ump_net_call call;
uint8_t payload[BUF_SIZE];
size_t send_len;
struct waitset_chanstate chan;
};
static uint16_t local_port;
static uint16_t remote_port;
static uint32_t remote_ip;
static void udp_listen_callback (void *arg, errval_t err, uint16_t src_port) {
if (err_is_fail(err)) {
printf("Failed to listen on port %d:\n", local_port);
err_print_calltrace(err);
return;
}
local_port = src_port;
DEBUG_PRINTF("Listening on UDP port %d.\n", src_port);
}
static void net_recv_packet (void *arg, size_t payload_size, void *payload) {
printf("%.*s", payload_size, arg);
free(arg);
}
static void handle_udp_recv (void *arg, struct ump_net_ev_udp_recv *udp_recv, size_t payload_size) {
void *payload = malloc(payload_size);
if (payload == NULL) {
printf("ERROR: malloc failed\n");
ump_net_recv_payload(NULL, NULL, NULL);
} else {
if (remote_ip == 0) remote_ip = udp_recv->src_ip;
if (remote_port == 0) remote_port = udp_recv->src_port;
ump_net_recv_payload(payload, net_recv_packet, payload);
}
}
static void send_callback (void *arg, errval_t err) {
struct send_buf *send_buf = arg;
free(send_buf);
if (err_is_fail(err)) {
DEBUG_ERR(err, "failed to send packet");
}
}
static void udp_send(void *arg) {
struct send_buf *send_buf = arg;
ump_net_udp_send(
&send_buf->call,
remote_ip,
local_port, remote_port,
send_buf->send_len, &send_buf->payload,
send_callback, send_buf
);
}
static struct send_buf *create_send_buffer (void) {
struct send_buf *send_buf = malloc(sizeof(struct send_buf));
if (send_buf == NULL) {
printf("ERROR: malloc failed\n");
return NULL;
}
waitset_chanstate_init(&send_buf->chan, CHANTYPE_OTHER);
send_buf->send_len = 0;
return send_buf;
}
static struct waitset_chanstate exitchan;
static struct ump_net_call stopcall;
static void udp_stop_callback (void *arg, errval_t err) {
exit(0);
}
static void exit_process(void *arg) {
ump_net_udp_listen_stop(&stopcall, local_port, udp_stop_callback, NULL);
}
static int input_reader (void *arg) {
errval_t err;
struct aos_rpc *rpc = aos_rpc_get_serial_channel();
struct waitset *default_ws = get_default_waitset();
struct send_buf *send_buf = create_send_buffer();
if (send_buf == NULL) return 1;
while (true) {
char in;
err = aos_rpc_serial_getchar(rpc, &in);
if (err_is_fail(err)) {
DEBUG_ERR(err, "failed to read");
return 1;
}
if (in == '\x03') { // Ctrl+C
waitset_chan_trigger_closure(default_ws, &exitchan, MKCLOSURE(exit_process, NULL));
return 0;
}
if (in == '\0') in = '\n';
send_buf->payload[send_buf->send_len] = in;
send_buf->send_len++;
if (send_buf->send_len == sizeof(send_buf->payload) || in == '\n') {
if (remote_port == 0 || remote_ip == 0) {
printf("Error: Can't send, remote ip/port not provided and no packet received yet.\n");
send_buf->send_len = 0;
} else {
waitset_chan_trigger_closure(default_ws, &send_buf->chan, MKCLOSURE(udp_send, send_buf));
send_buf = create_send_buffer();
if (send_buf == NULL) return 1;
}
}
}
}
int main (int argc, char *argv[]) {
errval_t err;
struct waitset *default_ws = get_default_waitset();
if (argc < 2) {
printf("Usage: netcat local_port [remote_ip] [remote_port]\n");
return 1;
}
local_port = strtol(argv[1], NULL, 10);
if (argc > 2) {
int a1, a2, a3, a4;
int parsed = sscanf(argv[2], "%d.%d.%d.%d.", &a1, &a2, &a3, &a4);
if (parsed != 4) {
printf("Error: failed to parse IP address\n");
return 1;
}
remote_ip = MK_IP(a1, a2, a3, a4);
remote_port = local_port;
}
if (argc > 3) {
remote_port = strtol(argv[3], NULL, 10);
}
err = ump_net_init(default_ws);
if (err_is_fail(err)) USER_PANIC_ERR(err, "Failed to connect to net server");
struct ump_net_call call_udp_listen;
ump_net_udp_listen(&call_udp_listen, local_port, handle_udp_recv, NULL, udp_listen_callback, NULL);
thread_create(input_reader, NULL);
while (true) {
err = event_dispatch(default_ws);
if (err_is_fail(err)) {
DEBUG_ERR(err, "in event_dispatch");
abort();
}
}
}