#pragma once #include "types.h" // Unix domain sockets. // // These exist for Schcom. A compositor and its clients have to exchange // messages, and a pipe cannot do it: a pipe is one-directional, has no // notion of a connection, and gives no way for a server to be *found* by a // client that starts later. A socket with a name in the filesystem is // exactly the missing piece. // // AF_INET arrived later, and exactly as planned: underneath the same syscalls // rather than reshaping them. A socket carries its domain and every entry point // dispatches on it -- kernel/net/unix.c for AF_UNIX, kernel/net/inet.c (lwIP) // for AF_INET. #define AF_UNIX 1 #define AF_LOCAL 1 #define AF_INET 2 // Linux's number, because a musl program passes Linux's constant. getifaddrs() // is implemented over this, which is why it exists here: enumerating interfaces // is something every networked program does and nothing else offers. #define AF_NETLINK 16 #define PF_NETLINK AF_NETLINK #define NETLINK_ROUTE 0 #define SOCK_STREAM 1 #define SOCK_DGRAM 2 #define SOCK_RAW 3 // Flags ORed into socket()'s and accept4()'s `type`/`flags` argument. Linux's // values, because a musl program passes Linux's constants. #define SOCK_NONBLOCK 0x800 // O_NONBLOCK #define SOCK_CLOEXEC 0x80000 // O_CLOEXEC // setsockopt/getsockopt levels and names, Linux's numbering. // // Only what is listed here is accepted; anything else is answered with // ENOPROTOOPT rather than a success it did not earn. See the comment above // sys_setsockopt for why that is worth the risk of failing a caller that never // checked before. #define SOL_SOCKET 1 #define IPPROTO_ICMP 1 #define IPPROTO_TCP 6 #define SO_REUSEADDR 2 #define SO_TYPE 3 #define SO_ERROR 4 #define SO_BROADCAST 6 #define SO_SNDBUF 7 #define SO_RCVBUF 8 #define SO_KEEPALIVE 9 #define SO_ACCEPTCONN 30 #define TCP_NODELAY 1 #define UNIX_PATH_MAX 108 #define SHUT_RD 0 #define SHUT_WR 1 #define SHUT_RDWR 2 struct sockaddr_un { uint16 sun_family; char sun_path[UNIX_PATH_MAX]; }; // The generic form syscalls take. Same shape as Linux's, so a musl-linked // program's struct lines up byte for byte. struct sockaddr { uint16 sa_family; char sa_data[UNIX_PATH_MAX]; }; // The AF_INET address. Same layout as Linux's, so a musl-linked program's // struct lines up byte for byte. sin_port and sin_addr are network byte order // and stay that way: lwIP wants them so, and converting on the way in and out // again would be two swaps that cancel. struct sockaddr_in { uint16 sin_family; uint16 sin_port; uint32 sin_addr; char sin_zero[8]; }; // --------------------------------------------------------------------------- // rtnetlink, enough of it for getifaddrs(3) // // Every structure below is Linux's, byte for byte, because musl parses what it // is handed with Linux's own headers. They are not ours to design. // // What musl actually does (src/network/netlink.c) is the whole specification // this has to meet: open PF_NETLINK/SOCK_RAW/NETLINK_ROUTE, send an // nlmsghdr+rtgenmsg asking RTM_GETLINK with NLM_F_DUMP, read replies until // NLMSG_DONE, then do it again for RTM_GETADDR on the same socket. // --------------------------------------------------------------------------- struct nlmsghdr { uint32 nlmsg_len; uint16 nlmsg_type; uint16 nlmsg_flags; uint32 nlmsg_seq; uint32 nlmsg_pid; }; struct rtgenmsg { uchar rtgen_family; }; struct ifinfomsg { uchar ifi_family; uchar __ifi_pad; uint16 ifi_type; // ARPHRD_* int32 ifi_index; uint32 ifi_flags; // IFF_* uint32 ifi_change; }; struct ifaddrmsg { uchar ifa_family; uchar ifa_prefixlen; uchar ifa_flags; uchar ifa_scope; uint32 ifa_index; }; struct rtattr { uint16 rta_len; uint16 rta_type; }; #define NLMSG_ERROR 2 #define NLMSG_DONE 3 #define NLM_F_REQUEST 0x001 #define NLM_F_MULTI 0x002 #define NLM_F_DUMP 0x300 #define RTM_NEWLINK 16 #define RTM_GETLINK 18 #define RTM_NEWADDR 20 #define RTM_GETADDR 22 #define IFLA_ADDRESS 1 #define IFLA_IFNAME 3 #define IFA_ADDRESS 1 #define IFA_LOCAL 2 #define IFA_LABEL 3 #define ARPHRD_ETHER 1 #define ARPHRD_LOOPBACK 772 #define IFF_UP 0x1 #define IFF_LOOPBACK 0x8 #define IFF_RUNNING 0x40 #define IFF_BROADCAST 0x2 #define IFF_MULTICAST 0x1000 // Both are four-byte aligned on every architecture Linux supports. #define NLMSG_ALIGN(n) (((n) + 3) & ~3) #define RTA_ALIGN(n) (((n) + 3) & ~3) #ifdef _KERNEL_SOCKET_INTERNALS #define NSOCK 32 // sockets in the system #define SOCKBUF 4096 // receive buffer per connected socket #define NBACKLOG 8 enum sockstate { SS_FREE = 0, SS_UNBOUND, SS_BOUND, SS_LISTENING, SS_CONNECTED, }; // Every field here is protected by the socket table's single lock in // kernel/net/unix.c -- there is deliberately no per-socket lock; see the // comment at the top of that file for why. struct socket { int ref; int type; int state; int domain; // AF_UNIX or AF_INET // For AF_INET: the lwIP-backed socket in kernel/net/inet.c. Opaque here so // that socket.h does not have to drag lwIP's headers into every file that // wants a struct socket. void *inet; char name[UNIX_PATH_MAX]; // the bound path, for a listener // A connected socket's peer. Writing to a socket appends to the *peer's* // buffer, which is what makes one buffer per socket enough for a // bidirectional connection. struct socket *peer; int peer_closed; char data[SOCKBUF]; uint nread, nwrite; // Connections waiting to be accepted, on a listener. struct socket *queue[NBACKLOG]; int nqueue; // Socket options that are genuinely honoured. Kept here rather than only in // lwIP's pcb because getsockopt has to answer for an AF_UNIX socket too, and // because a flag set before bind() has to survive until there is a pcb to // apply it to. int o_reuseaddr; int o_keepalive; int o_broadcast; int o_nodelay; }; #endif