Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle more TCP edge cases #61

Merged
merged 13 commits into from
Dec 16, 2024
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
6 changes: 3 additions & 3 deletions .github/workflows/quick.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@

smoketest_all_opts:
name: Smoke test With all options turned on
runs-on: ubuntu-latest
runs-on: ubuntu-22.04

steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -75,7 +75,7 @@
- name: Generate coverage reports
run: |
make gcov
make cover COVERAGEDIR=coverage/ubuntu-latest
make cover COVERAGEDIR=coverage/ubuntu-22.04
shell: bash

- name: Upload gcovr report artifact
Expand All @@ -89,7 +89,7 @@
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

# TODO: Since windows has a bunch of build differences, it would be good to

Check warning on line 92 in .github/workflows/quick.yml

View workflow job for this annotation

GitHub Actions / Code syntax

92:1 [comments-indentation] comment not indented like content
# have a smoketest for it, but it is about 5 times slower than the other
# quick tests...
#
Expand All @@ -114,7 +114,7 @@

lint:
name: Code syntax
runs-on: ubuntu-latest
runs-on: ubuntu-22.04

steps:
- uses: actions/checkout@v4
Expand Down
46 changes: 46 additions & 0 deletions doc/Containerfile.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#
# A simple example of how to build a docker container for n3n-edge
#
# Build with the command:
# podman build \
# --device=/dev/net/tun \
# --cap-add=NET_ADMIN \
# -t=n3n \
# -f doc/Containerfile.example \
# .
#
# Start a n3n session with:
# podman run \
# -it \
# --name=n3n \
# --device=/dev/net/tun \
# --cap-add=NET_ADMIN \
# -v $PWD/n3n:/etc/n3n/ \
# n3n start -vvvv
#
# Note that the build could be done without the --device and --cap-add if
# the `make test` is omitted

FROM docker.io/library/debian:12 AS builder

RUN apt-get update
RUN apt-get install -y build-essential autoconf git python3 jq sudo

WORKDIR /n3n

COPY . .

RUN \
./autogen.sh && \
./configure && \
make clean all && \
make test


FROM docker.io/library/debian:12

COPY --from=builder /n3n/apps/n3n-edge /n3n-edge

VOLUME [ "/etc/n3n" ]
ENTRYPOINT ["/n3n-edge"]
CMD ["start"]
39 changes: 25 additions & 14 deletions libs/connslot/connslot.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ void conn_check_ready(conn_t *conn) {
return;
}

