Blob


1 /*
2 * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
17 #include "compat.h"
19 #include <sys/types.h>
20 #include <sys/socket.h>
22 #include <netdb.h>
24 #include <assert.h>
25 #include <endian.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <inttypes.h>
29 #include <signal.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <syslog.h>
34 #include <tls.h>
35 #include <unistd.h>
37 #include "kami.h"
38 #include "log.h"
39 #include "utils.h"
40 #include "9pclib.h"
42 #define DEBUG_PACKETS 0
44 #define PROMPT "=% "
46 /* flags */
47 int verbose;
48 int tls;
49 const char *keypath;
50 const char *crtpath;
51 const char *host;
52 const char *port;
54 /* state */
55 struct tls_config *tlsconf;
56 struct tls *ctx;
57 struct bufferevent *bev, *inbev;
59 static void __dead usage(int);
61 static void sig_handler(int, short, void *);
63 static int openconn(void);
64 static void mark_nonblock(int);
66 static void tls_readcb(int, short, void *);
67 static void tls_writecb(int, short, void *);
69 static void client_read(struct bufferevent *, void *);
70 static void client_write(struct bufferevent *, void *);
71 static void client_error(struct bufferevent *, short, void *);
73 static void repl_read(struct bufferevent *, void *);
74 static void repl_error(struct bufferevent *, short, void *);
76 static void excmd_version(const char **, int);
77 static void excmd_attach(const char **, int);
78 static void excmd_clunk(const char **, int);
79 static void excmd_flush(const char **, int);
80 static void excmd_walk(const char ** , int);
81 static void excmd_open(const char ** , int);
82 static void excmd_create(const char ** , int);
83 static void excmd_read(const char ** , int);
84 static void excmd_write(const char **, int);
85 static void excmd(const char **, int);
87 static void pp_qid(const uint8_t *, uint32_t);
88 static void pp_msg(uint32_t, uint8_t, uint16_t, const uint8_t *);
89 static void handle_9p(const uint8_t *, size_t);
90 static void clr(void);
91 static void prompt(void);
93 static void __dead
94 usage(int ret)
95 {
96 fprintf(stderr,
97 "usage: %s [-chv] [-C crt] [-K key] [-H host] [-P port]\n",
98 getprogname());
99 fprintf(stderr, "kamid suite version " KAMID_VERSION "\n");
100 exit(ret);
103 static void
104 sig_handler(int sig, short event, void *d)
106 /*
107 * Normal signal handler rules don't apply because libevent
108 * decouples for us.
109 */
111 switch (sig) {
112 case SIGINT:
113 case SIGTERM:
114 clr();
115 log_warnx("Shutting down...");
116 event_loopbreak();
117 return;
118 default:
119 fatalx("unexpected signal %d", sig);
123 static int
124 openconn(void)
126 struct addrinfo hints, *res, *res0;
127 int error;
128 int save_errno;
129 int s;
130 const char *cause = NULL;
132 memset(&hints, 0, sizeof(hints));
133 hints.ai_family = AF_UNSPEC;
134 hints.ai_socktype = SOCK_STREAM;
135 if ((error = getaddrinfo(host, port, &hints, &res0))) {
136 warnx("%s", gai_strerror(error));
137 return -1;
140 s = -1;
141 for (res = res0; res; res = res->ai_next) {
142 s = socket(res->ai_family, res->ai_socktype,
143 res->ai_protocol);
144 if (s == -1) {
145 cause = "socket";
146 continue;
149 if (connect(s, res->ai_addr, res->ai_addrlen) == -1) {
150 cause = "connect";
151 save_errno = errno;
152 close(s);
153 errno = save_errno;
154 s = -1;
155 continue;
158 break;
161 freeaddrinfo(res0);
163 if (s == -1)
164 warn("%s", cause);
166 return s;
169 static void
170 mark_nonblock(int fd)
172 int flags;
174 if ((flags = fcntl(fd, F_GETFL)) == -1)
175 fatal("fcntl(F_GETFL)");
176 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
177 fatal("fcntl(F_SETFL)");
180 static void
181 tls_readcb(int fd, short event, void *d)
183 struct bufferevent *bufev = d;
184 char buf[IBUF_READ_SIZE];
185 int what = EVBUFFER_READ;
186 int howmuch = IBUF_READ_SIZE;
187 ssize_t ret;
188 size_t len;
190 if (event == EV_TIMEOUT) {
191 what |= EVBUFFER_TIMEOUT;
192 goto err;
195 if (bufev->wm_read.high != 0)
196 howmuch = MIN(sizeof(buf), bufev->wm_read.high);
198 switch (ret = tls_read(ctx, buf, howmuch)) {
199 case TLS_WANT_POLLIN:
200 case TLS_WANT_POLLOUT:
201 goto retry;
202 case -1:
203 what |= EVBUFFER_ERROR;
204 goto err;
206 len = ret;
208 if (len == 0) {
209 what |= EVBUFFER_EOF;
210 goto err;
213 if (evbuffer_add(bufev->input, buf, len) == -1) {
214 what |= EVBUFFER_ERROR;
215 goto err;
218 event_add(&bufev->ev_read, NULL);
220 len = EVBUFFER_LENGTH(bufev->input);
221 if (bufev->wm_read.low != 0 && len < bufev->wm_read.low)
222 return;
223 if (bufev->readcb != NULL)
224 (*bufev->readcb)(bufev, bufev->cbarg);
225 return;
227 retry:
228 event_add(&bufev->ev_read, NULL);
229 return;
231 err:
232 (*bufev->errorcb)(bufev, what, bufev->cbarg);
235 static void
236 tls_writecb(int fd, short event, void *d)
238 struct bufferevent *bufev = d;
239 ssize_t ret;
240 size_t len;
241 short what = EVBUFFER_WRITE;
242 void *data;
244 if (event == EV_TIMEOUT) {
245 what |= EVBUFFER_TIMEOUT;
246 goto err;
249 len = EVBUFFER_LENGTH(bufev->output);
250 if (len != 0) {
251 data = EVBUFFER_DATA(bufev->output);
253 #if DEBUG_PACKETS
254 hexdump("outgoing msg", data, len);
255 #endif
257 switch (ret = tls_write(ctx, data, len)) {
258 case TLS_WANT_POLLIN:
259 case TLS_WANT_POLLOUT:
260 goto retry;
261 case -1:
262 what |= EVBUFFER_ERROR;
263 goto err;
265 evbuffer_drain(bufev->output, ret);
268 if (EVBUFFER_LENGTH(bufev->output) != 0)
269 event_add(&bufev->ev_write, NULL);
271 if (bufev->writecb != NULL &&
272 EVBUFFER_LENGTH(bufev->output) <= bufev->wm_write.low)
273 (*bufev->writecb)(bufev, bufev->cbarg);
274 return;
276 retry:
277 event_add(&bufev->ev_write, NULL);
278 return;
279 err:
280 (*bufev->errorcb)(bufev, what, bufev->cbarg);
283 static void
284 client_read(struct bufferevent *bev, void *d)
286 struct evbuffer *src = EVBUFFER_INPUT(bev);
287 uint32_t len;
288 uint8_t *data;
290 for (;;) {
291 if (EVBUFFER_LENGTH(src) < sizeof(len))
292 return;
294 data = EVBUFFER_DATA(src);
296 memcpy(&len, data, sizeof(len));
297 len = le32toh(len);
299 if (len < HEADERSIZE)
300 fatal("incoming message is too small! (%d bytes)",
301 len);
303 if (len > EVBUFFER_LENGTH(src))
304 return;
306 #if DEBUG_PACKETS
307 hexdump("incoming msg", data, len);
308 #endif
310 handle_9p(data, len);
311 evbuffer_drain(src, len);
315 static void
316 client_write(struct bufferevent *bev, void *data)
318 return; /* nothing to do */
321 static void
322 client_error(struct bufferevent *bev, short err, void *data)
324 if (err & EVBUFFER_ERROR)
325 fatal("buffer event error");
327 if (err & EVBUFFER_EOF) {
328 clr();
329 log_info("EOF");
330 event_loopbreak();
331 return;
334 clr();
335 log_warnx("unknown event error");
336 event_loopbreak();
339 static void
340 repl_read(struct bufferevent *bev, void *d)
342 size_t len;
343 int argc;
344 const char *argv[10], **ap;
345 char *line;
347 line = evbuffer_readln(bev->input, &len, EVBUFFER_EOL_LF);
348 if (line == NULL)
349 return;
351 for (argc = 0, ap = argv; ap < &argv[9] &&
352 (*ap = strsep(&line, " \t")) != NULL;) {
353 if (**ap != '\0')
354 ap++, argc++;
357 clr();
358 excmd(argv, argc);
359 prompt();
361 free(line);
364 static void
365 repl_error(struct bufferevent *bev, short error, void *d)
367 fatalx("an error occurred");
370 static inline void
371 do_send(void)
373 bufferevent_write_buffer(bev, evb);
376 /* version [version-str] */
377 static void
378 excmd_version(const char **argv, int argc)
380 const char *s;
382 s = VERSION9P;
383 if (argc == 2)
384 s = argv[1];
386 tversion(s, MSIZE9P);
387 do_send();
390 /* attach fid uname aname */
391 static void
392 excmd_attach(const char **argv, int argc)
394 uint32_t fid;
395 const char *errstr;
397 if (argc != 4)
398 goto usage;
400 fid = strtonum(argv[1], 0, UINT32_MAX, &errstr);
401 if (errstr != NULL) {
402 log_warnx("fid is %s: %s", errstr, argv[1]);
403 return;
406 tattach(fid, NOFID, argv[2], argv[3]);
407 do_send();
408 return;
410 usage:
411 log_warnx("usage: attach fid uname aname");
414 /* clunk fid */
415 static void
416 excmd_clunk(const char **argv, int argc)
418 uint32_t fid;
419 const char *errstr;
421 if (argc != 2)
422 goto usage;
424 fid = strtonum(argv[1], 0, UINT32_MAX, &errstr);
425 if (errstr != NULL) {
426 log_warnx("fid is %s: %s", errstr, argv[1]);
427 return;
430 tclunk(fid);
431 do_send();
432 return;
434 usage:
435 log_warnx("usage: clunk fid");
438 /* flush oldtag */
439 static void
440 excmd_flush(const char **argv, int argc)
442 uint16_t oldtag;
443 const char *errstr;
445 if (argc != 2)
446 goto usage;
448 oldtag = strtonum(argv[1], 0, UINT16_MAX, &errstr);
449 if (errstr != NULL) {
450 log_warnx("oldtag is %s: %s", errstr, argv[1]);
451 return;
454 tflush(oldtag);
455 do_send();
456 return;
458 usage:
459 log_warnx("usage: flush oldtag");
462 /* walk fid newfid wnames... */
463 static void
464 excmd_walk(const char **argv, int argc)
466 uint32_t fid, newfid;
467 const char *errstr;
469 if (argc < 3)
470 goto usage;
472 fid = strtonum(argv[1], 0, UINT32_MAX, &errstr);
473 if (errstr != NULL) {
474 log_warnx("fid is %s: %s", errstr, argv[1]);
475 return;
478 newfid = strtonum(argv[2], 0, UINT32_MAX, &errstr);
479 if (errstr != NULL) {
480 log_warnx("newfid is %s: %s", errstr, argv[1]);
481 return;
484 twalk(fid, newfid, argv + 3, argc - 3);
485 do_send();
486 return;
488 usage:
489 log_warnx("usage: walk fid newfid wnames...");
492 /* open fid mode [flag] */
493 static void
494 excmd_open(const char **argv, int argc)
496 const char *errstr;
497 uint32_t fid;
498 uint8_t mode = 0;
500 if (argc != 3 && argc != 4)
501 goto usage;
503 fid = strtonum(argv[1], 0, UINT32_MAX, &errstr);
504 if (errstr != NULL) {
505 log_warnx("fid is %s: %s", errstr, argv[1]);
506 return;
509 /* parse mode */
510 if (!strcmp("read", argv[2]) || !strcmp("r", argv[2]))
511 mode = KOREAD;
512 else if (!strcmp("write", argv[2]) || !strcmp("w", argv[2]))
513 mode = KOWRITE;
514 else if (!strcmp("readwrite", argv[2]) || !strcmp("rw", argv[2]))
515 mode = KORDWR;
516 else {
517 log_warnx("invalid mode %s", argv[2]);
518 return;
521 /* parse flag */
522 if (argv[3] != NULL) {
523 if (!strcmp("trunc", argv[3]))
524 mode |= KOTRUNC;
525 else if (!strcmp("rclose", argv[3]))
526 mode |= KORCLOSE;
527 else {
528 log_warnx("invalid flag %s", argv[3]);
529 return;
533 topen(fid, mode);
534 do_send();
535 return;
537 usage:
538 log_warnx("usage: open fid mode [flag]");
541 /* create fid path perm mode */
542 static void
543 excmd_create(const char **argv, int argc)
545 const char *errstr;
546 uint32_t fid;
547 uint8_t mode = 0;
549 if (argc != 5)
550 goto usage;
552 fid = strtonum(argv[1], 0, UINT32_MAX, &errstr);
553 if (errstr != NULL) {
554 log_warnx("fid is %s: %s", errstr, argv[1]);
555 return;
558 /* parse mode */
559 if (!strcmp("write", argv[4]) || !strcmp("w", argv[4]))
560 mode = KOWRITE;
561 else if (!strcmp("readwrite", argv[4]) || !strcmp("rw", argv[4]))
562 mode = KORDWR;
563 else {
564 log_warnx("invalid mode %s for create", argv[4]);
565 return;
568 tcreate(fid, argv[2], 0, mode);
569 do_send();
570 return;
572 usage:
573 log_warnx("usage: create fid path perm mode ; perm is unused");
577 /* read fid offset count */
578 static void
579 excmd_read(const char **argv, int argc)
581 uint64_t off;
582 uint32_t fid, count;
583 const char *errstr;
585 if (argc != 4)
586 goto usage;
588 fid = strtonum(argv[1], 0, UINT32_MAX, &errstr);
589 if (errstr != NULL) {
590 log_warnx("fid is %s: %s", errstr, argv[1]);
591 return;
594 /* should really be UNT64_MAX but it fails... */
595 off = strtonum(argv[2], -1, UINT32_MAX, &errstr);
596 if (errstr != NULL) {
597 log_warnx("offset is %s: %s", errstr, argv[2]);
598 return;
601 count = strtonum(argv[3], 0, UINT32_MAX, &errstr);
602 if (errstr != NULL) {
603 log_warnx("count is %s: %s", errstr, argv[3]);
604 return;
607 tread(fid, off, count);
608 do_send();
609 return;
611 usage:
612 log_warnx("usage: read fid offset count");
615 /* write fid offset content */
616 static void
617 excmd_write(const char **argv, int argc)
619 uint64_t off;
620 uint32_t fid, count;
621 const char *errstr;
623 if (argc != 4)
624 goto usage;
626 fid = strtonum(argv[1], 0, UINT32_MAX, &errstr);
627 if (errstr != NULL) {
628 log_warnx("fid is %s: %s", errstr, argv[1]);
629 return;
632 /* should really be UINT64_MAX but... */
633 off = strtonum(argv[2], 0, UINT32_MAX, &errstr);
634 if (errstr != NULL) {
635 log_warnx("offset is %s: %s", errstr, argv[2]);
636 return;
639 count = strlen(argv[3]);
640 twrite(fid, off, argv[3], count);
641 do_send();
642 return;
644 usage:
645 log_warnx("usage: write fid offset content");
648 /* remove fid */
649 static void
650 excmd_remove(const char **argv, int argc)
652 const char *errstr;
653 uint32_t fid;
655 if (argc != 2)
656 goto usage;
658 fid = strtonum(argv[1], 0, UINT32_MAX, &errstr);
659 if (errstr != NULL) {
660 log_warnx("fid is %s: %s", errstr, argv[1]);
661 return;
664 tremove(fid);
665 do_send();
666 return;
668 usage:
669 log_warnx("usage: remove fid");
672 static void
673 excmd(const char **argv, int argc)
675 struct cmd {
676 const char *name;
677 void (*fn)(const char **, int);
678 } cmds[] = {
679 {"version", excmd_version},
680 {"attach", excmd_attach},
681 {"clunk", excmd_clunk},
682 {"flush", excmd_flush},
683 {"walk", excmd_walk},
684 {"open", excmd_open},
685 {"create", excmd_create},
686 {"read", excmd_read},
687 {"write", excmd_write},
688 /* TODO: stat */
689 {"remove", excmd_remove},
690 };
691 size_t i;
693 if (argc == 0)
694 return;
696 for (i = 0; i < sizeof(cmds)/sizeof(cmds[0]); ++i) {
697 if (!strcmp(cmds[i].name, argv[0])) {
698 cmds[i].fn(argv, argc);
699 return;
703 log_warnx("Unknown command %s", *argv);
706 static void
707 pp_qid(const uint8_t *d, uint32_t len)
709 uint64_t path;
710 uint32_t vers;
711 uint8_t type;
713 if (len < 13) {
714 printf("invalid");
715 return;
718 type = *d++;
720 memcpy(&vers, d, sizeof(vers));
721 d += sizeof(vers);
722 vers = le64toh(vers);
724 memcpy(&path, d, sizeof(path));
725 d += sizeof(path);
726 path = le64toh(path);
728 printf("qid{path=%"PRIu64" version=%"PRIu32" type=0x%x\"%s\"}",
729 path, vers, type, pp_qid_type(type));
732 static void
733 pp_msg(uint32_t len, uint8_t type, uint16_t tag, const uint8_t *d)
735 uint32_t msize, iounit, count;
736 uint16_t slen;
737 char *v;
739 printf("len=%"PRIu32" type=%d[%s] tag=0x%x[%d] ", len,
740 type, pp_msg_type(type), tag, tag);
742 len -= HEADERSIZE;
744 switch (type) {
745 case Rversion:
746 if (len < 6) {
747 printf("invalid: not enough space for msize "
748 "and version provided.");
749 break;
752 memcpy(&msize, d, sizeof(msize));
753 d += sizeof(msize);
754 len -= sizeof(msize);
755 msize = le32toh(msize);
757 memcpy(&slen, d, sizeof(slen));
758 d += sizeof(slen);
759 len -= sizeof(slen);
760 slen = le16toh(slen);
762 if (len != slen) {
763 printf("invalid: version string length doesn't "
764 "match. Got %d; want %d", slen, len);
765 break;
768 printf("msize=%"PRIu32" version[%"PRIu16"]=\"",
769 msize, slen);
770 fwrite(d, 1, slen, stdout);
771 printf("\"");
773 break;
775 case Rattach:
776 pp_qid(d, len);
777 break;
779 case Rclunk:
780 case Rflush:
781 case Rremove:
782 if (len != 0)
783 printf("invalid %s: %"PRIu32" extra bytes",
784 pp_msg_type(type), len);
785 break;
787 case Rwalk:
788 if (len < 2) {
789 printf("invaild Rwalk: less than two bytes (%d)",
790 (int)len);
791 break;
794 memcpy(&slen, d, sizeof(slen));
795 d += sizeof(slen);
796 len -= sizeof(slen);
797 slen = le16toh(slen);
799 if (len != QIDSIZE * slen) {
800 printf("invalid Rwalk: wanted %d bytes for %d qids "
801 "but got %"PRIu32" bytes instead",
802 QIDSIZE*slen, slen, len);
803 break;
806 printf("nwqid=%"PRIu16, slen);
808 for (; slen != 0; slen--) {
809 printf(" ");
810 pp_qid(d, len);
811 d += QIDSIZE;
812 len -= QIDSIZE;
815 break;
817 case Ropen:
818 case Rcreate:
819 if (len != QIDSIZE + 4) {
820 printf("invalid %s: expected %d bytes; "
821 "got %u\n", pp_msg_type(type), QIDSIZE + 4, len);
822 break;
825 pp_qid(d, len);
826 d += QIDSIZE;
827 len -= QIDSIZE;
829 memcpy(&iounit, d, sizeof(iounit));
830 d += sizeof(iounit);
831 len -= sizeof(iounit);
832 iounit = le32toh(iounit);
833 printf(" iounit=%"PRIu32, iounit);
834 break;
836 case Rread:
837 if (len < sizeof(count)) {
838 printf("invalid Rread: expected %zu bytes at least; "
839 "got %u\n", sizeof(count), len);
840 break;
843 memcpy(&count, d, sizeof(count));
844 d += sizeof(count);
845 len -= sizeof(count);
846 count = le32toh(count);
848 if (len != count) {
849 printf("invalid Rread: expected %d data bytes; "
850 "got %u\n", count, len);
851 break;
854 /* allocates three extra bytes, oh well... */
855 if ((v = calloc(count + 1, 4)) == NULL)
856 fatal("calloc");
857 strvisx(v, d, count, VIS_SAFE | VIS_TAB | VIS_NL | VIS_CSTYLE);
858 printf("data=%s", v);
859 free(v);
861 break;
863 case Rwrite:
864 if (len != sizeof(count)) {
865 printf("invalid Rwrite: expected %zu data bytes; "
866 "got %u\n", sizeof(count), len);
867 break;
870 memcpy(&count, d, sizeof(count));
871 d += sizeof(count);
872 len -= sizeof(count);
873 count = le32toh(count);
875 printf("count=%d", count);
876 break;
878 case Rerror:
879 memcpy(&slen, d, sizeof(slen));
880 d += sizeof(slen);
881 len -= sizeof(slen);
882 slen = le16toh(slen);
884 if (slen != len) {
885 printf("invalid: error string length doesn't "
886 "match. Got %d; want %d", slen, len);
887 break;
890 printf("error=\"");
891 fwrite(d, 1, slen, stdout);
892 printf("\"");
894 break;
896 default:
897 if ((v = calloc(len + 1, 4)) == NULL)
898 fatal("calloc");
899 strvisx(v, d, len, VIS_SAFE | VIS_TAB | VIS_NL | VIS_CSTYLE);
900 printf("body=%s", v);
901 free(v);
904 printf("\n");
907 static void
908 handle_9p(const uint8_t *data, size_t size)
910 uint32_t len;
911 uint16_t tag;
912 uint8_t type;
914 assert(size >= HEADERSIZE);
916 memcpy(&len, data, sizeof(len));
917 data += sizeof(len);
919 memcpy(&type, data, sizeof(type));
920 data += sizeof(type);
922 memcpy(&tag, data, sizeof(tag));
923 data += sizeof(tag);
925 len = le32toh(len);
926 /* type is one byte long, no endianness issues */
927 tag = le16toh(tag);
929 clr();
930 pp_msg(len, type, tag, data);
931 prompt();
934 static void
935 clr(void)
937 printf("\r");
938 fflush(stdout);
941 static void
942 prompt(void)
944 printf("%s", PROMPT);
945 fflush(stdout);
948 int
949 main(int argc, char **argv)
951 int ch, sock, handshake;
952 struct event ev_sigint, ev_sigterm;
954 signal(SIGPIPE, SIG_IGN);
956 while ((ch = getopt(argc, argv, "C:cH:hK:P:v")) != -1) {
957 switch (ch) {
958 case 'C':
959 crtpath = optarg;
960 break;
961 case 'c':
962 tls = 1;
963 break;
964 case 'H':
965 host = optarg;
966 break;
967 case 'h':
968 usage(0);
969 break;
970 case 'K':
971 keypath = optarg;
972 break;
973 case 'P':
974 port = optarg;
975 break;
976 case 'v':
977 verbose = 1;
978 break;
979 default:
980 usage(1);
984 if (host == NULL)
985 host = "localhost";
986 if (port == NULL)
987 port = "1337";
989 argc -= optind;
990 argv += optind;
992 if (argc != 0)
993 usage(1);
994 /* if (!tls || (crtpath != NULL || keypath != NULL)) */
995 /* usage(1); */
996 if (!tls)
997 errx(1, "must enable tls (for now)");
999 log_init(1, LOG_DAEMON);
1000 log_setverbose(verbose);
1001 log_procinit(getprogname());
1003 if ((tlsconf = tls_config_new()) == NULL)
1004 fatalx("tls_config_new");
1005 tls_config_insecure_noverifycert(tlsconf);
1006 tls_config_insecure_noverifyname(tlsconf);
1007 if (tls_config_set_keypair_file(tlsconf, crtpath, keypath) == -1)
1008 fatalx("can't load certs (%s, %s)", crtpath, keypath);
1010 if ((ctx = tls_client()) == NULL)
1011 fatal("tls_client");
1012 if (tls_configure(ctx, tlsconf) == -1)
1013 fatalx("tls_configure: %s", tls_error(ctx));
1015 log_info("connecting to %s:%s...", host, port);
1017 if ((sock = openconn()) == -1)
1018 fatalx("can't connect to %s:%s", host, port);
1020 if (tls_connect_socket(ctx, sock, host) == -1)
1021 fatalx("tls_connect_socket: %s", tls_error(ctx));
1023 for (handshake = 0; !handshake;) {
1024 switch (tls_handshake(ctx)) {
1025 case -1:
1026 fatalx("tls_handshake: %s", tls_error(ctx));
1027 case 0:
1028 handshake = 1;
1029 break;
1033 log_info("connected!");
1035 mark_nonblock(sock);
1037 event_init();
1039 /* initialize global evb */
1040 if ((evb = evbuffer_new()) == NULL)
1041 fatal("evbuffer_new");
1043 signal_set(&ev_sigint, SIGINT, sig_handler, NULL);
1044 signal_set(&ev_sigterm, SIGINT, sig_handler, NULL);
1046 signal_add(&ev_sigint, NULL);
1047 signal_add(&ev_sigterm, NULL);
1049 bev = bufferevent_new(sock, client_read, client_write, client_error,
1050 NULL);
1051 if (bev == NULL)
1052 fatal("bufferevent_new");
1054 /* setup tls/io */
1055 event_set(&bev->ev_read, sock, EV_READ, tls_readcb, bev);
1056 event_set(&bev->ev_write, sock, EV_WRITE, tls_writecb, bev);
1058 bufferevent_enable(bev, EV_READ|EV_WRITE);
1060 mark_nonblock(0);
1061 inbev = bufferevent_new(0, repl_read, NULL, repl_error, NULL);
1062 bufferevent_enable(inbev, EV_READ);
1064 prompt();
1065 event_dispatch();
1067 bufferevent_free(bev);
1068 tls_free(ctx);
1069 tls_config_free(tlsconf);
1070 close(sock);
1072 return 0;