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 66struct pass_trigger { 67 int connect_fd; 68 char *service; 69 int pass_fd[2]; 70}; 71 72/* pass_trigger_event - disconnect from peer */ 73 74static 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 99int 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