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