• В.1. Заголовочный файл unpipc.h
  • B.2. Заголовочный файл config.h
  • В.З. Стандартные функции вывода сообщений об ошибках
  • ПРИЛОЖЕНИЕ В

    Вспомогательные исходные коды

    В.1. Заголовочный файл unpipc.h

    Почти все программы книги подключают заголовочный файл unpipc.h, приведенный в листинге В.1.[1] Он подключает все стандартные системные заголовки, нужные большинству пpoгрaмм для работы с сетью, вместе с некоторыми общими системными заголовками. Он также определяет константы типа MAXLINE и прототипы функций ANSI С для функций, определенных в тексте (типа px_ipc_name), и для всех используемых в книге оберток. Мы не приводим эти прототипы.

    Листинг В.1. Заголовочный файл unpipc.h

    //lib/unpipc.h

    1   /* Наш заголовочный файл. */

    2   #ifndef __unpipc_h

    3   #define __unpipc_h


    4   #include "../config.h" /* параметры конфигурации ОС */

    5   /* "../config.h" создается сценарием configure */


    6   /* изменяя список директив #include, нужно изменять файлы

    7    ../aclocal.m4 и ../configure.in. чтобы работал сценарий configure */

    8   #include <sys/types.h> /* базовые типы данных */

    9   #include <sys/time.h> /* структура timeval{} для select() */


    10  #include <time.h> /* timespec{} для pselect() */

    11  #include <errno.h>

    12  #include <fcntl.h> /* отключение блокировки */

    13  #include <limits.h> /* PIPE_BUF */

    14  #include <signal.h>

    15  #include <stdio.h>

    16  #include <stdlib.h>

    17  #include <string.h>

    18  #include <sys/stat.h> /* константы режима доступа к файлу S_xxx */

    19  #include <unistd.h>

    20  #include <sys/wait.h>


    21  #ifdef HAVE_MQUEUE_H

    22  #include <mqueue.h> /* очереди сообщений Posix */

    23  #endif


    24  #ifdef HAVE_SEMAPHORE_H

    25  #include <semaphore.h> /* семафоры Posix */

    26  #ifndef SEM_FAILED

    27  #define SEM_FAILED ((sem_t *)(-1))

    28  #endif

    29  #endif


    30  #ifdef HAVE_SYS_MMAN_H

    31  #include <sys/mman.h> /* разделяемая память Posix */

    32  #endif


    33  #ifndef MAP_FAILED

    34  #define MAP_FAILED ((void *)(-1))

    35  #endif


    36  #ifdef HAVE_SYS_IPC_H

    37  #include <sys/ipc.h> /* System V IPC */

    38  #endif


    39  #ifdef HAVE_SYS_MSG_H

    40  #include <sys/msg.h> /* очереди сообщений System V */

    41  #endif


    42  #ifdef HAVE_SYS_SEM_H

    43  #ifdef __bsdi__

    44  #undef HAVE_SYS_SEM_H /* тонкий момент: прототип semctl() в BSDI's содержит ошибки*/

    45  #else

    46  #include <sys/sem.h> /* семафоры System V */

    47  #endif

    48  #ifndef HAVE_SEMUN_UNION /* $$.It semun$$ */

    49  union semun { /* определение объединения для semctl() */

    50   int val;

    51   struct semid_ds *buf;

    52   unsigned short *array;

    53  };

    54  #endif

    55  #endif /* HAVE_SYS_SEM_H */


    56  #ifdef HAVE_SYS_SHM_H

    57  #include <sys/shm.h> /* разделяемая память System V */

    58  #endif


    59  #ifdef HAVE_SYS_SELECT_H

    60  #include <sys/select.h> /* для удобства */

    61  #endif


    62  #ifdef HAVE_POLL_H

    63  #include <poll.h> /* для удобства */

    64  #endif


    65  #ifdef HAVE_STROPTS_H

    66  #include <stropts.h> /* для удобства */

    67  #endif


    68  #ifdef HAVE_STRINGS_H

    69  #include <strings.h> /* для удобства */

    70  #endif


    71  /* Следующие три заголовочных файла нужны для ioctl файлов и сокетов:

    72   * <sys/ioctl.h>, <sys/filio.h>, и <sys/sockio.h>.

    73   */

    74  #ifdef HAVE_SYS_IOCTL_H

    75  #include <sys/ioctl.h>

    76  #endif

    77  #ifdef HAVE_SYS_FILIO_H

    78  #include <sys/filio.h>

    79  #endif


    80  #ifdef HAVE_PTHREAD_H

    81  #include <pthread.h>

    82  #endif

    83  #ifdef HAVE_DOOR_H

    84  #include <door.h> /* интерфейс дверей Solaris */

    85  #endif

    86  #ifdef HAVE_RPC_RPC_H

    87  #ifdef _PSX4_NSPACE_H_TS /* баги Digital Unix 4.0b */

    88  #undef SUCCESS

    89  #endif

    90  #include <rpc/rpc.h> /* Sun RPC */

    91  #endif


    92  /* Определяем bzero() как макрос, если его нет в стандартной библиотеке С */

    93  #ifndef HAVE_BZERO

    94  #define bzero(ptr,n) memset(ptr, 0, n)

    95  #endif


    96  /* Posix.1g требует, чтобы INFTIM определялось в <poll.h>. но во многих системах эта

    97     константа все еще определяется в <sys/stropts.h>. Нам не нужно подключать все

    98     функции для работы с потоками, поэтому мы определяем INFTM здесь. Это стандартное

    99     значение, но нет гарантий, что оно равно –1 */

    100 #ifndef INFTIM

    101 #define INFTIM (-1) /* неограниченное время опроса */

    102 #ifdef HAVE_POLL_H

    103 #define INFTIM_UNPH /* чтобы из файла unpxti.h узнать, что константа определена */

    104 #endif

    105 #endif


    106 /* Прочие константы */

    107 #ifndef РАТН_МАХ /* должна быть в <limits.h> */

    108 #define PATH_MAX 1024 /* максимальное количество символов в полном имени файла */

    109 #endif

    110 #define MAX_PATH 1024

    111 #define MAXLINE 4096 /* максимальная длина строки */

    112 #define BUFFSI2E 8192 /* объем буфера чтения и записи */

    113 #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

    114  /* разрешения по умолчанию для новых файлов */

    115 #define DIR_MODE (FILE_MODE | S_IXUSR | S_IXGRP | S_IXOTH)

    116  /* разрешения по умолчанию для новых каталогов */

    117 #define SVMSG_MODE (MSG_R | MSG_W | MSG_R>>3 | MSG_R>>6)

    118  /* разрешения по умолчанию для новых очередей сообщений System V */

    119 #define SVSEM_MODE (SEM_R | SEM_A | SEM_R>>3 | SEM_R>>6)

    120  /* разрешения по умолчанию для новых семафоров System V */

    121 #define SVSHM_MODE (SHM_R | SHM_W | SHM_R>>3 | SHM_R>>6)

    122  /* разрешения по умолчанию для новой разделяемой памяти System V */


    123 typedef void Sigfunc(int); /* для обработчиков сигналов */

    124 #ifdef HAVE_SIGINFO_T_STRUCT

    125 typedef void Sigfunc_rt(int, siginfo_t*, void*);

    126 #endif


    127 #define min(a,b) ((a) < (b) ? (a) : (b))

    128 #define max(a,b) ((a) > (b) ? (a) : (b))

    129 #ifndef HAVE_TIMESPEC_STRUCT

    130 struct timespec {

    131  time_t tv_sec; /* секунды */

    132  long tv_nsec; /* и наносекунды */

    133 };

    134 #endif


    135 /*

    136 В функциях-обертках open(), mq_open(), sem_open() мы обрабатываем

    137 дополнительные аргументы с помощью макросов va_XXX().

    138 Один из аргументов имеет тип mode_t, что приводит

    139 к ошибке в BSD/OS, где для этого типа используются

    140 16-разрядные целые. При вызове обертки

    141 компилятор преобразовывает 16-разрядное целое

    142 в 32-разрядное. Поэтому и необходимо то.

    143 что сделано ниже.

    144 */

    145 #ifdef __bsdi__

    146 #define va_mode_t int

    147 #else

    148 #define va_mode_t mode_t

    149 #endif


    150 /* макросы блокировки записей */

    151 #define read_lock(fd, offset, whence, len) \

    152  lock_reg(fd, F_SETLK, F_RDLCK, offset, whence, len)

    153 #define readw_lock(fd, offset, whence, len) \

    154  lock_reg(fd, F_SETLKW, F_RDLCK, offset, whence, len)

    155 #define write_lock(fd, offset, whence, len) \

    156  lock_reg(fd, F_SETLK, F_WRLCK, offset, whence, len)

    157 #define writew_lock(fd, offset, whence, len) \

    158  lock_reg(fd, F_SETLKW, F_WRLCK, offset, whence, len)

    159 #define un_lock(fd, offset, whence, len) \

    160  lock_reg(fd, F_SETLK, F_UNLCK, offset, whence, len)

    161 #define is_read_lockable(fd, offset, whence, len) \

    162  lock_test(fd, F_RDLCK, offset, whence, len)

    163 #define is_write_lockable(fd, offset, whence, len) \

    164  lock_test(fd. F_WRLCK, offset, whence, len)

    B.2. Заголовочный файл config.h

    Для подготовки пpoгрaмм в этой книге использовалась утилита GNU autoconf, которая помогает сделать их более переносимыми. Она доступна по адресу ftp://prep.ai.mit.edu/pub/gnu. Утилита создает сценарий configure, который следует запустить после того, как вы зaгрyзитe пpoгрaммy из Сети. Этот сценарий определяет возможности вашей системы: поддерживаются ли очереди System V, определен ли тип uint8_t, определена ли функция gethostname и т. д. В процессе работы он создает заголовочный файл config.h, который включается нашим unpipc.h перед всеми остальными. В листинге В.2 приведен пример заголовочного файла config.h для системы Solaris 2.6 и компилятора gcc.

    Строки, начинающиеся с #define, описывают функции, поддерживаемые в системе. Закомментированные строки соответствуют неподдерживаемым функциям.

    Листинг В.2. Заголовочный файл config.h для Solaris 2.6

    //sparc-sun-solaris2.6/config.h

    1  /* config.h. Автоматически создается сценарием configure. */

    2  /* Константы следует указывать только тогда, когда есть соответствующий заголовочный файл */

    3  #define CPU_VENDOR_OS "sparc-sun-solaris2.6"

    4  #define HAVE_DOOR_H 1 /* <door.h> */

    5  #define HAVE_MQUEUE_H 1 /* <mqueue.h> */

    6  #define HAVE_POLL_H 1 /*<poll.h>*/

    7  #define HAVE_PTHREAD_H 1 /* <pthread.h> */

    8  #define HAVE_RPC_RPC_H 1 /* <rpc/rpc.h> */

    9  #define HAVE_SEMAPHORE_H 1 /* semaphore.h> */

    10 #define HAVE_STRINGS_H 1 /* <strings.h> */

    11 #define HAVE_SYS_FILIO_H 1 /* <sys/filio.h> */

    12 #define HAVE_SYS_IOCTL_H 1 /* <sys/ioctl.h> */

    13 #define HAVE_SYS_IPC_H 1 /* <sys/ipc.h> */

    14 #define HAVE_SYS_MMAN_H 1 /* <sys/mman.h> */

    15 #define HAVE_SYS_MSG_H 1 /* <sys/msg.h> */

    16 #define HAVE_SYS_SEM_H 1 /* <sys/sem.h> */

    17 #define HAVE_SYS_SHM_H 1 /* <sys/shm.h> */

    18 #define HAVE_SYS_SELECT_H 1 /* <sys/select.h> */

    19 /* #undef HAVE_SYS_SYSCTL_H */ /* <sys/sysctl.h> */

    20 #define HAVE_SYS_TIME_H 1 /* <sys/time.h> */


    21 /* Определена, если можно подключить <time.h> вместе с <sys/time.h> */

    22 #define TIME_WITH_SYS_TIME 1


    23 /* Определены, если имеются соответствующие функции */

    24 #define HAVE_BZERO 1

    25 #define HAVE_FATTACH 1

    26 #define HAVE_POLL 1

    27 /* #undef HAVE_PSELECT */

    28 #define HAVE_SIGWAIT 1

    29 #define HAVE_VALLOC 1

    30 #define HAVE_VSNPRINTF 1


    31 /* Определены, если прототипы функций есть в заголовках */

    32 #define HAVE_GETHOSTNAME_PROTO 1 /* <unistd.h> */

    33 #define HAVE_GETRUSAGE_PROTO 1 /* <sys/resource.h> */

    34 /* #undef HAVE_PSELECT_PROTO */ /* <sys/select.h> */

    35 #define HAVE SHM_OPEN_PROTO 1 /* <sys/mman.h> */

    36 #define HAVE_SNPRINTF_PROTO 1 /* <stdio.h> */

    37 #define HAVE_THR_SETCONCURRENCY_PROTO 1 /* <thread.h> */


    38 /* Определены, если определены соответствующие структуры */

    39 #define HAVE_SIGINFO_T_STRUCT 1 /* <signal.h> */

    40 #define HAVE_TIMESPEC_STRUCT 1 /* <time.h> */

    41 /* #undef HAVE_SEMUN_UNION */ /* <sys/sem.h> */


    42 /* Устройства */

    43 #define HAVE_DEV_ZERO 1


    44 /* Для соответствующих типов данных */

    45 /* #undef int8_t */ /* <sys/types.h> */

    46 /* #undef intl6_t */ /* <sys/types.h> */

    47 /* #undef int32_t */ /* <sys/types.h> */

    48 /* #undef uint8_t */ /* <sys/types.h> */

    49 /* #undef uintl6_t */ /* <sys/types.h> */

    50 /* #undef uint32_t */ /* <sys/types.n> */

    51 /* #undef size_t */ /* <sys/types.h> */

    52 /* #undef ssize_t */ /* <sys/types.h> */


    53 #define POSIX_IPC_PREFIX "/"

    54 #define RPCGEN_ANSIC 1 /* определена, если rpcgen поддерживает параметр –С */

    В.З. Стандартные функции вывода сообщений об ошибках

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

    if (условие_ошибки) err_sys(формат printf с произвольным количеством аргументов);

    вместо:

    if (условие_ошибки) {

     char buff[200];

     snprintf(buff, sizeof(buff), формат printf с произвольным количеством аргументов);

     perror(buff);

     exit(1);

    }

    Функции обработки ошибок используют возможности работы со списком аргументов переменной длины, определенные стандартом ANSI С. В разделе 7.3 [ 11 ] вы можете узнать подробности.

    В таблице В.1 приведены отличия между различными функциями обработки ошибок. Если глобальное целое daemon_proc отлично от нуля, сообщение передается демону syslog с указанным уровнем (см. главу 12 [24]); в противном случае сообщение выводится в стандартный поток сообщений об ошибках.


    Таблица В.1. Функции обработки ошибок

    Функция strerror(errno)? Завершение? Уровень syslog
    err_dump Да abort(); LOG_ERR
    err_msg Нет return; LOG_INFO
    err_quit Нет exit(1); LOG_ERR
    err_ret Да return; LOG_INFO
    err_sys Да exit(1); LOG_ERR

    В листинге В.3 приведен текст функций из табл. В.1.

    Листинг В.3. Функции обработки ошибок

    //lib/error.с

    1  #include "unpipc.h"

    2  #include <stdarg.h> /* заголовочный файл ANSI С */

    3  #include <syslog.h> /* для демона syslog() */


    4  int daemon_proc; /* устанавливается отличным от нуля daemon_init() */

    5  static void err_doit(int, int, const char*, va_list);


    6  /* Нефатальная ошибка при системном вызове.

    7   * Вывод сообщения и возврат из функции. */

    8  void

    9  err_ret(const char *fmt, ...)

    10 {

    11  va_list ар;

    12  va_start(ap, fmt);

    13  err_doit(1, LOG_INFO, fmt, ap);

    14  va_end(ap);

    15  return;

    16 }


    17 /* Фатальная ошибка при системном вызове.

    18  * Вывод сообщения и завершение работы. */

    19 void

    20 err_sys(const char *fmt, ...)

    21 {

    22  va_list ap;

    23  va_start(ap, fmt);

    24  err_doit(1, LOG_ERR, fmt, ар);

    25  va_end(ap);

    26  exit(1);

    27 }


    28 /* Фатальная ошибка при системном вызове.

    29  * Вывод сообщения, сохранение дампа памяти, завершение работы. */

    30 void

    31 err_dump(const char *fmt, ...)

    32 {

    33  va_list ар;

    34  va_start(ap, fmt);

    35  err_doit(1, LOG_ERR, fmt, ap);

    36  va_end(ap);

    37  abort(); /* сохранение дампа и завершение */

    38  exit(1); /* досюда не должно дойти */

    39 }


    40 /* Нефатальная ошибка не при системном вызове.

    41  * Вывод сообщения и возврат. */

    42 void

    43 err_msg(const char *fmt, ...)

    44 {

    45  va_list ap;

    46  va_start(ap, fmt);

    47  err_doit(0, LOG_INFO, fmt, ap);

    48  va_end(ap);

    49  return;

    50 }


    51 /* Фатальная ошибка не при системном вызове.

    52  * Вывод сообщения и возврат. */

    53 void

    54 err_quit(const char *fmt, ...)

    55 {

    56  va_list ap;

    57  va_start(ap, fmt);

    58  err_doit(0, LOG_ERR, fmt, ap);

    59  va_end(ap);

    60  exit(1);

    61 }


    62 /* Вывод сообщения и возврат.

    63  * Вызывающий указывает "errnoflag" и "level". */

    64 static void

    65 err_doit(int errnoflag, int level, const char *fmt, va_list ap)

    66 {

    67  int errno_save, n;

    68  char buf[MAXLINE];

    69  errno_save = errno; /* значение может понадобиться вызвавшему */

    70 #ifdef HAVE_VSNPRINTF

    71  vsnprintf(buf, sizeof(buf), fmt, ар); /* защищенный вариант */

    72 #else

    73  vsprintf(buf, fmt, ар); /* незащищенный вариант */

    74 #endif

    75  n = strlen(buf);

    76  if (errnoflag)

    77   snprintf(buf+n, sizeof(buf)-n, ": %s", strerror(errno_save));

    78  strcat(buf, "\n");

    79  if (daemon_proc) {

    80   syslog(level, buf);

    81  } else {

    82   fflush(stdout); /* если stdout и stderr одинаковы */

    83   fputs(buf, stderr);

    84   fflush(stderr);

    85  }

    86  return;

    87 }


    Примечания:



    1

    Все исходные тексты, опубликованные в этой книге, вы можете найти по адресу http://www.piter.com/download.








    Главная | В избранное | Наш E-MAIL | Прислать материал | Нашёл ошибку | Наверх