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 void 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 void 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
);
104 static void control_accept(struct thread
*thread
)
108 struct sockaddr_un s_un
;
112 if ((connfd
= accept(THREAD_FD(thread
), (struct sockaddr
*)&s_un
,
115 * Pause accept if we are out of file descriptors, or
116 * libevent will haunt us here too.
118 if (errno
== ENFILE
|| errno
== EMFILE
)
120 else if (errno
!= EWOULDBLOCK
&& errno
!= EINTR
&&
121 errno
!= ECONNABORTED
)
122 log_warn("%s: accept", __func__
);
125 sock_set_nonblock(connfd
);
127 if ((c
= calloc(1, sizeof(struct ctl_conn
))) == NULL
) {
133 imsg_init(&c
->iev
.ibuf
, connfd
);
134 c
->iev
.handler_read
= control_dispatch_imsg
;
135 c
->iev
.ev_read
= NULL
;
136 thread_add_read(master
, c
->iev
.handler_read
, &c
->iev
, c
->iev
.ibuf
.fd
,
138 c
->iev
.handler_write
= ldp_write_handler
;
139 c
->iev
.ev_write
= NULL
;
141 TAILQ_INSERT_TAIL(&ctl_conns
, c
, entry
);
144 static struct ctl_conn
*
145 control_connbyfd(int fd
)
149 TAILQ_FOREACH(c
, &ctl_conns
, entry
) {
150 if (c
->iev
.ibuf
.fd
== fd
)
157 static struct ctl_conn
*
158 control_connbypid(pid_t pid
)
162 TAILQ_FOREACH(c
, &ctl_conns
, entry
) {
163 if (c
->iev
.ibuf
.pid
== pid
)
171 control_close(int fd
)
175 if ((c
= control_connbyfd(fd
)) == NULL
) {
176 log_warnx("%s: fd %d: not found", __func__
, fd
);
180 msgbuf_clear(&c
->iev
.ibuf
.w
);
181 TAILQ_REMOVE(&ctl_conns
, c
, entry
);
183 THREAD_OFF(c
->iev
.ev_read
);
184 THREAD_OFF(c
->iev
.ev_write
);
185 close(c
->iev
.ibuf
.fd
);
191 static void control_dispatch_imsg(struct thread
*thread
)
193 int fd
= THREAD_FD(thread
);
199 if ((c
= control_connbyfd(fd
)) == NULL
) {
200 log_warnx("%s: fd %d: not found", __func__
, fd
);
204 c
->iev
.ev_read
= NULL
;
206 if (((n
= imsg_read(&c
->iev
.ibuf
)) == -1 && errno
!= EAGAIN
) ||
213 if ((n
= imsg_get(&c
->iev
.ibuf
, &imsg
)) == -1) {
221 switch (imsg
.hdr
.type
) {
222 case IMSG_CTL_FIB_COUPLE
:
223 case IMSG_CTL_FIB_DECOUPLE
:
224 case IMSG_CTL_RELOAD
:
225 case IMSG_CTL_KROUTE
:
226 case IMSG_CTL_KROUTE_ADDR
:
227 case IMSG_CTL_IFINFO
:
230 case IMSG_CTL_SHOW_INTERFACE
:
231 if (imsg
.hdr
.len
== IMSG_HEADER_SIZE
+
233 memcpy(&ifidx
, imsg
.data
, sizeof(ifidx
));
234 ldpe_iface_ctl(c
, ifidx
);
235 imsg_compose_event(&c
->iev
, IMSG_CTL_END
, 0,
239 case IMSG_CTL_SHOW_DISCOVERY
:
242 case IMSG_CTL_SHOW_DISCOVERY_DTL
:
243 ldpe_adj_detail_ctl(c
);
245 case IMSG_CTL_SHOW_LIB
:
246 case IMSG_CTL_SHOW_L2VPN_PW
:
247 case IMSG_CTL_SHOW_L2VPN_BINDING
:
248 c
->iev
.ibuf
.pid
= imsg
.hdr
.pid
;
249 ldpe_imsg_compose_lde(imsg
.hdr
.type
, 0, imsg
.hdr
.pid
,
250 imsg
.data
, imsg
.hdr
.len
- IMSG_HEADER_SIZE
);
252 case IMSG_CTL_SHOW_NBR
:
255 case IMSG_CTL_CLEAR_NBR
:
256 if (imsg
.hdr
.len
!= IMSG_HEADER_SIZE
+
257 sizeof(struct ctl_nbr
))
260 nbr_clear_ctl(imsg
.data
);
262 case IMSG_CTL_SHOW_LDP_SYNC
:
263 ldpe_ldp_sync_ctl(c
);
265 case IMSG_CTL_LOG_VERBOSE
:
269 log_debug("%s: error handling imsg %d", __func__
,
276 imsg_event_add(&c
->iev
);
280 control_imsg_relay(struct imsg
*imsg
)
284 if ((c
= control_connbypid(imsg
->hdr
.pid
)) == NULL
)
287 return (imsg_compose_event(&c
->iev
, imsg
->hdr
.type
, 0, imsg
->hdr
.pid
,
288 -1, imsg
->data
, imsg
->hdr
.len
- IMSG_HEADER_SIZE
));