keys.scala, etc.: Make merging public keys have a progress bar.
[tripe-android] / jni.c
1 /* -*-c-*-
2 *
3 * Native-code portions of the project
4 *
5 * (c) 2018 Straylight/Edgeware
6 */
7
8 /*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of the Trivial IP Encryption (TrIPE) Android app.
11 *
12 * TrIPE is free software: you can redistribute it and/or modify it under
13 * the terms of the GNU General Public License as published by the Free
14 * Software Foundation; either version 3 of the License, or (at your
15 * option) any later version.
16 *
17 * TrIPE is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with TrIPE. If not, see <https://www.gnu.org/licenses/>.
24 */
25
26 /*----- Header files ------------------------------------------------------*/
27
28 #define _FILE_OFFSET_BITS 64
29
30 #include <assert.h>
31 #include <ctype.h>
32 #include <errno.h>
33 #include <inttypes.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 #include <dirent.h>
40 #include <fcntl.h>
41 #include <netdb.h>
42 #include <unistd.h>
43 #include <sys/ioctl.h>
44 #include <sys/select.h>
45 #include <sys/socket.h>
46 #include <sys/stat.h>
47 #include <sys/sysmacros.h>
48 #include <sys/types.h>
49 #include <sys/un.h>
50
51 #include <jni.h>
52
53 //#include <linux/if.h>
54 #include <linux/if_tun.h>
55
56 #include <mLib/align.h>
57 #include <mLib/bits.h>
58 #include <mLib/dstr.h>
59 #include <mLib/macros.h>
60
61 #include <catacomb/ghash.h>
62
63 #define TUN_INTERNALS
64 #include <tripe.h>
65
66 #undef sun
67
68 /*----- Magic class names and similar -------------------------------------*/
69
70 /* The name decoration is horrific. Hide it. */
71 #define JNIFUNC(f) Java_uk_org_distorted_tripe_sys_package_00024_##f
72
73 /* The little class for bundling up error codes. */
74 #define ERRENTCLS "uk/org/distorted/tripe/sys/package$ErrorEntry"
75
76 /* The `sys' package class. */
77 #define SYSCLS "uk/org/distorted/tripe/sys/package"
78
79 /* The server lock class. */
80 #define LOCKCLS "uk/org/distorted/tripe/sys/package$ServerLock"
81
82 /* The `stat' class. */
83 #define STATCLS "uk/org/distorted/tripe/sys/package$FileInfo"
84
85 /* Standard Java classes. */
86 #define FDCLS "java/io/FileDescriptor"
87 #define STRCLS "java/lang/String"
88 #define RANDCLS "java/security/SecureRandom"
89
90 /* Exception class names. */
91 #define NULLERR "java/lang/NullPointerException"
92 #define TYPEERR "uk/org/distorted/tripe/sys/package$NativeObjectTypeException"
93 #define SYSERR "uk/org/distorted/tripe/sys/package$SystemError"
94 #define NAMEERR "uk/org/distorted/tripe/sys/package$NameResolutionException"
95 #define INITERR "uk/org/distorted/tripe/sys/package$InitializationException"
96 #define ARGERR "java/lang/IllegalArgumentException"
97 #define STERR "java/lang/IllegalStateException"
98 #define BOUNDSERR "java/lang/IndexOutOfBoundsException"
99
100 /*----- Essential state ---------------------------------------------------*/
101
102 static JNIEnv *jni_tripe = 0;
103
104 /*----- Miscellaneous utilities -------------------------------------------*/
105
106 static void vexcept(JNIEnv *jni, const char *clsname,
107 const char *msg, va_list *ap)
108 {
109 jclass cls;
110 int rc;
111 dstr d = DSTR_INIT;
112
113 cls = (*jni)->FindClass(jni, clsname); assert(cls);
114 if (!msg)
115 rc = (*jni)->ThrowNew(jni, cls, 0);
116 else {
117 dstr_vputf(&d, msg, ap);
118 rc = (*jni)->ThrowNew(jni, cls, d.buf);
119 assert(!rc);
120 dstr_destroy(&d);
121 }
122 assert(!rc);
123 }
124
125 static void except(JNIEnv *jni, const char *clsname, const char *msg, ...)
126 {
127 va_list ap;
128
129 va_start(ap, msg);
130 vexcept(jni, clsname, msg, &ap);
131 va_end(ap);
132 }
133
134 #ifdef DEBUG
135 static void dump_bytes(const void *p, size_t n, size_t o)
136 {
137 const unsigned char *q = p;
138 size_t i;
139
140 if (!n) return;
141 for (;;) {
142 fprintf(stderr, ";; %08zx\n", o);
143 for (i = 0; i < 8; i++)
144 if (i < n) fprintf(stderr, "%02x ", q[i]);
145 else fprintf(stderr, "** ");
146 fprintf(stderr, ": ");
147 for (i = 0; i < 8; i++)
148 fputc(i >= n ? '*' : isprint(q[i]) ? q[i] : '.', stderr);
149 fputc('\n', stderr);
150 if (n <= 8) break;
151 q += 8; n -= 8;
152 }
153 }
154
155 static void dump_byte_array(JNIEnv *jni, const char *what, jbyteArray v)
156 {
157 jsize n;
158 jbyte *p;
159
160 fprintf(stderr, ";; %s\n", what);
161 if (!v) { fprintf(stderr, ";; <null>\n"); return; }
162 n = (*jni)->GetArrayLength(jni, v);
163 p = (*jni)->GetByteArrayElements(jni, v, 0);
164 dump_bytes(p, n, 0);
165 (*jni)->ReleaseByteArrayElements(jni, v, p, JNI_ABORT);
166 }
167 #endif
168
169 static jbyteArray wrap_cstring(JNIEnv *jni, const char *p)
170 {
171 size_t n;
172 jbyteArray v;
173 jbyte *q;
174
175 if (!p) return (0);
176 n = strlen(p) + 1;
177 v = (*jni)->NewByteArray(jni, n); if (!v) return (0);
178 q = (*jni)->GetByteArrayElements(jni, v, 0); if (!q) return (0);
179 memcpy(q, p, n);
180 (*jni)->ReleaseByteArrayElements(jni, v, q, 0);
181 return (v);
182 }
183
184 static const char *get_cstring(JNIEnv *jni, jbyteArray v)
185 {
186 if (!v) { except(jni, NULLERR, 0); return (0); }
187 return ((const char *)(*jni)->GetByteArrayElements(jni, v, 0));
188 }
189
190 static void put_cstring(JNIEnv *jni, jbyteArray v, const char *p)
191 { if (p) (*jni)->ReleaseByteArrayElements(jni, v, (jbyte *)p, JNI_ABORT); }
192
193 static void vexcept_syserror(JNIEnv *jni, const char *clsname,
194 int err, const char *msg, va_list *ap)
195 {
196 jclass cls;
197 int rc;
198 dstr d = DSTR_INIT;
199 jbyteArray msgstr;
200 jthrowable e;
201 jmethodID init;
202
203 cls = (*jni)->FindClass(jni, clsname); assert(cls);
204 init = (*jni)->GetMethodID(jni, cls, "<init>", "(I[B)V"); assert(init);
205 dstr_vputf(&d, msg, ap);
206 msgstr = wrap_cstring(jni, d.buf); assert(msgstr);
207 dstr_destroy(&d);
208 e = (*jni)->NewObject(jni, cls, init, err, msgstr); assert(e);
209 rc = (*jni)->Throw(jni, e); assert(!rc);
210 }
211
212 static void except_syserror(JNIEnv *jni, const char *clsname,
213 int err, const char *msg, ...)
214 {
215 va_list ap;
216
217 va_start(ap, msg);
218 vexcept_syserror(jni, clsname, err, msg, &ap);
219 va_end(ap);
220 }
221
222 static int set_nonblocking(JNIEnv *jni, int fd, int nb)
223 {
224 int f0 = fcntl(fd, F_GETFL), f1;
225 if (f0 < 0) goto err;
226 if (nb) f1 = f0 | O_NONBLOCK;
227 else f1 = f0&~O_NONBLOCK;
228 if (fcntl(fd, F_SETFL, f1)) goto err;
229 return (f0 & O_NONBLOCK);
230 err:
231 except_syserror(jni, SYSERR, errno,
232 "failed to set descriptor nonblocking");
233 return (-1);
234 }
235
236 static int set_closeonexec(JNIEnv *jni, int fd)
237 {
238 int f = fcntl(fd, F_GETFD);
239 if (f < 0 || fcntl(fd, F_SETFD, f | FD_CLOEXEC)) {
240 except_syserror(jni, SYSERR, errno,
241 "failed to set descriptor close-on-exec");
242 return (-1);
243 }
244 return (0);
245 }
246
247 /*----- Wrapping native types ---------------------------------------------*/
248
249 /* There's no way defined in the JNI to stash a C pointer in a Java object.
250 * It seems that the usual approach is to cast to `jlong', but this is
251 * clearly unsatisfactory. Instead, we store structures as Java byte arrays,
252 * with a 32-bit tag on the front.
253 */
254
255 struct native_type {
256 const char *name;
257 size_t sz;
258 uint32 tag;
259 };
260
261 typedef jbyteArray wrapper;
262
263 struct native_base {
264 uint32 tag;
265 };
266
267 static int unwrap(JNIEnv *jni, void *p,
268 const struct native_type *ty, wrapper w)
269 {
270 jbyte *q;
271 jclass cls;
272 struct native_base *b = p;
273 jsize n;
274
275 if (!w) { except(jni, NULLERR, 0); return (-1); }
276 cls = (*jni)->FindClass(jni, "[B"); assert(cls);
277 if (!(*jni)->IsInstanceOf(jni, w, cls)) {
278 except(jni, TYPEERR,
279 "corrupted native object wrapper: expected a byte array");
280 return (-1);
281 }
282 n = (*jni)->GetArrayLength(jni, w);
283 if (n != ty->sz) {
284 except(jni, TYPEERR,
285 "corrupted native object wrapper: wrong size for `%s'",
286 ty->name);
287 return (-1);
288 }
289 q = (*jni)->GetByteArrayElements(jni, w, 0); if (!q) return (-1);
290 memcpy(b, q, ty->sz);
291 (*jni)->ReleaseByteArrayElements(jni, w, q, JNI_ABORT);
292 if (b->tag != ty->tag) {
293 except(jni, TYPEERR,
294 "corrupted native object wrapper: expected tag for `%s'",
295 ty->name);
296 return (-1);
297 }
298 return (0);
299 }
300
301 static int update_wrapper(JNIEnv *jni, const struct native_type *ty,
302 wrapper w, const void *p)
303 {
304 jbyte *q;
305
306 q = (*jni)->GetByteArrayElements(jni, w, 0); if (!q) return (-1);
307 memcpy(q, p, ty->sz);
308 (*jni)->ReleaseByteArrayElements(jni, w, q, 0);
309 return (0);
310 }
311
312 static wrapper wrap(JNIEnv *jni, const struct native_type *ty, const void *p)
313 {
314 wrapper w;
315
316 w = (*jni)->NewByteArray(jni, ty->sz); if (!w) return (0);
317 if (update_wrapper(jni, ty, w, p)) return (0);
318 return (w);
319 }
320
321 #define INIT_NATIVE(type, p) do (p)->_base.tag = type##_type.tag; while (0)
322
323 /*----- Crypto information ------------------------------------------------*/
324
325 JNIEXPORT jint JNICALL JNIFUNC(hashsz)(JNIEnv *jni, jobject cls,
326 jstring hnamestr)
327 {
328 jint rc = -1;
329 const char *hname;
330 const gchash *hc;
331
332 hname = (*jni)->GetStringUTFChars(jni, hnamestr, 0);
333 if (!hname) goto end;
334 hc = ghash_byname(hname); if (!hc) goto end;
335 rc = hc->hashsz;
336
337 end:
338 if (hname) (*jni)->ReleaseStringUTFChars(jni, hnamestr, hname);
339 return (rc);
340 }
341
342 /*----- System errors -----------------------------------------------------*/
343
344 static const struct errtab { const char *tag; int err; } errtab[] = {
345 /*
346 ;;; The errno name table is very boring to type. To make life less
347 ;;; awful, put the errno names in this list and evaluate the code to
348 ;;; get Emacs to regenerate it.
349
350 (let ((errors '(EPERM ENOENT ESRCH EINTR EIO ENXIO E2BIG ENOEXEC EBADF
351 ECHILD EAGAIN ENOMEM EACCES EFAULT ENOTBLK EBUSY EEXIST
352 EXDEV ENODEV ENOTDIR EISDIR EINVAL ENFILE EMFILE ENOTTY
353 ETXTBSY EFBIG ENOSPC ESPIPE EROFS EMLINK EPIPE EDOM
354 ERANGE
355
356 EDEADLK ENAMETOOLONG ENOLCK ENOSYS ENOTEMPTY ELOOP
357 EWOULDBLOCK ENOMSG EIDRM ECHRNG EL2NSYNC EL3HLT EL3RST
358 ELNRNG EUNATCH ENOCSI EL2HLT EBADE EBADR EXFULL ENOANO
359 EBADRQC EBADSLT EDEADLOCK EBFONT ENOSTR ENODATA ETIME
360 ENOSR ENONET ENOPKG EREMOTE ENOLINK EADV ESRMNT ECOMM
361 EPROTO EMULTIHOP EDOTDOT EBADMSG EOVERFLOW ENOTUNIQ
362 EBADFD EREMCHG ELIBACC ELIBBAD ELIBSCN ELIBMAX ELIBEXEC
363 EILSEQ ERESTART ESTRPIPE EUSERS ENOTSOCK EDESTADDRREQ
364 EMSGSIZE EPROTOTYPE ENOPROTOOPT EPROTONOSUPPORT
365 ESOCKTNOSUPPORT EOPNOTSUPP EPFNOSUPPORT EAFNOSUPPORT
366 EADDRINUSE EADDRNOTAVAIL ENETDOWN ENETUNREACH ENETRESET
367 ECONNABORTED ECONNRESET ENOBUFS EISCONN ENOTCONN
368 ESHUTDOWN ETOOMANYREFS ETIMEDOUT ECONNREFUSED EHOSTDOWN
369 EHOSTUNREACH EALREADY EINPROGRESS ESTALE EUCLEAN ENOTNAM
370 ENAVAIL EISNAM EREMOTEIO EDQUOT ENOMEDIUM EMEDIUMTYPE
371 ECANCELED ENOKEY EKEYEXPIRED EKEYREVOKED EKEYREJECTED
372 EOWNERDEAD ENOTRECOVERABLE ERFKILL EHWPOISON)))
373 (save-excursion
374 (goto-char (point-min))
375 (search-forward (concat "***" "BEGIN errtab" "***"))
376 (beginning-of-line 2)
377 (delete-region (point)
378 (progn
379 (search-forward "***END***")
380 (beginning-of-line)
381 (point)))
382 (dolist (err errors)
383 (insert (format "#ifdef %s\n { \"%s\", %s },\n#endif\n"
384 err err err)))))
385 */
386 /***BEGIN errtab***/
387 #ifdef EPERM
388 { "EPERM", EPERM },
389 #endif
390 #ifdef ENOENT
391 { "ENOENT", ENOENT },
392 #endif
393 #ifdef ESRCH
394 { "ESRCH", ESRCH },
395 #endif
396 #ifdef EINTR
397 { "EINTR", EINTR },
398 #endif
399 #ifdef EIO
400 { "EIO", EIO },
401 #endif
402 #ifdef ENXIO
403 { "ENXIO", ENXIO },
404 #endif
405 #ifdef E2BIG
406 { "E2BIG", E2BIG },
407 #endif
408 #ifdef ENOEXEC
409 { "ENOEXEC", ENOEXEC },
410 #endif
411 #ifdef EBADF
412 { "EBADF", EBADF },
413 #endif
414 #ifdef ECHILD
415 { "ECHILD", ECHILD },
416 #endif
417 #ifdef EAGAIN
418 { "EAGAIN", EAGAIN },
419 #endif
420 #ifdef ENOMEM
421 { "ENOMEM", ENOMEM },
422 #endif
423 #ifdef EACCES
424 { "EACCES", EACCES },
425 #endif
426 #ifdef EFAULT
427 { "EFAULT", EFAULT },
428 #endif
429 #ifdef ENOTBLK
430 { "ENOTBLK", ENOTBLK },
431 #endif
432 #ifdef EBUSY
433 { "EBUSY", EBUSY },
434 #endif
435 #ifdef EEXIST
436 { "EEXIST", EEXIST },
437 #endif
438 #ifdef EXDEV
439 { "EXDEV", EXDEV },
440 #endif
441 #ifdef ENODEV
442 { "ENODEV", ENODEV },
443 #endif
444 #ifdef ENOTDIR
445 { "ENOTDIR", ENOTDIR },
446 #endif
447 #ifdef EISDIR
448 { "EISDIR", EISDIR },
449 #endif
450 #ifdef EINVAL
451 { "EINVAL", EINVAL },
452 #endif
453 #ifdef ENFILE
454 { "ENFILE", ENFILE },
455 #endif
456 #ifdef EMFILE
457 { "EMFILE", EMFILE },
458 #endif
459 #ifdef ENOTTY
460 { "ENOTTY", ENOTTY },
461 #endif
462 #ifdef ETXTBSY
463 { "ETXTBSY", ETXTBSY },
464 #endif
465 #ifdef EFBIG
466 { "EFBIG", EFBIG },
467 #endif
468 #ifdef ENOSPC
469 { "ENOSPC", ENOSPC },
470 #endif
471 #ifdef ESPIPE
472 { "ESPIPE", ESPIPE },
473 #endif
474 #ifdef EROFS
475 { "EROFS", EROFS },
476 #endif
477 #ifdef EMLINK
478 { "EMLINK", EMLINK },
479 #endif
480 #ifdef EPIPE
481 { "EPIPE", EPIPE },
482 #endif
483 #ifdef EDOM
484 { "EDOM", EDOM },
485 #endif
486 #ifdef ERANGE
487 { "ERANGE", ERANGE },
488 #endif
489 #ifdef EDEADLK
490 { "EDEADLK", EDEADLK },
491 #endif
492 #ifdef ENAMETOOLONG
493 { "ENAMETOOLONG", ENAMETOOLONG },
494 #endif
495 #ifdef ENOLCK
496 { "ENOLCK", ENOLCK },
497 #endif
498 #ifdef ENOSYS
499 { "ENOSYS", ENOSYS },
500 #endif
501 #ifdef ENOTEMPTY
502 { "ENOTEMPTY", ENOTEMPTY },
503 #endif
504 #ifdef ELOOP
505 { "ELOOP", ELOOP },
506 #endif
507 #ifdef EWOULDBLOCK
508 { "EWOULDBLOCK", EWOULDBLOCK },
509 #endif
510 #ifdef ENOMSG
511 { "ENOMSG", ENOMSG },
512 #endif
513 #ifdef EIDRM
514 { "EIDRM", EIDRM },
515 #endif
516 #ifdef ECHRNG
517 { "ECHRNG", ECHRNG },
518 #endif
519 #ifdef EL2NSYNC
520 { "EL2NSYNC", EL2NSYNC },
521 #endif
522 #ifdef EL3HLT
523 { "EL3HLT", EL3HLT },
524 #endif
525 #ifdef EL3RST
526 { "EL3RST", EL3RST },
527 #endif
528 #ifdef ELNRNG
529 { "ELNRNG", ELNRNG },
530 #endif
531 #ifdef EUNATCH
532 { "EUNATCH", EUNATCH },
533 #endif
534 #ifdef ENOCSI
535 { "ENOCSI", ENOCSI },
536 #endif
537 #ifdef EL2HLT
538 { "EL2HLT", EL2HLT },
539 #endif
540 #ifdef EBADE
541 { "EBADE", EBADE },
542 #endif
543 #ifdef EBADR
544 { "EBADR", EBADR },
545 #endif
546 #ifdef EXFULL
547 { "EXFULL", EXFULL },
548 #endif
549 #ifdef ENOANO
550 { "ENOANO", ENOANO },
551 #endif
552 #ifdef EBADRQC
553 { "EBADRQC", EBADRQC },
554 #endif
555 #ifdef EBADSLT
556 { "EBADSLT", EBADSLT },
557 #endif
558 #ifdef EDEADLOCK
559 { "EDEADLOCK", EDEADLOCK },
560 #endif
561 #ifdef EBFONT
562 { "EBFONT", EBFONT },
563 #endif
564 #ifdef ENOSTR
565 { "ENOSTR", ENOSTR },
566 #endif
567 #ifdef ENODATA
568 { "ENODATA", ENODATA },
569 #endif
570 #ifdef ETIME
571 { "ETIME", ETIME },
572 #endif
573 #ifdef ENOSR
574 { "ENOSR", ENOSR },
575 #endif
576 #ifdef ENONET
577 { "ENONET", ENONET },
578 #endif
579 #ifdef ENOPKG
580 { "ENOPKG", ENOPKG },
581 #endif
582 #ifdef EREMOTE
583 { "EREMOTE", EREMOTE },
584 #endif
585 #ifdef ENOLINK
586 { "ENOLINK", ENOLINK },
587 #endif
588 #ifdef EADV
589 { "EADV", EADV },
590 #endif
591 #ifdef ESRMNT
592 { "ESRMNT", ESRMNT },
593 #endif
594 #ifdef ECOMM
595 { "ECOMM", ECOMM },
596 #endif
597 #ifdef EPROTO
598 { "EPROTO", EPROTO },
599 #endif
600 #ifdef EMULTIHOP
601 { "EMULTIHOP", EMULTIHOP },
602 #endif
603 #ifdef EDOTDOT
604 { "EDOTDOT", EDOTDOT },
605 #endif
606 #ifdef EBADMSG
607 { "EBADMSG", EBADMSG },
608 #endif
609 #ifdef EOVERFLOW
610 { "EOVERFLOW", EOVERFLOW },
611 #endif
612 #ifdef ENOTUNIQ
613 { "ENOTUNIQ", ENOTUNIQ },
614 #endif
615 #ifdef EBADFD
616 { "EBADFD", EBADFD },
617 #endif
618 #ifdef EREMCHG
619 { "EREMCHG", EREMCHG },
620 #endif
621 #ifdef ELIBACC
622 { "ELIBACC", ELIBACC },
623 #endif
624 #ifdef ELIBBAD
625 { "ELIBBAD", ELIBBAD },
626 #endif
627 #ifdef ELIBSCN
628 { "ELIBSCN", ELIBSCN },
629 #endif
630 #ifdef ELIBMAX
631 { "ELIBMAX", ELIBMAX },
632 #endif
633 #ifdef ELIBEXEC
634 { "ELIBEXEC", ELIBEXEC },
635 #endif
636 #ifdef EILSEQ
637 { "EILSEQ", EILSEQ },
638 #endif
639 #ifdef ERESTART
640 { "ERESTART", ERESTART },
641 #endif
642 #ifdef ESTRPIPE
643 { "ESTRPIPE", ESTRPIPE },
644 #endif
645 #ifdef EUSERS
646 { "EUSERS", EUSERS },
647 #endif
648 #ifdef ENOTSOCK
649 { "ENOTSOCK", ENOTSOCK },
650 #endif
651 #ifdef EDESTADDRREQ
652 { "EDESTADDRREQ", EDESTADDRREQ },
653 #endif
654 #ifdef EMSGSIZE
655 { "EMSGSIZE", EMSGSIZE },
656 #endif
657 #ifdef EPROTOTYPE
658 { "EPROTOTYPE", EPROTOTYPE },
659 #endif
660 #ifdef ENOPROTOOPT
661 { "ENOPROTOOPT", ENOPROTOOPT },
662 #endif
663 #ifdef EPROTONOSUPPORT
664 { "EPROTONOSUPPORT", EPROTONOSUPPORT },
665 #endif
666 #ifdef ESOCKTNOSUPPORT
667 { "ESOCKTNOSUPPORT", ESOCKTNOSUPPORT },
668 #endif
669 #ifdef EOPNOTSUPP
670 { "EOPNOTSUPP", EOPNOTSUPP },
671 #endif
672 #ifdef EPFNOSUPPORT
673 { "EPFNOSUPPORT", EPFNOSUPPORT },
674 #endif
675 #ifdef EAFNOSUPPORT
676 { "EAFNOSUPPORT", EAFNOSUPPORT },
677 #endif
678 #ifdef EADDRINUSE
679 { "EADDRINUSE", EADDRINUSE },
680 #endif
681 #ifdef EADDRNOTAVAIL
682 { "EADDRNOTAVAIL", EADDRNOTAVAIL },
683 #endif
684 #ifdef ENETDOWN
685 { "ENETDOWN", ENETDOWN },
686 #endif
687 #ifdef ENETUNREACH
688 { "ENETUNREACH", ENETUNREACH },
689 #endif
690 #ifdef ENETRESET
691 { "ENETRESET", ENETRESET },
692 #endif
693 #ifdef ECONNABORTED
694 { "ECONNABORTED", ECONNABORTED },
695 #endif
696 #ifdef ECONNRESET
697 { "ECONNRESET", ECONNRESET },
698 #endif
699 #ifdef ENOBUFS
700 { "ENOBUFS", ENOBUFS },
701 #endif
702 #ifdef EISCONN
703 { "EISCONN", EISCONN },
704 #endif
705 #ifdef ENOTCONN
706 { "ENOTCONN", ENOTCONN },
707 #endif
708 #ifdef ESHUTDOWN
709 { "ESHUTDOWN", ESHUTDOWN },
710 #endif
711 #ifdef ETOOMANYREFS
712 { "ETOOMANYREFS", ETOOMANYREFS },
713 #endif
714 #ifdef ETIMEDOUT
715 { "ETIMEDOUT", ETIMEDOUT },
716 #endif
717 #ifdef ECONNREFUSED
718 { "ECONNREFUSED", ECONNREFUSED },
719 #endif
720 #ifdef EHOSTDOWN
721 { "EHOSTDOWN", EHOSTDOWN },
722 #endif
723 #ifdef EHOSTUNREACH
724 { "EHOSTUNREACH", EHOSTUNREACH },
725 #endif
726 #ifdef EALREADY
727 { "EALREADY", EALREADY },
728 #endif
729 #ifdef EINPROGRESS
730 { "EINPROGRESS", EINPROGRESS },
731 #endif
732 #ifdef ESTALE
733 { "ESTALE", ESTALE },
734 #endif
735 #ifdef EUCLEAN
736 { "EUCLEAN", EUCLEAN },
737 #endif
738 #ifdef ENOTNAM
739 { "ENOTNAM", ENOTNAM },
740 #endif
741 #ifdef ENAVAIL
742 { "ENAVAIL", ENAVAIL },
743 #endif
744 #ifdef EISNAM
745 { "EISNAM", EISNAM },
746 #endif
747 #ifdef EREMOTEIO
748 { "EREMOTEIO", EREMOTEIO },
749 #endif
750 #ifdef EDQUOT
751 { "EDQUOT", EDQUOT },
752 #endif
753 #ifdef ENOMEDIUM
754 { "ENOMEDIUM", ENOMEDIUM },
755 #endif
756 #ifdef EMEDIUMTYPE
757 { "EMEDIUMTYPE", EMEDIUMTYPE },
758 #endif
759 #ifdef ECANCELED
760 { "ECANCELED", ECANCELED },
761 #endif
762 #ifdef ENOKEY
763 { "ENOKEY", ENOKEY },
764 #endif
765 #ifdef EKEYEXPIRED
766 { "EKEYEXPIRED", EKEYEXPIRED },
767 #endif
768 #ifdef EKEYREVOKED
769 { "EKEYREVOKED", EKEYREVOKED },
770 #endif
771 #ifdef EKEYREJECTED
772 { "EKEYREJECTED", EKEYREJECTED },
773 #endif
774 #ifdef EOWNERDEAD
775 { "EOWNERDEAD", EOWNERDEAD },
776 #endif
777 #ifdef ENOTRECOVERABLE
778 { "ENOTRECOVERABLE", ENOTRECOVERABLE },
779 #endif
780 #ifdef ERFKILL
781 { "ERFKILL", ERFKILL },
782 #endif
783 #ifdef EHWPOISON
784 { "EHWPOISON", EHWPOISON },
785 #endif
786 /***END***/
787 };
788
789 JNIEXPORT jobject JNIFUNC(errtab)(JNIEnv *jni, jobject cls)
790 {
791 size_t i;
792 jclass eltcls;
793 jarray v;
794 jmethodID init;
795 jobject e;
796
797 eltcls =
798 (*jni)->FindClass(jni, ERRENTCLS);
799 assert(eltcls);
800 v = (*jni)->NewObjectArray(jni, N(errtab), eltcls, 0); if (!v) return (0);
801 init = (*jni)->GetMethodID(jni, eltcls, "<init>",
802 "(L"STRCLS";I)V");
803 assert(init);
804
805 for (i = 0; i < N(errtab); i++) {
806 e = (*jni)->NewObject(jni, eltcls, init,
807 (*jni)->NewStringUTF(jni, errtab[i].tag),
808 errtab[i].err);
809 (*jni)->SetObjectArrayElement(jni, v, i, e);
810 }
811 return (v);
812 }
813
814 JNIEXPORT jobject JNIFUNC(strerror)(JNIEnv *jni, jobject cls, jint err)
815 { return (wrap_cstring(jni, strerror(err))); }
816
817 /*----- Messing with file descriptors -------------------------------------*/
818
819 static void fdguts(JNIEnv *jni, jclass *cls, jfieldID *fid)
820 {
821 *cls = (*jni)->FindClass(jni, FDCLS); assert(cls);
822 *fid = (*jni)->GetFieldID(jni, *cls, "fd", "I"); // OpenJDK
823 if (!*fid) *fid = (*jni)->GetFieldID(jni, *cls, "descriptor", "I"); // Android
824 assert(*fid);
825 }
826
827 static int fdint(JNIEnv *jni, jobject jfd)
828 {
829 jclass cls;
830 jfieldID fid;
831
832 fdguts(jni, &cls, &fid);
833 return ((*jni)->GetIntField(jni, jfd, fid));
834 }
835
836 static jobject newfd(JNIEnv *jni, int fd)
837 {
838 jobject jfd;
839 jclass cls;
840 jmethodID init;
841 jfieldID fid;
842
843 fdguts(jni, &cls, &fid);
844 init = (*jni)->GetMethodID(jni, cls, "<init>", "()V"); assert(init);
845 jfd = (*jni)->NewObject(jni, cls, init);
846 (*jni)->SetIntField(jni, jfd, fid, fd);
847 return (jfd);
848 }
849
850 JNIEXPORT jint JNIFUNC(fdint)(JNIEnv *jni, jobject cls, jobject jfd)
851 { return (fdint(jni, jfd)); }
852
853 JNIEXPORT jobject JNIFUNC(newfd)(JNIEnv *jni, jobject cls, jint fd)
854 { return (newfd(jni, fd)); }
855
856 JNIEXPORT jboolean JNIFUNC(isatty)(JNIEnv *jni, jobject cls, jobject jfd)
857 { return (isatty(fdint(jni, jfd))); }
858
859 /*----- Low-level file operations -----------------------------------------*/
860
861 /* Java has these already, as methods on `java.io.File' objects. Alas, these
862 * methods are useless at reporting errors: they tend to return a `boolean'
863 * success/fail indicator, and throw away any more detailed information.
864 * There's better functionality in `java.nio.file.Files', but that only turns
865 * up in Android API 26 (in 7.0 Nougat). There's `android.system.Os', which
866 * has a bunch of POSIX-shaped functions -- but they're only in Android API
867 * 21 (in 5.0 Lollipop), and there's nothing in the support library to help.
868 *
869 * So the other option is to implement them ourselves.
870 */
871
872 JNIEXPORT void JNIFUNC(unlink)(JNIEnv *jni, jobject cls, jobject path)
873 {
874 const char *pathstr = 0;
875
876 pathstr = get_cstring(jni, path); if (!pathstr) goto end;
877 if (unlink(pathstr)) {
878 except_syserror(jni, SYSERR, errno,
879 "failed to delete file `%s'", pathstr);
880 goto end;
881 }
882 end:
883 put_cstring(jni, path, pathstr);
884 }
885
886 JNIEXPORT void JNIFUNC(rmdir)(JNIEnv *jni, jobject cls, jobject path)
887 {
888 const char *pathstr = 0;
889
890 pathstr = get_cstring(jni, path); if (!pathstr) goto end;
891 if (rmdir(pathstr)) {
892 except_syserror(jni, SYSERR, errno,
893 "failed to delete directory `%s'", pathstr);
894 goto end;
895 }
896 end:
897 put_cstring(jni, path, pathstr);
898 }
899
900 JNIEXPORT void JNIFUNC(mkdir)(JNIEnv *jni, jobject cls,
901 jobject path, jint mode)
902 {
903 const char *pathstr = 0;
904
905 pathstr = get_cstring(jni, path); if (!pathstr) goto end;
906 if (mkdir(pathstr, mode)) {
907 except_syserror(jni, SYSERR, errno,
908 "failed to create directory `%s'", pathstr);
909 goto end;
910 }
911 end:
912 put_cstring(jni, path, pathstr);
913 }
914
915 JNIEXPORT void JNIFUNC(chmod)(JNIEnv *jni, jobject cls,
916 jobject path, jint mode)
917 {
918 const char *pathstr = 0;
919
920 pathstr = get_cstring(jni, path); if (!pathstr) goto end;
921 if (chmod(pathstr, mode)) {
922 except_syserror(jni, SYSERR, errno,
923 "failed st permissions on `%s'", pathstr);
924 goto end;
925 }
926 end:
927 put_cstring(jni, path, pathstr);
928 }
929
930 JNIEXPORT void JNIFUNC(mkfile)(JNIEnv *jni, jobject cls,
931 jobject path, jint mode)
932 {
933 const char *pathstr = 0;
934 int fd = -1;
935
936 pathstr = get_cstring(jni, path); if (!pathstr) goto end;
937 fd = open(pathstr, O_WRONLY | O_CREAT | O_EXCL, mode);
938 if (fd < 0) {
939 except_syserror(jni, SYSERR, errno,
940 "failed to create fresh file `%s'", pathstr);
941 goto end;
942 }
943 end:
944 if (fd != -1) close(fd);
945 put_cstring(jni, path, pathstr);
946 }
947
948 JNIEXPORT void JNIFUNC(rename)(JNIEnv *jni, jobject cls,
949 jobject from, jobject to)
950 {
951 const char *fromstr = 0, *tostr = 0;
952
953 fromstr = get_cstring(jni, from); if (!fromstr) goto end;
954 tostr = get_cstring(jni, to); if (!tostr) goto end;
955 if (rename(fromstr, tostr)) {
956 except_syserror(jni, SYSERR, errno,
957 "failed to rename `%s' as `%s'", fromstr, tostr);
958 goto end;
959 }
960 end:
961 put_cstring(jni, from, fromstr);
962 put_cstring(jni, to, tostr);
963 }
964
965 #define LKF_EXCL 0x1000u
966 #define LKF_WAIT 0x2000u
967 struct lockf {
968 struct native_base _base;
969 int fd;
970 };
971 static struct native_type lockf_type =
972 { "lock", sizeof(struct lockf), 0xb2648926};
973 JNIEXPORT wrapper JNIFUNC(lock)(JNIEnv *jni, jobject cls,
974 jobject path, jint flags)
975 {
976 const char *pathstr = 0;
977 int fd = -1;
978 struct flock l;
979 struct lockf lk;
980 struct stat st0, st1;
981 int f;
982 wrapper r = 0;
983
984 pathstr = get_cstring(jni, path); if (!pathstr) goto end;
985
986 again:
987 fd = open(pathstr, O_RDWR | O_CREAT, flags&07777); if (fd < 0) goto err;
988 if (fstat(fd, &st0)) goto err;
989 f = fcntl(fd, F_GETFD); if (f < 0) goto err;
990 if (fcntl(fd, F_SETFD, f | FD_CLOEXEC)) goto err;
991 l.l_type = (flags&LKF_EXCL) ? F_WRLCK : F_RDLCK;
992 l.l_whence = SEEK_SET;
993 l.l_start = 0;
994 l.l_len = 0;
995 if (fcntl(fd, (flags&LKF_WAIT) ? F_SETLKW : F_SETLK, &l)) goto err;
996 if (stat(pathstr, &st1))
997 { if (errno == ENOENT) goto again; else goto err; }
998 if (st0.st_dev != st1.st_dev || st0.st_ino != st1.st_ino)
999 { close(fd); fd = -1; goto again; }
1000
1001 INIT_NATIVE(lockf, &lk); lk.fd = fd; fd = -1;
1002 r = wrap(jni, &lockf_type, &lk);
1003 goto end;
1004
1005 err:
1006 except_syserror(jni, SYSERR, errno, "failed to lock file `%s'", pathstr);
1007 end:
1008 if (fd != -1) close(fd);
1009 put_cstring(jni, path, pathstr);
1010 return (r);
1011 }
1012
1013 JNIEXPORT void JNIFUNC(unlock)(JNIEnv *jni, jobject cls, wrapper wlk)
1014 {
1015 struct lockf lk;
1016 struct flock l;
1017 int rc;
1018
1019 if (unwrap(jni, &lk, &lockf_type, wlk)) goto end;
1020 if (lk.fd == -1) goto end;
1021 l.l_type = F_UNLCK;
1022 l.l_whence = SEEK_SET;
1023 l.l_start = 0;
1024 l.l_len = 0;
1025 if (fcntl(lk.fd, F_SETLK, &l)) goto end;
1026 close(lk.fd); lk.fd = -1;
1027 rc = update_wrapper(jni, &lockf_type, wlk, &lk); assert(!rc);
1028 end:;
1029 }
1030
1031 static jlong xlttimespec(const struct timespec *ts)
1032 { return (1000*(jlong)ts->tv_sec + ts->tv_nsec/1000000); }
1033
1034 static jobject xltstat(JNIEnv *jni, const struct stat *st)
1035 {
1036 jclass cls;
1037 jmethodID init;
1038 jint modehack;
1039
1040 modehack = st->st_mode&07777;
1041 if (S_ISFIFO(st->st_mode)) modehack |= 0010000;
1042 else if (S_ISCHR(st->st_mode)) modehack |= 0020000;
1043 else if (S_ISDIR(st->st_mode)) modehack |= 0040000;
1044 else if (S_ISBLK(st->st_mode)) modehack |= 0060000;
1045 else if (S_ISREG(st->st_mode)) modehack |= 0100000;
1046 else if (S_ISLNK(st->st_mode)) modehack |= 0120000;
1047 else if (S_ISSOCK(st->st_mode)) modehack |= 0140000;
1048
1049 cls = (*jni)->FindClass(jni, STATCLS); assert(cls);
1050 init = (*jni)->GetMethodID(jni, cls, "<init>", "(IIJIIIIIIJIJJJJ)V");
1051 assert(init);
1052 return ((*jni)->NewObject(jni, cls, init,
1053 (jint)major(st->st_dev), (jint)minor(st->st_dev),
1054 (jlong)st->st_ino,
1055 modehack,
1056 (jint)st->st_nlink,
1057 (jint)st->st_uid, (jint)st->st_gid,
1058 (jint)major(st->st_rdev), (jint)minor(st->st_rdev),
1059 (jlong)st->st_size,
1060 (jint)st->st_blksize, (jlong)st->st_blocks,
1061 xlttimespec(&st->st_atim),
1062 xlttimespec(&st->st_mtim),
1063 xlttimespec(&st->st_ctim)));
1064 }
1065
1066 JNIEXPORT jobject JNIFUNC(stat)(JNIEnv *jni, jobject cls, jobject path)
1067 {
1068 jobject r = 0;
1069 const char *pathstr = 0;
1070 struct stat st;
1071
1072 pathstr = get_cstring(jni, path); if (!pathstr) goto end;
1073 if (stat(pathstr, &st)) {
1074 except_syserror(jni, SYSERR, errno,
1075 "failed to read information about `%s'", pathstr);
1076 goto end;
1077 }
1078 r = xltstat(jni, &st);
1079 end:
1080 put_cstring(jni, path, pathstr);
1081 return (r);
1082 }
1083
1084 JNIEXPORT jobject JNIFUNC(lstat)(JNIEnv *jni, jobject cls, jobject path)
1085 {
1086 jobject r = 0;
1087 const char *pathstr = 0;
1088 struct stat st;
1089
1090 pathstr = get_cstring(jni, path); if (!pathstr) goto end;
1091 if (lstat(pathstr, &st)) {
1092 except_syserror(jni, SYSERR, errno,
1093 "failed to read information about `%s'", pathstr);
1094 goto end;
1095 }
1096 r = xltstat(jni, &st);
1097 end:
1098 put_cstring(jni, path, pathstr);
1099 return (r);
1100 }
1101
1102 struct dir {
1103 struct native_base _base;
1104 DIR *d;
1105 };
1106 static const struct native_type dir_type =
1107 { "dir", sizeof(struct dir), 0x0f5ca477 };
1108
1109 JNIEXPORT jobject JNIFUNC(opendir)(JNIEnv *jni, jobject cls, jobject path)
1110 {
1111 const char *pathstr = 0;
1112 struct dir dir;
1113 wrapper r = 0;
1114
1115 pathstr = get_cstring(jni, path); if (!pathstr) goto end;
1116 INIT_NATIVE(dir, &dir);
1117 dir.d = opendir(pathstr);
1118 if (!dir.d) {
1119 except_syserror(jni, SYSERR, errno,
1120 "failed to open directory `%s'", pathstr);
1121 goto end;
1122 }
1123 r = wrap(jni, &dir_type, &dir);
1124 end:
1125 put_cstring(jni, path, pathstr);
1126 return (r);
1127 }
1128
1129 JNIEXPORT jbyteArray JNIFUNC(readdir)(JNIEnv *jni, jobject cls,
1130 jobject path, jobject wdir)
1131 {
1132 const char *pathstr = 0;
1133 struct dir dir;
1134 struct dirent *d;
1135 jbyteArray r = 0;
1136
1137 if (unwrap(jni, &dir, &dir_type, wdir)) goto end;
1138 if (!dir.d) { except(jni, ARGERR, "directory has been closed"); goto end; }
1139 errno = 0; d = readdir(dir.d);
1140 if (errno) {
1141 pathstr = get_cstring(jni, path); if (!pathstr) goto end;
1142 except_syserror(jni, SYSERR, errno,
1143 "failed to read directory `%s'", pathstr);
1144 goto end;
1145 }
1146 if (d) r = wrap_cstring(jni, d->d_name);
1147 end:
1148 put_cstring(jni, path, pathstr);
1149 return (r);
1150 }
1151
1152 JNIEXPORT void JNIFUNC(closedir)(JNIEnv *jni, jobject cls,
1153 jobject path, jobject wdir)
1154 {
1155 const char *pathstr = 0;
1156 struct dir dir;
1157
1158 if (unwrap(jni, &dir, &dir_type, wdir)) goto end;
1159 if (!dir.d) goto end;
1160 if (closedir(dir.d)) {
1161 pathstr = get_cstring(jni, path); if (!pathstr) goto end;
1162 except_syserror(jni, SYSERR, errno,
1163 "failed to close directory `%s'", pathstr);
1164 goto end;
1165 }
1166 dir.d = 0;
1167 if (update_wrapper(jni, &dir_type, wdir, &dir)) goto end;
1168 end:
1169 put_cstring(jni, path, pathstr);
1170 }
1171
1172 /*----- Triggers ----------------------------------------------------------*/
1173
1174 /* A trigger is a gadget for waking up a thread which is blocking on I/O,
1175 * and it's used to implement interruptability.
1176 *
1177 * Really, a trigger is a pipe. A `blocking' I/O operation secretly uses
1178 * select(2) to block on the descriptor of interest /and/ the read side of
1179 * the trigger pipe. To wake up a thread that's blocked, we just write a
1180 * byte (nobody cares /which/ byte) to the write end.
1181 */
1182
1183 struct trigger {
1184 struct native_base _base;
1185 int rfd, wfd;
1186 };
1187 static const struct native_type trigger_type =
1188 { "trigger", sizeof(struct trigger), 0x65ffd8b4 };
1189
1190 JNIEXPORT wrapper JNICALL JNIFUNC(make_1trigger)(JNIEnv *jni, jobject cls)
1191 {
1192 struct trigger trig;
1193 int fd[2];
1194 int i;
1195 wrapper ret = 0;
1196
1197 fd[0] = fd[1] = -1;
1198 if (pipe(fd)) {
1199 except_syserror(jni, SYSERR, errno, "failed to create pipe");
1200 goto end;
1201 }
1202 for (i = 0; i < 2; i++) {
1203 if (set_nonblocking(jni, fd[i], 1) < 0 || set_closeonexec(jni, fd[i]))
1204 goto end;
1205 }
1206
1207 INIT_NATIVE(trigger, &trig);
1208 trig.rfd = fd[0]; fd[0] = -1;
1209 trig.wfd = fd[1]; fd[1] = -1;
1210 ret = wrap(jni, &trigger_type, &trig);
1211
1212 end:
1213 for (i = 0; i < 2; i++)
1214 if (fd[i] != -1) close(fd[i]);
1215 return (ret);
1216 }
1217
1218 JNIEXPORT void JNICALL JNIFUNC(destroy_1trigger)(JNIEnv *jni, jobject cls,
1219 wrapper wtrig)
1220 {
1221 struct trigger trig;
1222
1223 if (unwrap(jni, &trig, &trigger_type, wtrig)) return;
1224 if (trig.rfd != -1) { close(trig.rfd); trig.rfd = -1; }
1225 if (trig.wfd != -1) { close(trig.wfd); trig.wfd = -1; }
1226 update_wrapper(jni, &trigger_type, wtrig, &trig);
1227 }
1228
1229 JNIEXPORT void JNICALL JNIFUNC(reset_1trigger)(JNIEnv *jni, jobject cls,
1230 wrapper wtrig)
1231 {
1232 struct trigger trig;
1233 char buf[64];
1234 ssize_t n;
1235
1236 if (unwrap(jni, &trig, &trigger_type, wtrig)) return;
1237 for (;;) {
1238 n = read(trig.rfd, buf, sizeof(buf));
1239 if (n > 0) continue;
1240 assert(n < 0);
1241 if (errno == EAGAIN || errno == EWOULDBLOCK) break;
1242 else {
1243 except_syserror(jni, SYSERR, errno, "failed to reset trigger");
1244 break;
1245 }
1246 }
1247 }
1248
1249 JNIEXPORT void JNICALL JNIFUNC(trigger)(JNIEnv *jni, jobject cls,
1250 wrapper wtrig)
1251 {
1252 struct trigger trig;
1253 ssize_t n;
1254 char c = 0;
1255
1256 if (unwrap(jni, &trig, &trigger_type, wtrig)) return;
1257 n = write(trig.wfd, &c, 1);
1258 if (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK)
1259 except_syserror(jni, SYSERR, errno, "failed to pull trigger");
1260 }
1261
1262 /*----- A tunnel supplied by Java -----------------------------------------*/
1263
1264 struct tunnel {
1265 const tunnel_ops *ops;
1266 sel_file f;
1267 struct peer *p;
1268 };
1269
1270 static const struct tunnel_ops tun_java;
1271
1272 static int t_init(void) { return (0); }
1273
1274 static void t_read(int fd, unsigned mode, void *v)
1275 {
1276 tunnel *t = v;
1277 ssize_t n;
1278 buf b;
1279
1280 n = read(fd, buf_i, sizeof(buf_i));
1281 if (n < 0) {
1282 a_warn("TUN", "%s", p_ifname(t->p), "java",
1283 "read-error", "?ERRNO", A_END);
1284 return;
1285 }
1286 IF_TRACING(T_TUNNEL, {
1287 trace(T_TUNNEL, "tun-java: packet arrived");
1288 trace_block(T_PACKET, "tunnel: packet contents", buf_i, n);
1289 })
1290 buf_init(&b, buf_i, n);
1291 p_tun(t->p, &b);
1292 }
1293
1294 static tunnel *t_create(peer *p, int fd, char **ifn)
1295 {
1296 JNIEnv *jni = jni_tripe;
1297 tunnel *t = 0;
1298 const char *name = p_name(p);
1299 jbyteArray jname;
1300 size_t n = strlen(p_name(p));
1301 jclass cls, metacls;
1302 jstring jclsname, jexcmsg;
1303 const char *clsname, *excmsg;
1304 jmethodID mid;
1305 jthrowable exc;
1306
1307 assert(jni);
1308
1309 jname = wrap_cstring(jni, name);
1310 cls = (*jni)->FindClass(jni, SYSCLS); assert(cls);
1311 mid = (*jni)->GetStaticMethodID(jni, cls, "getTunnelFd", "([B)I");
1312 assert(mid);
1313 fd = (*jni)->CallStaticIntMethod(jni, cls, mid, jname);
1314
1315 exc = (*jni)->ExceptionOccurred(jni);
1316 if (exc) {
1317 cls = (*jni)->GetObjectClass(jni, exc);
1318 metacls = (*jni)->GetObjectClass(jni, cls);
1319 mid = (*jni)->GetMethodID(jni, metacls,
1320 "getName", "()L"STRCLS";");
1321 assert(mid);
1322 jclsname = (*jni)->CallObjectMethod(jni, cls, mid);
1323 clsname = (*jni)->GetStringUTFChars(jni, jclsname, 0);
1324 mid = (*jni)->GetMethodID(jni, cls,
1325 "getMessage", "()L"STRCLS";");
1326 jexcmsg = (*jni)->CallObjectMethod(jni, exc, mid);
1327 excmsg = (*jni)->GetStringUTFChars(jni, jexcmsg, 0);
1328 a_warn("TUN", "-", "java", "get-tunnel-fd-failed",
1329 "%s", clsname, "%s", excmsg, A_END);
1330 (*jni)->ReleaseStringUTFChars(jni, jclsname, clsname);
1331 (*jni)->ReleaseStringUTFChars(jni, jexcmsg, excmsg);
1332 (*jni)->ExceptionClear(jni);
1333 goto end;
1334 }
1335
1336 t = CREATE(tunnel);
1337 t->ops = &tun_java;
1338 t->p = p;
1339 sel_initfile(&sel, &t->f, fd, SEL_READ, t_read, t);
1340
1341 if (!*ifn) {
1342 *ifn = xmalloc(n + 5);
1343 sprintf(*ifn, "vpn-%s", name);
1344 }
1345
1346 end:
1347 return (t);
1348 }
1349
1350 static void t_inject(tunnel *t, buf *b)
1351 {
1352 IF_TRACING(T_TUNNEL, {
1353 trace(T_TUNNEL, "tun-java: inject decrypted packet");
1354 trace_block(T_PACKET, "tunnel: packet contents", BBASE(b), BLEN(b));
1355 })
1356 DISCARD(write(t->f.fd, BBASE(b), BLEN(b)));
1357 }
1358
1359 static void t_destroy(tunnel *t)
1360 { sel_rmfile(&t->f); close(t->f.fd); DESTROY(t); }
1361
1362 static const struct tunnel_ops tun_java = {
1363 "java", 0,
1364 /* init */ t_init,
1365 /* create */ t_create,
1366 /* setifname */ 0,
1367 /* inject */ t_inject,
1368 /* destroy */ t_destroy
1369 };
1370
1371
1372 JNIEXPORT jint JNICALL JNIFUNC(open_1tun)(JNIEnv *jni, jobject cls)
1373 {
1374 int ret = -1;
1375 int fd = -1;
1376 struct ifreq iff;
1377
1378 if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
1379 except_syserror(jni, SYSERR, errno, "failed to open tunnel device");
1380 goto end;
1381 }
1382
1383 if (set_nonblocking(jni, fd, 1) || set_closeonexec(jni, fd)) goto end;
1384
1385 memset(&iff, 0, sizeof(iff));
1386 iff.ifr_name[0] = 0;
1387 iff.ifr_flags = IFF_TUN | IFF_NO_PI;
1388 if (ioctl(fd, TUNSETIFF, &iff) < 0) {
1389 except_syserror(jni, SYSERR, errno, "failed to configure tunnel device");
1390 goto end;
1391 }
1392
1393 ret = fd; fd = -1;
1394
1395 end:
1396 if (fd != -1) close(fd);
1397 return (ret);
1398 }
1399
1400 /*----- A custom noise source ---------------------------------------------*/
1401
1402 static void javanoise(rand_pool *r)
1403 {
1404 JNIEnv *jni = jni_tripe;
1405 jclass cls;
1406 jmethodID mid;
1407 jbyteArray v;
1408 jbyte *p;
1409 jsize n;
1410
1411 noise_devrandom(r);
1412
1413 assert(jni);
1414 cls = (*jni)->FindClass(jni, RANDCLS); assert(cls);
1415 mid = (*jni)->GetStaticMethodID(jni, cls, "getSeed", "(I)[B"); assert(mid);
1416 v = (*jni)->CallStaticObjectMethod(jni, cls, mid, 32);
1417 if (v) {
1418 n = (*jni)->GetArrayLength(jni, v);
1419 p = (*jni)->GetByteArrayElements(jni, v, 0);
1420 rand_add(r, p, n, n);
1421 (*jni)->ReleaseByteArrayElements(jni, v, p, JNI_ABORT);
1422 }
1423 if ((*jni)->ExceptionOccurred(jni)) {
1424 (*jni)->ExceptionDescribe(jni);
1425 (*jni)->ExceptionClear(jni);
1426 }
1427 }
1428
1429 static const rand_source javasource = { javanoise, noise_timer };
1430
1431 /*----- Embedding the TrIPE server ----------------------------------------*/
1432
1433 static void lock_tripe(JNIEnv *jni)
1434 {
1435 jclass cls = (*jni)->FindClass(jni, LOCKCLS); assert(cls);
1436 (*jni)->MonitorEnter(jni, cls);
1437 }
1438
1439 static void unlock_tripe(JNIEnv *jni)
1440 {
1441 jclass cls = (*jni)->FindClass(jni, LOCKCLS); assert(cls);
1442 (*jni)->MonitorExit(jni, cls);
1443 }
1444
1445 #define STATES(_) \
1446 _(INIT) \
1447 _(RESOLVE) \
1448 _(KEYS) \
1449 _(BIND) \
1450 _(READY) \
1451 _(RUNNING)
1452
1453 enum {
1454 #define DEFTAG(st) st,
1455 STATES(DEFTAG)
1456 #undef DEFTAG
1457 MAXSTATE
1458 };
1459
1460 static const char *statetab[] = {
1461 #define DEFNAME(st) #st,
1462 STATES(DEFNAME)
1463 #undef DEFNAME
1464 };
1465
1466 static unsigned state = INIT;
1467 static int clientsk = -1;
1468
1469 static const char *statename(unsigned st)
1470 {
1471 if (st >= MAXSTATE) return ("<invalid>");
1472 else return (statetab[st]);
1473 }
1474
1475 static int ensure_state(JNIEnv *jni, unsigned want)
1476 {
1477 unsigned cur;
1478
1479 lock_tripe(jni);
1480 cur = state;
1481 unlock_tripe(jni);
1482
1483 if (cur != want) {
1484 except(jni, STERR, "server is in state %s (%u), not %s (%u)",
1485 statename(cur), cur, statename(want), want);
1486 return (-1);
1487 }
1488 return (0);
1489 }
1490
1491 JNIEXPORT void JNICALL JNIFUNC(base_1init)(JNIEnv *jni, jobject cls)
1492 {
1493 int fd[2];
1494 int i;
1495
1496 for (i = 0; i < N(fd); i++) fd[i] = -1;
1497
1498 lock_tripe(jni);
1499 jni_tripe = jni;
1500 if (ensure_state(jni, INIT)) goto end;
1501
1502 if (socketpair(PF_UNIX, SOCK_STREAM, 0, fd)) {
1503 except_syserror(jni, SYSERR, errno, "failed to create socket pair");
1504 goto end;
1505 }
1506
1507 clientsk = fd[0]; fd[0] = -1;
1508
1509 rand_noisesrc(RAND_GLOBAL, &javasource);
1510 rand_seed(RAND_GLOBAL, MAXHASHSZ);
1511 lp_init();
1512 a_create(fd[1], fd[1], AF_NOTE | AF_WARN | AF_TRACE); fd[1] = -1;
1513 a_switcherr();
1514 p_addtun(&tun_java); p_setdflttun(&tun_java);
1515 p_init();
1516 kx_init();
1517
1518 state++;
1519
1520 end:
1521 for (i = 0; i < N(fd); i++) if (fd[i] != -1) close(fd[i]);
1522 jni_tripe = 0;
1523 unlock_tripe(jni);
1524 }
1525
1526 JNIEXPORT void JNICALL JNIFUNC(setup_1resolver)(JNIEnv *jni, jobject cls)
1527 {
1528 lock_tripe(jni);
1529 if (ensure_state(jni, RESOLVE)) goto end;
1530
1531 if (a_init())
1532 { except(jni, INITERR, "failed to initialize resolver"); return; }
1533
1534 state++;
1535
1536 end:
1537 unlock_tripe(jni);
1538 }
1539
1540 JNIEXPORT void JNICALL JNIFUNC(load_1keys)(JNIEnv *jni, jobject cls,
1541 jobject privstr, jobject pubstr,
1542 jobject tagstr)
1543 {
1544 const char *priv = 0, *pub = 0, *tag = 0;
1545
1546 lock_tripe(jni);
1547 if (ensure_state(jni, KEYS)) return;
1548
1549 priv = get_cstring(jni, privstr); if (!priv) goto end;
1550 pub = get_cstring(jni, pubstr); if (!pub) goto end;
1551 tag = get_cstring(jni, tagstr); if (!tag) goto end;
1552
1553 if (km_init(priv, pub, tag))
1554 { except(jni, INITERR, "failed to load initial keys"); goto end; }
1555
1556 state++;
1557
1558 end:
1559 put_cstring(jni, privstr, priv);
1560 put_cstring(jni, pubstr, pub);
1561 put_cstring(jni, tagstr, tag);
1562 unlock_tripe(jni);
1563 }
1564
1565 JNIEXPORT void JNICALL JNIFUNC(unload_1keys)(JNIEnv *jni, jobject cls)
1566 {
1567 lock_tripe(jni);
1568 if (ensure_state(jni, KEYS + 1)) goto end;
1569
1570 km_clear();
1571
1572 state--;
1573
1574 end:
1575 unlock_tripe(jni);
1576 }
1577
1578 JNIEXPORT void JNICALL JNIFUNC(bind)(JNIEnv *jni, jobject cls,
1579 jbyteArray hoststr, jbyteArray svcstr)
1580 {
1581 const char *host = 0, *svc = 0;
1582 struct addrinfo hint, *ai = 0;
1583 int err;
1584
1585 lock_tripe(jni);
1586 if (ensure_state(jni, BIND)) goto end;
1587
1588 if (hoststr) { host = get_cstring(jni, hoststr); if (!host) goto end; }
1589 svc = get_cstring(jni, svcstr); if (!svc) goto end;
1590
1591 hint.ai_socktype = SOCK_DGRAM;
1592 hint.ai_family = AF_UNSPEC;
1593 hint.ai_protocol = IPPROTO_UDP;
1594 hint.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
1595 err = getaddrinfo(host, svc, &hint, &ai);
1596 if (err) {
1597 except(jni, NAMEERR, "failed to resolve %c%s%c, port `%s': %s",
1598 host ? '`' : '<', host ? host : "nil", host ? '\'' : '>',
1599 svc, gai_strerror(err));
1600 goto end;
1601 }
1602
1603 if (p_bind(ai))
1604 { except(jni, INITERR, "failed to bind master socket"); goto end; }
1605
1606 state++;
1607
1608 end:
1609 if (ai) freeaddrinfo(ai);
1610 put_cstring(jni, hoststr, host);
1611 put_cstring(jni, svcstr, svc);
1612 unlock_tripe(jni);
1613 }
1614
1615 JNIEXPORT void JNICALL JNIFUNC(unbind)(JNIEnv *jni, jobject cls)
1616 {
1617 lock_tripe(jni);
1618 if (ensure_state(jni, BIND + 1)) goto end;
1619
1620 p_unbind();
1621
1622 state--;
1623
1624 end:
1625 unlock_tripe(jni);
1626 }
1627
1628 JNIEXPORT void JNICALL JNIFUNC(mark)(JNIEnv *jni, jobject cls, jint seq)
1629 {
1630 lock_tripe(jni);
1631 a_notify("MARK", "%d", seq, A_END);
1632 unlock_tripe(jni);
1633 }
1634
1635 JNIEXPORT void JNICALL JNIFUNC(run)(JNIEnv *jni, jobject cls)
1636 {
1637 lock_tripe(jni);
1638 if (ensure_state(jni, READY)) goto end;
1639 assert(!jni_tripe);
1640 jni_tripe = jni;
1641 state = RUNNING;
1642 unlock_tripe(jni);
1643
1644 lp_run();
1645
1646 lock_tripe(jni);
1647 jni_tripe = 0;
1648 state = READY;
1649
1650 end:
1651 unlock_tripe(jni);
1652 }
1653
1654 static int check_buffer_bounds(JNIEnv *jni, const char *what,
1655 jbyteArray buf, jint start, jint len)
1656 {
1657 jsize bufsz;
1658 jclass cls;
1659
1660 cls = (*jni)->FindClass(jni, "[B"); assert(cls);
1661 if (!(*jni)->IsInstanceOf(jni, buf, cls)) {
1662 except(jni, ARGERR,
1663 "expected a byte array");
1664 return (-1);
1665 }
1666 bufsz = (*jni)->GetArrayLength(jni, buf);
1667 if (start > bufsz) {
1668 except(jni, BOUNDSERR,
1669 "bad %s buffer bounds: start %d > buffer size %d", start, bufsz);
1670 return (-1);
1671 }
1672 if (len > bufsz - start) {
1673 except(jni, BOUNDSERR,
1674 "bad %s buffer bounds: length %d > remaining buffer size %d",
1675 len, bufsz - start);
1676 return (-1);
1677 }
1678 return (0);
1679 }
1680
1681 JNIEXPORT void JNICALL JNIFUNC(send)(JNIEnv *jni, jobject cls,
1682 jbyteArray buf,
1683 jint start, jint len,
1684 wrapper wtrig)
1685 {
1686 struct trigger trig;
1687 int rc, maxfd;
1688 ssize_t n;
1689 fd_set rfds, wfds;
1690 jbyte *p = 0;
1691
1692 if (ensure_state(jni, RUNNING)) goto end;
1693
1694 if (unwrap(jni, &trig, &trigger_type, wtrig)) goto end;
1695 if (check_buffer_bounds(jni, "send", buf, start, len)) goto end;
1696
1697 p = (*jni)->GetByteArrayElements(jni, buf, 0);
1698 if (!p) goto end;
1699
1700 maxfd = trig.rfd;
1701 if (maxfd < clientsk) maxfd = clientsk;
1702 while (len) {
1703 FD_ZERO(&rfds); FD_SET(trig.rfd, &rfds);
1704 FD_ZERO(&wfds); FD_SET(clientsk, &wfds);
1705 rc = select(maxfd + 1, &rfds, &wfds, 0, 0); if (rc < 0) goto err;
1706 if (FD_ISSET(trig.rfd, &rfds)) break;
1707 if (FD_ISSET(clientsk, &wfds)) {
1708 n = send(clientsk, p + start, len, 0);
1709 if (n >= 0) { start += n; len -= n; }
1710 else if (errno != EAGAIN && errno != EWOULDBLOCK) goto err;
1711 }
1712 }
1713 goto end;
1714
1715 err:
1716 except_syserror(jni, SYSERR, errno, "failed to send on connection");
1717 end:
1718 if (p) (*jni)->ReleaseByteArrayElements(jni, buf, p, JNI_ABORT);
1719 return;
1720 }
1721
1722 JNIEXPORT jint JNICALL JNIFUNC(recv)(JNIEnv *jni, jobject cls,
1723 jbyteArray buf,
1724 jint start, jint len,
1725 wrapper wtrig)
1726 {
1727 struct trigger trig;
1728 int maxfd;
1729 fd_set rfds;
1730 jbyte *p = 0;
1731 jint rc = -1;
1732
1733 lock_tripe(jni);
1734 if (clientsk == -1) {
1735 except(jni, STERR, "client connection not established");
1736 unlock_tripe(jni);
1737 goto end;
1738 }
1739 unlock_tripe(jni);
1740
1741 if (unwrap(jni, &trig, &trigger_type, wtrig)) goto end;
1742 if (check_buffer_bounds(jni, "send", buf, start, len)) goto end;
1743
1744 p = (*jni)->GetByteArrayElements(jni, buf, 0);
1745 if (!p) goto end;
1746
1747 maxfd = trig.rfd;
1748 if (maxfd < clientsk) maxfd = clientsk;
1749 for (;;) {
1750 FD_ZERO(&rfds); FD_SET(trig.rfd, &rfds); FD_SET(clientsk, &rfds);
1751 rc = select(maxfd + 1, &rfds, 0, 0, 0); if (rc < 0) goto err;
1752 if (FD_ISSET(trig.rfd, &rfds)) {
1753 break;
1754 }
1755 if (FD_ISSET(clientsk, &rfds)) {
1756 rc = recv(clientsk, p + start, len, 0);
1757 if (rc >= 0) break;
1758 else if (errno != EAGAIN && errno != EWOULDBLOCK) goto err;
1759 }
1760 }
1761 if (!rc) rc = -1;
1762 goto end;
1763
1764 err:
1765 except_syserror(jni, SYSERR, errno, "failed to read from connection");
1766 end:
1767 if (p) (*jni)->ReleaseByteArrayElements(jni, buf, p, 0);
1768 return (rc);
1769 }
1770
1771 /*----- That's all, folks -------------------------------------------------*/