4 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
27 #define CONTROL_BACKLOG 5
29 static int control_accept(struct thread
*);
30 static struct ctl_conn
*control_connbyfd(int);
31 static struct ctl_conn
*control_connbypid(pid_t
);
32 static void control_close(int);
33 static int control_dispatch_imsg(struct thread
*);
35 struct ctl_conns ctl_conns
;
37 static int control_fd
;
40 control_init(char *path
)
42 struct sockaddr_un s_un
;
46 if ((fd
= socket(AF_UNIX
, SOCK_STREAM
, 0)) == -1) {
47 log_warn("%s: socket", __func__
);
50 sock_set_nonblock(fd
);
52 memset(&s_un
, 0, sizeof(s_un
));
53 s_un
.sun_family
= AF_UNIX
;
54 strlcpy(s_un
.sun_path
, path
, sizeof(s_un
.sun_path
));
56 if (unlink(path
) == -1)
57 if (errno
!= ENOENT
) {
58 log_warn("%s: unlink %s", __func__
, path
);
63 old_umask
= umask(S_IXUSR
|S_IXGRP
|S_IWOTH
|S_IROTH
|S_IXOTH
);
64 if (bind(fd
, (struct sockaddr
*)&s_un
, sizeof(s_un
)) == -1) {
65 log_warn("%s: bind: %s", __func__
, path
);
72 if (chmod(path
, S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
) == -1) {
73 log_warn("%s: chmod", __func__
);
87 if (listen(control_fd
, CONTROL_BACKLOG
) == -1) {
88 log_warn("%s: listen", __func__
);
92 return (accept_add(control_fd
, control_accept
, NULL
));
96 control_cleanup(char *path
)
98 accept_del(control_fd
);
105 control_accept(struct thread
*thread
)
109 struct sockaddr_un s_un
;
113 if ((connfd
= accept(THREAD_FD(thread
), (struct sockaddr
*)&s_un
,
116 * Pause accept if we are out of file descriptors, or
117 * libevent will haunt us here too.
119 if (errno
== ENFILE
|| errno
== EMFILE
)
121 else if (errno
!= EWOULDBLOCK
&& errno
!= EINTR
&&
122 errno
!= ECONNABORTED
)
123 log_warn("%s: accept", __func__
);
126 sock_set_nonblock(connfd
);
128 if ((c
= calloc(1, sizeof(struct ctl_conn
))) == NULL
) {
134 imsg_init(&c
->iev
.ibuf
, connfd
);
135 c
->iev
.handler_read
= control_dispatch_imsg
;
136 c
->iev
.ev_read
= NULL
;
137 thread_add_read(master
, c
->iev
.handler_read
, &c
->iev
, c
->iev
.ibuf
.fd
,
139 c
->iev
.handler_write
= ldp_write_handler
;
140 c
->iev
.ev_write
= NULL
;
142 TAILQ_INSERT_TAIL(&ctl_conns
, c
, entry
);
147 static struct ctl_conn
*
148 control_connbyfd(int fd
)
152 TAILQ_FOREACH(c
, &ctl_conns
, entry
) {
153 if (c
->iev
.ibuf
.fd
== fd
)
160 static struct ctl_conn
*
161 control_connbypid(pid_t pid
)
165 TAILQ_FOREACH(c
, &ctl_conns
, entry
) {
166 if (c
->iev
.ibuf
.pid
== pid
)
174 control_close(int fd
)
178 if ((c
= control_connbyfd(fd
)) == NULL
) {
179 log_warnx("%s: fd %d: not found", __func__
, fd
);
183 msgbuf_clear(&c
->iev
.ibuf
.w
);
184 TAILQ_REMOVE(&ctl_conns
, c
, entry
);
186 THREAD_READ_OFF(c
->iev
.ev_read
);
187 THREAD_WRITE_OFF(c
->iev
.ev_write
);
188 close(c
->iev
.ibuf
.fd
);
195 control_dispatch_imsg(struct thread
*thread
)
197 int fd
= THREAD_FD(thread
);
203 if ((c
= control_connbyfd(fd
)) == NULL
) {
204 log_warnx("%s: fd %d: not found", __func__
, fd
);
208 c
->iev
.ev_read
= NULL
;
210 if (((n
= imsg_read(&c
->iev
.ibuf
)) == -1 && errno
!= EAGAIN
) ||
217 if ((n
= imsg_get(&c
->iev
.ibuf
, &imsg
)) == -1) {
225 switch (imsg
.hdr
.type
) {
226 case IMSG_CTL_FIB_COUPLE
:
227 case IMSG_CTL_FIB_DECOUPLE
:
228 case IMSG_CTL_RELOAD
:
229 case IMSG_CTL_KROUTE
:
230 case IMSG_CTL_KROUTE_ADDR
:
231 case IMSG_CTL_IFINFO
:
234 case IMSG_CTL_SHOW_INTERFACE
:
235 if (imsg
.hdr
.len
== IMSG_HEADER_SIZE
+
237 memcpy(&ifidx
, imsg
.data
, sizeof(ifidx
));
238 ldpe_iface_ctl(c
, ifidx
);
239 imsg_compose_event(&c
->iev
, IMSG_CTL_END
, 0,
243 case IMSG_CTL_SHOW_DISCOVERY
:
246 case IMSG_CTL_SHOW_DISCOVERY_DTL
:
247 ldpe_adj_detail_ctl(c
);
249 case IMSG_CTL_SHOW_LIB
:
250 case IMSG_CTL_SHOW_L2VPN_PW
:
251 case IMSG_CTL_SHOW_L2VPN_BINDING
:
252 c
->iev
.ibuf
.pid
= imsg
.hdr
.pid
;
253 ldpe_imsg_compose_lde(imsg
.hdr
.type
, 0, imsg
.hdr
.pid
,
254 imsg
.data
, imsg
.hdr
.len
- IMSG_HEADER_SIZE
);
256 case IMSG_CTL_SHOW_NBR
:
259 case IMSG_CTL_CLEAR_NBR
:
260 if (imsg
.hdr
.len
!= IMSG_HEADER_SIZE
+
261 sizeof(struct ctl_nbr
))
264 nbr_clear_ctl(imsg
.data
);
266 case IMSG_CTL_LOG_VERBOSE
:
270 log_debug("%s: error handling imsg %d", __func__
,
277 imsg_event_add(&c
->iev
);
283 control_imsg_relay(struct imsg
*imsg
)
287 if ((c
= control_connbypid(imsg
->hdr
.pid
)) == NULL
)
290 return (imsg_compose_event(&c
->iev
, imsg
->hdr
.type
, 0, imsg
->hdr
.pid
,
291 -1, imsg
->data
, imsg
->hdr
.len
- IMSG_HEADER_SIZE
));