|
||||||||||||||||||||||||||
|
ПРИЛОЖЕНИЕ ВВспомогательные исходные коды В.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. Функции обработки ошибок
В листинге В.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 | Прислать материал | Нашёл ошибку | Наверх |
||||||||||||||||||||||||||
|