Merge branch 'vendor/OPENSSH'
[dragonfly.git] / contrib / bind / lib / bind / isc / ctl_clnt.c
1 #if !defined(lint) && !defined(SABER)
2 static const char rcsid[] = "$Id: ctl_clnt.c,v 1.9.140.1 2008/02/18 04:10:16 marka Exp $";
3 #endif /* not lint */
4
5 /*
6  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7  * Copyright (c) 1998,1999 by Internet Software Consortium.
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  */
21
22 /* Extern. */
23
24 #include "port_before.h"
25
26 #include <sys/param.h>
27 #include <sys/file.h>
28 #include <sys/socket.h>
29
30 #include <netinet/in.h>
31 #include <arpa/nameser.h>
32 #include <arpa/inet.h>
33
34 #include <ctype.h>
35 #include <errno.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <time.h>
40 #include <unistd.h>
41 #ifdef HAVE_MEMORY_H
42 #include <memory.h>
43 #endif
44
45 #include <isc/assertions.h>
46 #include <isc/ctl.h>
47 #include <isc/eventlib.h>
48 #include <isc/list.h>
49 #include <isc/memcluster.h>
50
51 #include "ctl_p.h"
52
53 #include "port_after.h"
54
55 /* Constants. */
56
57
58 /* Macros. */
59
60 #define donefunc_p(ctx) ((ctx).donefunc != NULL)
61 #define arpacode_p(line) (isdigit((unsigned char)(line[0])) && \
62                           isdigit((unsigned char)(line[1])) && \
63                           isdigit((unsigned char)(line[2])))
64 #define arpacont_p(line) (line[3] == '-')
65 #define arpadone_p(line) (line[3] == ' ' || line[3] == '\t' || \
66                           line[3] == '\r' || line[3] == '\0')
67
68 /* Types. */
69
70 enum state {
71         initializing = 0, connecting, connected, destroyed
72 };
73
74 struct ctl_tran {
75         LINK(struct ctl_tran)   link;
76         LINK(struct ctl_tran)   wlink;
77         struct ctl_cctx *       ctx;
78         struct ctl_buf          outbuf;
79         ctl_clntdone            donefunc;
80         void *                  uap;
81 };
82
83 struct ctl_cctx {
84         enum state              state;
85         evContext               ev;
86         int                     sock;
87         ctl_logfunc             logger;
88         ctl_clntdone            donefunc;
89         void *                  uap;
90         evConnID                coID;
91         evTimerID               tiID;
92         evFileID                rdID;
93         evStreamID              wrID;
94         struct ctl_buf          inbuf;
95         struct timespec         timeout;
96         LIST(struct ctl_tran)   tran;
97         LIST(struct ctl_tran)   wtran;
98 };
99
100 /* Forward. */
101
102 static struct ctl_tran *new_tran(struct ctl_cctx *, ctl_clntdone, void *, int);
103 static void             start_write(struct ctl_cctx *);
104 static void             destroy(struct ctl_cctx *, int);
105 static void             error(struct ctl_cctx *);
106 static void             new_state(struct ctl_cctx *, enum state);
107 static void             conn_done(evContext, void *, int,
108                                   const void *, int,
109                                   const void *, int);
110 static void             write_done(evContext, void *, int, int);
111 static void             start_read(struct ctl_cctx *);
112 static void             stop_read(struct ctl_cctx *);
113 static void             readable(evContext, void *, int, int);
114 static void             start_timer(struct ctl_cctx *);
115 static void             stop_timer(struct ctl_cctx *);
116 static void             touch_timer(struct ctl_cctx *);
117 static void             timer(evContext, void *,
118                               struct timespec, struct timespec);
119
120 #ifndef HAVE_MEMCHR
121 static void *
122 memchr(const void *b, int c, size_t len) {
123         const unsigned char *p = b;
124         size_t i;
125
126         for (i = 0; i < len; i++, p++)
127                 if (*p == (unsigned char)c)
128                         return ((void *)p); 
129         return (NULL);
130 }
131 #endif
132
133 /* Private data. */
134
135 static const char * const state_names[] = {
136         "initializing", "connecting", "connected", "destroyed"
137 };
138
139 /* Public. */
140
141 /*%
142  * void
143  * ctl_client()
144  *      create, condition, and connect to a listener on the control port.
145  */
146 struct ctl_cctx *
147 ctl_client(evContext lev, const struct sockaddr *cap, size_t cap_len,
148            const struct sockaddr *sap, size_t sap_len,
149            ctl_clntdone donefunc, void *uap,
150            u_int timeout, ctl_logfunc logger)
151 {
152         static const char me[] = "ctl_client";
153         static const int on = 1;
154         struct ctl_cctx *ctx;
155         struct sockaddr *captmp;
156
157         if (logger == NULL)
158                 logger = ctl_logger;
159         ctx = memget(sizeof *ctx);
160         if (ctx == NULL) {
161                 (*logger)(ctl_error, "%s: getmem: %s", me, strerror(errno));
162                 goto fatal;
163         }
164         ctx->state = initializing;
165         ctx->ev = lev;
166         ctx->logger = logger;
167         ctx->timeout = evConsTime(timeout, 0);
168         ctx->donefunc = donefunc;
169         ctx->uap = uap;
170         ctx->coID.opaque = NULL;
171         ctx->tiID.opaque = NULL;
172         ctx->rdID.opaque = NULL;
173         ctx->wrID.opaque = NULL;
174         buffer_init(ctx->inbuf);
175         INIT_LIST(ctx->tran);
176         INIT_LIST(ctx->wtran);
177         ctx->sock = socket(sap->sa_family, SOCK_STREAM, PF_UNSPEC);
178         if (ctx->sock > evHighestFD(ctx->ev)) {
179                 ctx->sock = -1;
180                 errno = ENOTSOCK;
181         }
182         if (ctx->sock < 0) {
183                 (*ctx->logger)(ctl_error, "%s: socket: %s",
184                                me, strerror(errno));
185                 goto fatal;
186         }
187         if (cap != NULL) {
188                 if (setsockopt(ctx->sock, SOL_SOCKET, SO_REUSEADDR,
189                                (const char *)&on, sizeof on) != 0) {
190                         (*ctx->logger)(ctl_warning,
191                                        "%s: setsockopt(REUSEADDR): %s",
192                                        me, strerror(errno));
193                 }
194                 DE_CONST(cap, captmp);
195                 if (bind(ctx->sock, captmp, cap_len) < 0) {
196                         (*ctx->logger)(ctl_error, "%s: bind: %s", me,
197                                        strerror(errno));
198                         goto fatal;
199                 }
200         }
201         if (evConnect(lev, ctx->sock, (const struct sockaddr *)sap, sap_len,
202                       conn_done, ctx, &ctx->coID) < 0) {
203                 (*ctx->logger)(ctl_error, "%s: evConnect(fd %d): %s",
204                                me, ctx->sock, strerror(errno));
205  fatal:
206                 if (ctx != NULL) {
207                         if (ctx->sock >= 0)
208                                 close(ctx->sock);
209                         memput(ctx, sizeof *ctx);
210                 }
211                 return (NULL);
212         }
213         new_state(ctx, connecting);
214         return (ctx);
215 }
216
217 /*%
218  * void
219  * ctl_endclient(ctx)
220  *      close a client and release all of its resources.
221  */
222 void
223 ctl_endclient(struct ctl_cctx *ctx) {
224         if (ctx->state != destroyed)
225                 destroy(ctx, 0);
226         memput(ctx, sizeof *ctx);
227 }
228
229 /*%
230  * int
231  * ctl_command(ctx, cmd, len, donefunc, uap)
232  *      Queue a transaction, which will begin with sending cmd
233  *      and complete by calling donefunc with the answer.
234  */
235 int
236 ctl_command(struct ctl_cctx *ctx, const char *cmd, size_t len,
237             ctl_clntdone donefunc, void *uap)
238 {
239         struct ctl_tran *tran;
240         char *pc;
241         unsigned int n;
242
243         switch (ctx->state) {
244         case destroyed:
245                 errno = ENOTCONN;
246                 return (-1);
247         case connecting:
248         case connected:
249                 break;
250         default:
251                 abort();
252         }
253         if (len >= (size_t)MAX_LINELEN) {
254                 errno = EMSGSIZE;
255                 return (-1);
256         }
257         tran = new_tran(ctx, donefunc, uap, 1);
258         if (tran == NULL)
259                 return (-1);
260         if (ctl_bufget(&tran->outbuf, ctx->logger) < 0)
261                 return (-1);
262         memcpy(tran->outbuf.text, cmd, len);
263         tran->outbuf.used = len;
264         for (pc = tran->outbuf.text, n = 0; n < tran->outbuf.used; pc++, n++)
265                 if (!isascii((unsigned char)*pc) ||
266                     !isprint((unsigned char)*pc))
267                         *pc = '\040';
268         start_write(ctx);
269         return (0);
270 }
271
272 /* Private. */
273
274 static struct ctl_tran *
275 new_tran(struct ctl_cctx *ctx, ctl_clntdone donefunc, void *uap, int w) {
276         struct ctl_tran *new = memget(sizeof *new);
277
278         if (new == NULL)
279                 return (NULL);
280         new->ctx = ctx;
281         buffer_init(new->outbuf);
282         new->donefunc = donefunc;
283         new->uap = uap;
284         INIT_LINK(new, link);
285         INIT_LINK(new, wlink);
286         APPEND(ctx->tran, new, link);
287         if (w)
288                 APPEND(ctx->wtran, new, wlink);
289         return (new);
290 }
291
292 static void
293 start_write(struct ctl_cctx *ctx) {
294         static const char me[] = "isc/ctl_clnt::start_write";
295         struct ctl_tran *tran;
296         struct iovec iov[2], *iovp = iov;
297         char * tmp;
298
299         REQUIRE(ctx->state == connecting || ctx->state == connected);
300         /* If there is a write in progress, don't try to write more yet. */
301         if (ctx->wrID.opaque != NULL)
302                 return;
303         /* If there are no trans, make sure timer is off, and we're done. */
304         if (EMPTY(ctx->wtran)) {
305                 if (ctx->tiID.opaque != NULL)
306                         stop_timer(ctx);
307                 return;
308         }
309         /* Pull it off the head of the write queue. */
310         tran = HEAD(ctx->wtran);
311         UNLINK(ctx->wtran, tran, wlink);
312         /* Since there are some trans, make sure timer is successfully "on". */
313         if (ctx->tiID.opaque != NULL)
314                 touch_timer(ctx);
315         else
316                 start_timer(ctx);
317         if (ctx->state == destroyed)
318                 return;
319         /* Marshall a newline-terminated message and clock it out. */
320         *iovp++ = evConsIovec(tran->outbuf.text, tran->outbuf.used);
321         DE_CONST("\r\n", tmp);
322         *iovp++ = evConsIovec(tmp, 2);
323         if (evWrite(ctx->ev, ctx->sock, iov, iovp - iov,
324                     write_done, tran, &ctx->wrID) < 0) {
325                 (*ctx->logger)(ctl_error, "%s: evWrite: %s", me,
326                                strerror(errno));
327                 error(ctx);
328                 return;
329         }
330         if (evTimeRW(ctx->ev, ctx->wrID, ctx->tiID) < 0) {
331                 (*ctx->logger)(ctl_error, "%s: evTimeRW: %s", me,
332                                strerror(errno));
333                 error(ctx);
334                 return;
335         }
336 }
337
338 static void
339 destroy(struct ctl_cctx *ctx, int notify) {
340         struct ctl_tran *this, *next;
341
342         if (ctx->sock != -1) {
343                 (void) close(ctx->sock);
344                 ctx->sock = -1;
345         }
346         switch (ctx->state) {
347         case connecting:
348                 REQUIRE(ctx->wrID.opaque == NULL);
349                 REQUIRE(EMPTY(ctx->tran));
350                 /*
351                  * This test is nec'y since destroy() can be called from
352                  * start_read() while the state is still "connecting".
353                  */
354                 if (ctx->coID.opaque != NULL) {
355                         (void)evCancelConn(ctx->ev, ctx->coID);
356                         ctx->coID.opaque = NULL;
357                 }
358                 break;
359         case connected:
360                 REQUIRE(ctx->coID.opaque == NULL);
361                 if (ctx->wrID.opaque != NULL) {
362                         (void)evCancelRW(ctx->ev, ctx->wrID);
363                         ctx->wrID.opaque = NULL;
364                 }
365                 if (ctx->rdID.opaque != NULL)
366                         stop_read(ctx);
367                 break;
368         case destroyed:
369                 break;
370         default:
371                 abort();
372         }
373         if (allocated_p(ctx->inbuf))
374                 ctl_bufput(&ctx->inbuf);
375         for (this = HEAD(ctx->tran); this != NULL; this = next) {
376                 next = NEXT(this, link);
377                 if (allocated_p(this->outbuf))
378                         ctl_bufput(&this->outbuf);
379                 if (notify && this->donefunc != NULL)
380                         (*this->donefunc)(ctx, this->uap, NULL, 0);
381                 memput(this, sizeof *this);
382         }
383         if (ctx->tiID.opaque != NULL)
384                 stop_timer(ctx);
385         new_state(ctx, destroyed);
386 }
387
388 static void
389 error(struct ctl_cctx *ctx) {
390         REQUIRE(ctx->state != destroyed);
391         destroy(ctx, 1);
392 }
393
394 static void
395 new_state(struct ctl_cctx *ctx, enum state new_state) {
396         static const char me[] = "isc/ctl_clnt::new_state";
397
398         (*ctx->logger)(ctl_debug, "%s: %s -> %s", me,
399                        state_names[ctx->state], state_names[new_state]);
400         ctx->state = new_state;
401 }
402
403 static void
404 conn_done(evContext ev, void *uap, int fd,
405           const void *la, int lalen,
406           const void *ra, int ralen)
407 {
408         static const char me[] = "isc/ctl_clnt::conn_done";
409         struct ctl_cctx *ctx = uap;
410         struct ctl_tran *tran;
411
412         UNUSED(ev);
413         UNUSED(la);
414         UNUSED(lalen);
415         UNUSED(ra);
416         UNUSED(ralen);
417
418         ctx->coID.opaque = NULL;
419         if (fd < 0) {
420                 (*ctx->logger)(ctl_error, "%s: evConnect: %s", me,
421                                strerror(errno));
422                 error(ctx);
423                 return;
424         }
425         new_state(ctx, connected);
426         tran = new_tran(ctx, ctx->donefunc, ctx->uap, 0);
427         if (tran == NULL) {
428                 (*ctx->logger)(ctl_error, "%s: new_tran failed: %s", me,
429                                strerror(errno));
430                 error(ctx);
431                 return;
432         }
433         start_read(ctx);
434         if (ctx->state == destroyed) {
435                 (*ctx->logger)(ctl_error, "%s: start_read failed: %s",
436                                me, strerror(errno));
437                 error(ctx);
438                 return;
439         }
440 }
441
442 static void
443 write_done(evContext lev, void *uap, int fd, int bytes) {
444         struct ctl_tran *tran = (struct ctl_tran *)uap;
445         struct ctl_cctx *ctx = tran->ctx;
446
447         UNUSED(lev);
448         UNUSED(fd);
449
450         ctx->wrID.opaque = NULL;
451         if (ctx->tiID.opaque != NULL)
452                 touch_timer(ctx);
453         ctl_bufput(&tran->outbuf);
454         start_write(ctx);
455         if (bytes < 0)
456                 destroy(ctx, 1);
457         else
458                 start_read(ctx);
459 }
460
461 static void
462 start_read(struct ctl_cctx *ctx) {
463         static const char me[] = "isc/ctl_clnt::start_read";
464
465         REQUIRE(ctx->state == connecting || ctx->state == connected);
466         REQUIRE(ctx->rdID.opaque == NULL);
467         if (evSelectFD(ctx->ev, ctx->sock, EV_READ, readable, ctx,
468                        &ctx->rdID) < 0)
469         {
470                 (*ctx->logger)(ctl_error, "%s: evSelect(fd %d): %s", me,
471                                ctx->sock, strerror(errno));
472                 error(ctx);
473                 return;
474         }
475 }
476
477 static void
478 stop_read(struct ctl_cctx *ctx) {
479         REQUIRE(ctx->coID.opaque == NULL);
480         REQUIRE(ctx->rdID.opaque != NULL);
481         (void)evDeselectFD(ctx->ev, ctx->rdID);
482         ctx->rdID.opaque = NULL;
483 }
484
485 static void
486 readable(evContext ev, void *uap, int fd, int evmask) {
487         static const char me[] = "isc/ctl_clnt::readable";
488         struct ctl_cctx *ctx = uap;
489         struct ctl_tran *tran;
490         ssize_t n;
491         char *eos;
492
493         UNUSED(ev);
494
495         REQUIRE(ctx != NULL);
496         REQUIRE(fd >= 0);
497         REQUIRE(evmask == EV_READ);
498         REQUIRE(ctx->state == connected);
499         REQUIRE(!EMPTY(ctx->tran));
500         tran = HEAD(ctx->tran);
501         if (!allocated_p(ctx->inbuf) &&
502             ctl_bufget(&ctx->inbuf, ctx->logger) < 0) {
503                 (*ctx->logger)(ctl_error, "%s: can't get an input buffer", me);
504                 error(ctx);
505                 return;
506         }
507         n = read(ctx->sock, ctx->inbuf.text + ctx->inbuf.used,
508                  MAX_LINELEN - ctx->inbuf.used);
509         if (n <= 0) {
510                 (*ctx->logger)(ctl_warning, "%s: read: %s", me,
511                                (n == 0) ? "Unexpected EOF" : strerror(errno));
512                 error(ctx);
513                 return;
514         }
515         if (ctx->tiID.opaque != NULL)
516                 touch_timer(ctx);
517         ctx->inbuf.used += n;
518         (*ctx->logger)(ctl_debug, "%s: read %d, used %d", me,
519                        n, ctx->inbuf.used);
520  again:
521         eos = memchr(ctx->inbuf.text, '\n', ctx->inbuf.used);
522         if (eos != NULL && eos != ctx->inbuf.text && eos[-1] == '\r') {
523                 int done = 0;
524
525                 eos[-1] = '\0';
526                 if (!arpacode_p(ctx->inbuf.text)) {
527                         /* XXX Doesn't FTP do this sometimes? Is it legal? */
528                         (*ctx->logger)(ctl_error, "%s: no arpa code (%s)", me,
529                                        ctx->inbuf.text);
530                         error(ctx);
531                         return;
532                 }
533                 if (arpadone_p(ctx->inbuf.text))
534                         done = 1;
535                 else if (arpacont_p(ctx->inbuf.text))
536                         done = 0;
537                 else {
538                         /* XXX Doesn't FTP do this sometimes? Is it legal? */
539                         (*ctx->logger)(ctl_error, "%s: no arpa flag (%s)", me,
540                                        ctx->inbuf.text);
541                         error(ctx);
542                         return;
543                 }
544                 (*tran->donefunc)(ctx, tran->uap, ctx->inbuf.text,
545                                   (done ? 0 : CTL_MORE));
546                 ctx->inbuf.used -= ((eos - ctx->inbuf.text) + 1);
547                 if (ctx->inbuf.used == 0U)
548                         ctl_bufput(&ctx->inbuf);
549                 else
550                         memmove(ctx->inbuf.text, eos + 1, ctx->inbuf.used);
551                 if (done) {
552                         UNLINK(ctx->tran, tran, link);
553                         memput(tran, sizeof *tran);
554                         stop_read(ctx);
555                         start_write(ctx);
556                         return;
557                 }
558                 if (allocated_p(ctx->inbuf))
559                         goto again;
560                 return;
561         }
562         if (ctx->inbuf.used == (size_t)MAX_LINELEN) {
563                 (*ctx->logger)(ctl_error, "%s: line too long (%-10s...)", me,
564                                ctx->inbuf.text);
565                 error(ctx);
566         }
567 }
568
569 /* Timer related stuff. */
570
571 static void
572 start_timer(struct ctl_cctx *ctx) {
573         static const char me[] = "isc/ctl_clnt::start_timer";
574
575         REQUIRE(ctx->tiID.opaque == NULL);
576         if (evSetIdleTimer(ctx->ev, timer, ctx, ctx->timeout, &ctx->tiID) < 0){
577                 (*ctx->logger)(ctl_error, "%s: evSetIdleTimer: %s", me,
578                                strerror(errno));
579                 error(ctx);
580                 return;
581         }
582 }
583
584 static void
585 stop_timer(struct ctl_cctx *ctx) {
586         static const char me[] = "isc/ctl_clnt::stop_timer";
587
588         REQUIRE(ctx->tiID.opaque != NULL);
589         if (evClearIdleTimer(ctx->ev, ctx->tiID) < 0) {
590                 (*ctx->logger)(ctl_error, "%s: evClearIdleTimer: %s", me,
591                                strerror(errno));
592                 error(ctx);
593                 return;
594         }
595         ctx->tiID.opaque = NULL;
596 }
597
598 static void
599 touch_timer(struct ctl_cctx *ctx) {
600         REQUIRE(ctx->tiID.opaque != NULL);
601
602         evTouchIdleTimer(ctx->ev, ctx->tiID);
603 }
604
605 static void
606 timer(evContext ev, void *uap, struct timespec due, struct timespec itv) {
607         static const char me[] = "isc/ctl_clnt::timer";
608         struct ctl_cctx *ctx = uap;
609
610         UNUSED(ev);
611         UNUSED(due);
612         UNUSED(itv);
613
614         ctx->tiID.opaque = NULL;
615         (*ctx->logger)(ctl_error, "%s: timeout after %u seconds while %s", me,
616                        ctx->timeout.tv_sec, state_names[ctx->state]);
617         error(ctx);
618 }
619
620 /*! \file */