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
pass_trigger_event(int event,void * context)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
pass_trigger(const char * service,const char * buf,ssize_t len,int timeout)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