Книга: UNIX: разработка сетевых приложений

Пример

Пример

В качестве примера передачи идентифицирующих данных мы изменим наш потоковый доменный сервер Unix, так чтобы он запрашивал идентифицирующие данные клиента. В листинге 15.12 показана новая функция, read_cred, аналогичная функции read, но возвращающая также структуру fcred, содержащую идентифицирующие данные отправителя.

Листинг 15.12. Функция read_cred: чтение и возвращение идентифицирующих данных отправителя

//unixdomain/readcred.c
 1 #include "unp.h"
 2 #define CONTROL_LEN (sizeof(struct cmsghdr) + sizeof(struct cmsgcred))
 3 ssize_t
 4 read_cred(int fd, void *ptr, size_t nbytes, struct cmsgcred *cmsgcredptr)
 5 {
 6  struct msghdr msg;
 7  struct iovec iov[1];
 8  char control[CONTROL_LEN];
 9  int n;
10  msg.msg_name = NULL;
11  msg.msg_namelen = 0;
12  iov[0].iov_base = ptr;
13  iov[0].iov_len = nbytes;
14  msg.msg_iov = iov;
15  msg.msg_iovlen = 1;
16  msg.msg_control = control;
17  msg.msg_controllen = sizeof(control);
18  msg.msg_flags = 0;
19  if ((n = recvmsg(fd, &msg, 0)) < 0)
20   return(n);
21  cmsgcredptr->cmcred_ngroups = 0; /* идентифицирующие данные не получены */
22  if (cmsgcredptr && msg.msg_controllen > 0) {
23   struct cmsghdr *cmptr = (struct cmsghdr*)control;
24   if (cmptr->cmsg_len < CONTROL_LEN)
25    err_quit("control length = %d", cmptr->cmsg_len);
26   if (cmptr->cmsg_level != SOL_SOCKET)
27    err_quit("control level != SOL_SOCKET");
28   if (cmptr->cmsg_type != SCM_CREDS)
29    err_quit("control type != SCM_CREDS");
30   memcpy(cmsgcredptr, CMSG_DATA(cmptr), sizeof(struct cmsgcred));
31  }
32  return(n);
33 }
3-4
 Первые три аргумента идентичны аргументам функции read, а четвертый аргумент — это указатель на структуру cmsgcred, которая будет заполнена.

22-31 Если данные были переданы, проверяются длина, уровень и тип вспомогательных данных, и результирующая структура копируется обратно вызывающему процессу. Если никаких идентифицирующих данных не было передано, мы обнуляем структуру. Поскольку число групп (cmcred_ngroups) всегда равно 1 или больше, нулевое значение указывает вызывающему процессу, что ядро не возвратило никаких идентифицирующих данных.

Функция main для нашего эхо-сервера (см. листинг 15.3) остается неизменной. В листинге 15.13 показана новая версия функции str_echo, полученная путем модификации листинга 5.2. Эта функция вызывается дочерним процессом после того, как родительский процесс принял новое клиентское соединение и вызвал функцию fork.

Листинг 15.13. Функция str_echo, запрашивающая идентифицирующие данные клиента

//unixdomain/strecho.c
 1 #include "unp.h"
 2 ssize_t read_cred(int, void*, size_t, struct cmsgcred*);
 3 void
 4 str_echo(int sockfd)
 5 {
 6  ssize_t n;
 7  int i;
 8  char buf[MAXLINE];
 9  struct cmsgcred cred;
10 again:
11  while ((n = read_cred(sockfd, buf, MAXLINE, &cred)) > 0) {
12   if (cred.cmcred_ngroups == 0) {
13    printf("(no credentials returned)n");
14   } else {
15    printf("PID of sender = %dn", cred.cmcred_pid);
16    printf("real user ID = %dn", cred.cmcred_uid);
17    printf("real group ID = %dn", cred.cmcred_gid);
18    printf("effective user ID = %dn", cred.cmcred_euid);
19    printf("%d groups:", cred.cmcred_ngroups - 1);
20    for (i = 1; i < cred.cmcred_ngroups; i++)
21     printf(" %d", cred.cmcred_groups[i]);
22    printf("n");
23   }
24   Writen(sockfd, buf, n);
25  }
26  if (n < 0 && errno == EINTR)
27   goto again;
28  else if (n < 0)
29   err_sys("str_echo: read error");
30 }
11-23
 Если идентифицирующие данные возвращаются, они выводятся.

24-25 Оставшаяся часть цикла не меняется. Этот код считывает строки от клиента и затем отправляет их обратно клиенту.

Наш клиент, представленный в листинге 15.4, остается практически неизменным. Мы добавляем передачу пустой структуры cmsgcred при вызове sendmsg, которая заполняется ядром.

Перед запуском клиента определим свои личные данные командой id:

freebsd % id
uid=1007(andy) gid=1007(andy) groups=1007(andy), 0(wheel)

Если мы запустим сервер в одном окне, а клиент в другом, то для сервера после однократного выполнения клиента получим представленный ниже вывод.

freebsd % unixstrserv02
PID of sender = 26881
real user ID = 1007
real group ID = 1007
effective user ID = 1007
2 groups: 1007 0

Информация выводится только после отправки клиентом данных серверу. Мы видим, что сведения соответствуют тем, которые были получены командой id.

Оглавление книги

Оглавление статьи/книги

Генерация: 0.080. Запросов К БД/Cache: 0 / 0
поделиться
Вверх Вниз