chiark / gitweb /
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 -------------------------------------------------*/