(get|set)sockopt

Menu de seleção de opções para fazer em uma sexta que você está de folga:
  1. 1: Ir a praia
  2. 2: Fazer uma trilha de bicicleta
  3. 3: Ver TV
  4. 4: Ler: "Programação para redes Unix"
  5. Digite sua Opção:
  6. 4
  7. Opção 4: você é um nerd.
  8.  
  9. – Eu   n ã o   s o u    N E R D…

Os sockets possuem algumas opções e ajustes que podem ser feitos, como por exemplo, o tamanho do buffer de envio e recebimento de pacotes, se o pacote pode ser enviado para broadcast (este somente para sockets de datagrama (ex: UDP)), o TTL do pacote, etc.

Um dos meios de ajustar estes valores é utilizando as chamadas do sistema getsockopt(2) e setsockopt(2)

int getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen);
  1. int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);

Os argumentos, são:

int s: Descritor do soquete aberto
int level: Nivel do protocolo que deseja alterar a opção (ip, tcp, udp…)
int optname: Opção que deseja alterar
void *optval: Um ponteiro para a variável ao qual o valor deve ser gravado em getsockopt() ou lido em setsockopt().
socklen_t optlen: Tamanho da variável optval

Os valores para level, optname e optval estão descritos nas sessões “Socket Options” de ip(7),tcp(7),udp(7),socket(7) e unix(7).

O código abaixo, trás dois exemplos de opções:

  • Aumentar o tamanho do buffer de recebimento
  • Liberar o envio de pacotes UDP para o endereço de broadcast da rede:

sockopt.c

  1.  
  2. #include<errno.h>
  3. #include<stdio.h>
  4. #include<stdlib.h>
  5. #include<string.h>
  6. #include<sys/types.h>
  7. #include<netinet/in.h>
  8. #include<sys/socket.h>
  9.  
  10. #define MAXLINE 1500
  11.  
  12. void send_udp(int fd, struct sockaddr *servaddr, socklen_t servlen);
  13.  
  14. int main (int argc, char **argv){
  15. int fd, retval;
  16. int val;
  17. socklen_t servlen;
  18. struct sockaddr_in servaddr;
  19.  
  20. fd = socket (AF_INET, SOCK_DGRAM, 0);
  21.  
  22. /* Pegar o valor do buffer de recebimento, exibir,
  23. * dobrar o valor e exibir novamente.
  24. */
  25. val = sizeof(int);
  26. getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &retval, &val);
  27. printf("rcvbuf: %d\n",retval);
  28.  
  29. /* Dobrar o Valor */
  30. retval =  retval * 2;
  31. setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &retval, val);
  32.  
  33. /* Exibir o novo valor */
  34. getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &retval, &val);
  35. printf("rcvbuf: %d\n",retval);
  36.  
  37. /* Enviar um pacote em broadcast.
  38. * Antes e depois de ajustar a opção SO_BROADCAST.
  39. */
  40.  
  41. memset(&amp;servaddr, 0, sizeof(servaddr));
  42. servaddr.sin_family = AF_INET;
  43. servaddr.sin_port = htons(atoi(argv[2]));
  44. inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
  45. servlen = sizeof(servaddr);
  46.  
  47. /* Irá falhar: Permissão negada */
  48. send_udp(fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
  49.  
  50. /* Ajustar o valor para !=0 */
  51. retval = 1;
  52. setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &retval, sizeof(int));
  53.  
  54. /* Agora com a permissão o pacote será enviado */
  55. send_udp(fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
  56.  
  57. exit(0);
  58. }
  59.  
  60. /* Função para o envio de pacote… */
  61. void send_udp(int fd, struct sockaddr *servaddr, socklen_t servlen){
  62. char sendline[MAXLINE];
  63. int len;
  64.  
  65. snprintf(sendline,11,"Ola mundo\n");
  66.  
  67. if ( (len = sendto(fd,sendline,strlen(sendline),0,servaddr,servlen)) < 0 )
  68. printf("Erro ao enviar pacote: %s\n", strerror(errno));
  69. else
  70. printf("Sucesso ao enviar o pacote: %d bits enviados\n", len);
  71. }

Como saída temos:

Linux 2.6:

  1. [bristot@kiron cap6]$ ./sockopts 10.1.17.255 22
  2. rcvbuf: 124928
  3. rcvbuf: 262142
  4. Erro ao enviar pacote: Permission denied
  5. Sucesso ao enviar o pacote: 10 bits enviados

FreeBSD-6.3:

  1. > ./sockopts 172.16.200.255 22
  2. rcvbuf: 42080
  3. rcvbuf: 84160
  4. Erro ao enviar pacote: Permission denied
  5. Sucesso ao enviar o pacote: 10 bits enviados

HPUX-11.23

  1. rx4640> ./sockopts 192.168.255.255 22
  2. rcvbuf: 65535
  3. rcvbuf: 131070
  4. Sucesso ao enviar o pacote: 10 bits enviados
  5. Sucesso ao enviar o pacote: 10 bits enviados

Legal, o HP-UX, apesar de não acusar erro com o setsockopt para a opção de broadcast, não bloqueou o primeiro pacote(Como o FreeBSD e o Linux fizeram). Ao procurar pelas páginas do manual, no HP-UX, não achei referencia sobre as opções de socket…

Como dica final, recomento livro “Programação para redes Unix”, de Stevens, Fenner e Rudoff… ótima literatura …

Até.