O Linux limpa automaticamente soquetes de domínio abstrato?

15

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

Em resumo, a solução conta com soquetes de domínio de espaço para nome abstrato do Linux, que rastreia os soquetes por nome para você, em vez de depender de arquivos, que podem permanecer depois que o daemon é SIGKILL. O exemplo mostra que o Linux parece liberar o soquete assim que o processo termina.

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

Em outras palavras, quando exatamente o soquete abstrato é liberado para ser usado novamente?

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

CivFan
fonte
3
Não consigo encontrar nada que responda isso diretamente. Mas como não há API para remover soquetes abstratos, parece que eles precisariam ser gerenciados automaticamente pelo kernel. Quando não há processos com o soquete aberto, ele deve desaparecer.
Barmar
@ Barmar Fair o suficiente. Gostaria de adicioná-lo como resposta?
CivFan
Eu preferiria ter informações mais definidas.
Barmar

Respostas:

5

Sim, o linux "limpa" automaticamente os soquetes abstratos na medida em que a limpeza faz sentido. Aqui está um exemplo de trabalho mínimo 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 &, em seguida, execute ss -ax | grep test-sockete você verá o soquete em uso. Então kill %./a.out, e ss -axmostrará que o soquete se foi.

No entanto, o motivo pelo qual você não consegue encontrar essa limpeza em nenhuma documentação é que ela não está realmente limpando no mesmo sentido que soquetes de domínio unix não abstratos precisam ser limpos. Na verdade, um soquete não abstrato 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 como um número de porta TCP ou UDP. Claro, se você ligar uma porta TCP e depois sair, essa porta TCP estará livre novamente. Mas qualquer número de 16 bits que você usou ainda existe abstratamente e sempre existiu. O espaço para nome dos números das portas é 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, apenas escolhido em um conjunto muito maior de números de porta possíveis que parecem com nomes de caminho, mas não são. Você não pode vincular o mesmo número de porta duas vezes (barramento SO_REUSEADDRou SO_REUSEPORT). Mas fechar o soquete (explícita ou implicitamente ao finalizar) libera a porta, sem mais nada para limpar.

user3188445
fonte
Já passou no teste do pato. Isso é bom para algumas coisas, como python, mas espero mais pelos recursos do kernel do Linux. Veja seus exemplos de portas TCP / UDP - há muita documentação descrevendo com precisão quando a porta pode ser reutilizada.
precisa saber é o seguinte
2
E por que essa documentação não se aplica igualmente a soquetes abstratos? Você tem uma referência? Uma pergunta melhor pode ser onde está documentada a complicação de limpeza extra para soquetes de domínio Unix não abstratos. No meu sistema, isso é no unix (7) , que diz "O Linux também suporta um espaço para nome abstrato que é independente do sistema de arquivos". Então, para mim, "independente do sistema de arquivos", não implica nenhuma limpeza específica do sistema de arquivos.
precisa saber é o seguinte
5

Publiquei essa pergunta há mais de um ano e nunca fiquei bastante satisfeito com a falta de documentação definitiva. Eu pensei em verificar a documentação do Linux novamente para obter quaisquer atualizações e fiquei feliz em ver isso :

Soquetes abstratos

Permissões de soquete não têm significado para soquetes abstratos: o processo umask (2) não tem efeito ao vincular um soquete abstrato e alterar a propriedade e as permissões do objeto (via fchown (2) e fchmod (2)) não afeta o acessibilidade do soquete.

Soquetes abstratos desaparecem automaticamente quando todas as referências abertas ao soquete são fechadas.

Além disso, a Interface de Programação do Linux, de Michael Kerrisk, cobre a pergunta (postada nesta outra resposta ):

57.6 Espaço para nome do Linux Abstract Socket

O chamado espaço de nome abstrato é um recurso específico do Linux que nos permite vincular um soquete de domínio UNIX a um nome sem que esse nome seja criado no sistema de arquivos. Isso fornece algumas vantagens em potencial:

  • Não precisamos nos preocupar com possíveis colisões com nomes existentes no sistema de arquivos.
  • Não é necessário desvincular o nome do caminho do soquete quando terminarmos de usá-lo. O nome do resumo é removido automaticamente quando o soquete é fechado.
  • Não precisamos criar um nome de caminho do sistema de arquivos para o soquete. Isso pode ser útil em um ambiente chroot ou se não tivermos acesso de gravação a um sistema de arquivos.

Para criar uma ligação abstrata, especificamos o primeiro byte do campo sun_path como um byte nulo (\ 0). [...]

Acho que, junto com a resposta de @ user3188445, isso esclarece a questão com muita precisão.

Dito isto, ainda existe uma suposição feita aqui, de que os processos que são da SIGKILL terão todos os soquetes abertos fechados. Parece uma suposição razoável, mas não tenho documentação que defina esse comportamento.

CivFan
fonte
1
Último parágrafo: soquetes são descritores de arquivos e todos os descritores de arquivos abertos são fechados quando um processo é encerrado. Ish. Mais especificamente, um soquete é um arquivo aberto, arquivos abertos podem ser transmitidos, por exemplo, herdados por processos filhos. Portanto, certifique-se de chamar socket SOCK_CLOEXEC, caso algum código (incluindo uma biblioteca) faça fork () + exec (). Criar processos filhos extras usando fork () sem exec () é menos comum; você provavelmente já sabe se está fazendo isso.
sourcejedi
Não é necessário desvincular ... - hum, já que não há nome de caminho, não é possível desvincular, não apenas desnecessário.
domen