netstack: only return from open() once the socket connects

This commit is contained in:
dzwdz 2023-09-02 22:39:59 +02:00
parent c8d6ce89f1
commit fd80c0b227
4 changed files with 55 additions and 58 deletions

View File

@ -48,7 +48,7 @@ struct handle {
};
static void tcp_listen_callback(struct tcp_conn *c, void *arg) {
static void tcp_conn_callback(struct tcp_conn *c, void *arg) {
struct handle *h = arg;
h->tcp.c = c;
_sys_fs_respond(h->reqh, h, 0, 0);
@ -181,11 +181,10 @@ static void fs_open(hid_t reqh, char *path, int flags) {
port_s = strtok_r(NULL, "/", &save);
if (port_s) {
uint16_t port = strtol(port_s, NULL, 0);
h = malloc(sizeof *h);
memset(h, 0, sizeof *h);
h = calloc(1, sizeof *h);
h->type = H_TCP;
h->reqh = reqh;
tcp_listen(port, tcp_listen_callback, tcp_recv_callback, tcp_close_callback, h);
tcp_listen(port, tcp_conn_callback, tcp_recv_callback, tcp_close_callback, h);
return;
}
}
@ -198,19 +197,14 @@ static void fs_open(hid_t reqh, char *path, int flags) {
port_s = strtok_r(NULL, "/", &save);
if (port_s) {
uint16_t port = strtol(port_s, NULL, 0);
h = malloc(sizeof *h);
memset(h, 0, sizeof *h);
h = calloc(1, sizeof *h);
h->type = H_TCP;
h->tcp.c = tcpc_new((struct tcp){
h->reqh = reqh;
tcp_connect((struct tcp){
.dst = port,
.ip.dst = dstip,
}, tcp_recv_callback, tcp_close_callback, h);
if (h->tcp.c) {
respond(h, 0);
} else {
free(h);
respond(NULL, -1);
}
}, tcp_conn_callback, tcp_recv_callback, tcp_close_callback, h);
return;
}
}
if (strcmp(proto, "udp") == 0) {

View File

@ -97,8 +97,9 @@ void tcp_listen(
void (*on_recv)(void *carg),
void (*on_close)(void *carg),
void *carg);
struct tcp_conn *tcpc_new(
void tcp_connect(
struct tcp t,
void (*on_conn)(struct tcp_conn *, void *carg),
void (*on_recv)(void *carg),
void (*on_close)(void *carg),
void *carg);

View File

@ -108,8 +108,9 @@ void tcp_listen(
c->rx = (ring_t){malloc(4096), 4096, 0, 0};
conns_append(c);
}
struct tcp_conn *tcpc_new(
void tcp_connect(
struct tcp t,
void (*on_conn)(struct tcp_conn *, void *carg),
void (*on_recv)(void *carg),
void (*on_close)(void *carg),
void *carg)
@ -126,11 +127,13 @@ struct tcp_conn *tcpc_new(
if (arpcache_get(state.gateway, &c->rmac) < 0) {
warnx("neither target nor gateway not in ARP cache, dropping");
free(c);
return NULL;
on_close(carg);
return;
}
}
c->state = SYN_SENT;
c->on_conn = on_conn;
c->on_recv = on_recv;
c->on_close = on_close;
c->carg = carg;
@ -139,7 +142,6 @@ struct tcp_conn *tcpc_new(
tcpc_sendraw(c, FlagSYN, NULL, 0);
c->lseq++;
return c;
}
size_t tcpc_tryread(struct tcp_conn *c, void *buf, size_t len) {
if (!buf) return ring_used(&c->rx);
@ -198,52 +200,53 @@ void tcp_parse(const uint8_t *buf, size_t len, struct ipv4 ip) {
return;
}
if (iter->rip == ip.src && iter->rport == srcport) {
// TODO doesn't handle seq/ack overflows
if (iter->state == SYN_SENT) {
if (flags & FlagSYN) {
iter->state = ESTABILISHED;
iter->lack = seq + 1;
tcpc_sendraw(iter, FlagACK, NULL, 0);
return;
} else {
// TODO resend syn?
return;
}
}
if (flags & FlagACK) {
if (iter->rack < acknum)
iter->rack = acknum;
if (iter->state == LAST_ACK) {
// TODO check if ack has correct number
iter->state = CLOSED;
tcpc_tryfree(iter);
// TODO free (also after a timeout)
return;
}
}
if (iter->lack != seq && iter->lack - 1 != seq) {
warnx("remote seq jumped by %d", seq - iter->lack);
if (iter->rip != ip.src || iter->rport != srcport) continue;
// TODO doesn't handle seq/ack overflows
if (iter->state == SYN_SENT) {
if (flags & FlagSYN) {
iter->state = ESTABILISHED;
iter->lack = seq + 1;
tcpc_sendraw(iter, FlagACK, NULL, 0);
if (iter->on_conn) iter->on_conn(iter, iter->carg);
return;
} else {
// TODO resend syn?
return;
}
// TODO check if overflows window size
if (payloadlen) {
iter->lack = seq + payloadlen;
ring_put(&iter->rx, buf + hdrlen, payloadlen);
if (iter->on_recv) iter->on_recv(iter->carg);
tcpc_sendraw(iter, FlagACK, NULL, 0);
}
if (flags & FlagFIN) {
// TODO should resend the packet until an ACK is received
// TODO duplicated in tcpc_close
tcpc_sendraw(iter, FlagFIN | FlagACK, NULL, 0);
iter->state = LAST_ACK;
if (iter->on_close) iter->on_close(iter->carg);
}
if (flags & FlagACK) {
if (iter->rack < acknum)
iter->rack = acknum;
if (iter->state == LAST_ACK) {
// TODO check if ack has correct number
iter->state = CLOSED;
tcpc_tryfree(iter);
// TODO free (also after a timeout)
return;
}
}
if (iter->lack != seq && iter->lack - 1 != seq) {
warnx("remote seq jumped by %d", seq - iter->lack);
tcpc_sendraw(iter, FlagACK, NULL, 0);
return;
}
// TODO check if overflows window size
if (payloadlen) {
iter->lack = seq + payloadlen;
ring_put(&iter->rx, buf + hdrlen, payloadlen);
if (iter->on_recv) iter->on_recv(iter->carg);
tcpc_sendraw(iter, FlagACK, NULL, 0);
}
if (flags & FlagFIN) {
// TODO should resend the packet until an ACK is received
// TODO duplicated in tcpc_close
tcpc_sendraw(iter, FlagFIN | FlagACK, NULL, 0);
iter->state = LAST_ACK;
if (iter->on_close) iter->on_close(iter->carg);
return;
}
return;
}
if ((flags & FlagRST) == 0) {

View File

@ -70,7 +70,6 @@ fs_open(char *path, int flags) {
* 0x01 one authentication method:
* 0x00 no auth */
char buf[512];
sleep(1); // TODO fix the netstack
write(h->sock, "\x05\x01\x00", 3);
errno = EGENERIC;