33#include <aquila/errno.h>
34#include <aquila/fcntl.h>
36#include <aquila/ioctl.h>
37#include <aquila/tcp.h>
42#define PORT_FIRST 49152
43#define PORT_LAST 65535
45#define MSL 30000000000ULL
46#define FIN_WAIT_2_TIME 60000000000ULL
47#define RTO_INITIAL 1000000000ULL
49#define KEEP_IDLE 7200000000000ULL
50#define KEEP_INTERVAL 75000000000ULL
74 return hashmap_digest(key,
sizeof(*key));
78static int key_eq(
void *entry,
void *k)
120 if (hashmap_lookup(
conns, hash, &key))
123 if (hashmap_insert(
conns, hash, pcb))
126 pcb->
hnode = hashmap_lookup(
conns, hash, &key);
146 if (pcb->laddr ==
laddr)
173 ringbuf_free(pcb->
sndbuf);
174 ringbuf_free(pcb->
rcvbuf);
218 ringbuf_free(pcb->
sndbuf);
219 ringbuf_free(pcb->
rcvbuf);
434 if (pcb->lport != port || (pcb->laddr && addr && pcb->laddr != addr))
517 return (
file->
flags & O_NONBLOCK) || (flags & MSG_DONTWAIT);
543 return -EADDRNOTAVAIL;
587 return err < 0 ? err : -EAGAIN;
623 switch (pcb->
state) {
644 if (!ip || !port || ip == 0xffffffff)
645 return -EADDRNOTAVAIL;
701 const struct sockaddr *to, socklen_t tolen)
706 size_t sent = 0, len = io->
resid;
713 int err = pcb->
error;
715 return sent ? (
ssize_t) sent : -err;
721 return sent ? (
ssize_t) sent : -EAGAIN;
724 return sent ? (
ssize_t) sent : r < 0 ? r : -EAGAIN;
738 return sent ? (
ssize_t) sent : -EAGAIN;
741 return sent ? (
ssize_t) sent : r < 0 ? r : -EAGAIN;
784 struct sockaddr *from, socklen_t *fromlen)
789 size_t got = 0, len = io->
resid;
799 size_t avail = ringbuf_available(pcb->
rcvbuf);
803 if ((flags & MSG_PEEK) && avail > got) {
804 size_t n = ringbuf_read_noconsume(pcb->
rcvbuf, got,
MIN(len - got,
sizeof(chunk)), chunk);
808 return got ? (
ssize_t) got : c;
820 if (avail && !(flags & MSG_PEEK)) {
824 return got ? (
ssize_t) got : n;
836 if (got && (!(flags & MSG_WAITALL) || (flags & MSG_PEEK)))
840 int err = pcb->
error;
842 return got ? (
ssize_t) got : -err;
853 return got ? (
ssize_t) got : -EAGAIN;
856 return got ? (
ssize_t) got : r < 0 ? r : -EAGAIN;
917static int int_get(
void *val, socklen_t *len,
int v)
919 if (*len <
sizeof(
int))
930 if (*len <
sizeof(
struct timeval))
934 tv->
tv_sec = ns / 1000000000ULL;
935 tv->
tv_usec = ns % 1000000000ULL / 1000;
944 if (len <
sizeof(
struct timeval))
947 const struct timeval *tv = val;
961 if (level == IPPROTO_TCP) {
964 case TCP_MAXSEG:
return int_get(val, len, pcb->
mss);
970 if (level != SOL_SOCKET)
975 int err = pcb->
error;
996 if (level == IPPROTO_TCP) {
997 if (len <
sizeof(
int))
1002 pcb->
nodelay = !!*(
const int *) val;
1011 return -ENOPROTOOPT;
1014 if (level != SOL_SOCKET)
1015 return -ENOPROTOOPT;
1019 if (len <
sizeof(
int))
1027 if (len <
sizeof(
int))
1038 return -ENOPROTOOPT;
1047 if (request == FIONREAD) {
1048 int n = ringbuf_available(pcb->
rcvbuf);
1049 return copyout(argp, &n,
sizeof(n));
1080 if (how & SHUT_RD) {
1101 switch (pcb->
state) {
1113 if (p->parent == pcb)
1129 if (ringbuf_available(pcb->
rcvbuf) || pcb->
ooo) {
void callout_stop(struct callout *c)
Cancels a callout, if it is pending.
static int port_used(uint8_t proto, uint32_t addr, uint16_t port)
Returns whether a socket of proto is bound to port on addr (or on any address, or addr is any).
void inet_sockaddr_put(struct sockaddr *addr, socklen_t *len, uint32_t ip, uint16_t port)
Writes an AF_INET address, cut to *len bytes if it doesn't fit.
int inet_ifioctl(int request, void *argp)
Handles an interface ioctl() request on an AF_INET socket.
struct netif * ipv4_route(uint32_t dst)
Chooses the interface to send a packet to dst through: the one whose link it is on,...
int ipv4_is_local(uint32_t ip)
Says whether an address is one of ours: a loopback address, or an interface's.
uint32_t ipv4_source(struct netif *netif, uint32_t dst)
Chooses the source address of a packet to dst sent through netif.
int inet_sockaddr_get(const struct sockaddr *addr, socklen_t len, uint32_t *ip, uint16_t *port)
Reads an AF_INET address.
ssize_t iobuf_out(struct iobuf *io, const void *src, size_t n)
Copies bytes from the kernel into the iobuf's buffer, and moves past them.
#define MALLOC_DEFINE(type, _name, _desc)
void * kmalloc(size_t size, struct malloc_type *type, int flags)
Allocates memory for one of the kernel's structures.
#define MALLOC_DECLARE(type)
void kfree(void *)
Frees an object that kmalloc() gave.
void * memcpy(void *dst, const void *src, size_t n)
Copies n bytes; dst and src must not overlap.
void netbuf_free(struct netbuf *nb)
Frees a netbuf.
void net_callout_set(struct callout *c, uint64_t ns, void(*fn)(void *), void *arg)
Sets a callout that the network's thread runs: fn(arg) is called once ns ns have passed.
void random_get(void *_buf, size_t len)
Fills a buffer with random bytes.
int sched_wait(struct waitq *waitq, uint64_t until)
Puts the current thread to sleep on a wait queue until it is woken up, a signal ends the sleep,...
int socket_tcp_create(struct file *file, int domain, int type, int protocol)
Makes a TCP socket, with its connection, CLOSED.
unsigned long long int uint64_t
unsigned short int uint16_t
An open file (POSIX's "open file description", fs/file.c).
A hash table's node: an entry, with its key's hash.
A network interface (net/netif.c): a device that sends and receives Ethernet frames,...
A domain's socket operations.
What identifies a connection: both ends' addresses and ports.
A connection (its control block, or PCB).
struct tcp_pcb * accept_next
struct tcp_pcb * accept_head
struct tcp_pcb * accept_tail
struct hashmap_node * hnode
void tcp_established(struct tcp_pcb *pcb)
Moves a connection to ESTABLISHED: its congestion window starts, and a listener's connection is queue...
struct tcp_pcb * tcp_lookup(uint32_t laddr, uint16_t lport, uint32_t raddr, uint16_t rport)
Finds a connection by both ends' addresses and ports.
void tcp_send_syn(struct tcp_pcb *pcb)
Sends the SYN (or, in SYN_RECEIVED, the SYN and ACK), the first time or again, and starts the retrans...
struct tcp_pcb * tcp_pcb_new(void)
Makes a connection, CLOSED, with its send and receive buffers, on the list of connections.
void tcp_closed(struct tcp_pcb *pcb)
Moves a connection to CLOSED: it leaves the hashmap, its timers stop, and its waiters wake up.
struct tcp_pcb * tcp_listener(uint32_t laddr, uint16_t lport)
Finds the listener for a local address and port: one bound to that address, or else one bound to any ...
void tcp_output(struct tcp_pcb *pcb)
Sends as much of the send buffer as the windows allow, in segments of at most mss bytes.
void tcp_wakeup(struct tcp_pcb *pcb)
Wakes up the threads waiting on a connection (in accept(), connect(), recv() or send()).
void tcp_fin_wait_2(struct tcp_pcb *pcb)
Handles our FIN being acknowledged (FIN_WAIT_2): if the socket is closed, the connection waits for th...
void tcp_send_rst(struct tcp_pcb *pcb)
Sends a reset on a connection.
void tcp_send_ack(struct tcp_pcb *pcb)
Sends an ACK, now.
void tcp_time_wait(struct tcp_pcb *pcb)
Moves a connection to TIME_WAIT, which it leaves after 2 MSL.
int tcp_insert(struct tcp_pcb *pcb)
Adds a connection to the hashmap of connections, by its addresses and ports, which it must have now.
struct tcp_pcb * tcp_pcbs
uint16_t tcp_rcv_window(struct tcp_pcb *pcb)
Computes the window to advertise: the room in the receive buffer.
uint32_t tcp_iss(struct tcp_pcb *pcb)
Chooses a connection's initial sequence number (RFC 6528): a clock that ticks every 4 us,...
void tcp_drop(struct tcp_pcb *pcb, int err)
Drops a connection that is lost, giving its socket an error.
void tcp_send_keepalive(struct tcp_pcb *pcb)
Sends a keepalive probe: a segment one byte before what the peer has acknowledged (with no data),...
void tcp_keepalive_reset(struct tcp_pcb *pcb)
Restarts the keepalive timer, when the peer was heard from.
void tcp_pcb_free(struct tcp_pcb *pcb)
Frees a connection: its timers stop, it leaves the lists, and its buffers and waiting segments are fr...
static ssize_t socket_tcp_recv(struct file *file, struct iobuf *io, int flags, struct sockaddr *from, socklen_t *fromlen)
Receives data, waiting for some unless the socket doesn't block or the receive timeout passes (with M...
static int socket_tcp_shutdown(struct file *file, int how)
Detaches the connection when the socket's last descriptor is closed: the connection is closed,...
static struct hashmap * conns
static int can_send(struct tcp_pcb *pcb)
Returns whether data may be sent in the connection's state.
static int socket_tcp_can_read(struct file *file, size_t len)
Says whether a read (or an accept) wouldn't wait: there is data, a connection to accept,...
static int timeo_get(void *val, socklen_t *len, uint64_t ns)
Sets an option's value to a timeout, as a struct timeval.
static int key_eq(void *entry, void *k)
Returns whether a connection has the key k.
static int nonblock(struct file *file, int flags)
Returns whether a call shouldn't wait: the socket doesn't block, or the call has MSG_DONTWAIT.
static int socket_tcp_setsockopt(struct file *file, int level, int name, const void *val, socklen_t len)
Sets a TCP or socket option.
static int socket_tcp_connect(struct file *file, const struct sockaddr *addr, socklen_t len)
Connects to a peer: sends the SYN, and waits for the connection to be established,...
static uint64_t deadline(uint64_t timeo)
Returns the deadline for a timeout of timeo ns from now, or 0 for none.
static void keepalive_timeout(void *arg)
Sends a keepalive probe after a silence, or drops the connection (ETIMEDOUT) once too many probes wen...
static int socket_tcp_getsockopt(struct file *file, int level, int name, void *val, socklen_t *len)
Reads a TCP or socket option.
static void window_update(struct tcp_pcb *pcb)
Tells the peer that reading made room in the receive window, if it opened enough (tcp_rcv_window()).
static int socket_tcp_can_write(struct file *file, size_t len)
Says whether a write wouldn't wait: there is room in the send buffer, or an error or the end of sendi...
static uint8_t iss_secret[16]
static ssize_t socket_tcp_send(struct file *file, struct iobuf *io, int flags, const struct sockaddr *to, socklen_t tolen)
Sends data: it goes into the send buffer, waiting for room unless the socket doesn't block,...
static void timer2_closed(void *arg)
Closes a connection when its TIME_WAIT or FIN_WAIT_2 time is over.
static struct waitq * socket_tcp_wait_queue(struct file *file, int write)
Returns the connection's wait queue, which accept(), connect(), recv() and send() all wait on.
static int socket_tcp_ioctl(struct file *file, int request, void *argp)
Handles FIONREAD (how much data can be read) and the interface requests.
static struct sock_ops socket_tcp_ops
static int int_get(void *val, socklen_t *len, int v)
Sets an option's value to the int v.
static void send_fin(struct tcp_pcb *pcb)
Queues our FIN, to go after what is in the send buffer.
static void unlink_parent(struct tcp_pcb *pcb)
Takes a connection off its listener's queue, when it is done or accept() took it.
static hash_t key_hash(const struct tcp_key *key)
Returns a connection key's hash.
static int socket_tcp_accept(struct file *file, struct file *conn, const struct sockaddr *addr, socklen_t *len)
Accepts an established connection, waiting for one unless the socket doesn't block or the receive tim...
static int socket_tcp_shut(struct file *file, int how)
Shuts down reading (readers see the end), writing (the FIN is sent), or both, for shutdown().
static int socket_tcp_bind(struct file *file, const struct sockaddr *addr, socklen_t len)
Binds the socket to a local address (ours, or any) and port; ports below 1024 are root's.
static int socket_tcp_listen(struct file *file, int backlog)
Makes the socket listen, binding it to an ephemeral port if it isn't bound.
static int socket_tcp_getname(struct file *file, struct sockaddr *addr, socklen_t *len, int peer)
Gets the socket's local address, or its peer's (-ENOTCONN before the peer is known).
static int timeo_set(const void *val, socklen_t len, uint64_t *ns)
Reads a timeout from an option's value, a struct timeval, into *ns.
static int bind_port(struct tcp_pcb *pcb, uint32_t addr, uint16_t port)
Binds a connection to a local address and port; port 0 picks a free ephemeral port.
uint64_t arch_rtime_ns(void)
Reads the monotonic clock, which starts at boot.
void waitq_wakeup(struct waitq *waitq)
Wakes up every thread sleeping on a wait queue, and every thread polling it.