1/*++ 2/* NAME 3/* unix_pass_trigger 3 4/* SUMMARY 5/* wakeup UNIX-domain file descriptor listener 6/* SYNOPSIS 7/* #include <trigger.h> 8/* 9/* int unix_pass_trigger(service, buf, len, timeout) 10/* const char *service; 11/* const char *buf; 12/* ssize_t len; 13/* int timeout; 14/* DESCRIPTION 15/* unix_pass_trigger() wakes up the named UNIX-domain server by sending 16/* a brief connection to it and writing the named buffer. 17/* 18/* The connection is closed by a background thread. Some kernels 19/* cannot handle client-side disconnect before the server has 20/* received the message. 21/* 22/* Arguments: 23/* .IP service 24/* Name of the communication endpoint. 25/* .IP buf 26/* Address of data to be written. 27/* .IP len 28/* Amount of data to be written. 29/* .IP timeout 30/* Deadline in seconds. Specify a value <= 0 to disable 31/* the time limit. 32/* DIAGNOSTICS 33/* The result is zero in case of success, -1 in case of problems. 34/* SEE ALSO 35/* unix_pass_connect(3), UNIX-domain client 36/* LICENSE 37/* .ad 38/* .fi 39/* The Secure Mailer license must be distributed with this software. 40/* AUTHOR(S) 41/* Wietse Venema 42/* IBM T.J. Watson Research 43/* P.O. Box 704 44/* Yorktown Heights, NY 10598, USA 45/*--*/ 46 47/* System library. */ 48 49#include <sys_defs.h> 50#include <sys/socket.h> 51#include <unistd.h> 52#include <string.h> 53 54/* Utility library. */ 55 56#include <msg.h> 57#include <connect.h> 58#include <iostuff.h> 59#include <mymalloc.h> 60#include <events.h> 61#include <trigger.h> 62 63struct unix_pass_trigger { 64 int fd; 65 char *service; 66 int *pair; 67}; 68 69/* unix_pass_trigger_event - disconnect from peer */ 70 71static void unix_pass_trigger_event(int event, char *context) 72{ 73 struct unix_pass_trigger *up = (struct unix_pass_trigger *) context; 74 static const char *myname = "unix_pass_trigger_event"; 75 76 /* 77 * Disconnect. 78 */ 79 if (event == EVENT_TIME) 80 msg_warn("%s: read timeout for service %s", myname, up->service); 81 event_disable_readwrite(up->fd); 82 event_cancel_timer(unix_pass_trigger_event, context); 83 /* Don't combine multiple close() calls into one boolean expression. */ 84 if (close(up->fd) < 0) 85 msg_warn("%s: close %s: %m", myname, up->service); 86 if (close(up->pair[0]) < 0) 87 msg_warn("%s: close pipe: %m", myname); 88 if (close(up->pair[1]) < 0) 89 msg_warn("%s: close pipe: %m", myname); 90 myfree(up->service); 91 myfree((char *) up); 92} 93 94/* unix_pass_trigger - wakeup UNIX-domain server */ 95 96int unix_pass_trigger(const char *service, const char *buf, ssize_t len, int timeout) 97{ 98 const char *myname = "unix_pass_trigger"; 99 int pair[2]; 100 struct unix_pass_trigger *up; 101 int fd; 102 103 if (msg_verbose > 1) 104 msg_info("%s: service %s", myname, service); 105 106 /* 107 * Connect... 108 */ 109 if ((fd = unix_pass_connect(service, BLOCKING, timeout)) < 0) { 110 if (msg_verbose) 111 msg_warn("%s: connect to %s: %m", myname, service); 112 return (-1); 113 } 114 close_on_exec(fd, CLOSE_ON_EXEC); 115 116 /* 117 * Create a pipe, and send one pipe end to the server. 118 */ 119 if (pipe(pair) < 0) 120 msg_fatal("%s: pipe: %m", myname); 121 close_on_exec(pair[0], CLOSE_ON_EXEC); 122 close_on_exec(pair[1], CLOSE_ON_EXEC); 123 if (unix_send_fd(fd, pair[0]) < 0) 124 msg_fatal("%s: send file descriptor: %m", myname); 125 126 /* 127 * Stash away context. 128 */ 129 up = (struct unix_pass_trigger *) mymalloc(sizeof(*up)); 130 up->fd = fd; 131 up->service = mystrdup(service); 132 up->pair = pair; 133 134 /* 135 * Write the request... 136 */ 137 if (write_buf(pair[1], buf, len, timeout) < 0 138 || write_buf(pair[1], "", 1, timeout) < 0) 139 if (msg_verbose) 140 msg_warn("%s: write to %s: %m", myname, service); 141 142 /* 143 * Wakeup when the peer disconnects, or when we lose patience. 144 */ 145 if (timeout > 0) 146 event_request_timer(unix_pass_trigger_event, (char *) up, timeout + 100); 147 event_enable_read(fd, unix_pass_trigger_event, (char *) up); 148 return (0); 149} 150