void conn_read(conn_t *conn, int fd) {
ssize_t conn_read(conn_t *conn, int fd) {
conn->state = CONN_READING;

// If no space available, try increasing our capacity
Expand All @@ -195,28 +195,26 @@ void conn_read(conn_t *conn, int fd) {
// zero-sized read request, the only time we get a zero back is if the
// far end has closed
conn->state = CONN_CLOSED;
return;
return 0;
}

if (size == -1) {
if (errno == EWOULDBLOCK || errno == EAGAIN) {
conn->state = CONN_EMPTY;
return;
return 0;
}
conn->state = CONN_ERROR;
return;
return 0;
}

// This will truncate the time to a int - usually 32bits
conn->activity = time(NULL);
conn_check_ready(conn);
return size;
}

ssize_t conn_write(conn_t *conn, int fd) {
ssize_t sent;

conn->state = CONN_SENDING;

if (fd == -1) {
return 0;
}
Expand Down Expand Up @@ -267,11 +265,17 @@ ssize_t conn_write(conn_t *conn, int fd) {
unsigned int end_pos = sb_len(conn->reply_header) + sb_len(conn->reply);
#endif

if (sent == -1) {
sent = 0;
if (errno != EAGAIN && errno != EWOULDBLOCK) {
conn->state = CONN_ERROR;
}
}

conn->reply_sendpos += sent;

if (conn->reply_sendpos >= end_pos) {
// We have sent the last bytes of this reply
conn->state = CONN_EMPTY;
conn->reply_sendpos = 0;
sb_zero(conn->reply_header);
sb_zero(conn->reply);
Expand All @@ -282,13 +286,20 @@ ssize_t conn_write(conn_t *conn, int fd) {
return sent;
}

int conn_iswriter(conn_t *conn) {
switch (conn->state) {
case CONN_SENDING:
return 1;
default:
return 0;
bool conn_iswriter(conn_t *conn) {
int endpos = 0;
if (conn->reply_header) {
endpos += sb_len(conn->reply_header);
}
if (conn->reply) {
endpos += sb_len(conn->reply);
}

// If there are any bytes ready to send, then we are writable
if(endpos) {
return true;
}
return false;
}

void conn_close(conn_t *conn, int fd) {
Expand Down
5 changes: 2 additions & 3 deletions libs/connslot/connslot.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ enum __attribute__((__packed__)) conn_state {
CONN_EMPTY = 0,
CONN_READING = 1,
CONN_READY = 2,
CONN_SENDING = 3,
CONN_CLOSED = 4,
CONN_ERROR = 5,
};
Expand Down Expand Up @@ -64,9 +63,9 @@ void conn_zero(conn_t *);
int conn_init(conn_t *, size_t, size_t);
void conn_accept(conn_t *, int, enum conn_proto);
void conn_check_ready(conn_t *);
void conn_read(conn_t *, int);
ssize_t conn_read(conn_t *, int);
ssize_t conn_write(conn_t *, int);
int conn_iswriter(conn_t *);
bool conn_iswriter(conn_t *);
void conn_close(conn_t *, int);
bool conn_closeidle(conn_t *, int, int, int);
void conn_dump(strbuf_t **, conn_t *);
Expand Down
12 changes: 7 additions & 5 deletions src/edge_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -1630,11 +1630,13 @@ void update_supernode_reg (struct n3n_runtime_data * eee, time_t now) {
if(eee->conf.bind_address) {
// do not explicitly disconnect every time as the condition described is rare, so ...
// ... check that there are no external peers (indicating a working socket) ...
HASH_ITER(hh, eee->known_peers, peer, tmp_peer)
if(!peer->local) {
cnt++;
break;
HASH_ITER(hh, eee->known_peers, peer, tmp_peer) {
if(!peer->local) {
cnt++;
break;
}
}

if(!cnt) {
// ... and then count the connection retries
(eee->close_socket_counter)++;
Expand Down Expand Up @@ -2297,7 +2299,7 @@ void process_udp (struct n3n_runtime_data *eee,
via_multicast = (in_sock == eee->udp_multicast_sock);
#endif

traceEvent(TRACE_DEBUG, "Rx N2N_UDP of size %d from [%s]",
traceEvent(TRACE_DEBUG, "Rx VPN packet of size %d from [%s]",
(signed int)udp_size, sock_to_cstr(sockbuf1, &sender));

if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) {
Expand Down
6 changes: 4 additions & 2 deletions src/mainloop.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,10 @@ static int fdlist_allocslot (int fd, enum fd_info_proto proto) {

static void fdlist_freefd (int fd) {
int slot = 0;
if(fd == -1) {
// Cannot release an error fd!
return;
}
while(slot < MAX_HANDLES) {
if(fdlist[slot].fd != fd) {
slot++;
Expand Down Expand Up @@ -331,7 +335,6 @@ static void handle_fd (const time_t now, const struct fd_info info, struct n3n_r
switch(conn->state) {
case CONN_EMPTY:
case CONN_READING:
case CONN_SENDING:
// These states dont require us to do anything
// TODO:
// - handle reading/sending simultaneous?
Expand Down Expand Up @@ -402,7 +405,6 @@ static void handle_fd (const time_t now, const struct fd_info info, struct n3n_r
switch(conn->state) {
case CONN_EMPTY:
case CONN_READING:
case CONN_SENDING:
// These states dont require us to do anything
// TODO:
// - handle reading/sending simultaneous?
Expand Down
35 changes: 34 additions & 1 deletion src/n2n.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,41 @@ SOCKET open_socket (struct sockaddr *local_address, socklen_t addrlen, int type
/* fcntl(sock_fd, F_SETFL, O_NONBLOCK); */
#endif

int result;

sockopt = 1;
setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&sockopt, sizeof(sockopt));
result = setsockopt(
sock_fd,
SOL_SOCKET,
SO_REUSEADDR,
(char *)&sockopt,
sizeof(sockopt)
);
if(result == -1) {
traceEvent(
TRACE_ERROR,
"SO_REUSEADDR fd=%i, error=%s\n",
sock_fd,
strerror(errno)
);
}
#ifdef SO_REUSEPORT /* no SO_REUSEPORT in Windows / old linux versions */
result = setsockopt(
sock_fd,
SOL_SOCKET,
SO_REUSEPORT,
(char *)&sockopt,
sizeof(sockopt)
);
if(result == -1) {
traceEvent(
TRACE_ERROR,
"SO_REUSEPORT fd=%i, error=%s\n",
sock_fd,
strerror(errno)
);
}
#endif

if(!local_address) {
// skip binding if we dont have the right details
Expand Down
10 changes: 8 additions & 2 deletions tools/crypto_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,10 @@ static void cmd_header_decrypt (int argc, char **argv, void *conf) {
exit(1);
}

write(1, &buf, size);
int r = write(1, &buf, size);
if(r != size) {
printf("Short write\n");
}
exit(0);

}
Expand Down Expand Up @@ -130,7 +133,10 @@ static void cmd_pearson_128 (int argc, char **argv, void *conf) {
unsigned char hash[16];
size = read(0, &buf, sizeof(buf));
pearson_hash_128(hash, buf, size);
write(1, &hash, sizeof(hash));
int r = write(1, &hash, sizeof(hash));
if(r != sizeof(hash)) {
printf("Short write\n");
}
exit(0);
}

Expand Down
Loading