kernel: timers that fire, raw ping, and the sockets X needs
alarm() and setitimer() stored a countdown nothing counted down, so no
timer has ever fired; setitimer and getitimer were also registered with
no Linux number. alarmd now posts SIGALRM on the tick, while any process
has a timer armed. busybox's ping, /bin/ping on the Alpine root, sends
every request after the first from its SIGALRM handler.
It also opens SOCK_RAW, which was EPROTOTYPE. A raw ICMP socket is now a
ping socket whose reads start at the IP header. And a blocked socket
call gives up for a signal with a handler, not only for a kill: the
alarm woke recvfrom, and the wait put it straight back to sleep.
For Xorg: AF_UNIX abstract names, which read as the empty path and so as
EADDRINUSE ("server already running"); and getsockname and getpeername,
which did not exist, so libxcb sent no cookie and the server refused
every client.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
parent
d0941780f5
commit
a4ed556543
9 changed files with 428 additions and 28 deletions
|
|
@ -688,6 +688,61 @@ sockbind(struct socket *s, const char *path, uint dev, uint64 ino)
|
|||
return 0;
|
||||
}
|
||||
|
||||
// The abstract namespace: a sun_path that starts with a NUL names no file.
|
||||
// Linux keeps these names in the socket layer, and Xorg binds one before its
|
||||
// /tmp/.X11-unix path -- which this used to read as the empty path, resolve
|
||||
// to the directory it was called from and refuse with EADDRINUSE, so Xorg
|
||||
// reported "server already running" and exited.
|
||||
//
|
||||
// The name becomes a key on a device number no filesystem has, and the rest
|
||||
// is the inode machinery unchanged: connect() finds the listener bound to
|
||||
// (SOCK_ABSTRACT_DEV, key). The name goes when the socket does, because
|
||||
// nothing else holds it.
|
||||
int
|
||||
sockbind_abstract(struct socket *s, uint64 key)
|
||||
{
|
||||
acquire(&stab.lock);
|
||||
if(s->state != SS_UNBOUND){
|
||||
release(&stab.lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
for(struct socket *o = stab.sock; o < stab.sock + NSOCK; o++)
|
||||
if(o != s && o->state != SS_FREE && o->state != SS_UNBOUND &&
|
||||
o->bind_dev == SOCK_ABSTRACT_DEV && o->bind_ino == key){
|
||||
release(&stab.lock);
|
||||
return -EADDRINUSE;
|
||||
}
|
||||
s->name[0] = '\0'; // getsockname reports it unnamed, not as a path
|
||||
s->bind_dev = SOCK_ABSTRACT_DEV;
|
||||
s->bind_ino = key;
|
||||
s->state = SS_BOUND;
|
||||
release(&stab.lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The path for getsockname (peer 0) or getpeername (peer 1) of an AF_UNIX
|
||||
// socket. Empty for an unnamed one -- a client that never bound, or an
|
||||
// abstract name, which the caller reports as the family alone.
|
||||
int
|
||||
sockname_inet(struct socket *s, int peer, uint *addr, ushort *port)
|
||||
{
|
||||
return inet_name(s->inet, peer, addr, port);
|
||||
}
|
||||
|
||||
int
|
||||
sockname_unix(struct socket *s, int peer, char *path)
|
||||
{
|
||||
acquire(&stab.lock);
|
||||
struct socket *o = peer ? s->peer : s;
|
||||
if(o == 0){
|
||||
release(&stab.lock);
|
||||
return -ENOTCONN;
|
||||
}
|
||||
safestrcpy(path, o->name, UNIX_PATH_MAX);
|
||||
release(&stab.lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
socklisten(struct socket *s, int backlog)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue