chiark / gitweb /
Integrate the TrIPE server into the Java edifice.
[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(mkfile)(JNIEnv *jni, jobject cls,
916                             jobject path, jint mode)
917 {
918   const char *pathstr = 0;
919   int fd = -1;
920
921   pathstr = get_cstring(jni, path); if (!pathstr) goto end;
922   fd = open(pathstr, O_WRONLY | O_CREAT | O_EXCL, mode);
923   if (fd < 0) {
924     except_syserror(jni, SYSERR, errno,
925                     "failed to create fresh file `%s'", pathstr);
926     goto end;
927   }
928 end:
929   if (fd != -1) close(fd);
930   put_cstring(jni, path, pathstr);
931 }
932
933 JNIEXPORT void JNIFUNC(rename)(JNIEnv *jni, jobject cls,
934                                jobject from, jobject to)
935 {
936   const char *fromstr = 0, *tostr = 0;
937
938   fromstr = get_cstring(jni, from); if (!fromstr) goto end;
939   tostr = get_cstring(jni, to); if (!tostr) goto end;
940   if (rename(fromstr, tostr)) {
941     except_syserror(jni, SYSERR, errno,
942                     "failed to rename `%s' as `%s'", fromstr, tostr);
943     goto end;
944   }
945 end:
946   put_cstring(jni, from, fromstr);
947   put_cstring(jni, to, tostr);
948 }
949
950 #define LKF_EXCL 0x1000u
951 #define LKF_WAIT 0x2000u
952 struct lockf {
953   struct native_base _base;
954   int fd;
955 };
956 static struct native_type lockf_type =
957         { "lock", sizeof(struct lockf), 0xb2648926};
958 JNIEXPORT wrapper JNIFUNC(lock)(JNIEnv *jni, jobject cls,
959                                 jobject path, jint flags)
960 {
961   const char *pathstr = 0;
962   int fd = -1;
963   struct flock l;
964   struct lockf lk;
965   struct stat st0, st1;
966   int f;
967   wrapper r = 0;
968
969   pathstr = get_cstring(jni, path); if (!pathstr) goto end;
970
971 again:
972   fd = open(pathstr, O_RDWR | O_CREAT, flags&07777); if (fd < 0) goto err;
973   if (fstat(fd, &st0)) goto err;
974   f = fcntl(fd, F_GETFD); if (f < 0) goto err;
975   if (fcntl(fd, F_SETFD, f | FD_CLOEXEC)) goto err;
976   l.l_type = (flags&LKF_EXCL) ? F_WRLCK : F_RDLCK;
977   l.l_whence = SEEK_SET;
978   l.l_start = 0;
979   l.l_len = 0;
980   if (fcntl(fd, (flags&LKF_WAIT) ? F_SETLKW : F_SETLK, &l)) goto err;
981   if (stat(pathstr, &st1))
982     { if (errno == ENOENT) goto again; else goto err; }
983   if (st0.st_dev != st1.st_dev || st0.st_ino != st1.st_ino)
984     { close(fd); fd = -1; goto again; }
985
986   INIT_NATIVE(lockf, &lk); lk.fd = fd; fd = -1;
987   r = wrap(jni, &lockf_type, &lk);
988   goto end;
989
990 err:
991   except_syserror(jni, SYSERR, errno, "failed to lock file `%s'", pathstr);
992 end:
993   if (fd != -1) close(fd);
994   put_cstring(jni, path, pathstr);
995   return (r);
996 }
997
998 JNIEXPORT void JNIFUNC(unlock)(JNIEnv *jni, jobject cls, wrapper wlk)
999 {
1000   struct lockf lk;
1001   struct flock l;
1002   int rc;
1003
1004   if (unwrap(jni, &lk, &lockf_type, wlk)) goto end;
1005   if (lk.fd == -1) goto end;
1006   l.l_type = F_UNLCK;
1007   l.l_whence = SEEK_SET;
1008   l.l_start = 0;
1009   l.l_len = 0;
1010   if (fcntl(lk.fd, F_SETLK, &l)) goto end;
1011   close(lk.fd); lk.fd = -1;
1012   rc = update_wrapper(jni, &lockf_type, wlk, &lk); assert(!rc);
1013 end:;
1014 }
1015
1016 static jlong xlttimespec(const struct timespec *ts)
1017   { return (1000*(jlong)ts->tv_sec + ts->tv_nsec/1000000); }
1018
1019 static jobject xltstat(JNIEnv *jni, const struct stat *st)
1020 {
1021   jclass cls;
1022   jmethodID init;
1023   jint modehack;
1024
1025   modehack = st->st_mode&07777;
1026   if (S_ISFIFO(st->st_mode)) modehack |= 0010000;
1027   else if (S_ISCHR(st->st_mode)) modehack |= 0020000;
1028   else if (S_ISDIR(st->st_mode)) modehack |= 0040000;
1029   else if (S_ISBLK(st->st_mode)) modehack |= 0060000;
1030   else if (S_ISREG(st->st_mode)) modehack |= 0100000;
1031   else if (S_ISLNK(st->st_mode)) modehack |= 0120000;
1032   else if (S_ISSOCK(st->st_mode)) modehack |= 0140000;
1033
1034   cls = (*jni)->FindClass(jni, STATCLS); assert(cls);
1035   init = (*jni)->GetMethodID(jni, cls, "<init>", "(IIJIIIIIIJIJJJJ)V");
1036   assert(init);
1037   return ((*jni)->NewObject(jni, cls, init,
1038                             (jint)major(st->st_dev), (jint)minor(st->st_dev),
1039                             (jlong)st->st_ino,
1040                             modehack,
1041                             (jint)st->st_nlink,
1042                             (jint)st->st_uid, (jint)st->st_gid,
1043                             (jint)major(st->st_rdev), (jint)minor(st->st_rdev),
1044                             (jlong)st->st_size,
1045                             (jint)st->st_blksize, (jlong)st->st_blocks,
1046                             xlttimespec(&st->st_atim),
1047                             xlttimespec(&st->st_mtim),
1048                             xlttimespec(&st->st_ctim)));
1049 }
1050
1051 JNIEXPORT jobject JNIFUNC(stat)(JNIEnv *jni, jobject cls, jobject path)
1052 {
1053   jobject r = 0;
1054   const char *pathstr = 0;
1055   struct stat st;
1056
1057   pathstr = get_cstring(jni, path); if (!pathstr) goto end;
1058   if (stat(pathstr, &st)) {
1059     except_syserror(jni, SYSERR, errno,
1060                     "failed to read information about `%s'", pathstr);
1061     goto end;
1062   }
1063   r = xltstat(jni, &st);
1064 end:
1065   put_cstring(jni, path, pathstr);
1066   return (r);
1067 }
1068
1069 JNIEXPORT jobject JNIFUNC(lstat)(JNIEnv *jni, jobject cls, jobject path)
1070 {
1071   jobject r = 0;
1072   const char *pathstr = 0;
1073   struct stat st;
1074
1075   pathstr = get_cstring(jni, path); if (!pathstr) goto end;
1076   if (lstat(pathstr, &st)) {
1077     except_syserror(jni, SYSERR, errno,
1078                     "failed to read information about `%s'", pathstr);
1079     goto end;
1080   }
1081   r = xltstat(jni, &st);
1082 end:
1083   put_cstring(jni, path, pathstr);
1084   return (r);
1085 }
1086
1087 struct dir {
1088   struct native_base _base;
1089   DIR *d;
1090 };
1091 static const struct native_type dir_type =
1092         { "dir", sizeof(struct dir), 0x0f5ca477 };
1093
1094 JNIEXPORT jobject JNIFUNC(opendir)(JNIEnv *jni, jobject cls, jobject path)
1095 {
1096   const char *pathstr = 0;
1097   struct dir dir;
1098   wrapper r = 0;
1099
1100   pathstr = get_cstring(jni, path); if (!pathstr) goto end;
1101   INIT_NATIVE(dir, &dir);
1102   dir.d = opendir(pathstr);
1103   if (!dir.d) {
1104     except_syserror(jni, SYSERR, errno,
1105                     "failed to open directory `%s'", pathstr);
1106     goto end;
1107   }
1108   r = wrap(jni, &dir_type, &dir);
1109 end:
1110   put_cstring(jni, path, pathstr);
1111   return (r);
1112 }
1113
1114 JNIEXPORT jbyteArray JNIFUNC(readdir)(JNIEnv *jni, jobject cls,
1115                                       jobject path, jobject wdir)
1116 {
1117   const char *pathstr = 0;
1118   struct dir dir;
1119   struct dirent *d;
1120   jbyteArray r = 0;
1121
1122   if (unwrap(jni, &dir, &dir_type, wdir)) goto end;
1123   if (!dir.d) { except(jni, ARGERR, "directory has been closed"); goto end; }
1124   errno = 0; d = readdir(dir.d);
1125   if (errno) {
1126     pathstr = get_cstring(jni, path); if (!pathstr) goto end;
1127     except_syserror(jni, SYSERR, errno,
1128                     "failed to read directory `%s'", pathstr);
1129     goto end;
1130   }
1131   if (d) r = wrap_cstring(jni, d->d_name);
1132 end:
1133   put_cstring(jni, path, pathstr);
1134   return (r);
1135 }
1136
1137 JNIEXPORT void JNIFUNC(closedir)(JNIEnv *jni, jobject cls,
1138                                  jobject path, jobject wdir)
1139 {
1140   const char *pathstr = 0;
1141   struct dir dir;
1142
1143   if (unwrap(jni, &dir, &dir_type, wdir)) goto end;
1144   if (!dir.d) goto end;
1145   if (closedir(dir.d)) {
1146     pathstr = get_cstring(jni, path); if (!pathstr) goto end;
1147     except_syserror(jni, SYSERR, errno,
1148                     "failed to close directory `%s'", pathstr);
1149     goto end;
1150   }
1151   dir.d = 0;
1152   if (update_wrapper(jni, &dir_type, wdir, &dir)) goto end;
1153 end:
1154   put_cstring(jni, path, pathstr);
1155 }
1156
1157 /*----- Triggers ----------------------------------------------------------*/
1158
1159 /* A trigger is a gadget for waking up a thread which is blocking on I/O,
1160  * and it's used to implement interruptability.
1161  *
1162  * Really, a trigger is a pipe.  A `blocking' I/O operation secretly uses
1163  * select(2) to block on the descriptor of interest /and/ the read side of
1164  * the trigger pipe.  To wake up a thread that's blocked, we just write a
1165  * byte (nobody cares /which/ byte) to the write end.
1166  */
1167
1168 struct trigger {
1169   struct native_base _base;
1170   int rfd, wfd;
1171 };
1172 static const struct native_type trigger_type =
1173         { "trigger", sizeof(struct trigger), 0x65ffd8b4 };
1174
1175 JNIEXPORT wrapper JNICALL JNIFUNC(make_1trigger)(JNIEnv *jni, jobject cls)
1176 {
1177   struct trigger trig;
1178   int fd[2];
1179   int i;
1180   wrapper ret = 0;
1181
1182   fd[0] = fd[1] = -1;
1183   if (pipe(fd)) {
1184     except_syserror(jni, SYSERR, errno, "failed to create pipe");
1185     goto end;
1186   }
1187   for (i = 0; i < 2; i++) {
1188     if (set_nonblocking(jni, fd[i], 1) < 0 || set_closeonexec(jni, fd[i]))
1189       goto end;
1190   }
1191
1192   INIT_NATIVE(trigger, &trig);
1193   trig.rfd = fd[0]; fd[0] = -1;
1194   trig.wfd = fd[1]; fd[1] = -1;
1195   ret = wrap(jni, &trigger_type, &trig);
1196
1197 end:
1198   for (i = 0; i < 2; i++)
1199     if (fd[i] != -1) close(fd[i]);
1200   return (ret);
1201 }
1202
1203 JNIEXPORT void JNICALL JNIFUNC(destroy_1trigger)(JNIEnv *jni, jobject cls,
1204                                                 wrapper wtrig)
1205 {
1206   struct trigger trig;
1207
1208   if (unwrap(jni, &trig, &trigger_type, wtrig)) return;
1209   if (trig.rfd != -1) { close(trig.rfd); trig.rfd = -1; }
1210   if (trig.wfd != -1) { close(trig.wfd); trig.wfd = -1; }
1211   update_wrapper(jni, &trigger_type, wtrig, &trig);
1212 }
1213
1214 JNIEXPORT void JNICALL JNIFUNC(reset_1trigger)(JNIEnv *jni, jobject cls,
1215                                               wrapper wtrig)
1216 {
1217   struct trigger trig;
1218   char buf[64];
1219   ssize_t n;
1220
1221   if (unwrap(jni, &trig, &trigger_type, wtrig)) return;
1222   for (;;) {
1223     n = read(trig.rfd, buf, sizeof(buf));
1224     if (n > 0) continue;
1225     assert(n < 0);
1226     if (errno == EAGAIN || errno == EWOULDBLOCK) break;
1227     else {
1228       except_syserror(jni, SYSERR, errno, "failed to reset trigger");
1229       break;
1230     }
1231   }
1232 }
1233
1234 JNIEXPORT void JNICALL JNIFUNC(trigger)(JNIEnv *jni, jobject cls,
1235                                         wrapper wtrig)
1236 {
1237   struct trigger trig;
1238   ssize_t n;
1239   char c = 0;
1240
1241   if (unwrap(jni, &trig, &trigger_type, wtrig)) return;
1242   n = write(trig.wfd, &c, 1);
1243   if (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK)
1244     except_syserror(jni, SYSERR, errno, "failed to pull trigger");
1245 }
1246
1247 /*----- A tunnel supplied by Java -----------------------------------------*/
1248
1249 struct tunnel {
1250   const tunnel_ops *ops;
1251   sel_file f;
1252   struct peer *p;
1253 };
1254
1255 static const struct tunnel_ops tun_java;
1256
1257 static int t_init(void) { return (0); }
1258
1259 static void t_read(int fd, unsigned mode, void *v)
1260 {
1261   tunnel *t = v;
1262   ssize_t n;
1263   buf b;
1264
1265   n = read(fd, buf_i, sizeof(buf_i));
1266   if (n < 0) {
1267     a_warn("TUN", "%s", p_ifname(t->p), "java",
1268            "read-error", "?ERRNO", A_END);
1269     return;
1270   }
1271   IF_TRACING(T_TUNNEL, {
1272     trace(T_TUNNEL, "tun-java: packet arrived");
1273     trace_block(T_PACKET, "tunnel: packet contents", buf_i, n);
1274   })
1275   buf_init(&b, buf_i, n);
1276   p_tun(t->p, &b);
1277 }
1278
1279 static tunnel *t_create(peer *p, int fd, char **ifn)
1280 {
1281   JNIEnv *jni = jni_tripe;
1282   tunnel *t = 0;
1283   const char *name = p_name(p);
1284   jbyteArray jname;
1285   size_t n = strlen(p_name(p));
1286   jclass cls, metacls;
1287   jstring jclsname, jexcmsg;
1288   const char *clsname, *excmsg;
1289   jmethodID mid;
1290   jthrowable exc;
1291
1292   assert(jni);
1293
1294   jname = wrap_cstring(jni, name);
1295   cls = (*jni)->FindClass(jni, SYSCLS); assert(cls);
1296   mid = (*jni)->GetStaticMethodID(jni, cls, "getTunnelFd", "([B)I");
1297   assert(mid);
1298   fd = (*jni)->CallStaticIntMethod(jni, cls, mid, jname);
1299
1300   exc = (*jni)->ExceptionOccurred(jni);
1301   if (exc) {
1302     cls = (*jni)->GetObjectClass(jni, exc);
1303     metacls = (*jni)->GetObjectClass(jni, cls);
1304     mid = (*jni)->GetMethodID(jni, metacls,
1305                               "getName", "()L"STRCLS";");
1306     assert(mid);
1307     jclsname = (*jni)->CallObjectMethod(jni, cls, mid);
1308     clsname = (*jni)->GetStringUTFChars(jni, jclsname, 0);
1309     mid = (*jni)->GetMethodID(jni, cls,
1310                               "getMessage", "()L"STRCLS";");
1311     jexcmsg = (*jni)->CallObjectMethod(jni, exc, mid);
1312     excmsg = (*jni)->GetStringUTFChars(jni, jexcmsg, 0);
1313     a_warn("TUN", "-", "java", "get-tunnel-fd-failed",
1314            "%s", clsname, "%s", excmsg, A_END);
1315     (*jni)->ReleaseStringUTFChars(jni, jclsname, clsname);
1316     (*jni)->ReleaseStringUTFChars(jni, jexcmsg, excmsg);
1317     (*jni)->ExceptionClear(jni);
1318     goto end;
1319   }
1320
1321   t = CREATE(tunnel);
1322   t->ops = &tun_java;
1323   t->p = p;
1324   sel_initfile(&sel, &t->f, fd, SEL_READ, t_read, t);
1325
1326   if (!*ifn) {
1327     *ifn = xmalloc(n + 5);
1328     sprintf(*ifn, "vpn-%s", name);
1329   }
1330
1331 end:
1332   return (t);
1333 }
1334
1335 static void t_inject(tunnel *t, buf *b)
1336 {
1337   IF_TRACING(T_TUNNEL, {
1338     trace(T_TUNNEL, "tun-java: inject decrypted packet");
1339     trace_block(T_PACKET, "tunnel: packet contents", BBASE(b), BLEN(b));
1340   })
1341   DISCARD(write(t->f.fd, BBASE(b), BLEN(b)));
1342 }
1343
1344 static void t_destroy(tunnel *t)
1345   { sel_rmfile(&t->f); close(t->f.fd); DESTROY(t); }
1346
1347 static const struct tunnel_ops tun_java = {
1348   "java", 0,
1349   /*      init */ t_init,
1350   /*    create */ t_create,
1351   /* setifname */ 0,
1352   /*    inject */ t_inject,
1353   /*   destroy */ t_destroy
1354 };
1355
1356
1357 JNIEXPORT jint JNICALL JNIFUNC(open_1tun)(JNIEnv *jni, jobject cls)
1358 {
1359   int ret = -1;
1360   int fd = -1;
1361   struct ifreq iff;
1362
1363   if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
1364     except_syserror(jni, SYSERR, errno, "failed to open tunnel device");
1365     goto end;
1366   }
1367
1368   if (set_nonblocking(jni, fd, 1) || set_closeonexec(jni, fd)) goto end;
1369
1370   memset(&iff, 0, sizeof(iff));
1371   iff.ifr_name[0] = 0;
1372   iff.ifr_flags = IFF_TUN | IFF_NO_PI;
1373   if (ioctl(fd, TUNSETIFF, &iff) < 0) {
1374     except_syserror(jni, SYSERR, errno, "failed to configure tunnel device");
1375     goto end;
1376   }
1377
1378   ret = fd; fd = -1;
1379
1380 end:
1381   if (fd != -1) close(fd);
1382   return (ret);
1383 }
1384
1385 /*----- A custom noise source ---------------------------------------------*/
1386
1387 static void javanoise(rand_pool *r)
1388 {
1389   JNIEnv *jni = jni_tripe;
1390   jclass cls;
1391   jmethodID mid;
1392   jbyteArray v;
1393   jbyte *p;
1394   jsize n;
1395
1396   noise_devrandom(r);
1397
1398   assert(jni);
1399   cls = (*jni)->FindClass(jni, RANDCLS); assert(cls);
1400   mid = (*jni)->GetStaticMethodID(jni, cls, "getSeed", "(I)[B"); assert(mid);
1401   v = (*jni)->CallStaticObjectMethod(jni, cls, mid, 32);
1402   if (v) {
1403     n = (*jni)->GetArrayLength(jni, v);
1404     p = (*jni)->GetByteArrayElements(jni, v, 0);
1405     rand_add(r, p, n, n);
1406     (*jni)->ReleaseByteArrayElements(jni, v, p, JNI_ABORT);
1407   }
1408   if ((*jni)->ExceptionOccurred(jni)) {
1409     (*jni)->ExceptionDescribe(jni);
1410     (*jni)->ExceptionClear(jni);
1411   }
1412 }
1413
1414 static const rand_source javasource = { javanoise, noise_timer };
1415
1416 /*----- Embedding the TrIPE server ----------------------------------------*/
1417
1418 static void lock_tripe(JNIEnv *jni)
1419 {
1420   jclass cls = (*jni)->FindClass(jni, LOCKCLS); assert(cls);
1421   (*jni)->MonitorEnter(jni, cls);
1422 }
1423
1424 static void unlock_tripe(JNIEnv *jni)
1425 {
1426   jclass cls = (*jni)->FindClass(jni, LOCKCLS); assert(cls);
1427   (*jni)->MonitorExit(jni, cls);
1428 }
1429
1430 #define STATES(_)                                                       \
1431         _(INIT)                                                         \
1432         _(RESOLVE)                                                      \
1433         _(KEYS)                                                         \
1434         _(BIND)                                                         \
1435         _(READY)                                                        \
1436         _(RUNNING)
1437
1438 enum {
1439 #define DEFTAG(st) st,
1440   STATES(DEFTAG)
1441 #undef DEFTAG
1442   MAXSTATE
1443 };
1444
1445 static const char *statetab[] = {
1446 #define DEFNAME(st) #st,
1447   STATES(DEFNAME)
1448 #undef DEFNAME
1449 };
1450
1451 static unsigned state = INIT;
1452 static int clientsk = -1;
1453
1454 static const char *statename(unsigned st)
1455 {
1456   if (st >= MAXSTATE) return ("<invalid>");
1457   else return (statetab[st]);
1458 }
1459
1460 static int ensure_state(JNIEnv *jni, unsigned want)
1461 {
1462   unsigned cur;
1463
1464   lock_tripe(jni);
1465   cur = state;
1466   unlock_tripe(jni);
1467
1468   if (cur != want) {
1469     except(jni, STERR, "server is in state %s (%u), not %s (%u)",
1470            statename(cur), cur, statename(want), want);
1471     return (-1);
1472   }
1473   return (0);
1474 }
1475
1476 JNIEXPORT void JNICALL JNIFUNC(base_1init)(JNIEnv *jni, jobject cls)
1477 {
1478   int fd[2];
1479   int i;
1480
1481   for (i = 0; i < N(fd); i++) fd[i] = -1;
1482
1483   lock_tripe(jni);
1484   jni_tripe = jni;
1485   if (ensure_state(jni, INIT)) goto end;
1486
1487   if (socketpair(PF_UNIX, SOCK_STREAM, 0, fd)) {
1488     except_syserror(jni, SYSERR, errno, "failed to create socket pair");
1489     goto end;
1490   }
1491
1492   clientsk = fd[0]; fd[0] = -1;
1493
1494   rand_noisesrc(RAND_GLOBAL, &javasource);
1495   rand_seed(RAND_GLOBAL, MAXHASHSZ);
1496   lp_init();
1497   a_create(fd[1], fd[1], AF_NOTE | AF_WARN | AF_TRACE); fd[1] = -1;
1498   a_switcherr();
1499   p_addtun(&tun_java); p_setdflttun(&tun_java);
1500   p_init();
1501   kx_init();
1502
1503   state++;
1504
1505 end:
1506   for (i = 0; i < N(fd); i++) if (fd[i] != -1) close(fd[i]);
1507   jni_tripe = 0;
1508   unlock_tripe(jni);
1509 }
1510
1511 JNIEXPORT void JNICALL JNIFUNC(setup_1resolver)(JNIEnv *jni, jobject cls)
1512 {
1513   lock_tripe(jni);
1514   if (ensure_state(jni, RESOLVE)) goto end;
1515
1516   if (a_init())
1517     { except(jni, INITERR, "failed to initialize resolver"); return; }
1518
1519   state++;
1520
1521 end:
1522   unlock_tripe(jni);
1523 }
1524
1525 JNIEXPORT void JNICALL JNIFUNC(load_1keys)(JNIEnv *jni, jobject cls,
1526                                           jobject privstr, jobject pubstr,
1527                                           jobject tagstr)
1528 {
1529   const char *priv = 0, *pub = 0, *tag = 0;
1530
1531   lock_tripe(jni);
1532   if (ensure_state(jni, KEYS)) return;
1533
1534   priv = get_cstring(jni, privstr); if (!priv) goto end;
1535   pub = get_cstring(jni, pubstr); if (!pub) goto end;
1536   tag = get_cstring(jni, tagstr); if (!tag) goto end;
1537
1538   if (km_init(priv, pub, tag))
1539     { except(jni, INITERR, "failed to load initial keys"); goto end; }
1540
1541   state++;
1542
1543 end:
1544   put_cstring(jni, privstr, priv);
1545   put_cstring(jni, pubstr, pub);
1546   put_cstring(jni, tagstr, tag);
1547   unlock_tripe(jni);
1548 }
1549
1550 JNIEXPORT void JNICALL JNIFUNC(unload_1keys)(JNIEnv *jni, jobject cls)
1551 {
1552   lock_tripe(jni);
1553   if (ensure_state(jni, KEYS + 1)) goto end;
1554
1555   km_clear();
1556
1557   state--;
1558
1559 end:
1560   unlock_tripe(jni);
1561 }
1562
1563 JNIEXPORT void JNICALL JNIFUNC(bind)(JNIEnv *jni, jobject cls,
1564                                      jbyteArray hoststr, jbyteArray svcstr)
1565 {
1566   const char *host = 0, *svc = 0;
1567   struct addrinfo hint, *ai = 0;
1568   int err;
1569
1570   lock_tripe(jni);
1571   if (ensure_state(jni, BIND)) goto end;
1572
1573   if (hoststr) { host = get_cstring(jni, hoststr); if (!host) goto end; }
1574   svc = get_cstring(jni, svcstr); if (!svc) goto end;
1575
1576   hint.ai_socktype = SOCK_DGRAM;
1577   hint.ai_family = AF_UNSPEC;
1578   hint.ai_protocol = IPPROTO_UDP;
1579   hint.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
1580   err = getaddrinfo(host, svc, &hint, &ai);
1581   if (err) {
1582     except(jni, NAMEERR, "failed to resolve %c%s%c, port `%s': %s",
1583            host ? '`' : '<', host ? host : "nil", host ? '\'' : '>',
1584            svc, gai_strerror(err));
1585     goto end;
1586   }
1587
1588   if (p_bind(ai))
1589     { except(jni, INITERR, "failed to bind master socket"); goto end; }
1590
1591   state++;
1592
1593 end:
1594   if (ai) freeaddrinfo(ai);
1595   put_cstring(jni, hoststr, host);
1596   put_cstring(jni, svcstr, svc);
1597   unlock_tripe(jni);
1598 }
1599
1600 JNIEXPORT void JNICALL JNIFUNC(unbind)(JNIEnv *jni, jobject cls)
1601 {
1602   lock_tripe(jni);
1603   if (ensure_state(jni, BIND + 1)) goto end;
1604
1605   p_unbind();
1606
1607   state--;
1608
1609 end:
1610   unlock_tripe(jni);
1611 }
1612
1613 JNIEXPORT void JNICALL JNIFUNC(mark)(JNIEnv *jni, jobject cls, jint seq)
1614 {
1615   lock_tripe(jni);
1616   a_notify("MARK", "%d", seq, A_END);
1617   unlock_tripe(jni);
1618 }
1619
1620 JNIEXPORT void JNICALL JNIFUNC(run)(JNIEnv *jni, jobject cls)
1621 {
1622   lock_tripe(jni);
1623   if (ensure_state(jni, READY)) goto end;
1624   assert(!jni_tripe);
1625   jni_tripe = jni;
1626   state = RUNNING;
1627   unlock_tripe(jni);
1628
1629   lp_run();
1630
1631   lock_tripe(jni);
1632   jni_tripe = 0;
1633   state = READY;
1634
1635 end:
1636   unlock_tripe(jni);
1637 }
1638
1639 static int check_buffer_bounds(JNIEnv *jni, const char *what,
1640                                jbyteArray buf, jint start, jint len)
1641 {
1642   jsize bufsz;
1643   jclass cls;
1644
1645   cls = (*jni)->FindClass(jni, "[B"); assert(cls);
1646   if (!(*jni)->IsInstanceOf(jni, buf, cls)) {
1647     except(jni, ARGERR,
1648            "expected a byte array");
1649     return (-1);
1650   }
1651   bufsz = (*jni)->GetArrayLength(jni, buf);
1652   if (start > bufsz) {
1653     except(jni, BOUNDSERR,
1654            "bad %s buffer bounds: start %d > buffer size %d", start, bufsz);
1655     return (-1);
1656   }
1657   if (len > bufsz - start) {
1658     except(jni, BOUNDSERR,
1659            "bad %s buffer bounds: length %d > remaining buffer size %d",
1660            len, bufsz - start);
1661     return (-1);
1662   }
1663   return (0);
1664 }
1665
1666 JNIEXPORT void JNICALL JNIFUNC(send)(JNIEnv *jni, jobject cls,
1667                                      jbyteArray buf,
1668                                      jint start, jint len,
1669                                      wrapper wtrig)
1670 {
1671   struct trigger trig;
1672   int rc, maxfd;
1673   ssize_t n;
1674   fd_set rfds, wfds;
1675   jbyte *p = 0;
1676
1677   if (ensure_state(jni, RUNNING)) goto end;
1678
1679   if (unwrap(jni, &trig, &trigger_type, wtrig)) goto end;
1680   if (check_buffer_bounds(jni, "send", buf, start, len)) goto end;
1681
1682   p = (*jni)->GetByteArrayElements(jni, buf, 0);
1683   if (!p) goto end;
1684
1685   maxfd = trig.rfd;
1686   if (maxfd < clientsk) maxfd = clientsk;
1687   while (len) {
1688     FD_ZERO(&rfds); FD_SET(trig.rfd, &rfds);
1689     FD_ZERO(&wfds); FD_SET(clientsk, &wfds);
1690     rc = select(maxfd + 1, &rfds, &wfds, 0, 0); if (rc < 0) goto err;
1691     if (FD_ISSET(trig.rfd, &rfds)) break;
1692     if (FD_ISSET(clientsk, &wfds)) {
1693       n = send(clientsk, p + start, len, 0);
1694       if (n >= 0) { start += n; len -= n; }
1695       else if (errno != EAGAIN && errno != EWOULDBLOCK) goto err;
1696     }
1697   }
1698   goto end;
1699
1700 err:
1701   except_syserror(jni, SYSERR, errno, "failed to send on connection");
1702 end:
1703   if (p) (*jni)->ReleaseByteArrayElements(jni, buf, p, JNI_ABORT);
1704   return;
1705 }
1706
1707 JNIEXPORT jint JNICALL JNIFUNC(recv)(JNIEnv *jni, jobject cls,
1708                                      jbyteArray buf,
1709                                      jint start, jint len,
1710                                      wrapper wtrig)
1711 {
1712   struct trigger trig;
1713   int maxfd;
1714   fd_set rfds;
1715   jbyte *p = 0;
1716   jint rc = -1;
1717
1718   lock_tripe(jni);
1719   if (clientsk == -1) {
1720     except(jni, STERR, "client connection not established");
1721     unlock_tripe(jni);
1722     goto end;
1723   }
1724   unlock_tripe(jni);
1725
1726   if (unwrap(jni, &trig, &trigger_type, wtrig)) goto end;
1727   if (check_buffer_bounds(jni, "send", buf, start, len)) goto end;
1728
1729   p = (*jni)->GetByteArrayElements(jni, buf, 0);
1730   if (!p) goto end;
1731
1732   maxfd = trig.rfd;
1733   if (maxfd < clientsk) maxfd = clientsk;
1734   for (;;) {
1735     FD_ZERO(&rfds); FD_SET(trig.rfd, &rfds); FD_SET(clientsk, &rfds);
1736     rc = select(maxfd + 1, &rfds, 0, 0, 0); if (rc < 0) goto err;
1737     if (FD_ISSET(trig.rfd, &rfds)) {
1738       break;
1739     }
1740     if (FD_ISSET(clientsk, &rfds)) {
1741       rc = recv(clientsk, p + start, len, 0);
1742       if (rc >= 0) break;
1743       else if (errno != EAGAIN && errno != EWOULDBLOCK) goto err;
1744     }
1745   }
1746   if (!rc) rc = -1;
1747   goto end;
1748
1749 err:
1750   except_syserror(jni, SYSERR, errno, "failed to read from connection");
1751 end:
1752   if (p) (*jni)->ReleaseByteArrayElements(jni, buf, p, 0);
1753   return (rc);
1754 }
1755
1756 /*----- That's all, folks -------------------------------------------------*/