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