O Linux limpa automaticamente sockets de domínio abstratos?

14

Há uma ótima resposta no StackOverflow sobre fornecimento de um bloqueio melhor para daemons (sintetizado de Eduardo Fleury ) que não depende do mecanismo de bloqueio de arquivo PID comum para daemons. Há muitos bons comentários sobre o porquê de os arquivos de bloqueio do PID às vezes causarem problemas, por isso não os atualizarei aqui.

Em suma, a solução se baseia em soquetes de domínio de namespace abstrato Linux, que mantém o controle dos soquetes por nome para você, em vez de depender de arquivos, que podem ficar por perto depois que o daemon é SIGKILL. O exemplo mostra que o Linux parece liberar o socket uma vez que o processo está morto.

Mas não consigo encontrar documentação definitiva no Linux que diga exatamente o que o Linux faz com o soquete abstrato quando o processo vinculado é SIGKILL. Alguém sabe?

Dito de outra forma, quando precisamente o soquete abstrato é liberado para ser usado novamente?

Eu não quero substituir o mecanismo de arquivo PID por soquetes abstratos, a menos que isso resolva definitivamente o problema.

    
por CivFan 17.07.2015 / 18:12

2 respostas

4

Sim, o Linux automaticamente "limpa" sockets abstratos na medida em que a limpeza até faz sentido. Aqui está um exemplo mínimo de trabalho com o qual você pode verificar isso:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>

int
main(int argc, char **argv)
{
  int s;
  struct sockaddr_un sun;

  if (argc != 2 || strlen(argv[1]) + 1 > sizeof(sun.sun_path)) {
    fprintf(stderr, "usage: %s abstract-path\n", argv[0]);
    exit(1);
  }

  s = socket(AF_UNIX, SOCK_STREAM, 0);
  if (s < 0) {
    perror("socket");
    exit(1);
  }
  memset(&sun, 0, sizeof(sun));
  sun.sun_family = AF_UNIX;
  strcpy(sun.sun_path + 1, argv[1]);
  if (bind(s, (struct sockaddr *) &sun, sizeof(sun))) {
    perror("bind");
    exit(1);
  }
  pause();
}

Execute este programa como ./a.out /test-socket & , depois execute ss -ax | grep test-socket e você verá o soquete em uso. Então, kill %./a.out e ss -ax mostrarão que o soquete desapareceu.

No entanto, o motivo pelo qual você não pode encontrar essa limpeza em qualquer documentação é que ela não está realmente sendo limpa, da mesma forma que os soquetes não-abstratos do domínio unix precisam ser limpos. Um soquete não abstrato realmente aloca um inode e cria uma entrada em um diretório, que precisa ser limpo no sistema de arquivos subjacente. Por outro lado, pense em um soquete abstrato mais parecido com um número de porta TCP ou UDP. Claro, se você ligar uma porta TCP e sair, essa porta TCP estará livre novamente. Mas o número de 16 bits que você usou ainda existe abstratamente e sempre o fez. O namespace dos números de porta é 1-65535 e nunca muda ou precisa de limpeza.

Portanto, pense no nome do soquete abstrato, como um número de porta TCP ou UDP, que acabou de ser escolhido de um conjunto muito maior de números de portas possíveis que parecem ser nomes de caminho, mas não são. Você não pode ligar o mesmo número de porta duas vezes (com exceção de SO_REUSEADDR ou SO_REUSEPORT ). Mas fechar o socket (explicitamente ou implicitamente por terminação) libera a porta, sem nada para limpar.

    
por 02.08.2015 / 00:11
2

Eu postei essa pergunta há mais de um ano e nunca fiquei satisfeito com a falta de documentação definitiva. Eu pensei em checar a documentação Linux novamente para qualquer atualização, e fiquei feliz para ver isso :

Abstract sockets

Socket permissions have no meaning for abstract sockets: the process umask(2) has no effect when binding an abstract socket, and changing the ownership and permissions of the object (via fchown(2) and fchmod(2)) has no effect on the accessibility of the socket.

Abstract sockets automatically disappear when all open references to the socket are closed.

Além disso, A interface de programação do Linux Michael Kerrisk aborda a questão (postagem cruzada de esta outra resposta ):

57.6 The Linux Abstract Socket Namespace

The so-called abstract namespace is a Linux-specific feature that allows us to bind a UNIX domain socket to a name without that name being created in the file system. This provides a few potential advantages:

  • We don’t need to worry about possible collisions with existing names in the file system.
  • It is not necessary to unlink the socket pathname when we have finished using the socket. The abstract name is automatically removed when the socket is closed.
  • We don’t need to create a file-system pathname for the socket. This may be useful in a chroot environment, or if we don’t have write access to a file system.

To create an abstract binding, we specify the first byte of the sun_path field as a null byte (%bl0ck_qu0te%). [...]

Acho que, junto com a resposta do @ user3188445, elimina a questão com muita precisão.

Dito isso, ainda há uma suposição feita aqui, de que os processos que são SIGKILL'd terão todos os sockets abertos fechados. Isso parece uma suposição razoável, mas não tenho documentação que defina esse comportamento.

    
por 29.11.2016 / 20:52