Литмир - Электронная Библиотека
ЛитМир: бестселлеры месяца
Содержание  
A
A

16   if (strlen(temp) >= len) {

17    errno = ENOSPC;

18    return (NULL);

19   }

20   strcpy(strptr, temp);

21   return (strptr);

22  }

23  errno = EAFNOSUPPORT;

24  return (NULL);

25 }

3.8. Функция sock_ntop и связанные с ней функции

Основная проблема, связанная с функцией

inet_ntop
, состоит в том, что вызывающий процесс должен передать ей указатель на двоичный адрес. Этот адрес обычно содержится в структуре адреса сокета, поэтому вызывающему процессу необходимо знать формат структуры и семейство адресов. Следовательно, чтобы использовать эту функцию, для IPv4 нужно написать код следующего вида:

struct sockaddr_in addr;

inet_ntop(AF_INET, &addr.sin_addr, str, sizeof(str));

или для IPv6 такого вида:

struct sockaddr_in6 addr6:

inet_ntop(AF_INET6, &addr6.sin6_addr, str, sizeof(str));

Как видите, код становится зависящим от протокола.

Чтобы решить эту проблему, напишем собственную функцию и назовем ее

sock_ntop
. Она получает указатель на структуру адреса сокета, исследует эту структуру и вызывает соответствующую функцию для того, чтобы возвратить формат представления адреса.

#include "unp.h"

char *sock_ntop(const struct sockaddr *<i>sockaddr</i>, socklen_t <i>addrlen</i>);

<i>Возвращает: непустой указатель, если функция выполнена успешно, NULL в случае ошибки</i>

sockaddr
указывает на структуру адреса сокета, длина которой равна значению
addrlen
. Функция
sock_ntop
использует свой собственный статический буфер для хранения результата и возвращает указатель на этот буфер.

Формат представления — либо точечно-десятичная форма записи адреса IPv4, либо шестнадцатеричная форма записи адреса IPv6, за которой следует завершающий символ (мы используем точку, как в программе

netstat
), затем десятичный номер порта, а затем завершающий нуль. Следовательно, размер буфера должен быть равен как минимум
INET_ADDRSTRLEN
плюс 6 байт для IPv4 (16 + 6 - 22) либо
INET6_ADDRSTRLEN
плюс 6 байт для IPv6 (46 + 6 - 52).

ПРИМЕЧАНИЕ

Обратите внимание, что при статическом хранении результата функция не допускает повторного вхождения (не является повторно входимой) и не может быть использована несколькими программными потоками (не является безопасной в многопоточной среде — thread-safe). Более подробно мы поговорим об этом в разделе 11.18. Мы допустили такое решение для этой функции, чтобы ее было легче вызывать из простых программ, приведенных в книге.

В листинге 3.8 представлена часть исходного кода, обрабатывающая семейство

AF_INET
.

Листинг 3.8. Наша функция sock_ntop

//lib/sock_ntop.c

 5 char *

 6 sock_ntop(const struct sockaddr *sa, socklen_t salen)

 7 {

 8  char portstr[7];

 9  static char str[128]; /* макс. длина для доменного сокета Unix */

10  switch (sa-&gt;sa_family) {

11  case AF_INET: {

12    struct sockaddr_in *sin = (struct sockaddr_in*)sa;

13    if (inet_ntop(AF_INET, &amp;sin-&gt;sin_addr. str, sizeof(str)) == NULL)

14     return (NULL);

15    if (ntohs(sin-&gt;sin_port) != 0) {

16     snprintf(portstr, sizeof(portstr), ntohs(sin-&gt;sin_port));

17     strcat(str, portstr);

18    }

19    return (str);

20   }

Для работы со структурами адресов сокетов мы определяем еще несколько функций, которые упростят переносимость нашего кода между IPv4 и IPv6.

#include &quot;unp.h&quot;

int sock_bind_wild(int <i>sockfd</i>, int <i>family</i>);

<i>Возвращает: 0 в случае успешного выполнения функции, -1 в случае ошибки</i>

int sock_cmp_addr(const struct sockaddr *<i>sockaddr1</i>,

 const struct sockaddr *<i>sockaddr2</i>, socklen_t <i>addrlen</i>);

<i>Возвращает: 0, если адреса относятся к одному семейству и совпадают, ненулевое значение в противном случае</i>

int sock_cmp_port(const struct sockaddr *<i>sockaddr1</i>,

 const struct sockaddr *<i>sockaddr2</i>, socklen_t <i>addrlen</i>);

<i>Возвращает: 0, если адреса относятся к одному семейству и порты совпадают, ненулевое значение в противном случае</i>

int sock_get_port(const struct sockaddr *<i>sockaddr</i>, socklen_t <i>addrlen</i>);

<i>Возвращает: неотрицательный номер порта для адресов IPv4 или IPv6, иначе -1</i>

char *sock_ntop_host(const struct sockaddr *<i>sockaddr</i>, socklen_t <i>addrlen</i>);

<i>Возвращает: непустой указатель в случае успешного выполнения функции, NULL в случае ошибки</i>

void sock_set_addr(const struct sockaddr *<i>sockaddr</i>,

 socklen_t <i>addrlen</i>, void *<i>ptr</i>);

void sock_set_port(const struct sockaddr *<i>sockaddr</i>,

 socklen_t <i>addrlen</i>, int <i>port</i>);

33
{"b":"225366","o":1}
ЛитМир: бестселлеры месяца