From 84adefa331c4159d432d22840663c38f155cd4c1 Mon Sep 17 00:00:00 2001 From: Erlang/OTP Date: Fri, 20 Nov 2009 14:54:40 +0000 Subject: The R13B03 release. --- lib/erl_interface/AUTHORS | 9 + lib/erl_interface/Makefile | 32 + lib/erl_interface/aclocal.m4 | 1 + lib/erl_interface/configure.in | 443 ++++ lib/erl_interface/doc/html/.gitignore | 0 lib/erl_interface/doc/man1/.gitignore | 0 lib/erl_interface/doc/man3/.gitignore | 0 lib/erl_interface/doc/pdf/.gitignore | 0 lib/erl_interface/doc/src/Makefile | 129 ++ lib/erl_interface/doc/src/book.xml | 49 + lib/erl_interface/doc/src/ei.xml | 728 +++++++ lib/erl_interface/doc/src/ei_connect.xml | 639 ++++++ lib/erl_interface/doc/src/ei_users_guide.xml | 612 ++++++ lib/erl_interface/doc/src/erl_call.xml | 240 +++ lib/erl_interface/doc/src/erl_connect.xml | 566 ++++++ lib/erl_interface/doc/src/erl_error.xml | 136 ++ lib/erl_interface/doc/src/erl_eterm.xml | 675 +++++++ lib/erl_interface/doc/src/erl_format.xml | 141 ++ lib/erl_interface/doc/src/erl_global.xml | 141 ++ lib/erl_interface/doc/src/erl_interface.xml | 625 ++++++ lib/erl_interface/doc/src/erl_malloc.xml | 200 ++ lib/erl_interface/doc/src/erl_marshal.xml | 272 +++ lib/erl_interface/doc/src/fascicules.xml | 24 + lib/erl_interface/doc/src/make.dep | 24 + lib/erl_interface/doc/src/note.gif | Bin 0 -> 1539 bytes lib/erl_interface/doc/src/notes.xml | 535 +++++ lib/erl_interface/doc/src/notes_history.xml | 367 ++++ lib/erl_interface/doc/src/part.xml | 33 + lib/erl_interface/doc/src/part_erl_interface.xml | 33 + lib/erl_interface/doc/src/part_notes.xml | 38 + lib/erl_interface/doc/src/part_notes_history.xml | 36 + lib/erl_interface/doc/src/ref_man.xml | 55 + lib/erl_interface/doc/src/ref_man_ei.xml | 47 + .../doc/src/ref_man_erl_interface.xml | 52 + lib/erl_interface/doc/src/registry.xml | 611 ++++++ lib/erl_interface/doc/src/warning.gif | Bin 0 -> 1498 bytes lib/erl_interface/include/ei.h | 785 ++++++++ lib/erl_interface/include/ei_connect.h | 26 + lib/erl_interface/include/eicode.h | 26 + lib/erl_interface/include/erl_interface.h | 449 +++++ lib/erl_interface/info | 2 + lib/erl_interface/priv/.gitignore | 0 lib/erl_interface/src/INSTALL | 182 ++ lib/erl_interface/src/Makefile | 31 + lib/erl_interface/src/Makefile.in | 903 +++++++++ lib/erl_interface/src/README | 186 ++ lib/erl_interface/src/README.internal | 285 +++ lib/erl_interface/src/auxdir/config.guess | 1 + lib/erl_interface/src/auxdir/config.h.in | 277 +++ lib/erl_interface/src/auxdir/config.sub | 1 + lib/erl_interface/src/auxdir/install-sh | 1 + lib/erl_interface/src/connect/ei_connect.c | 1738 ++++++++++++++++ lib/erl_interface/src/connect/ei_connect_int.h | 114 ++ lib/erl_interface/src/connect/ei_resolve.c | 645 ++++++ lib/erl_interface/src/connect/ei_resolve.h | 24 + lib/erl_interface/src/connect/eirecv.c | 280 +++ lib/erl_interface/src/connect/eirecv.h | 26 + lib/erl_interface/src/connect/eisend.h | 41 + lib/erl_interface/src/connect/send.c | 125 ++ lib/erl_interface/src/connect/send_exit.c | 101 + lib/erl_interface/src/connect/send_reg.c | 122 ++ lib/erl_interface/src/decode/decode_atom.c | 42 + lib/erl_interface/src/decode/decode_big.c | 331 +++ lib/erl_interface/src/decode/decode_bignum.c | 75 + lib/erl_interface/src/decode/decode_binary.c | 42 + lib/erl_interface/src/decode/decode_boolean.c | 57 + lib/erl_interface/src/decode/decode_char.c | 69 + lib/erl_interface/src/decode/decode_double.c | 39 + lib/erl_interface/src/decode/decode_fun.c | 123 ++ lib/erl_interface/src/decode/decode_intlist.c | 82 + lib/erl_interface/src/decode/decode_list_header.c | 45 + lib/erl_interface/src/decode/decode_long.c | 86 + lib/erl_interface/src/decode/decode_longlong.c | 100 + lib/erl_interface/src/decode/decode_pid.c | 54 + lib/erl_interface/src/decode/decode_port.c | 53 + lib/erl_interface/src/decode/decode_ref.c | 94 + lib/erl_interface/src/decode/decode_skip.c | 90 + lib/erl_interface/src/decode/decode_skip.h | 27 + lib/erl_interface/src/decode/decode_string.c | 85 + lib/erl_interface/src/decode/decode_trace.c | 43 + lib/erl_interface/src/decode/decode_tuple_header.c | 47 + lib/erl_interface/src/decode/decode_ulong.c | 78 + lib/erl_interface/src/decode/decode_ulonglong.c | 83 + lib/erl_interface/src/decode/decode_version.c | 38 + lib/erl_interface/src/depend.mk | 1133 +++++++++++ lib/erl_interface/src/eidefs.mk.in | 31 + lib/erl_interface/src/encode/eicode.h | 69 + lib/erl_interface/src/encode/encode_atom.c | 51 + lib/erl_interface/src/encode/encode_big.c | 84 + lib/erl_interface/src/encode/encode_bignum.c | 81 + lib/erl_interface/src/encode/encode_binary.c | 41 + lib/erl_interface/src/encode/encode_boolean.c | 47 + lib/erl_interface/src/encode/encode_char.c | 38 + lib/erl_interface/src/encode/encode_double.c | 42 + lib/erl_interface/src/encode/encode_fun.c | 82 + lib/erl_interface/src/encode/encode_list_header.c | 45 + lib/erl_interface/src/encode/encode_long.c | 64 + lib/erl_interface/src/encode/encode_longlong.c | 103 + lib/erl_interface/src/encode/encode_pid.c | 52 + lib/erl_interface/src/encode/encode_port.c | 51 + lib/erl_interface/src/encode/encode_ref.c | 59 + lib/erl_interface/src/encode/encode_string.c | 77 + lib/erl_interface/src/encode/encode_trace.c | 36 + lib/erl_interface/src/encode/encode_tuple_header.c | 49 + lib/erl_interface/src/encode/encode_ulong.c | 57 + lib/erl_interface/src/encode/encode_ulonglong.c | 94 + lib/erl_interface/src/encode/encode_version.c | 35 + lib/erl_interface/src/epmd/ei_epmd.h | 66 + lib/erl_interface/src/epmd/epmd_port.c | 299 +++ lib/erl_interface/src/epmd/epmd_publish.c | 228 +++ lib/erl_interface/src/epmd/epmd_unpublish.c | 106 + lib/erl_interface/src/legacy/decode_term.c | 142 ++ lib/erl_interface/src/legacy/encode_term.c | 53 + lib/erl_interface/src/legacy/erl_config.h | 22 + lib/erl_interface/src/legacy/erl_connect.c | 457 +++++ lib/erl_interface/src/legacy/erl_connect.h | 24 + lib/erl_interface/src/legacy/erl_error.c | 180 ++ lib/erl_interface/src/legacy/erl_error.h | 25 + lib/erl_interface/src/legacy/erl_eterm.c | 1308 ++++++++++++ lib/erl_interface/src/legacy/erl_eterm.h | 61 + lib/erl_interface/src/legacy/erl_fix_alloc.c | 193 ++ lib/erl_interface/src/legacy/erl_fix_alloc.h | 26 + lib/erl_interface/src/legacy/erl_format.c | 729 +++++++ lib/erl_interface/src/legacy/erl_format.h | 22 + lib/erl_interface/src/legacy/erl_global.h | 27 + lib/erl_interface/src/legacy/erl_internal.h | 47 + lib/erl_interface/src/legacy/erl_malloc.c | 239 +++ lib/erl_interface/src/legacy/erl_malloc.h | 26 + lib/erl_interface/src/legacy/erl_marshal.c | 2117 ++++++++++++++++++++ lib/erl_interface/src/legacy/erl_marshal.h | 29 + lib/erl_interface/src/legacy/erl_resolve.c | 106 + lib/erl_interface/src/legacy/erl_timeout.c | 161 ++ lib/erl_interface/src/legacy/erl_timeout.h | 74 + lib/erl_interface/src/legacy/global_names.c | 109 + lib/erl_interface/src/legacy/global_register.c | 110 + lib/erl_interface/src/legacy/global_unregister.c | 102 + lib/erl_interface/src/legacy/global_whereis.c | 91 + lib/erl_interface/src/legacy/portability.h | 33 + lib/erl_interface/src/misc/ei_compat.c | 39 + lib/erl_interface/src/misc/ei_decode_term.c | 156 ++ lib/erl_interface/src/misc/ei_decode_term.h | 31 + lib/erl_interface/src/misc/ei_format.c | 466 +++++ lib/erl_interface/src/misc/ei_format.h | 26 + lib/erl_interface/src/misc/ei_internal.h | 157 ++ lib/erl_interface/src/misc/ei_locking.c | 164 ++ lib/erl_interface/src/misc/ei_locking.h | 76 + lib/erl_interface/src/misc/ei_malloc.c | 41 + lib/erl_interface/src/misc/ei_malloc.h | 28 + lib/erl_interface/src/misc/ei_portio.c | 377 ++++ lib/erl_interface/src/misc/ei_portio.h | 35 + lib/erl_interface/src/misc/ei_printterm.c | 342 ++++ lib/erl_interface/src/misc/ei_printterm.h | 24 + lib/erl_interface/src/misc/ei_pthreads.c | 226 +++ lib/erl_interface/src/misc/ei_trace.c | 56 + lib/erl_interface/src/misc/ei_trace.h | 26 + lib/erl_interface/src/misc/ei_x_encode.c | 255 +++ lib/erl_interface/src/misc/ei_x_encode.h | 31 + lib/erl_interface/src/misc/eidef.h | 51 + lib/erl_interface/src/misc/eiext.h | 35 + lib/erl_interface/src/misc/eimd5.c | 319 +++ lib/erl_interface/src/misc/eimd5.h | 48 + lib/erl_interface/src/misc/get_type.c | 149 ++ lib/erl_interface/src/misc/putget.h | 85 + lib/erl_interface/src/misc/show_msg.c | 584 ++++++ lib/erl_interface/src/misc/show_msg.h | 27 + lib/erl_interface/src/not_used/ei_send.c | 104 + lib/erl_interface/src/not_used/ei_send_reg.c | 107 + lib/erl_interface/src/not_used/send_link.c | 102 + lib/erl_interface/src/not_used/whereis.c | 70 + lib/erl_interface/src/prog/ei_fake_prog.c | 303 +++ lib/erl_interface/src/prog/erl_call.c | 906 +++++++++ lib/erl_interface/src/prog/erl_fake_prog.c | 250 +++ lib/erl_interface/src/prog/erl_start.c | 735 +++++++ lib/erl_interface/src/prog/erl_start.h | 46 + lib/erl_interface/src/registry/hash.h | 47 + lib/erl_interface/src/registry/hash_dohash.c | 45 + lib/erl_interface/src/registry/hash_foreach.c | 44 + lib/erl_interface/src/registry/hash_freetab.c | 58 + lib/erl_interface/src/registry/hash_insert.c | 108 + lib/erl_interface/src/registry/hash_isprime.c | 57 + lib/erl_interface/src/registry/hash_lookup.c | 42 + lib/erl_interface/src/registry/hash_newtab.c | 52 + lib/erl_interface/src/registry/hash_remove.c | 87 + lib/erl_interface/src/registry/hash_resize.c | 67 + lib/erl_interface/src/registry/hash_rlookup.c | 43 + lib/erl_interface/src/registry/reg.h | 46 + lib/erl_interface/src/registry/reg_close.c | 68 + lib/erl_interface/src/registry/reg_delete.c | 36 + lib/erl_interface/src/registry/reg_dirty.c | 36 + lib/erl_interface/src/registry/reg_dump.c | 321 +++ lib/erl_interface/src/registry/reg_free.c | 47 + lib/erl_interface/src/registry/reg_get.c | 94 + lib/erl_interface/src/registry/reg_getf.c | 35 + lib/erl_interface/src/registry/reg_geti.c | 35 + lib/erl_interface/src/registry/reg_getp.c | 39 + lib/erl_interface/src/registry/reg_gets.c | 38 + lib/erl_interface/src/registry/reg_make.c | 49 + lib/erl_interface/src/registry/reg_open.c | 41 + lib/erl_interface/src/registry/reg_purge.c | 76 + lib/erl_interface/src/registry/reg_resize.c | 36 + lib/erl_interface/src/registry/reg_restore.c | 323 +++ lib/erl_interface/src/registry/reg_set.c | 78 + lib/erl_interface/src/registry/reg_setf.c | 61 + lib/erl_interface/src/registry/reg_seti.c | 62 + lib/erl_interface/src/registry/reg_setp.c | 62 + lib/erl_interface/src/registry/reg_sets.c | 65 + lib/erl_interface/src/registry/reg_stat.c | 41 + lib/erl_interface/src/registry/reg_tabstat.c | 37 + lib/erl_interface/vsn.mk | 1 + 209 files changed, 34134 insertions(+) create mode 100644 lib/erl_interface/AUTHORS create mode 100644 lib/erl_interface/Makefile create mode 120000 lib/erl_interface/aclocal.m4 create mode 100644 lib/erl_interface/configure.in create mode 100644 lib/erl_interface/doc/html/.gitignore create mode 100644 lib/erl_interface/doc/man1/.gitignore create mode 100644 lib/erl_interface/doc/man3/.gitignore create mode 100644 lib/erl_interface/doc/pdf/.gitignore create mode 100644 lib/erl_interface/doc/src/Makefile create mode 100644 lib/erl_interface/doc/src/book.xml create mode 100644 lib/erl_interface/doc/src/ei.xml create mode 100644 lib/erl_interface/doc/src/ei_connect.xml create mode 100644 lib/erl_interface/doc/src/ei_users_guide.xml create mode 100644 lib/erl_interface/doc/src/erl_call.xml create mode 100644 lib/erl_interface/doc/src/erl_connect.xml create mode 100644 lib/erl_interface/doc/src/erl_error.xml create mode 100644 lib/erl_interface/doc/src/erl_eterm.xml create mode 100644 lib/erl_interface/doc/src/erl_format.xml create mode 100644 lib/erl_interface/doc/src/erl_global.xml create mode 100644 lib/erl_interface/doc/src/erl_interface.xml create mode 100644 lib/erl_interface/doc/src/erl_malloc.xml create mode 100644 lib/erl_interface/doc/src/erl_marshal.xml create mode 100644 lib/erl_interface/doc/src/fascicules.xml create mode 100644 lib/erl_interface/doc/src/make.dep create mode 100644 lib/erl_interface/doc/src/note.gif create mode 100644 lib/erl_interface/doc/src/notes.xml create mode 100644 lib/erl_interface/doc/src/notes_history.xml create mode 100644 lib/erl_interface/doc/src/part.xml create mode 100644 lib/erl_interface/doc/src/part_erl_interface.xml create mode 100644 lib/erl_interface/doc/src/part_notes.xml create mode 100644 lib/erl_interface/doc/src/part_notes_history.xml create mode 100644 lib/erl_interface/doc/src/ref_man.xml create mode 100644 lib/erl_interface/doc/src/ref_man_ei.xml create mode 100644 lib/erl_interface/doc/src/ref_man_erl_interface.xml create mode 100644 lib/erl_interface/doc/src/registry.xml create mode 100644 lib/erl_interface/doc/src/warning.gif create mode 100644 lib/erl_interface/include/ei.h create mode 100644 lib/erl_interface/include/ei_connect.h create mode 100644 lib/erl_interface/include/eicode.h create mode 100644 lib/erl_interface/include/erl_interface.h create mode 100644 lib/erl_interface/info create mode 100644 lib/erl_interface/priv/.gitignore create mode 100644 lib/erl_interface/src/INSTALL create mode 100644 lib/erl_interface/src/Makefile create mode 100644 lib/erl_interface/src/Makefile.in create mode 100644 lib/erl_interface/src/README create mode 100644 lib/erl_interface/src/README.internal create mode 120000 lib/erl_interface/src/auxdir/config.guess create mode 100644 lib/erl_interface/src/auxdir/config.h.in create mode 120000 lib/erl_interface/src/auxdir/config.sub create mode 120000 lib/erl_interface/src/auxdir/install-sh create mode 100644 lib/erl_interface/src/connect/ei_connect.c create mode 100644 lib/erl_interface/src/connect/ei_connect_int.h create mode 100644 lib/erl_interface/src/connect/ei_resolve.c create mode 100644 lib/erl_interface/src/connect/ei_resolve.h create mode 100644 lib/erl_interface/src/connect/eirecv.c create mode 100644 lib/erl_interface/src/connect/eirecv.h create mode 100644 lib/erl_interface/src/connect/eisend.h create mode 100644 lib/erl_interface/src/connect/send.c create mode 100644 lib/erl_interface/src/connect/send_exit.c create mode 100644 lib/erl_interface/src/connect/send_reg.c create mode 100644 lib/erl_interface/src/decode/decode_atom.c create mode 100644 lib/erl_interface/src/decode/decode_big.c create mode 100644 lib/erl_interface/src/decode/decode_bignum.c create mode 100644 lib/erl_interface/src/decode/decode_binary.c create mode 100644 lib/erl_interface/src/decode/decode_boolean.c create mode 100644 lib/erl_interface/src/decode/decode_char.c create mode 100644 lib/erl_interface/src/decode/decode_double.c create mode 100644 lib/erl_interface/src/decode/decode_fun.c create mode 100644 lib/erl_interface/src/decode/decode_intlist.c create mode 100644 lib/erl_interface/src/decode/decode_list_header.c create mode 100644 lib/erl_interface/src/decode/decode_long.c create mode 100644 lib/erl_interface/src/decode/decode_longlong.c create mode 100644 lib/erl_interface/src/decode/decode_pid.c create mode 100644 lib/erl_interface/src/decode/decode_port.c create mode 100644 lib/erl_interface/src/decode/decode_ref.c create mode 100644 lib/erl_interface/src/decode/decode_skip.c create mode 100644 lib/erl_interface/src/decode/decode_skip.h create mode 100644 lib/erl_interface/src/decode/decode_string.c create mode 100644 lib/erl_interface/src/decode/decode_trace.c create mode 100644 lib/erl_interface/src/decode/decode_tuple_header.c create mode 100644 lib/erl_interface/src/decode/decode_ulong.c create mode 100644 lib/erl_interface/src/decode/decode_ulonglong.c create mode 100644 lib/erl_interface/src/decode/decode_version.c create mode 100644 lib/erl_interface/src/depend.mk create mode 100644 lib/erl_interface/src/eidefs.mk.in create mode 100644 lib/erl_interface/src/encode/eicode.h create mode 100644 lib/erl_interface/src/encode/encode_atom.c create mode 100644 lib/erl_interface/src/encode/encode_big.c create mode 100644 lib/erl_interface/src/encode/encode_bignum.c create mode 100644 lib/erl_interface/src/encode/encode_binary.c create mode 100644 lib/erl_interface/src/encode/encode_boolean.c create mode 100644 lib/erl_interface/src/encode/encode_char.c create mode 100644 lib/erl_interface/src/encode/encode_double.c create mode 100644 lib/erl_interface/src/encode/encode_fun.c create mode 100644 lib/erl_interface/src/encode/encode_list_header.c create mode 100644 lib/erl_interface/src/encode/encode_long.c create mode 100644 lib/erl_interface/src/encode/encode_longlong.c create mode 100644 lib/erl_interface/src/encode/encode_pid.c create mode 100644 lib/erl_interface/src/encode/encode_port.c create mode 100644 lib/erl_interface/src/encode/encode_ref.c create mode 100644 lib/erl_interface/src/encode/encode_string.c create mode 100644 lib/erl_interface/src/encode/encode_trace.c create mode 100644 lib/erl_interface/src/encode/encode_tuple_header.c create mode 100644 lib/erl_interface/src/encode/encode_ulong.c create mode 100644 lib/erl_interface/src/encode/encode_ulonglong.c create mode 100644 lib/erl_interface/src/encode/encode_version.c create mode 100644 lib/erl_interface/src/epmd/ei_epmd.h create mode 100644 lib/erl_interface/src/epmd/epmd_port.c create mode 100644 lib/erl_interface/src/epmd/epmd_publish.c create mode 100644 lib/erl_interface/src/epmd/epmd_unpublish.c create mode 100644 lib/erl_interface/src/legacy/decode_term.c create mode 100644 lib/erl_interface/src/legacy/encode_term.c create mode 100644 lib/erl_interface/src/legacy/erl_config.h create mode 100644 lib/erl_interface/src/legacy/erl_connect.c create mode 100644 lib/erl_interface/src/legacy/erl_connect.h create mode 100644 lib/erl_interface/src/legacy/erl_error.c create mode 100644 lib/erl_interface/src/legacy/erl_error.h create mode 100644 lib/erl_interface/src/legacy/erl_eterm.c create mode 100644 lib/erl_interface/src/legacy/erl_eterm.h create mode 100644 lib/erl_interface/src/legacy/erl_fix_alloc.c create mode 100644 lib/erl_interface/src/legacy/erl_fix_alloc.h create mode 100644 lib/erl_interface/src/legacy/erl_format.c create mode 100644 lib/erl_interface/src/legacy/erl_format.h create mode 100644 lib/erl_interface/src/legacy/erl_global.h create mode 100644 lib/erl_interface/src/legacy/erl_internal.h create mode 100644 lib/erl_interface/src/legacy/erl_malloc.c create mode 100644 lib/erl_interface/src/legacy/erl_malloc.h create mode 100644 lib/erl_interface/src/legacy/erl_marshal.c create mode 100644 lib/erl_interface/src/legacy/erl_marshal.h create mode 100644 lib/erl_interface/src/legacy/erl_resolve.c create mode 100644 lib/erl_interface/src/legacy/erl_timeout.c create mode 100644 lib/erl_interface/src/legacy/erl_timeout.h create mode 100644 lib/erl_interface/src/legacy/global_names.c create mode 100644 lib/erl_interface/src/legacy/global_register.c create mode 100644 lib/erl_interface/src/legacy/global_unregister.c create mode 100644 lib/erl_interface/src/legacy/global_whereis.c create mode 100644 lib/erl_interface/src/legacy/portability.h create mode 100644 lib/erl_interface/src/misc/ei_compat.c create mode 100644 lib/erl_interface/src/misc/ei_decode_term.c create mode 100644 lib/erl_interface/src/misc/ei_decode_term.h create mode 100644 lib/erl_interface/src/misc/ei_format.c create mode 100644 lib/erl_interface/src/misc/ei_format.h create mode 100644 lib/erl_interface/src/misc/ei_internal.h create mode 100644 lib/erl_interface/src/misc/ei_locking.c create mode 100644 lib/erl_interface/src/misc/ei_locking.h create mode 100644 lib/erl_interface/src/misc/ei_malloc.c create mode 100644 lib/erl_interface/src/misc/ei_malloc.h create mode 100644 lib/erl_interface/src/misc/ei_portio.c create mode 100644 lib/erl_interface/src/misc/ei_portio.h create mode 100644 lib/erl_interface/src/misc/ei_printterm.c create mode 100644 lib/erl_interface/src/misc/ei_printterm.h create mode 100644 lib/erl_interface/src/misc/ei_pthreads.c create mode 100644 lib/erl_interface/src/misc/ei_trace.c create mode 100644 lib/erl_interface/src/misc/ei_trace.h create mode 100644 lib/erl_interface/src/misc/ei_x_encode.c create mode 100644 lib/erl_interface/src/misc/ei_x_encode.h create mode 100644 lib/erl_interface/src/misc/eidef.h create mode 100644 lib/erl_interface/src/misc/eiext.h create mode 100644 lib/erl_interface/src/misc/eimd5.c create mode 100644 lib/erl_interface/src/misc/eimd5.h create mode 100644 lib/erl_interface/src/misc/get_type.c create mode 100644 lib/erl_interface/src/misc/putget.h create mode 100644 lib/erl_interface/src/misc/show_msg.c create mode 100644 lib/erl_interface/src/misc/show_msg.h create mode 100644 lib/erl_interface/src/not_used/ei_send.c create mode 100644 lib/erl_interface/src/not_used/ei_send_reg.c create mode 100644 lib/erl_interface/src/not_used/send_link.c create mode 100644 lib/erl_interface/src/not_used/whereis.c create mode 100644 lib/erl_interface/src/prog/ei_fake_prog.c create mode 100644 lib/erl_interface/src/prog/erl_call.c create mode 100644 lib/erl_interface/src/prog/erl_fake_prog.c create mode 100644 lib/erl_interface/src/prog/erl_start.c create mode 100644 lib/erl_interface/src/prog/erl_start.h create mode 100644 lib/erl_interface/src/registry/hash.h create mode 100644 lib/erl_interface/src/registry/hash_dohash.c create mode 100644 lib/erl_interface/src/registry/hash_foreach.c create mode 100644 lib/erl_interface/src/registry/hash_freetab.c create mode 100644 lib/erl_interface/src/registry/hash_insert.c create mode 100644 lib/erl_interface/src/registry/hash_isprime.c create mode 100644 lib/erl_interface/src/registry/hash_lookup.c create mode 100644 lib/erl_interface/src/registry/hash_newtab.c create mode 100644 lib/erl_interface/src/registry/hash_remove.c create mode 100644 lib/erl_interface/src/registry/hash_resize.c create mode 100644 lib/erl_interface/src/registry/hash_rlookup.c create mode 100644 lib/erl_interface/src/registry/reg.h create mode 100644 lib/erl_interface/src/registry/reg_close.c create mode 100644 lib/erl_interface/src/registry/reg_delete.c create mode 100644 lib/erl_interface/src/registry/reg_dirty.c create mode 100644 lib/erl_interface/src/registry/reg_dump.c create mode 100644 lib/erl_interface/src/registry/reg_free.c create mode 100644 lib/erl_interface/src/registry/reg_get.c create mode 100644 lib/erl_interface/src/registry/reg_getf.c create mode 100644 lib/erl_interface/src/registry/reg_geti.c create mode 100644 lib/erl_interface/src/registry/reg_getp.c create mode 100644 lib/erl_interface/src/registry/reg_gets.c create mode 100644 lib/erl_interface/src/registry/reg_make.c create mode 100644 lib/erl_interface/src/registry/reg_open.c create mode 100644 lib/erl_interface/src/registry/reg_purge.c create mode 100644 lib/erl_interface/src/registry/reg_resize.c create mode 100644 lib/erl_interface/src/registry/reg_restore.c create mode 100644 lib/erl_interface/src/registry/reg_set.c create mode 100644 lib/erl_interface/src/registry/reg_setf.c create mode 100644 lib/erl_interface/src/registry/reg_seti.c create mode 100644 lib/erl_interface/src/registry/reg_setp.c create mode 100644 lib/erl_interface/src/registry/reg_sets.c create mode 100644 lib/erl_interface/src/registry/reg_stat.c create mode 100644 lib/erl_interface/src/registry/reg_tabstat.c create mode 100644 lib/erl_interface/vsn.mk (limited to 'lib/erl_interface') diff --git a/lib/erl_interface/AUTHORS b/lib/erl_interface/AUTHORS new file mode 100644 index 0000000000..c8ad36400d --- /dev/null +++ b/lib/erl_interface/AUTHORS @@ -0,0 +1,9 @@ +Original Authors and Contributors: + +Torbjörn Törnqvist +Claes Wikström +Tony Rogval +Björn Gustavsson +Kenneth Lundin +Jakob Cederlund +Gordon Beaton diff --git a/lib/erl_interface/Makefile b/lib/erl_interface/Makefile new file mode 100644 index 0000000000..256b0309cd --- /dev/null +++ b/lib/erl_interface/Makefile @@ -0,0 +1,32 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1996-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Common Macros +# ---------------------------------------------------- +SUB_DIRECTORIES = src doc/src + +SPECIAL_TARGETS = + +# ---------------------------------------------------- +# Default Subdir Targets +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_subdir.mk diff --git a/lib/erl_interface/aclocal.m4 b/lib/erl_interface/aclocal.m4 new file mode 120000 index 0000000000..151fd5ea5a --- /dev/null +++ b/lib/erl_interface/aclocal.m4 @@ -0,0 +1 @@ +../../erts/aclocal.m4 \ No newline at end of file diff --git a/lib/erl_interface/configure.in b/lib/erl_interface/configure.in new file mode 100644 index 0000000000..80b229c1c3 --- /dev/null +++ b/lib/erl_interface/configure.in @@ -0,0 +1,443 @@ +# -*- Autoconf -*- +# %CopyrightBegin% +# +# Copyright Ericsson AB 2000-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# Process this file with autoconf to produce a configure script. +# The starting point for this file was the output from 'autoscan'. + +# Strange, VxWorks HAVE_SENS not set here, see "ei_resolve.h" + +# Find the erl_interface version number and set m4 macro to it. +# We do this because AC_INIT can't handle shell variables. Still broken. +dnl m4_define(EI_VERSION,`grep EI_VSN ../vsn.mk | sed 's/^.*=[ ]*//'`) +dnl m4_define(EI_VERSION,regexp(m4_include(VERSION),[version \([-.0-9A-Za-z]+\)],[\1])) + +AC_INIT() + +if test "x$no_recursion" != "xyes" -a "x$OVERRIDE_CONFIG_CACHE" = "x"; then + # We do not want to use a common cache! + cache_file=/dev/null +fi + +dnl How to set srcdir absolute is taken from the GNU Emacs distribution +#### Make srcdir absolute, if it isn't already. It's important to +#### avoid running the path through pwd unnecessary, since pwd can +#### give you automounter prefixes, which can go away. +case "${srcdir}" in + /* ) ;; + . ) + ## We may be able to use the $PWD environment variable to make this + ## absolute. But sometimes PWD is inaccurate. + ## Make sure CDPATH doesn't affect cd (in case PWD is relative). + CDPATH= + if test "${PWD}" != "" && test "`(cd ${PWD} ; sh -c pwd)`" = "`pwd`" ; + then + srcdir="$PWD" + else + srcdir="`(cd ${srcdir}; pwd)`" + fi + ;; + * ) srcdir="`(cd ${srcdir}; pwd)`" ;; +esac + +AC_CONFIG_AUX_DIR([$srcdir/src/auxdir]) + +if test "X$host" != "Xfree_source" -a "X$host" != "Xwin32"; then + AC_CANONICAL_HOST +else + host_os=win32 +fi + +TARGET=$host +AC_SUBST(TARGET) + +AC_CONFIG_HEADER([src/$host/config.h:src/auxdir/config.h.in]) + +dnl ---------------------------------------------------------------------- +dnl Optional features +dnl ---------------------------------------------------------------------- + +AC_ARG_WITH(xcomp-conf, +[ --with-xcompconf=PATH path to cross compilation configuration]) +if test "x$with_xcompconf" != "xno" -a "x$with_xcompconf" != "x" ; then + . $with_xcompconf +fi + +# Use --disable-threads to force building single threaded libs even +# if pthreads exists (for test purposes). +AC_ARG_ENABLE(threads, +[ --disable-threads use to only build single threaded libs], +[ case "$enableval" in + no) threads_disabled=yes ;; + *) threads_disabled=no ;; + esac ], +[ threads_disabled=no ]) + +dnl ---------------------------------------------------------------------- +dnl Checks for programs +dnl ---------------------------------------------------------------------- + +AC_PROG_CC +AC_PROG_CPP +dnl AC_PROG_LIBTOOL +AC_PROG_RANLIB +if test "x$LD" = "x"; then + AC_CHECK_TOOL([LD],[ld],[ld]) +fi +AC_SUBST(LD) + +AC_CHECK_SIZEOF(short, $erl_xcomp_short) +AC_CHECK_SIZEOF(int, $erl_xcomp_int) +AC_CHECK_SIZEOF(long, $erl_xcomp_long) +AC_CHECK_SIZEOF(void *, $erl_xcomp_void_p) +AC_CHECK_SIZEOF(long long, $erl_xcomp_long_long) + +if test $ac_cv_sizeof_void_p = 8; then + CFLAGS="$CFLAGS -DEI_64BIT" +fi + +AC_CHECK_PROG(AR, ar, ar, false) +if test "$ac_cv_prog_AR" = false; then + AC_MSG_ERROR([No 'ar' command found in PATH]) +fi + +dnl +dnl We can live with Solaris /usr/ucb/install +dnl +case $host in + *-*-solaris*|free_source) + if test -x /usr/ucb/install; then + INSTALL="/usr/ucb/install -c" + fi + ;; + *) + ;; +esac + +AC_PROG_INSTALL +LM_PROG_INSTALL_DIR +AC_SUBST(INSTALL_DIR) + +case $host_os in + darwin*) + dnl Need to preserve modification time on archives; + dnl otherwise, ranlib has to be run on archives + dnl again after installation. + INSTALL_DATA="$INSTALL_DATA -p";; + *) + ;; +esac + +# Checks for libraries. +AC_CHECK_LIB([nsl], [gethostbyname]) +AC_CHECK_LIB([socket], [getpeername]) + +# Checks for header files. +AC_HEADER_STDC +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h malloc.h netdb.h netinet/in.h stddef.h stdlib.h string.h sys/param.h sys/socket.h sys/select.h sys/time.h unistd.h sys/types.h]) + +# Checks for typedefs, structures, and compiler characteristics. +# fixme AC_C_CONST & AC_C_VOLATILE needed for Windows? +dnl AC_C_CONST +dnl AC_C_VOLATILE +AC_TYPE_UID_T +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_HEADER_TIME +AC_MSG_CHECKING([for socklen_t usability]) +AC_TRY_COMPILE([#include +#include ], +[socklen_t mylen;], +[AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SOCKLEN_T)], +[AC_MSG_RESULT(no)]) + +# Checks for library functions. +AC_FUNC_ALLOCA +dnl AC_FUNC_FORK +# FIXME check that this isn't set in normal cases +AC_PROG_GCC_TRADITIONAL +# Check if malloc(0) is ok +dnl AC_FUNC_MALLOC +dnl AC_FUNC_REALLOC +AC_FUNC_MEMCMP +dnl AC_FUNC_SELECT_ARGTYPES +dnl AC_TYPE_SIGNAL +dnl AC_FUNC_STRERROR_R +dnl AC_FUNC_VPRINTF +AC_CHECK_FUNCS([dup2 gethostbyaddr gethostbyname \ + gethostbyaddr_r \ + gethostbyname_r gethostname writev \ + gethrtime gettimeofday inet_ntoa memchr memmove memset select \ + socket strchr strerror strrchr strstr uname]) +AC_CHECK_FUNC(res_gethostbyname, [], + AC_CHECK_LIB(resolv, res_gethostbyname) +) +AC_CHECK_FUNC(clock_gettime, [], + AC_CHECK_LIB(rt, clock_gettime) +) + +# --------------------------------------------------------------------------- +# We don't link against libgmp except for "make check" +# but linking will also tell us that it is >= 4.1 +# --------------------------------------------------------------------------- + +AC_ARG_WITH(gmp, +[ --with-gmp=PATH specify location of GNU MP include and lib + --with-gmp use GNU MP (will search for it)]) + +# We don't just want any GNU MP version, we want 4.1 or later +# that contain the import/export functions we need. + +if test "x$with_gmp" = "xyes" ;then + for dir in /usr /usr/pkg /usr/local /usr/local/gmp /usr/lib/gmp /usr/gmp; do + AC_CHECK_HEADER($dir/include/gmp.h, ac_cv_gmp=yes, ac_cv_gmp=no) + if test $ac_cv_gmp = yes ; then + CFLAGS="$CFLAGS -I$dir/include -L$dir/lib" + AC_DEFINE(HAVE_GMP_H) + break + fi + done + if test $ac_cv_gmp = no ; then + AC_MSG_ERROR([No GNU MP installation found]) + fi + AC_CHECK_LIB(gmp, __gmpz_export) + # FIXME return ERROR if no lib +elif test "x$with_gmp" != "xno" -a -n "$with_gmp" ;then + # Option given with PATH to package + AC_MSG_CHECKING(for GNU MP) + if test ! -d "$with_gmp" ; then + AC_MSG_ERROR(Invalid path to option --with-gmp=PATH) + fi + AC_MSG_RESULT(yes) + CFLAGS="$CFLAGS -I$with_gmp/include -L$with_gmp/lib" + AC_DEFINE(HAVE_GMP_H) + AC_CHECK_LIB(gmp, __gmpz_export) + # FIXME return ERROR if no lib +fi + +MIXED_CYGWIN=no + +AC_MSG_CHECKING(for mixed cygwin and native VC++ environment) +if test "X$CC" = "Xcc.sh" -a "X$host" = "Xwin32" -a "x$GCC" != x"yes"; then + if test -x /usr/bin/cygpath; then + CFLAGS="-O2" + MIXED_CYGWIN=yes + AC_MSG_RESULT([yes]) + MIXED_CYGWIN_VC=yes + else + AC_MSG_RESULT([undeterminable]) + AC_MSG_ERROR(Seems to be mixed windows but not with cygwin, cannot handle this!) + fi +else + AC_MSG_RESULT([no]) + MIXED_CYGWIN_VC=no +fi +AC_SUBST(MIXED_CYGWIN_VC) + +AC_MSG_CHECKING(for mixed cygwin and native MinGW environment) +if test "X$CC" = "Xcc.sh" -a "X$host" = "Xwin32" -a "x$GCC" = x"yes"; then + if test -x /usr/bin/cygpath; then + CFLAGS="-O2" + MIXED_CYGWIN=yes + AC_MSG_RESULT([yes]) + MIXED_CYGWIN_MINGW=yes + else + AC_MSG_RESULT([undeterminable]) + AC_MSG_ERROR(Seems to be mixed windows but not with cygwin, cannot handle this!) + fi +else + AC_MSG_RESULT([no]) + MIXED_CYGWIN_MINGW=no +fi +AC_SUBST(MIXED_CYGWIN_MINGW) + +AC_MSG_CHECKING(if we mix cygwin with any native compiler) +if test "X$MIXED_CYGWIN" = "Xyes" ; then + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + +AC_SUBST(MIXED_CYGWIN) + +dnl +dnl Threads +dnl +found_threads=no +THR_LIBS= +THR_DEFS= +EI_THREADS="false" +AC_SUBST(THR_LIBS) +AC_SUBST(THR_DEFS) +AC_SUBST(EI_THREADS) + +case "$threads_disabled" in + no) + AC_MSG_CHECKING([for native win32 threads]) + if test "X$host_os" = "Xwin32"; then + THR_DEFS="-DWIN32_THREADS" + found_threads=yes + EI_THREADS="true" + AC_MSG_RESULT([yes]) + AC_MSG_CHECKING([for __declspec(thread) usability]) + if test "X$GCC" = "Xyes"; then + AC_MSG_RESULT([no]) + else + THR_DEFS="$THR_DEFS -DUSE_DECLSPEC_THREAD" + AC_MSG_RESULT([yes]) + fi + else + AC_MSG_RESULT(no) + + dnl Check for POSIX threads + + pthread_lib="" + AC_CHECK_LIB(pthread, + pthread_create, + [found_threads=yes + EI_THREADS="true" + THR_LIBS="-lpthread" + THR_DEFS="-D_REENTRANT -D_THREAD_SAFE -DPOSIX_THREADS" + pthread_lib=pthread]) + + # FreeBSD has pthreads in special c library, c_r + if test $found_threads = no; then + AC_CHECK_LIB(c_r, + pthread_create, + [found_threads=yes + EI_THREADS="true" + THR_LIBS="-lc_r" + THR_DEFS="-D_REENTRANT -D_THREAD_SAFE -DPOSIX_THREADS" + pthread_lib=c_r]) + fi + + if test "x$pthread_lib" != "x"; then + AC_CHECK_LIB($pthread_lib,pthread_atfork,AC_DEFINE(HAVE_PTHREAD_ATFORK)) + AC_CHECK_HEADER(pthread.h, AC_DEFINE(HAVE_PTHREAD_H)) + dnl Some Linuxes have instead of + AC_CHECK_HEADER(pthread/mit/pthread.h, AC_DEFINE(HAVE_MIT_PTHREAD_H)) + case $host_os in + solaris*) + THR_DEFS="$THR_DEFS -D_POSIX_PTHREAD_SEMANTICS";; + linux*) + dnl NPTL test stolen from $ERL_TOP/erts/aclocal.m4 + AC_MSG_CHECKING(for Native POSIX Thread Library) + case `getconf GNU_LIBPTHREAD_VERSION 2>/dev/null` in + nptl*) nptl=yes;; + NPTL*) nptl=yes;; + *) nptl=no;; + esac + AC_MSG_RESULT($nptl) + if test $nptl = yes; then + need_nptl_incldir=no + AC_CHECK_HEADER(nptl/pthread.h, need_nptl_incldir=yes) + if test $need_nptl_incldir = yes; then + # Ahh... + nptl_path="$C_INCLUDE_PATH:$CPATH:/usr/local/include:/usr/include" + nptl_ws_path= + save_ifs="$IFS"; IFS=":" + for dir in $nptl_path; do + if test "x$dir" != "x"; then + nptl_ws_path="$nptl_ws_path $dir" + fi + done + IFS=$save_ifs + nptl_incldir= + for dir in $nptl_ws_path; do + AC_CHECK_HEADER($dir/nptl/pthread.h, + nptl_incldir=$dir/nptl) + if test "x$nptl_incldir" != "x"; then + THR_DEFS="$THR_DEFS -isystem $nptl_incldir" + break + fi + done + if test "x$nptl_incldir" = "x"; then + AC_MSG_ERROR(Failed to locate nptl system include directory) + fi + fi + fi + + ;; + *) + ;; + esac + fi + fi + ;; + yes) + # Threads disabled + ;; +esac + +# --------------------------------------------------------------------------- +# Warning flags to the C compiler +# --------------------------------------------------------------------------- +AC_SUBST(WFLAGS) + +if test "x$GCC" = xyes; then + WFLAGS="-Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Winline" + # check which GCC version + GCC_VERSION=`$CC -v 2>&1 | sed -n 's/gcc version //p'` + # GCC 3.3 and later supports C99 strict aliasing + # until all source is compliant with strict aliasing we disable it + case "$GCC_VERSION" in + 1*) ;; + 2*) ;; + 3.0*) ;; + 3.1*) ;; + 3.2*) ;; + *) + WFLAGS="$WFLAGS -fno-strict-aliasing";; + esac +else + WFLAGS="" +fi + +# --------------------------------------------------------------------------- +# FIXME We want to use libtool but until then.... +# --------------------------------------------------------------------------- + +AC_SUBST(DED_CFLAGS) +dnl AC_SUBST(DED_LD) +dnl AC_SUBST(DED_LDFLAGS) + +if test "X$host" = "Xwin32"; then + DED_CFLAGS="$CFLAGS" +else + case $host_os in + darwin*) + CFLAGS="$CFLAGS -no-cpp-precomp" + ;; + esac + + if test "x$GCC" = xyes; then + DED_CFLAGS="$CFLAGS -fPIC" + else + DED_CFLAGS="$CFLAGS" + fi +fi + +# --------------------------------------------------------------------------- +# XXX +# --------------------------------------------------------------------------- + +AC_OUTPUT( + src/$host/Makefile:src/Makefile.in + src/$host/eidefs.mk:src/eidefs.mk.in + ) diff --git a/lib/erl_interface/doc/html/.gitignore b/lib/erl_interface/doc/html/.gitignore new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lib/erl_interface/doc/man1/.gitignore b/lib/erl_interface/doc/man1/.gitignore new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lib/erl_interface/doc/man3/.gitignore b/lib/erl_interface/doc/man3/.gitignore new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lib/erl_interface/doc/pdf/.gitignore b/lib/erl_interface/doc/pdf/.gitignore new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lib/erl_interface/doc/src/Makefile b/lib/erl_interface/doc/src/Makefile new file mode 100644 index 0000000000..e05b647cb2 --- /dev/null +++ b/lib/erl_interface/doc/src/Makefile @@ -0,0 +1,129 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1998-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../../vsn.mk +VSN=$(EI_VSN) +APPLICATION=erl_interface + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +XML_REF1_FILES = erl_call.xml +XML_REF3_FILES = erl_connect.xml \ + erl_error.xml \ + erl_eterm.xml \ + erl_format.xml \ + erl_malloc.xml \ + erl_marshal.xml \ + erl_global.xml \ + ei.xml \ + ei_connect.xml \ + registry.xml + +BOOK_FILES = book.xml +XML_APPLICATION_FILES = ref_man.xml +#ref_man_ei.xml ref_man_erl_interface.xml +XML_PART_FILES = \ + part.xml \ + part_notes.xml \ + part_notes_history.xml +XML_CHAPTER_FILES = ei_users_guide.xml notes.xml notes_history.xml + +XML_FILES = $(XML_REF1_FILES) $(XML_REF3_FILES) $(BOOK_FILES) \ + $(XML_APPLICATION_FILES) $(XML_PART_FILES) $(XML_CHAPTER_FILES) +# ---------------------------------------------------- + +HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html) + +INFO_FILE = ../../info + +GIF_FILES = + +MAN1_FILES = $(XML_REF1_FILES:%.xml=$(MAN1DIR)/%.1) +MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) + +HTML_REF_MAN_FILE = $(HTMLDIR)/index.html + +TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +$(HTMLDIR)/%.gif: %.gif + $(INSTALL_DATA) $< $@ + +docs: pdf html man + +$(TOP_PDF_FILE): $(XML_FILES) + +pdf: $(TOP_PDF_FILE) + +html: gifs $(HTML_REF_MAN_FILE) + +man: $(MAN1_FILES) $(MAN3_FILES) + +gifs: $(GIF_FILES:%=$(HTMLDIR)/%) + +debug opt: + +clean clean_docs clean_tex: + rm -rf $(HTMLDIR)/* + rm -f $(MAN1DIR)/* + rm -f $(MAN3DIR)/* + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f errs core *~ + + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf + $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf + $(INSTALL_DIR) $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(HTMLDIR)/* \ + $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) + $(INSTALL_DIR) $(RELEASE_PATH)/man/man1 + $(INSTALL_DATA) $(MAN1_FILES) $(RELEASE_PATH)/man/man1 + $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 + $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 + + +release_spec: + diff --git a/lib/erl_interface/doc/src/book.xml b/lib/erl_interface/doc/src/book.xml new file mode 100644 index 0000000000..e911b6aa2b --- /dev/null +++ b/lib/erl_interface/doc/src/book.xml @@ -0,0 +1,49 @@ + + + + +
+ + 19982009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Erlang Interface + Gordon Beaton + + 1998-11-30 + 1.2 + book.sgml +
+ + + Erlang Interface + + + + + + + + + + + + + + +
+ diff --git a/lib/erl_interface/doc/src/ei.xml b/lib/erl_interface/doc/src/ei.xml new file mode 100644 index 0000000000..2f65a8c375 --- /dev/null +++ b/lib/erl_interface/doc/src/ei.xml @@ -0,0 +1,728 @@ + + + + +
+ + 20012009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + ei + Jakob Cederlund + Kent Boortz + 1 + Kenneth Lundin + + 2000-11-27 + PA1 + ei.sgml +
+ ei + routines for handling the erlang binary term format + +

The library contains macros and functions to encode + and decode the erlang binary term format.

+

With , you can convert atoms, lists, numbers and + binaries to and from the binary format. This is useful when + writing port programs and drivers. uses a given + buffer, and no dynamic memory (with the exception of + ), and is often quite fast.

+

It also handles C-nodes, C-programs that talks erlang + distribution with erlang nodes (or other C-nodes) using the + erlang distribution format. The difference between and + is that uses the binary format + directly when sending and receiving terms. It is also thread + safe, and using threads, one process can handle multiple + C-nodes. The library is built on top of + , but of legacy reasons, it doesn't allow for multiple + C-nodes. In general, is the preferred way of doing + C-nodes.

+

The decode and encode functions use a buffer an index into the + buffer, which points at the point where to encode and + decode. The index is updated to point right after the term + encoded/decoded. No checking is done whether the term fits in + the buffer or not. If encoding goes outside the buffer, the + program may crash.

+

All functions takes two parameter, is a pointer to + the buffer where the binary data is / will be, is a + pointer to an index into the buffer. This parameter will be + incremented with the size of the term decoded / encoded. The + data is thus at when an function is + called.

+

The encode functions all assumes that the and + parameters points to a buffer big enough for the + data. To get the size of an encoded term, without encoding it, + pass instead of a buffer pointer. The + parameter will be incremented, but nothing will be encoded. This + is the way in to "preflight" term encoding.

+

There are also encode-functions that uses a dynamic buffer. It + is often more convenient to use these to encode data. All encode + functions comes in two versions: those starting with , + uses a dynamic buffer.

+

All functions return if successful, and if + not. (For instance, if a term is not of the expected type, or + the data to decode is not a valid erlang term.)

+

Some of the decode-functions needs a preallocated buffer. This + buffer must be allocated big enough, and for non compound types + the + function returns the size required (note that for strings an + extra byte is needed for the 0 string terminator).

+
+ + + voidei_set_compat_rel(release_number) + Set the ei library in compatibility mode + + unsigned release_number; + + + +

By default, the library is only guaranteed + to be compatible with other Erlang/OTP components from the same + release as the library itself. For example, from + the OTP R10 release is not compatible with an Erlang emulator + from the OTP R9 release by default.

+

A call to sets the + library in compatibility mode of release + . Valid range of + is [7, current release]. This makes it possible to + communicate with Erlang/OTP components from earlier releases.

+ +

If this function is called, it may only be called once + and must be called before any other functions in the + library is called.

+
+ +

You may run into trouble if this feature is used + carelessly. Always make sure that all communicating + components are either from the same Erlang/OTP release, or + from release X and release Y where all components + from release Y are in compatibility mode of release X.

+
+
+
+ + intei_encode_version(char *buf, int *index) + intei_x_encode_version(ei_x_buff* x) + Encode version + +

Encodes a version magic number for the binary format. Must + be the first token in a binary term.

+
+
+ + intei_encode_long(char *buf, int *index, long p) + intei_x_encode_long(ei_x_buff* x, long p) + Encode integer + +

Encodes a long integer in the binary format. + Note that if the code is 64 bits the function ei_encode_long() is + exactly the same as ei_encode_longlong().

+
+
+ + intei_encode_ulong(char *buf, int *index, unsigned long p) + intei_x_encode_ulong(ei_x_buff* x, unsigned long p) + Encode unsigned integer + +

Encodes an unsigned long integer in the binary format. + Note that if the code is 64 bits the function ei_encode_ulong() is + exactly the same as ei_encode_ulonglong().

+
+
+ + intei_encode_longlong(char *buf, int *index, long long p) + intei_x_encode_longlong(ei_x_buff* x, long long p) + Encode integer + +

Encodes a GCC or Visual C++ (64 bit) + integer in the binary format. Note that this function is missing + in the VxWorks port.

+
+
+ + intei_encode_ulonglong(char *buf, int *index, unsigned long long p) + intei_x_encode_ulonglong(ei_x_buff* x, unsigned long long p) + Encode unsigned integer + +

Encodes a GCC or Visual C++ (64 bit) integer in the binary format. Note that + this function is missing in the VxWorks port.

+
+
+ + intei_encode_bignum(char *buf, int *index, mpz_t obj) + intei_x_encode_bignum(ei_x_buff *x, mpz_t obj) + Encode an arbitrary precision integer + +

Encodes a GMP integer to binary format. + To use this function the ei library needs to be configured and compiled + to use the GMP library.

+
+
+ + intei_encode_double(char *buf, int *index, double p) + intei_x_encode_double(ei_x_buff* x, double p) + Encode a double float + +

Encodes a double-precision (64 bit) floating point number in + the binary format.

+
+
+ + intei_encode_boolean(char *buf, int *index, int p) + intei_x_encode_boolean(ei_x_buff* x, int p) + Encode a boolean + +

Encodes a boolean value, as the atom if p is not + zero or if p is zero.

+
+
+ + intei_encode_char(char *buf, int *index, char p) + intei_x_encode_char(ei_x_buff* x, char p) + Encode an 8-bit integer between 0-255 + +

Encodes a char (8-bit) as an integer between 0-255 in the binary format. + Note that for historical reasons the integer argument is of + type . Your C code should consider the + given argument to be of type even if + the C compilers and system may define to be + signed.

+
+
+ + intei_encode_string(char *buf, int *index, const char *p) + intei_encode_string_len(char *buf, int *index, const char *p, int len) + intei_x_encode_string(ei_x_buff* x, const char *p) + intei_x_encode_string_len(ei_x_buff* x, const char* s, int len) + Encode a string + +

Encodes a string in the binary format. (A string in erlang + is a list, but is encoded as a character array in the binary + format.) The string should be zero-terminated, except for + the function.

+
+
+ + intei_encode_atom(char *buf, int *index, const char *p) + intei_encode_atom_len(char *buf, int *index, const char *p, int len) + intei_x_encode_atom(ei_x_buff* x, const char *p) + intei_x_encode_atom_len(ei_x_buff* x, const char *p, int len) + Encode an atom + +

Encodes an atom in the binary format. The parameter + is the name of the atom. Only upto bytes + are encoded. The name should be zero-terminated, except for + the function.

+
+
+ + intei_encode_binary(char *buf, int *index, const void *p, long len) + intei_x_encode_binary(ei_x_buff* x, const void *p, long len) + Encode a binary + +

Encodes a binary in the binary format. The data is at + , of bytes length.

+
+
+ + intei_encode_pid(char *buf, int *index, const erlang_pid *p) + intei_x_encode_pid(ei_x_buff* x, const erlang_pid *p) + Encode a pid + +

Encodes an erlang process identifier, pid, in the binary + format. The parameter points to an + structure (which should have been obtained + earlier with ).

+
+
+ + intei_encode_fun(char *buf, int *index, const erlang_fun *p) + intei_x_encode_fun(ei_x_buff* x, const erlang_fun* fun) + Encode a fun + +

Encodes a fun in the binary format. The parameter + points to an structure. The + is not freed automatically, the + should be called if the fun is not needed + after encoding.

+
+
+ + intei_encode_port(char *buf, int *index, const erlang_port *p) + intei_x_encode_port(ei_x_buff* x, const erlang_port *p) + Encodes a port + +

Encodes an erlang port in the binary format. The + parameter points to a structure (which + should have been obtained earlier with + .

+
+
+ + intei_encode_ref(char *buf, int *index, const erlang_ref *p) + intei_x_encode_ref(ei_x_buff* x, const erlang_ref *p) + Encodes a ref + +

Encodes an erlang reference in the binary format. The + parameter points to a structure + (which should have been obtained earlier with + .

+
+
+ + intei_encode_term(char *buf, int *index, void *t) + intei_x_encode_term(ei_x_buff* x, void *t) + Encode an term + +

This function encodes an , as obtained from + . The parameter is actually an + pointer. This function doesn't free the + .

+
+
+ + intei_encode_trace(char *buf, int *index, const erlang_trace *p) + intei_x_encode_trace(ei_x_buff* x, const erlang_trace *p) + Encode a trace token + +

This function encodes an erlang trace token in the binary + format. The parameter points to a + structure (which should have been + obtained earlier with .

+
+
+ + intei_encode_tuple_header(char *buf, int *index, int arity) + intei_x_encode_tuple_header(ei_x_buff* x, int arity) + Encode a tuple + +

This function encodes a tuple header, with a specified + arity. The next terms encoded will be the + elements of the tuple. Tuples and lists are encoded + recursively, so that a tuple may contain another tuple or + list.

+

E.g. to encode the tuple :

+
+ei_encode_tuple_header(buf, &i, 2);
+ei_encode_atom(buf, &i, "a");
+ei_encode_tuple_header(buf, &i, 2);
+ei_encode_atom(buf, &i, "b");
+ei_encode_tuple_header(buf, &i, 0);
+        
+
+
+ + intei_encode_list_header(char *buf, int *index, int arity) + intei_x_encode_list_header(ei_x_buff* x, int arity) + Encode a list + +

This function encodes a list header, with a specified + arity. The next terms are the elements + (actually it's cons cells) and the tail of the + list. Lists and tuples are encoded recursively, so that a + list may contain another list or tuple.

+

E.g. to encode the list :

+
+ei_encode_list_header(buf, &i, 3);
+ei_encode_atom(buf, &i, "c");
+ei_encode_atom(buf, &i, "d");
+ei_encode_list_header(buf, &i, 1);
+ei_encode_atom(buf, &i, "e");
+ei_encode_atom(buf, &i, "f");
+ei_encode_empty_list(buf, &i);
+        
+ +

It may seem that there is no way to create a list without + knowing the number of elements in advance. But indeed + there is a way. Note that the list can be + written as . Using this, a list can + be written as conses.

+
+

To encode a list, without knowing the arity in advance:

+
+while (something()) {
+    ei_x_encode_list_header(&x, 1);
+    ei_x_encode_ulong(&x, i); /* just an example */
+}
+ei_x_encode_empty_list(&x);
+        
+
+
+ + intei_encode_empty_list(char* buf, int* index) + intei_x_encode_empty_list(ei_x_buff* x) + Encode an empty list () + +

This function encodes an empty list. It's often used at the + tail of a list.

+
+
+ + intei_get_type(const char *buf, const int *index, int *type, int *size) + Fetch the type and size of an encoded term + +

This function returns the type in and size in + of the encoded term. + For strings and atoms, size + is the number of characters not including the + terminating 0. For binaries, is the number of + bytes. For lists and tuples, is the arity of the + object. For other types, is 0. In all cases, + is left unchanged.

+
+
+ + intei_decode_version(const char *buf, int *index, int *version) + Encode an empty list () + +

This function decodes the version magic number for the + erlang binary term format. It must be the first token in a + binary term.

+
+
+ + intei_decode_long(const char *buf, int *index, long *p) + Decode integer + +

This function decodes a long integer from the binary format. + Note that if the code is 64 bits the function ei_decode_long() is + exactly the same as ei_decode_longlong().

+
+
+ + intei_decode_ulong(const char *buf, int *index, unsigned long *p) + Decode unsigned integer + +

This function decodes an unsigned long integer from + the binary format. + Note that if the code is 64 bits the function ei_decode_ulong() is + exactly the same as ei_decode_ulonglong().

+
+
+ + intei_decode_longlong(const char *buf, int *index, long long *p) + Decode integer + +

This function decodes a GCC or Visual C++ + (64 bit) integer from the binary format. Note that this + function is missing in the VxWorks port.

+
+
+ + intei_decode_ulonglong(const char *buf, int *index, unsigned long long *p) + Decode unsigned integer + +

This function decodes a GCC or Visual C++ + (64 bit) integer from the binary format. + Note that this function is missing in the VxWorks port.

+
+
+ + intei_decode_bignum(const char *buf, int *index, mpz_t obj) + Decode a GMP arbitrary precision integer + +

This function decodes an integer in the binary format to a GMP integer. + To use this function the ei library needs to be configured and compiled + to use the GMP library.

+
+
+ + intei_decode_double(const char *buf, int *index, double *p) + Decode a double + +

This function decodes an double-precision (64 bit) floating + point number from the binary format.

+
+
+ + intei_decode_boolean(const char *buf, int *index, int *p) + Decode a boolean + +

This function decodes a boolean value from the binary + format. A boolean is actually an atom, decodes 1 + and decodes 0.

+
+
+ + intei_decode_char(const char *buf, int *index, char *p) + Decode an 8-bit integer between 0-255 + +

This function decodes a char (8-bit) integer between 0-255 + from the binary format. + Note that for historical reasons the returned integer is of + type . Your C code should consider the + returned value to be of type even if + the C compilers and system may define to be + signed.

+
+
+ + intei_decode_string(const char *buf, int *index, char *p) + Decode a string + +

This function decodes a string from the binary format. A + string in erlang is a list of integers between 0 and + 255. Note that since the string is just a list, sometimes + lists are encoded as strings by , + even if it was not intended.

+

The string is copied to , and enough space must be + allocated. The returned string is null terminated so you + need to add an extra byte to the memory requirement.

+
+
+ + intei_decode_atom(const char *buf, int *index, char *p) + Decode an atom + +

This function decodes an atom from the binary format. The + name of the atom is placed at . There can be at most + bytes placed in the buffer.

+
+
+ + intei_decode_binary(const char *buf, int *index, void *p, long *len) + Decode a binary + +

This function decodes a binary from the binary format. The + parameter is set to the actual size of the + binary. Note that assumes that there + are enough room for the binary. The size required can be + fetched by .

+
+
+ + intei_decode_fun(const char *buf, int *index, erlang_fun *p) + voidfree_fun(erlang_fun* f) + Decode a fun + +

This function decodes a fun from the binary format. The + parameter should be NULL or point to an + structure. This is the only decode + function that allocates memory; when the + is no longer needed, it should be freed with + . (This has to do with the arbitrary size of + the environment for a fun.)

+
+
+ + intei_decode_pid(const char *buf, int *index, erlang_pid *p) + Decode a + +

Decodes a pid, process identifier, from the binary format.

+
+
+ + intei_decode_port(const char *buf, int *index, erlang_port *p) + Decode a port + +

This function decodes a port identifier from the binary + format.

+
+
+ + intei_decode_ref(const char *buf, int *index, erlang_ref *p) + Decode a reference + +

This function decodes a reference from the binary format.

+
+
+ + intei_decode_trace(const char *buf, int *index, erlang_trace *p) + Decode a trace token + +

Decodes an erlang trace token from the binary format.

+
+
+ + intei_decode_tuple_header(const char *buf, int *index, int *arity) + Decode a tuple + +

This function decodes a tuple header, the number of elements + is returned in . The tuple elements follows in order in + the buffer.

+
+
+ + intei_decode_list_header(const char *buf, int *index, int *arity) + Decode a list + +

This function decodes a list header from the binary + format. The number of elements is returned in + . The elements follows (the last + one is the tail of the list, normally an empty list.) If + is , it's an empty list.

+

Note that lists are encoded as strings, if they consist + entirely of integers in the range 0..255. This function will + not decode such strings, use + instead.

+
+
+ + intei_decode_ei_term(const char* buf, int* index, ei_term* term) + Decode a term, without prior knowledge of type + +

This function decodes any term, or at least tries to. If the + term pointed at by in fits in the + union, it is decoded, and the appropriate field + in value]]> is set, and is + incremented by the term size.

+

The function returns 0 on successful encoding, -1 on error, + and 1 if the term seems alright, but does not fit in the + structure. If it returns 0, the + will be incremented, and the contains the + decoded term.

+

The structure will contain the arity for a tuple + or list, size for a binary, string or atom. It will contains + a term if it's any of the following: integer, float, atom, + pid, port or ref.

+
+
+ + intei_decode_term(const char *buf, int *index, void *t) + Decode a + +

This function decodes a term from the binary format. The + term is return in as a , so + is actually an (see + . The term should later be + deallocated.

+

Note that this function is located in the erl_interface + library.

+
+
+ + intei_print_term(FILE* fp, const char* buf, int* index) + intei_s_print_term(char** s, const char* buf, int* index) + Print a term in clear text + +

This function prints a term, in clear text, to the file + given by , or the buffer pointed to by . It + tries to resemble the term printing in the erlang shell.

+

In , the parameter should + point to a dynamically (malloc) allocated string of + bytes or a NULL pointer. The string may be + reallocated (and may be updated) by this function + if the result is more than characters. The + string returned is zero-terminated.

+

The return value is the number of characters written to the + file or string, or -1 if doesn't contain a + valid term. Unfortunately, I/O errors on is not + checked.

+

The argument is updated, i.e. this function can + be viewed as en decode function that decodes a term into a + human readable format.

+
+
+ + intei_x_format(ei_x_buff* x, const char* fmt, ...) + intei_x_format_wo_ver(ei_x_buff* x, const char *fmt, ... ) + Format a term from a format string and parameters. + +

Format a term, given as a string, to a buffer. This + functions works like a sprintf for erlang terms. The + contains a format string, with arguments like + , to insert terms from variables. The following + formats are supported (with the C types given):

+

+
+~a - an atom, char*
+~s - a string, char*
+~i - an integer, int
+~l - a long integer, long int
+~u - a unsigned long integer, unsigned long int
+~f - a float, float
+~d - a double float, double float
+        
+

For instance, to encode a tuple with some stuff:

+
+ei_x_format("{~a,~i,~d}", "numbers", 12, 3.14159)
+encodes the tuple {numbers,12,3.14159}
+        
+

The formats into a buffer, without + the initial version byte.

+
+
+ + intei_x_new(ei_x_buff* x) + intei_x_new_with_version(ei_x_buff* x) + Allocate a new buffer + +

This function allocates a new buffer. The + fields of the structure pointed to by parameter is + filled in, and a default buffer is allocated. The + also puts an initial version + byte, that is used in the binary format. (So that + won't be needed.)

+
+
+ + intei_x_free(ei_x_buff* x) + Frees a buffer + +

This function frees an buffer. The memory + used by the buffer is returned to the OS.

+
+
+ + intei_x_append(ei_x_buff* x, const ei_x_buff* x2) + intei_x_append_buf(ei_x_buff* x, const char* buf, int len) + Appends a buffer at the end + +

These functions appends data at the end of the buffer .

+
+
+ + intei_skip_term(const char* buf, int* index) + skip a term + +

This function skips a term in the given buffer, it + recursively skips elements of lists and tuples, so that a + full term is skipped. This is a way to get the size of an + erlang term.

+

is the buffer.

+

is updated to point right after the term in the + buffer.

+ +

This can be useful when you want to hold arbitrary + terms: just skip them and copy the binary term data to some + buffer.

+
+

The function returns on success and on + failure.

+
+
+
+ +
+ Debug Information +

Some tips on what to check when the emulator doesn't seem to + receive the terms that you send.

+ + be careful with the version header, use + when appropriate + turn on distribution tracing on the erlang node + check the result codes from ei_decode_-calls + +
+ +
+ See Also +

erl_interface(3)

+
+
+ diff --git a/lib/erl_interface/doc/src/ei_connect.xml b/lib/erl_interface/doc/src/ei_connect.xml new file mode 100644 index 0000000000..08e7b122c6 --- /dev/null +++ b/lib/erl_interface/doc/src/ei_connect.xml @@ -0,0 +1,639 @@ + + + + +
+ + 20012009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + ei_connect + Jakob Cederlund + + ? + ? + 2001-09-01 + A + ei_connect.sgml +
+ ei_connect + Communicate with distributed erlang + +

This module enables C programs to communicate with erlang nodes, + using the erlang distribution over TCP/IP.

+

A C node appears to Erlang as a + hidden node. + That is, Erlang processes that know the name of the + C node are able to communicate with it in a normal manner, but + the node name will not appear in the listing provided by the + Erlang function .

+

The environment variable can be used + to indicate which logical cluster a C node belongs to.

+
+ +
+ Timeout functions +

Most functions appear in a version with the suffix + appended to the function name. Those function take + an additional argument, a timeout in milliseconds. The + semantics is this; for each communication primitive involved in + the operation, if the primitive does not complete within the time + specified, the function will return an error and + will be set to . With + communication primitive is ment an operation on the socket, like + , , or .

+

Obviously the timeouts are for implementing fault tolerance, + not to keep hard realtime promises. The functions + are for detecting non-responsive peers and to avoid blocking on + socket operations.

+

A timeout value of (zero), means that timeouts are + disabled. Calling a -function with the last argument as + is therefore exactly the same thing as calling the + function without the suffix.

+

As with all other ei functions, you are not expected + to put the socket in non blocking mode yourself in the program. Every + use of non blocking mode is embedded inside the timeout + functions. The socket will always be back in blocking mode after + the operations are completed (regardless of the result). To + avoid problems, leave the socket options alone. Ei will handle + any socket options that need modification.

+

In all other senses, the functions inherit all + the return values and the semantics from the functions without + the suffix.

+
+ + + intei_connect_init(ei_cnode* ec, const char* this_node_name, const char *cookie, short creation) + intei_connect_xinit(ei_cnode* ec, const char *thishostname, const char *thisalivename, const char *thisnodename, Erl_IpAddr thisipaddr, const char *cookie, short creation) + Initialize for a connection. + +

These function initializes the structure, to + identify the node name and cookie of the server. One of them + has to be called before other functions that works on the + type or a file descriptor associated with a + connection to another node are used.

+

is a structure containing information about the + C-node. It is used in other functions for + connecting and receiving data.

+

is the registered name of the process + (the name before '@').

+

is the cookie for the node.

+

identifies a specific instance of a C + node. It can help prevent the node from receiving messages + sent to an earlier process with the same registered name.

+

is the name of the machine we're running + on. If long names are to be used, it should be fully + qualified (i.e. instead of + ).

+

is the registered name of the process.

+

is the full name of the node, + i.e. .

+

if the IP address of the host.

+

A C node acting as a server will be assigned a creation + number when it calls .

+

A connection is closed by simply closing the socket. Refer + to system documentation to close the socket gracefully (when + there are outgoing packets before close).

+

This function return a negative value indicating that an error + occurred.

+

Example 1: +

+ +

Example 2: +

+ +
+
+ + intei_connect(ei_cnode* ec, char *nodename) + intei_xconnect(ei_cnode* ec, Erl_IpAddr adr, char *alivename) + Establishe a connection to an Erlang node + +

These functions set up a connection to an Erlang node.

+

requires the IP address of the remote + host and the alive name of the remote node + to be specified. provides an alternative + interface, and determines the information from the node name + provided.

+

is the 32-bit IP address of the remote host.

+

is the alivename of the remote node.

+

is the name of the remote node.

+

These functions return an open file descriptor on success, or + a negative value indicating that an error occurred --- in + which case they will set to one of:

+ + + The remote host is unreachable + + No more memory available. + + I/O error. + +

Additionally, values from + (2) and (2) + system calls may be propagated into .

+

Example:

+ +
+
+ + intei_connect_tmo(ei_cnode* ec, char *nodename, unsigned timeout_ms) + intei_xconnect_tmo(ei_cnode* ec, Erl_IpAddr adr, char *alivename, unsigned timeout_ms) + Establish a connection to an Erlang node with optional timeout + +

ei_connect and ei_xconnect with an optional timeout argument, + see the description at the beginning of this document.

+
+
+ + intei_receive(int fd, unsigned char* bufp, int bufsize) + Receive a message + +

This function receives a message consisting of a sequence + of bytes in the Erlang external format.

+

is an open descriptor to an Erlang connection. It + is obtained from a previous or + .

+

is a buffer large enough to hold the expected + message.

+

indicates the size of .

+

If a tick occurs, i.e., the Erlang node on the + other end of the connection has polled this node to see if it + is still alive, the function will return and + no message will be placed in the buffer. Also, + will be set to .

+

On success, the message is placed in the specified buffer + and the function returns the number of bytes actually read. On + failure, the function returns and will set + to one of:

+ + + Temporary error: Try again. + + Buffer too small. + + I/O error. + +
+
+ + intei_receive_tmo(int fd, unsigned char* bufp, int bufsize, unsigned timeout_ms) + Receive a message with optional timeout + +

ei_receive with an optional timeout argument, + see the description at the beginning of this document.

+
+
+ + intei_receive_msg(int fd, erlang_msg* msg, ei_x_buff* x) + intei_xreceive_msg(int fd, erlang_msg* msg, ei_x_buff* x) + Receive a message + +

These functions receives a message to the buffer in + . allows the buffer in + to grow, but fails if the + message is bigger than the preallocated buffer in .

+

is an open descriptor to an Erlang connection.

+

is a pointer to an structure + and contains information on the message received.

+

is buffer obtained from .

+

On success, the function returns and the + struct will be initialized. + is defined as follows:

+ +

identifies the type of message, and is one of + , , , + and .

+

If is this indicates that an + ordinary send operation has taken place, and to]]> + contains the Pid of the recipient (the C-node). If + is then a registered send + operation took place, and from]]> contains the Pid + of the sender.

+

If is or , then + to]]> and from]]> contain the pids of the + sender and recipient of the link or unlink.

+

If is , then this indicates that + a link has been broken. In this case, to]]> and + from]]> contain the pids of the linked processes.

+

The return value is the same as for , see + above.

+
+
+ + intei_receive_msg_tmo(int fd, erlang_msg* msg, ei_x_buff* x, unsigned imeout_ms) + intei_xreceive_msg_tmo(int fd, erlang_msg* msg, ei_x_buff* x, unsigned timeout_ms) + Receive a message with optional timeout + +

ei_receive_msg and ei_xreceive_msg with an optional timeout argument, + see the description at the beginning of this document.

+
+
+ + intei_receive_encoded(int fd, char **mbufp, int *bufsz, erlang_msg *msg, int *msglen) + Obsolete function for receiving a message + +

This function is retained for compatibility with code + generated by the interface compiler and with code following + examples in the same application.

+

In essence the function performs the same operation as + , but instead of using an ei_x_buff, the + function expects a pointer to a character pointer + (), where the character pointer should point to a + memory area allocated by . The argument + should be a pointer to an integer containing the + exact size (in bytes) of the memory area. The function may + reallocate the memory area and will in such cases put the new + size in and update .

+

Furthermore the function returns either ERL_TICK or the + field of the . The actual + length of the message is put in . On error it + will return a value .

+

It is recommended to use ei_xreceive_msg instead when + possible, for the sake of readability. The function will + however be retained in the interface for compatibility and + will not be removed not be removed in future releases + without notice.

+
+
+ + intei_receive_encoded_tmo(int fd, char **mbufp, int *bufsz, erlang_msg *msg, int *msglen, unsigned timeout_ms) + Obsolete function for receiving a message with timeout + +

ei_receive_encoded with an optional timeout argument, + see the description at the beginning of this document.

+
+
+ + intei_send(int fd, erlang_pid* to, char* buf, int len) + Send a message + +

This function sends an Erlang term to a process.

+

is an open descriptor to an Erlang connection.

+

is the Pid of the intended recipient of the + message.

+

is the buffer containing the term in binary + format.

+

is the length of the message in bytes.

+

The function returns 0 if successful, otherwise -1, in the + latter case it will set to .

+
+
+ + intei_send_tmo(int fd, erlang_pid* to, char* buf, int len, unsigned timeout_ms) + Send a message with optional timeout + +

ei_send with an optional timeout argument, + see the description at the beginning of this document.

+
+
+ + intei_send_encoded(int fd, erlang_pid* to, char* buf, int len) + Obsolete function to send a message + +

Works exactly as ei_send, the alternative name retained for + backward compatibility. The function will not be + removed without notice.

+
+
+ + intei_send_encoded_tmo(int fd, erlang_pid* to, char* buf, int len, unsigned timeout_ms) + Obsolete function to send a message with optional timeout + +

ei_send_encoded with an optional timeout argument, + see the description at the beginning of this document.

+
+
+ + intei_reg_send(ei_cnode* ec, int fd, char* server_name, char* buf, int len) + Send a message to a registered name + +

This function sends an Erlang term to a registered process. +

+

This function sends an Erlang term to a process.

+

is an open descriptor to an Erlang connection.

+

is the registered name of the intended + recipient.

+

is the buffer containing the term in binary + format.

+

is the length of the message in bytes.

+

The function returns 0 if successful, otherwise -1, in the + latter case it will set to .

+

Example, send the atom "ok" to the process "worker":

+ +
+
+ + intei_reg_send_tmo(ei_cnode* ec, int fd, char* server_name, char* buf, int len, unsigned timeout_ms) + Send a message to a registered name with optional timeout + +

ei_reg_send with an optional timeout argument, + see the description at the beginning of this document.

+
+
+ + intei_send_reg_encoded(int fd, const erlang_pid *from, const char *to, const char *buf, int len) + Obsolete function to send a message to a registered name + +

This function is retained for compatibility with code + generated by the interface compiler and with code following + examples in the same application.

+

The function works as with one + exception. Instead of taking the as a first + argument, it takes a second argument, an + which should be the process identifier of the sending process + (in the erlang distribution protocol).

+

A suitable can be constructed from the + structure by the following example code:

+ num = fd; + ]]> +
+
+ + intei_send_reg_encoded_tmo(int fd, const erlang_pid *from, const char *to, const char *buf, int len) + Obsolete function to send a message to a registered name with timeout + +

ei_send_reg_encoded with an optional timeout argument, + see the description at the beginning of this document.

+
+
+ + intei_rpc(ei_cnode *ec, int fd, char *mod, char *fun, const char *argbuf, int argbuflen, ei_x_buff *x) + intei_rpc_to(ei_cnode *ec, int fd, char *mod, char *fun, const char *argbuf, int argbuflen) + intei_rpc_from(ei_cnode *ec, int fd, int timeout, erlang_msg *msg, ei_x_buff *x) + Remote Procedure Call from C to Erlang + +

These functions support calling Erlang functions on remote nodes. + sends an rpc request to a remote node and + receives the results of such a call. + combines the functionality of these two functions + by sending an rpc request and waiting for the results. See also + .

+

is the C-node structure previously initiated by a + call to or +

+

is an open descriptor to an Erlang connection.

+

is the maximum time (in ms) to wait for + results. Specify to wait forever. + will wait infinitely for the answer, + i.e. the call will never time out.

+

is the name of the module containing the function + to be run on the remote node.

+

is the name of the function to run.

+

is a pointer to a buffer with an encoded + Erlang list, without a version magic number, containing the + arguments to be passed to the function.

+

is the length of the buffer containing the + encoded Erlang list.

+

structure of type and contains + information on the message received. See + for a description of the format.

+

points to the dynamic buffer that receives the + result. For for this will be the result + without the version magic number. For + the result will return a version magic number and a 2-tuple + .

+

returns the number of bytes in the result + on success and -1 on failure. returns + number of bytes or one of , + and otherwise. When failing, + all three functions set to one of:

+ + + I/O error. + + Timeout expired. + + Temporary error: Try again. + +

Example, check to see if an erlang process is alive:

+ +
+
+ + intei_publish(ei_cnode *ec, int port) + Publish a node name + +

These functions are used by a server process to register + with the local name server epmd, thereby allowing + other processes to send messages by using the registered name. + Before calling either of these functions, the process should + have called and on an open socket.

+

is the C-node structure.

+

is the local name to register, and should be the + same as the port number that was previously bound to the socket.

+

is the 32-bit IP address of the local host.

+

To unregister with epmd, simply close the returned + descriptor. See also .

+

On success, the functions return a descriptor connecting the + calling process to epmd. On failure, they return -1 and set + to .

+

Additionally, values from (2) + and (2) system calls may be propagated + into .

+
+
+ + intei_publish_tmo(ei_cnode *ec, int port, unsigned timeout_ms) + Publish a node name with optional timeout + +

ei_publish with an optional timeout argument, + see the description at the beginning of this document.

+
+
+ + intei_accept(ei_cnode *ec, int listensock, ErlConnect *conp) + Accept a connection from another node + +

This function is used by a server process to accept a + connection from a client process.

+

is the C-node structure.

+

is an open socket descriptor on which + has previously been called.

+

is a pointer to an struct, + described as follows:

+ +

On success, is filled in with the address and + node name of the connecting client and a file descriptor is + returned. On failure, is returned and + is set to .

+
+
+ + intei_accept_tmo(ei_cnode *ec, int listensock, ErlConnect *conp, unsigned timeout_ms) + Accept a connection from another node with optional timeout + +

ei_accept with an optional timeout argument, + see the description at the beginning of this document.

+
+
+ + intei_unpublish(ei_cnode *ec) + Unpublish a node name + +

This function can be called by a process to unregister a + specified node from epmd on the localhost. This may be + useful, for example, when epmd has not detected the failure of a + node, and will not allow the name to be reused. If you use this + function to unregister your own process, be sure to also close + the descriptor that was returned by .

+ +

Careless use of this function may have unpredictable + results, if the registered node is in fact still running.

+
+

is the node structure of the node to unregister.

+

If the node was successfully unregistered from epmd, the + function returns 0. Otherwise, it returns -1 and sets + is to .

+
+
+ + intei_unpublish_tmo(ei_cnode *ec, unsigned timeout_ms) + Unpublish a node name with optional timeout + +

ei_unpublish with an optional timeout argument, + see the description at the beginning of this document.

+
+
+ + const char *ei_thisnodename(ei_cnode *ec) + const char *ei_thishostname(ei_cnode *ec) + const char *ei_thisalivename(ei_cnode *ec) + Retrieve some values + +

These functions can be used to retrieve information about + the C Node. These values are initially set with + or .

+

They simply fetches the appropriate field from the + structure. Read the field directly will probably be safe for + a long time, so these functions are not really needed.

+
+
+ + erlang_pid *ei_self(ei_cnode *ec) + Retrieve the Pid of the C-node + +

This function retrieves the Pid of the C-node. Every C-node + has a (pseudo) pid used in , + and others. This is contained in a field in the + structure. It will be safe for a long time to fetch this + field directly from the structure.

+
+
+ + struct hostent*ei_gethostbyname(const char *name) + struct hostent*ei_gethostbyaddr(const char *addr, int len, int type) + struct hostent*ei_gethostbyname_r(const char *name, struct hostent *hostp, char *buffer, int buflen, int *h_errnop) + struct hostent*ei_gethostbyaddr_r(const char *addr, int length, int type, struct hostent *hostp, char *buffer, int buflen, int *h_errnop) + Name lookup functions + +

These are convenience functions for some common name lookup functions.

+
+
+
+ +
+ Debug Information +

If a connection attempt fails, the following can be checked:

+ + + that the right cookie was used + that epmd is running + the remote Erlang node on the other side is running the + same version of Erlang as the + library. + the environment variable + is set correctly. + +
+
+ diff --git a/lib/erl_interface/doc/src/ei_users_guide.xml b/lib/erl_interface/doc/src/ei_users_guide.xml new file mode 100644 index 0000000000..5d18e356cb --- /dev/null +++ b/lib/erl_interface/doc/src/ei_users_guide.xml @@ -0,0 +1,612 @@ + + + + +
+ + 20022009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + The El Library User's Guide + Kent Boortz + Kent Boortz + + + + + + ei_users_guide.xml +
+

The Erl_Interface library contains functions. which help you + integrate programs written in C and Erlang. The functions in + Erl_Interface support the following:

+ + manipulation of data represented as Erlang data types + conversion of data between C and Erlang formats + encoding and decoding of Erlang data types for transmission or storage + communication between C nodes and Erlang processes + backup and restore of C node state to and from Mnesia + +

In the following sections, these topics are described:

+ + compiling your code for use with Erl_Interface + initializing Erl_Interface + encoding, decoding, and sending Erlang terms + building terms and patterns + pattern matching + connecting to a distributed Erlang node + using EPMD + sending and receiving Erlang messages + remote procedure calls + global names + the registry + + +
+ Compiling and Linking Your Code +

In order to use any of the Erl_Interface functions, include the + following lines in your code:

+ +

Determine where the top directory of your OTP installation is. You + can find this out by starting Erlang and entering the following + command at the Eshell prompt:

+ code:root_dir(). +/usr/local/otp ]]> +

To compile your code, make sure that your C compiler knows where + to find by specifying an appropriate + argument on the command line, or by adding it to the + definition in your . The correct value for this path is + Vsn, where is the path + reported by in the above example, and Vsn is + the version of the Erl_interface application, for example +

+ +

When linking, you will need to specify the path to + and with + , and you will need to specify the + name of the libraries with . You can do + this on the command line or by adding the flags to the + definition in your .

+ +

Also, on some systems it may be necessary to link with some + additional libraries (e.g. and on + Solaris, or on Windows) in order to use the + communication facilities of Erl_Interface.

+

If you are using Erl_Interface functions in a threaded + application based on POSIX threads or Solaris threads, then + Erl_Interface needs access to some of the synchronization + facilities in your threads package, and you will need to specify + additional compiler flags in order to indicate which of the packages + you are using. Define and either or + . The default is to use POSIX threads if + is specified.

+
+ +
+ Initializing the erl_interface Library +

Before calling any of the other Erl_Interface functions, you + must call exactly once to initialize the library. + takes two arguments, however the arguments are no + longer used by Erl_Interface, and should therefore be specified + as .

+
+ +
+ Encoding, Decoding and Sending Erlang Terms +

Data sent between distributed Erlang nodes is encoded in the + Erlang external format. Consequently, you have to encode and decode + Erlang terms into byte streams if you want to use the distribution + protocol to communicate between a C program and Erlang.

+

The Erl_Interface library supports this activity. It has a + number of C functions which create and manipulate Erlang data + structures. The library also contains an encode and a decode function. + The example below shows how to create and encode an Erlang tuple + :

+ +

Alternatively, you can use and + , which handle the encoding and decoding of + messages transparently.

+

Refer to the Reference Manual for a complete description of the + following modules:

+ + the module for creating Erlang terms + the module for encoding and decoding routines. + +
+ +
+ Building Terms and Patterns +

The previous example can be simplified by using + to create an Erlang term.

+ +

Refer to the Reference Manual, the module, for a + full description of the different format directives. The following + example is more complex:

+ +

As in previous examples, it is your responsibility to free the + memory allocated for Erlang terms. In this example, + ensures that the complete term pointed to + by is released. This is necessary, because the pointer from + the second call to is lost.

+

The following + example shows a slightly different solution:

+ +

In this case, you free the two terms independently. The order in + which you free the terms and is not important, + because the Erl_Interface library uses reference counting to + determine when it is safe to actually remove objects.

+

If you are not sure whether you have freed the terms properly, you + can use the following function to see the status of the fixed term + allocator:

+ +

Refer to the Reference Manual, the module for more + information.

+
+ +
+ Pattern Matching +

An Erlang pattern is a term that may contain unbound variables or + symbols. Such a pattern can be matched against a + term and, if the match is successful, any unbound variables in the + pattern will be bound as a side effect. The content of a bound + variable can then be retrieved.

+ +

is used to perform pattern matching. It takes a + pattern and a term and tries to match them. As a side effect any unbound + variables in the pattern will be bound. In the following example, we + create a pattern with a variable Age which appears at two + positions in the tuple. The pattern match is performed as follows:

+ + will bind the contents of + Age to 21 the first time it reaches the variable + the second occurrence of Age will cause a test for + equality between the terms since Age is already bound to + 21. Since Age is bound to 21, the equality test will + succeed and the match continues until the end of the pattern. + if the end of the pattern is reached, the match succeeds and you + can retrieve the contents of the variable + + +

Refer to the Reference Manual, the function for + more information.

+
+ +
+ Connecting to a Distributed Erlang Node +

In order to connect to a distributed Erlang node you need to first + initialize the connection routine with , + which stores information such as the host name, node name, and IP + address for later use:

+ +

Refer to the Reference Manual, the module for more information.

+

After initialization, you set up the connection to the Erlang node. + Use to specify the Erlang node you want to + connect to. The following example sets up the connection and should + result in a valid socket file descriptor:

+ +

prints the specified string and terminates + the program. Refer to the Reference Manual, the + function for more information.

+
+ +
+ Using EPMD +

is the Erlang Port Mapper Daemon. Distributed Erlang nodes + register with on the localhost to indicate to other nodes that + they exist and can accept connections. maintains a register of + node and port number information, and when a node wishes to connect to + another node, it first contacts in order to find out the correct + port number to connect to.

+

When you use to connect to an Erlang node, a + connection is first made to and, if the node is known, a + connection is then made to the Erlang node.

+

C nodes can also register themselves with if they want other + nodes in the system to be able to find and connect to them.

+

Before registering with , you need to first create a listen socket + and bind it to a port. Then:

+ +

is a file descriptor now connected to . + monitors the other end of the connection, and if it detects that the + connection has been closed, the node will be unregistered. So, if you + explicitly close the descriptor or if your node fails, it will be + unregistered from .

+

Be aware that on some systems (such as VxWorks), a failed node will + not be detected by this mechanism since the operating system does not + automatically close descriptors that were left open when the node + failed. If a node has failed in this way, will prevent you from + registering a new node with the old name, since it thinks that the old + name is still in use. In this case, you must unregister the name + explicitly:

+ +

This will cause to close the connection from the far end. Note + that if the name was in fact still in use by a node, the results of + this operation are unpredictable. Also, doing this does not cause the + local end of the connection to close, so resources may be consumed.

+
+ +
+ Sending and Receiving Erlang Messages +

Use one of the following two functions to send messages:

+ + + + +

As in Erlang, it is possible to send messages to a + Pid or to a registered name. It is easier to send a + message to a registered name because it avoids the problem of finding + a suitable Pid.

+

Use one of the following two functions to receive messages:

+ + + + +

receives the message into a buffer, while + decodes the message into an Erlang term.

+ +
+ Example of Sending Messages +

In the following example, is + sent to a registered process . The message is encoded + by :

+ +

The first element of the tuple that is sent is your own + Pid. This enables to reply. Refer to the + Reference Manual, the module for more information + about send primitives.

+
+ +
+ Example of Receiving Messages +

In this example is received. The + received Pid is then used to return

+ +

In order to provide robustness, a distributed Erlang node + occasionally polls all its connected neighbours in an attempt to + detect failed nodes or communication links. A node which receives such + a message is expected to respond immediately with an message. + This is done automatically by , however when this + has occurred returns to the caller + without storing a message into the structure.

+

When a message has been received, it is the caller's responsibility + to free the received message as well as + or , depending on the type of message received.

+

Refer to the Reference Manual for additional information about the + following modules:

+ + + . + +
+
+ +
+ Remote Procedure Calls +

An Erlang node acting as a client to another Erlang node + typically sends a request and waits for a reply. Such a request is + included in a function call at a remote node and is called a remote + procedure call. The following example shows how the + Erl_Interface library supports remote procedure calls:

+ when compiling file: %s.erl !\n", modname); +erl_free_term(ep); +ep = erl_format("{ok,_}"); +if (!erl_match(ep, reply)) + erl_err_msg(" compiler errors !\n"); +erl_free_term(ep); +erl_free_term(reply); ]]> +

is called to compile the specified module on the + remote node. checks that the compilation was + successful by testing for the expected .

+

Refer to the Reference Manual, the module for + more information about , and its companions + and .

+
+ +
+ Using Global Names +

A C node has access to names registered through the Erlang Global + module. Names can be looked up, allowing the C node to send messages + to named Erlang services. C nodes can also register global names, + allowing them to provide named services to Erlang processes or other C + nodes.

+

Erl_Interface does not provide a native implementation of the global + service. Instead it uses the global services provided by a "nearby" + Erlang node. In order to use the services described in this section, + it is necessary to first open a connection to an Erlang node.

+

To see what names there are:

+ +

allocates and returns a buffer containing + all the names known to global. will be initialized to + indicate how many names are in the array. The array of strings in + names is terminated by a NULL pointer, so it is not necessary to use + to determine when the last name is reached.

+

It is the caller's responsibility to free the array. + allocates the array and all of the strings + using a single call to , so is all + that is necessary.

+

To look up one of the names:

+ +

If is known to global, an Erlang pid is returned + that can be used to send messages to the schedule service. + Additionally, will be initialized to contain the name of + the node where the service is registered, so that you can make a + connection to it by simply passing the variable to .

+

Before registering a name, you should already have registered your + port number with . This is not strictly necessary, but if you + neglect to do so, then other nodes wishing to communicate with your + service will be unable to find or connect to your process.

+

Create a pid that Erlang processes can use to communicate with your + service:

+ +

After registering the name, you should use to wait for + incoming connections.

+

Do not forget to free later with !

+

To unregister a name:

+ +
+ +
+ The Registry +

This section describes the use of the registry, a simple mechanism + for storing key-value pairs in a C-node, as well as backing them up or + restoring them from a Mnesia table on an Erlang node. More detailed + information about the individual API functions can be found in the + Reference Manual.

+

Keys are strings, i.e. 0-terminated arrays of characters, and values + are arbitrary objects. Although integers and floating point numbers + are treated specially by the registry, you can store strings or binary + objects of any type as pointers.

+

To start, you need to open a registry:

+ +

The number 45 in the example indicates the approximate number of + objects that you expect to store in the registry. Internally the + registry uses hash tables with collision chaining, so there is no + absolute upper limit on the number of objects that the registry can + contain, but if performance or memory usage are important, then you + should choose a number accordingly. The registry can be resized later.

+

You can open as many registries as you like (if memory permits).

+

Objects are stored and retrieved through set and get functions. In + the following examples you see how to store integers, floats, strings + and arbitrary binary objects:

+ l = 42; +b->m = 12; +ei_reg_setpval(reg,"jox",b,sizeof(*b)); ]]> +

If you attempt to store an object in the registry and there is an + existing object with the same key, the new value will replace the old + one. This is done regardless of whether the new object and the old one + have the same type, so you can, for example, replace a string with an + integer. If the existing value is a string or binary, it will be freed + before the new value is assigned.

+

Stored values are retrieved from the registry as follows:

+ +

In all of the above examples, the object must exist and it must be of + the right type for the specified operation. If you do not know the + type of a given object, you can ask:

+ +

Buf will be initialized to contain object attributes.

+

Objects can be removed from the registry:

+ +

When you are finished with a registry, close it to remove all the + objects and free the memory back to the system:

+ + +
+ Backing Up the Registry to Mnesia +

The contents of a registry can be backed up to Mnesia on a "nearby" + Erlang node. You need to provide an open connection to the Erlang node + (see ). Also, Mnesia 3.0 or later must be running + on the Erlang node before the backup is initiated:

+ +

The example above will backup the contents of the registry to the + specified Mnesia table . Once a registry has been backed + up to Mnesia in this manner, additional backups will only affect + objects that have been modified since the most recent backup, i.e. + objects that have been created, changed or deleted. The backup + operation is done as a single atomic transaction, so that the entire + backup will be performed or none of it will.

+

In the same manner, a registry can be restored from a Mnesia table:

+ +

This will read the entire contents of into the specified + registry. After the restore, all of the objects in the registry will + be marked as unmodified, so a subsequent backup will only affect + objects that you have modified since the restore.

+

Note that if you restore to a non-empty registry, objects in the + table will overwrite objects in the registry with the same keys. Also, + the entire contents of the registry is marked as unmodified + after the restore, including any modified objects that were not + overwritten by the restore operation. This may not be your intention.

+
+ +
+ Storing Strings and Binaries +

When string or binary objects are stored in the registry it is + important that a number of simple guidelines are followed.

+

Most importantly, the object must have been created with a single call + to (or similar), so that it can later be removed by a + single call to . Objects will be freed by the registry + when it is closed, or when you assign a new value to an object that + previously contained a string or binary.

+

You should also be aware that if you store binary objects that are + context-dependent (e.g. containing pointers or open file descriptors), + they will lose their meaning if they are backed up to a Mnesia table + and subsequently restored in a different context.

+

When you retrieve a stored string or binary value from the registry, + the registry maintains a pointer to the object and you are passed a + copy of that pointer. You should never free an object retrieved in + this manner because when the registry later attempts to free it, a + runtime error will occur that will likely cause the C-node to crash.

+

You are free to modify the contents of an object retrieved this way. + However when you do so, the registry will not be aware of the changes + you make, possibly causing it to be missed the next time you make a + Mnesia backup of the registry contents. This can be avoided if you + mark the object as dirty after any such changes with + , or pass appropriate flags to + .

+
+
+
+ diff --git a/lib/erl_interface/doc/src/erl_call.xml b/lib/erl_interface/doc/src/erl_call.xml new file mode 100644 index 0000000000..2d88e7616a --- /dev/null +++ b/lib/erl_interface/doc/src/erl_call.xml @@ -0,0 +1,240 @@ + + + + +
+ + 19962009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + erl_call + Torbjörn Törnkvist + Torbjörn Törnkvist + + Bjarne Däcker + Torbjörn Törnkvist + 97-05-16 + B + erl_call.sgml +
+ erl_call + Call/Start a Distributed Erlang Node + +

makes it possible to start and/or communicate with + a distributed Erlang node. It is built upon the + library as an example application. Its purpose is to use an Unix shell script to interact with a distributed Erlang node. It performs all + communication with the Erlang rex server, using the standard Erlang RPC facility. It does not require any special + software to be run at the Erlang target node.

+

The main use is to either start a distributed Erlang node + or to make an ordinary function call. However, it is also + possible to pipe an Erlang module to and have it + compiled, or to pipe a sequence of Erlang expressions to be evaluated + (similar to the Erlang shell).

+

Options, which cause to be read, can be used with + advantage + as scripts from within (Unix) shell scripts. Another + nice use of could be from (http) CGI-bin scripts.

+
+ + + erl_call <options> + Start/Call Erlang + +

Each option flag is described below with its name, type and + meaning.

+ + -a [Mod [Fun [Args]]]] + +

(optional): Applies the specified function + and returns the result. must be specified, however + [] is assumed for unspecified and . should + be in the same format as for . Note + that this flag takes exactly one argument, so quoting + may be necessary in order to group , + and , in a manner dependent on the behavior + of your command shell.

+

+
+ -c Cookie + +

(optional): Use this option to specify a certain cookie. If no cookie is specified, the file is read and its content are used as cookie. The Erlang node we want to communicate with must have the same cookie.

+
+ -d + +

(optional): Debug mode. This causes all IO to be output + to the file , where + is the node name of the Erlang node in question.

+

+
+ -e + +

(optional): Reads a sequence of Erlang expressions, separated + by ',' and ended with a '.', from until + EOF (Control-D). Evaluates the expressions and returns the result from + the last expression. Returns if successful.

+

+
+ -h HiddenName + +

(optional): Specifies the name of the hidden node + that represents.

+

+
+ -m + +

(optional): Reads an Erlang module from and + compiles it.

+

+
+ -n Node + +

(one of is required): + Has the same meaning as and can still be used for + backwards compatibility reasons.

+

+
+ -name Node + +

(one of is required): is the name of the node to be + started or communicated with. It is assumed that + is started with , which means that fully + qualified long node names are used. + If the option is given, an Erlang node will (if necessary) + be started with .

+

+
+ -q + +

(optional): Halts the Erlang node specified + with the -n switch. This switch overrides the -s switch.

+

+
+ -r + +

(optional): Generates a random name of the hidden node + that represents.

+

+
+ -s + +

(optional): Starts a distributed Erlang node if necessary. + This means that in a sequence of calls, where the '' + and '' are constant, only the first call will start + the Erlang node. This makes the rest of the communication + very fast. This flag is currently only available on the Unix platform.

+

+
+ -sname Node + +

(one of is required): is the name of the node to + be started or communicated with. It is assumed that is started with which means that short node names are used. + If option is given, an Erlang node will be started (if necessary) with .

+

+
+ -v + +

(optional): Prints a lot of information. + This is only useful for the developer and maintainer of .

+

+
+ -x ErlScript + +

(optional): Specifies another name of the Erlang start-up script + to be used. If not specified, the standard start-up script + is used.

+
+
+
+
+
+ +
+ Examples +

Starts an Erlang node and calls .

+ +

Terminates an Erlang node by calling .

+ +

An apply with several arguments.

+ +

Evaluates a couple of expressions. The input ends with EOF (Control-D).

+ +

Compiles a module and runs it. Again, the input ends with EOF (Control-D). (In the example shown, the output has been formatted afterwards).

+ + P = processes(), + F = fun(X) -> {X,process_info(X,registered_name)} end, + lists:map(F,[],P). +^D +[{, + {registered_name,init}}, + {, + {registered_name,erl_prim_loader}}, + {, + {registered_name,error_logger}}, + {, + {registered_name,application_controller}}, + {, + {registered_name,kernel}}, + {, + []}, + {, + {registered_name,kernel_sup}}, + {, + {registered_name,net_sup}}, + {, + {registered_name,net_kernel}}, + {, + []}, + {, + {registered_name,global_name_server}}, + {, + {registered_name,auth}}, + {, + {registered_name,rex}}, + {, + []}, + {, + {registered_name,file_server}}, + {, + {registered_name,code_server}}, + {, + {registered_name,user}}, + {, + []}] + ]]> +
+
+ diff --git a/lib/erl_interface/doc/src/erl_connect.xml b/lib/erl_interface/doc/src/erl_connect.xml new file mode 100644 index 0000000000..b2235925b2 --- /dev/null +++ b/lib/erl_interface/doc/src/erl_connect.xml @@ -0,0 +1,566 @@ + + + + +
+ + 19962009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + erl_connect + Torbjörn Törnkvist + Torbjörn Törnkvist + + Bjarne Däcker + Torbjörn Törnkvist + 980703 + A + erl_connect.sgml +
+ erl_connect + Communicate with Distributed Erlang + +

This module provides support for communication between distributed + Erlang nodes and C nodes, in a manner that is transparent to Erlang + processes.

+

A C node appears to Erlang as a + hidden node. + That is, Erlang processes that know the name of the + C node are able to communicate with it in a normal manner, but + the node name will not appear in the listing provided by the + Erlang function .

+
+ + + interl_connect_init(number, cookie, creation) + interl_connect_xinit(host, alive, node, addr, cookie, creation) + Initialize communication + + int number; + char *cookie; + short creation; + char *host,*alive,*node; + struct in_addr *addr; + + +

These functions initialize the + module. In particular, they are used to identify the name of the + C-node from which they are called. One of these functions must + be called before any of the other functions in the erl_connect + module are used.

+

stores for later use information about + the node's host name , alive name , node + name , IP address , cookie , + and creation number . + provides an alternative interface which does not require as much + information from the caller. Instead, + uses to obtain default values. +

+

If you use your node will have a + short name, i.e., it will not be fully qualified. If you need to + use fully qualified (a.k.a. long) names, use + instead. +

+

is the name of the host on which the node is running.

+

is the alivename of the node.

+

is the name of the node. The nodename should + be of the form alivename@hostname.

+

is the 32-bit IP address of .

+

is the authorization string required for access + to the remote node. If NULL the user HOME directory is + searched for a cookie file . The path to + the home directory is retrieved from the environment variable + on Unix and from the and + variables on Windows. Refer to the + module for more details.

+

helps identify a particular instance of a C + node. In particular, it can help prevent us from receiving + messages sent to an earlier process with the same registered + name.

+

A C node acting as a server will be assigned a creation number + when it calls .

+

is used by to + construct the actual node name. In the second example shown + below, "c17@a.DNS.name" will be the resulting node + name.

+

Example 1:

+ when initializing !"); + ]]> +

Example 2:

+ when initializing !"); + ]]> +
+
+ + interl_connect(node) + interl_xconnect(addr, alive) + Establishe a connection to an Erlang node + + char *node, *alive; + struct in_addr *addr; + + +

These functions set up a connection to an Erlang node.

+

requires the IP address of the remote + host and the alive name of the remote node + to be specified. provides an alternative + interface, and determines the information from the node name + provided.

+

is the 32-bit IP address of the remote host.

+

is the alivename of the remote node.

+

is the name of the remote node.

+

These functions return an open file descriptor on success, or + a negative value indicating that an error occurred --- in + which case they will set to one of:

+ + + The remote host is unreachable + + No more memory available. + + I/O error. + +

Additionally, values from + (2) and (2) + system calls may be propagated into .

+ +
+
+ + interl_close_connection(fd) + Close a connection to an Erlang node + + int fd; + + +

This function closes an open connection to an Erlang node.

+

is a file descriptor obtained from + or .

+

On success, 0 is returned. If the call fails, a non-zero value + is returned, and the reason for + the error can be obtained with the appropriate platform-dependent + call.

+
+
+ + interl_receive(fd, bufp, bufsize) + Receive a message + + int fd; + char *bufp; + int bufsize; + + +

This function receives a message consisting of a sequence + of bytes in the Erlang external format.

+

is an open descriptor to an Erlang connection.

+

is a buffer large enough to hold the expected + message.

+

indicates the size of .

+

If a tick occurs, i.e., the Erlang node on the + other end of the connection has polled this node to see if it + is still alive, the function will return and + no message will be placed in the buffer. Also, + will be set to .

+

On success, the message is placed in the specified buffer + and the function returns the number of bytes actually read. On + failure, the function returns a negative value and will set + to one of:

+ + + Temporary error: Try again. + + Buffer too small. + + I/O error. + +
+
+ + interl_receive_msg(fd, bufp, bufsize, emsg) + Receive and decodes a message + + int fd; + unsigned char *bufp; + int bufsize; + ErlMessage *emsg; + + +

This function receives the message into the specified buffer, + and decodes into the .

+

is an open descriptor to an Erlang connection.

+

is a buffer large enough to hold the expected message.

+

indicates the size of .

+

is a pointer to an structure, + into which the message will be decoded. is + defined as follows:

+ + +

The definition of has changed since + earlier versions of Erl_Interface.

+
+

identifies the type of message, one of + , , , + and . +

+

If contains + this indicates that an ordinary send operation has taken + place, and to]]> contains the Pid of the + recipient. If contains then a + registered send operation took place, and from]]> + contains the Pid of the sender. In both cases, the actual + message will be in msg]]>. +

+

If contains one of or + , then to]]> and from]]> + contain the pids of the sender and recipient of the link or unlink. + msg]]> is not used in these cases. +

+

If contains , then this + indicates that a link has been broken. In this case, + to]]> and from]]> contain the pids of the + linked processes, and msg]]> contains the reason for + the exit. +

+ +

It is the caller's responsibility to release the + memory pointed to by msg]]>, to]]> and + from]]>.

+
+

If a tick occurs, i.e., the Erlang node on the + other end of the connection has polled this node to see if it + is still alive, the function will return + indicating that the tick has been received and responded to, + but no message will be placed in the buffer. In this case you + should call again.

+

On success, the function returns and the + struct will be initialized as described above, or + , in which case no message is returned. On + failure, the function returns and will set + to one of:

+ + + Buffer too small. + + No more memory available. + + I/O error. + +
+
+ + interl_xreceive_msg(fd, bufpp, bufsizep, emsg) + Receive and decodes a message + + int fd; + unsigned char **bufpp; + int *bufsizep; + ErlMessage *emsg; + + +

This function is similar to . The + difference is that expects the buffer to + have been allocated by , and reallocates it if the received + message does not fit into the original buffer. For that reason, + both buffer and buffer length are given as pointers - their values + may change by the call. +

+

On success, the function returns and the + struct will be initialized as described above, or + , in which case no message is returned. On + failure, the function returns and will set + to one of:

+ + + Buffer too small. + + No more memory available. + + I/O error. + +
+
+ + interl_send(fd, to, msg) + Send a message + + int fd; + ETERM *to, *msg; + + +

This function sends an Erlang term to a process.

+

is an open descriptor to an Erlang connection.

+

is an Erlang term containing the Pid of the + intended recipient of the message.

+

is the Erlang term to be sent.

+

The function returns 1 if successful, otherwise 0 --- in + which case it will set to one of:

+ + + Invalid argument: is not a valid Erlang pid. + + No more memory available. + + I/O error. + +
+
+ + interl_reg_send(fd, to, msg) + Send a message to a registered name + + int fd; + char *to; + ETERM *msg; + + +

This function sends an Erlang term to a registered process.

+

is an open descriptor to an Erlang connection.

+

is a string containing the registered name of + the intended recipient of the message.

+

is the Erlang term to be sent.

+

The function returns 1 if successful, otherwise 0 --- in + which case it will set to one of:

+ + + No more memory available. + + I/O error. + +
+
+ + ETERM *erl_rpc(fd, mod, fun, args) + interl_rpc_to(fd, mod, fun, args) + interl_rpc_from(fd, timeout, emsg) + Remote Procedure Call + + int fd, timeout; + char *mod, *fun; + ETERM *args; + ErlMessage *emsg; + + +

These functions support calling Erlang functions on remote nodes. + sends an rpc request to a remote node and + receives the results of such a call. + combines the functionality of these two functions + by sending an rpc request and waiting for the results. See also + .

+

is an open descriptor to an Erlang connection.

+

is the maximum time (in ms) to wait for + results. Specify to wait forever. + When erl_rpc() calls erl_rpc_from(), the call will never + timeout.

+

is the name of the module containing the function + to be run on the remote node.

+

is the name of the function to run.

+

is an Erlang list, containing the arguments to be + passed to the function.

+

is a message containing the result of the + function call.

+

The actual message returned by the rpc server + is a 2-tuple . If you are using + in your code then this is the message you + will need to parse. If you are using then the + tuple itself is parsed for you, and the message returned to your + program is the erlang term containing only. Replies + to rpc requests are always ERL_SEND messages. +

+ +

It is the caller's responsibility to free the returned + structure as well as the memory pointed to by + msg]]> and to]]>.

+
+

returns the remote function's return value (or + if it failed). returns 0 on + success, and a negative number on failure. + returns when successful (with now + containing the reply tuple), and one of , + and otherwise. When failing, + all three functions set to one of:

+ + + No more memory available. + + I/O error. + + Timeout expired. + + Temporary error: Try again. + +
+
+ + interl_publish(port) + Publish a node name + + int port; + + +

These functions are used by a server process to register + with the local name server epmd, thereby allowing + other processes to send messages by using the registered name. + Before calling either of these functions, the process should + have called and on an open socket.

+

is the local name to register, and should be the + same as the port number that was previously bound to the socket.

+

To unregister with epmd, simply close the returned + descriptor. See also . +

+

On success, the functions return a descriptor connecting the + calling process to epmd. On failure, they return -1 and set + to:

+ + + I/O error + +

Additionally, values from (2) + and (2) system calls may be propagated + into . +

+
+
+ + interl_accept(listensock, conp) + Accept a connection + + int listensock; + ErlConnect *conp; + + +

This function is used by a server process to accept a + connection from a client process.

+

is an open socket descriptor on which + has previously been called.

+

is a pointer to an struct, + described as follows:

+ +

On success, is filled in with the address and + node name of the connecting client and a file descriptor is + returned. On failure, is returned and + is set to .

+
+
+ + const char *erl_thiscookie() + const char *erl_thisnodename() + const char *erl_thishostname() + const char *erl_thisalivename() + shorterl_thiscreation() + Retrieve some values + +

These functions can be used to retrieve information about + the C Node. These values are initially set with + or .

+
+
+ + interl_unpublish(alive) + Unpublish a node name + + char *alive; + + +

This function can be called by a process to unregister a + specified node name from epmd on the localhost. This may be + useful, for example, when epmd has not detected the failure of a + node, and will not allow the name to be reused. If you use this + function to unregister your own process, be sure to also close + the descriptor that was returned by .

+ +

Careless use of this function may have unpredictable + results, if the registered node is in fact still running.

+
+

is the name of the node to unregister, i.e., the + first component of the nodename, without the .

+

If the node was successfully unregistered from epmd, the + function returns 0. Otherwise, it returns -1 and sets + is to .

+
+
+ + struct hostent*erl_gethostbyname(name) + struct hostent*erl_gethostbyaddr(addr, length, type) + struct hostent*erl_gethostbyname_r(name, hostp, buffer, buflen, h_errnop) + struct hostent*erl_gethostbyaddr_r(addr, length, type, hostp, buffer, buflen, h_errnop) + Name lookup functions + + const char *name; + const char *addr; + int length; + int type; + struct hostent *hostp; + char *buffer; + int buflen; + int *h_errnop; + + +

These are convenience functions for some common name lookup functions.

+
+
+
+ +
+ Debug Information +

If a connection attempt fails, the following can be checked:

+ + + that the right cookie was used + that epmd is running + the remote Erlang node on the other side is running the same + version of Erlang as the library. + +
+
+ diff --git a/lib/erl_interface/doc/src/erl_error.xml b/lib/erl_interface/doc/src/erl_error.xml new file mode 100644 index 0000000000..4a3f34fac7 --- /dev/null +++ b/lib/erl_interface/doc/src/erl_error.xml @@ -0,0 +1,136 @@ + + + + +
+ + 19962009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + erl_error + Torbjörn Törnkvist + Torbjörn Törnkvist + + Bjarne Däcker + Torbjörn Törnkvist + 961014 + A + erl_error.sgml +
+ erl_error + Error Print Routines + +

This module contains some error printing routines taken + from Advanced Programming in the UNIX Environment + by W. Richard Stevens.

+

These functions are all called in the same manner as + , i.e. with a string containing format specifiers + followed by a list of corresponding arguments. All output from + these functions is to .

+
+ + + voiderl_err_msg(FormatStr, ... ) + Non-fatal error, and not system call error + + const char *FormatStr; + + +

The message provided by the caller is printed. This + function is simply a wrapper for .

+
+
+ + voiderl_err_quit(FormatStr, ... ) + Fatal error, but not system call error + + const char *FormatStr; + + +

Use this function when a fatal error has occurred that + is not due to a system call. The message provided by the + caller is printed and the process terminates with an exit + value of 1. The function does not return.

+
+
+ + voiderl_err_ret(FormatStr, ... ) + Non-fatal system call error + + const char *FormatStr; + + +

Use this function after a failed system call. The message + provided by the caller is printed followed by a string + describing the reason for failure.

+
+
+ + voiderl_err_sys(FormatStr, ... ) + Fatal system call error + + const char *FormatStr; + + +

Use this function after a failed system call. The message + provided by the caller is printed followed by a string + describing the reason for failure, and the process + terminates with an exit value of 1. The function does not + return.

+
+
+
+ +
+ Error Reporting +

Most functions in erl_interface report failures to the caller by + returning some otherwise meaningless value (typically + or a negative number). As this only tells you that things did not + go well, you will have to examine the error code in + if you want to find out more about the failure.

+
+ + + volatile interl_errno + The variable contains the erl_interface error number. You can change the value if you wish. + +

is initially (at program startup) zero and + is then set by many erl_interface functions on failure to a + non-zero error code to indicate what kind of error it + encountered. A successful function call might change + (by calling some other function that + fails), but no function will ever set it to zero. This means + that you cannot use to see if a + function call failed. Instead, each function reports failure + in its own way (usually by returning a negative number or + ), in which case you can examine + for details.

+

uses the error codes defined in your + system's ]]>.

+ +

Actually, is a "modifiable lvalue" (just + like ISO C defines to be) rather than a + variable. This means it might be implemented as a macro + (expanding to, e.g., ). For reasons of + thread- (or task-)safety, this is exactly what we do on most + platforms.

+
+
+
+
+
+ diff --git a/lib/erl_interface/doc/src/erl_eterm.xml b/lib/erl_interface/doc/src/erl_eterm.xml new file mode 100644 index 0000000000..ce14549672 --- /dev/null +++ b/lib/erl_interface/doc/src/erl_eterm.xml @@ -0,0 +1,675 @@ + + + + +
+ + 19962009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + erl_eterm + Torbjörn Törnkvist + Torbjörn Törnkvist + + Bjarne Däcker + Torbjörn Törnkvist + 980703 + A + erl_eterm.sgml +
+ erl_eterm + Functions for Erlang Term Construction + +

This module contains functions for creating and manipulating + Erlang terms.

+

An Erlang term is represented by a C structure of type + . Applications should not reference any fields in this + structure directly, because it may be changed in future releases + to provide faster and more compact term storage. Instead, + applications should us the macros and functions provided.

+

The following macros each take a single ETERM pointer as an + argument. They return a non-zero value if the test is true, and 0 + otherwise:

+ + + True if is an integer. + + True if is an integer. + + True if is a floating point number. + + True if is an atom. + + True if is a Pid (process identifier). + + True if is a port. + + True if is a reference. + + True if is a tuple. + + True if is a binary. + + True if is a list with zero or more elements. + + True if is an empty list. + + True if is a list with at least one element. + +

The following macros can be used for retrieving parts of Erlang + terms. None of these do any type checking; results are undefined + if you pass an ETERM* containing the wrong type. For example, + passing a tuple to ERL_ATOM_PTR() will likely result in garbage. +

+ + + A string representing atom . + + + The length (in characters) of atom t. + + A pointer to the contents of + + The length (in bytes) of binary object . + + The integer of . + + The unsigned integer value of . + + The floating point value of . + + The Node in pid . + + The sequence number in pid . + + The serial number in pid . + + The creation number in pid . + + The sequence number in port . + + The creation number in port . + + The node in port . + + The first part of the reference number in ref . Use + only for compatibility. + + Pointer to the array of reference numbers in ref . + + The number of used reference numbers in ref . + + The creation number in ref . + + The number of elements in tuple . + + The head element of list . + + A List representing the tail elements of list . + +
+ + + ETERM *erl_cons(head, tail) + Prepends a term to the head of a list. + + ETERM *head; + ETERM *tail; + + +

This function concatenates two Erlang terms, prepending + onto and thereby creating a cell. + To make a proper list, should always be a + list or an empty list. Note that NULL is not a valid list.

+

is the new term to be added.

+

is the existing list to which will + be concatenated.

+

The function returns a new list.

+

and + can be used to retrieve the head and tail components + from the list. and will do + the same thing, but check that the argument really is a list.

+

For example:

+ +
+
+ + ETERM *erl_copy_term(term) + Creates a copy of an Erlang term + + ETERM *term; + + +

This function creates and returns a copy of the Erlang term + .

+
+
+ + ETERM *erl_element(position, tuple) + Extracts an element from an Erlang tuple + + int position; + ETERM *tuple; + + +

This function extracts a specified element from an Erlang + tuple.

+

specifies which element to retrieve from + . The elements are numbered starting from 1.

+

is an Erlang term containing at least + elements.

+

The function returns a new Erlang term corresponding to the + requested element, or NULL if was greater than + the arity of .

+
+
+ + voiderl_init(NULL, 0) + Initialization routine + + void *NULL; + int 0; + + + +

This function must be called before any of the others in + the library in order to initialize the + library functions. The arguments must be specified as + .

+
+
+ + ETERM *erl_hd(list) + Extracts the first element from a list + + ETERM *list; + + +

Extracts the first element from a list.

+

is an Erlang term containing a list.

+

The function returns an Erlang term corresponding to the + head element in the list, or a NULL pointer if was + not a list.

+
+
+ + ETERM *erl_iolist_to_binary(term) + Converts an IO list to a binary + + ETERM *list; + + +

This function converts an IO list to a binary term.

+

is an Erlang term containing a list.

+

This function an Erlang binary term, or NULL if + was not an IO list.

+

Informally, an IO list is a deep list of characters and + binaries which can be sent to an Erlang port. In BNF, an IO + list is formally defined as follows:

+ +
+
+ + char *erl_iolist_to_string(list) + Converts an IO list to a zero terminated string + + ETERM *list; + + +

This function converts an IO list to a '\\0' terminated C + string.

+

is an Erlang term containing an IO list. The IO + list must not contain the integer 0, since C strings may not + contain this value except as a terminating marker.

+

This function returns a pointer to a dynamically allocated + buffer containing a string. If is not an IO list, + or if contains the integer 0, NULL is returned. It + is the caller's responsibility free the allocated buffer + with .

+

Refer to for the definition of an + IO list.

+
+
+ + interl_iolist_length(list) + Return the length of an IO list + + ETERM *list; + + +

Returns the length of an IO list. +

+

is an Erlang term containing an IO list.

+

The function returns the length of , or -1 if + is not an IO list.

+

Refer to for the definition of + an IO list.

+
+
+ + interl_length(list) + Determines the length of a list + + ETERM *list; + + +

Determines the length of a proper list.

+

is an Erlang term containing proper list. In a + proper list, all tails except the last point to another list + cell, and the last tail points to an empty list.

+

Returns -1 if is not a proper list.

+
+
+ + ETERM *erl_mk_atom(string) + Creates an atom + + char *string; + + +

Creates an atom.

+

is the sequence of characters that will be + used to create the atom.

+

Returns an Erlang term containing an atom. Note that it is + the callers responsibility to make sure that + contains a valid name for an atom.

+

can be used to retrieve the + atom name (as a string). Note that the string is not + 0-terminated in the atom. returns + the length of the atom name.

+
+
+ + ETERM *erl_mk_binary(bptr, size) + Creates a binary object + + char *bptr; + int size; + + +

This function produces an Erlang binary object from a + buffer containing a sequence of bytes.

+

is a pointer to a buffer containing data to be converted.

+

indicates the length of .

+

The function returns an Erlang binary object.

+

retrieves a pointer to + the binary data. retrieves the + size.

+
+
+ + ETERM *erl_mk_empty_list() + Creates an empty Erlang list + +

This function creates and returns an empty Erlang list. + Note that NULL is not used to represent an empty list; + Use this function instead.

+
+
+ + ETERM *erl_mk_estring(string, len) + Creates an Erlang string + + char *string; + int len; + + +

This function creates a list from a sequence of bytes.

+

is a buffer containing a sequence of + bytes. The buffer does not need to be zero-terminated.

+

is the length of .

+

The function returns an Erlang list object corresponding to + the character sequence in .

+
+
+ + ETERM *erl_mk_float(f) + Creates an Erlang float + + double f; + + +

Creates an Erlang float.

+

is a value to be converted to an Erlang float.

+

+

The function returns an Erlang float object with the value + specified in .

+

can be used to retrieve the + value from an Erlang float.

+
+
+ + ETERM *erl_mk_int(n) + Creates an Erlang integer + + int n; + + +

Creates an Erlang integer.

+

is a value to be converted to an Erlang integer.

+

+

The function returns an Erlang integer object with the + value specified in .

+

can be used to retrieve the value + value from an Erlang integer.

+
+
+ + ETERM *erl_mk_list(array, arrsize) + Creates a list from an array + + ETERM **array; + int arrsize; + + +

Creates an Erlang list from an array of Erlang terms, such + that each element in the list corresponds to one element in + the array.

+

is an array of Erlang terms.

+

is the number of elements in .

+

The function creates an Erlang list object, whose length + and whose elements are taken from the terms in + .

+
+
+ + ETERM *erl_mk_pid(node, number, serial, creation) + Creates a process identifier + + const char *node; + unsigned int number; + unsigned int serial; + unsigned int creation; + + +

This function creates an Erlang process identifier. The + resulting pid can be used by Erlang processes wishing to + communicate with the C node.

+

is the name of the C node.

+

, and are + arbitrary numbers. Note though, that these are limited in + precision, so only the low 15, 3 and 2 bits of these numbers + are actually used.

+

The function returns an Erlang pid object.

+

, , + and + can be used to retrieve the four values used to create the pid.

+
+
+ + ETERM *erl_mk_port(node, number, creation) + Creates a port identifier + + const char *node; + unsigned int number; + unsigned int creation; + + +

This function creates an Erlang port identifier.

+

is the name of the C node.

+

and are arbitrary numbers. + Note though, that these are limited in + precision, so only the low 18 and 2 bits of these numbers + are actually used.

+

The function returns an Erlang port object.

+

, + and can be used to retrieve the three + values used to create the port.

+
+
+ + ETERM *erl_mk_ref(node, number, creation) + Creates an old Erlang reference + + const char *node; + unsigned int number; + unsigned int creation; + + +

This function creates an old Erlang reference, with + only 18 bits - use instead.

+

is the name of the C node.

+

should be chosen uniquely for each reference + created for a given C node.

+

is an arbitrary number.

+

Note that and are limited in + precision, so only the low 18 and 2 bits of these numbers + are actually used. +

+

The function returns an Erlang reference object.

+

, , and + to retrieve the three values used + to create the reference.

+
+
+ + ETERM *erl_mk_long_ref(node, n1, n2, n3, creation) + Creates an Erlang reference + + const char *node; + unsigned int n1, n2, n3; + unsigned int creation; + + +

This function creates an Erlang reference, with 82 bits.

+

is the name of the C node.

+

, and can be seen as one big number + which should be chosen uniquely for + each reference + created for a given C node.

+

is an arbitrary number.

+

Note that and are limited in + precision, so only the low 18 and 2 bits of these numbers + are actually used. +

+

The function returns an Erlang reference object.

+

, , + and + to retrieve the values used + to create the reference.

+
+
+ + ETERM *erl_mk_string(string) + Creates a string + + char *string; + + +

This function creates a list from a zero terminated string.

+

is the zero-terminated sequence of characters + (i.e. a C string) from which the list will be created.

+

The function returns an Erlang list.

+
+
+ + ETERM *erl_mk_tuple(array, arrsize) + Creates an Erlang tuple from an array + + ETERM **array; + int arrsize; + + +

Creates an Erlang tuple from an array of Erlang terms.

+

is an array of Erlang terms.

+

is the number of elements in .

+

The function creates an Erlang tuple, whose arity is + and whose elements are taken from the terms in + .

+

To retrieve the size of a tuple, either use the + function (which checks the type of the checked + term and works for a binary as well as for a tuple), or the + returns the arity of a tuple. + will do the same thing, but it checks that + the argument really is a tuple. + returns the element + corresponding to a given position in the tuple.

+
+
+ + ETERM *erl_mk_uint(n) + Creates an unsigned integer + + unsigned int n; + + +

Creates an Erlang unsigned integer.

+

is a value to be converted to an Erlang + unsigned integer.

+

+

The function returns an Erlang unsigned integer object with + the value specified in .

+

can be used to retrieve the + value from an Erlang unsigned integer.

+
+
+ + ETERM *erl_mk_var(name) + Creates an Erlang variable + + char *name; + + +

This function creates an unbound Erlang variable. The + variable can later be bound through pattern matching or assignment.

+

specifies a name for the variable.

+

The function returns an Erlang variable object with the + name .

+
+
+ + interl_print_term(stream, term) + Prints an Erlang term + + FILE *stream; + ETERM *term; + + +

This function prints the specified Erlang term to the given + output stream.

+

indicates where the function should send its + output.

+

is the Erlang term to print.

+

The function returns the number of characters written, or a + negative value if there was an error.

+
+
+ + voiderl_set_compat_rel(release_number) + Set the erl_interface library in compatibility mode + + unsigned release_number; + + + +

By default, the library is only guaranteed + to be compatible with other Erlang/OTP components from the same + release as the library itself. For example, + from the OTP R10 release is not compatible + with an Erlang emulator from the OTP R9 release by default.

+

A call to sets the + library in compatibility mode of release + . Valid range of + is [7, current release]. This makes it possible to + communicate with Erlang/OTP components from earlier releases.

+ +

If this function is called, it may only be called once + directly after the call to the + erl_init() function.

+
+ +

You may run into trouble if this feature is used + carelessly. Always make sure that all communicating + components are either from the same Erlang/OTP release, or + from release X and release Y where all components + from release Y are in compatibility mode of release X.

+
+
+
+ + interl_size(term) + Return the arity of a tuple or binary + + ETERM *term; + + +

Returns the arity of an Erlang tuple, or the + number of bytes in an Erlang binary object.

+

is an Erlang tuple or an Erlang binary object.

+

The function returns the size of as described + above, or -1 if is not one of the two supported + types.

+
+
+ + ETERM *erl_tl(list) + Extracts the tail from a list + + ETERM *list; + + +

Extracts the tail from a list.

+

is an Erlang term containing a list.

+

The function returns an Erlang list corresponding to the + original list minus the first element, or NULL pointer if + was not a list.

+
+
+ + ETERM *erl_var_content(term, name) + Extracts the content of a variable + + ETERM *term; + char *name; + + +

This function returns the contents of the specified + variable in an Erlang term. +

+

is an Erlang term. In order for this function + to succeed, must be an Erlang variable with the + specified name, or it must be an Erlang list or tuple + containing a variable with the specified name. Other Erlang + types cannot contain variables.

+

is the name of an Erlang variable.

+

Returns the Erlang object corresponding to the value of + in . If no variable with the name + was found in , or if is + not a valid Erlang term, NULL is returned.

+
+
+
+
+ diff --git a/lib/erl_interface/doc/src/erl_format.xml b/lib/erl_interface/doc/src/erl_format.xml new file mode 100644 index 0000000000..5699485845 --- /dev/null +++ b/lib/erl_interface/doc/src/erl_format.xml @@ -0,0 +1,141 @@ + + + + +
+ + 19962009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + erl_format + Torbjörn Törnkvist + Torbjörn Törnkvist + + Bjarne Däcker + Torbjörn Törnkvist + 961016 + A + erl_format.sgml +
+ erl_format + Create and Match Erlang Terms + +

This module contains two routines - one general function for + creating Erlang terms and one for pattern matching Erlang terms.

+
+ + + ETERM *erl_format(FormatStr, ... ) + Creates an Erlang term + + char *FormatStr; + + +

This is a general function for creating Erlang terms using + a format specifier and a corresponding set of arguments, much + in the way works.

+

is a format specification string. The set + of valid format specifiers is as follows:

+ + +

~i - Integer

+
+ +

~f - Floating point

+
+ +

~a - Atom

+
+ +

~s - String

+
+ +

~w - Arbitrary Erlang term

+
+
+

For each format specifier that appears in , + there must be a corresponding argument following + . An Erlang term is built according to the + with values and Erlang terms substituted from + the corresponding arguments and according to the individual + format specifiers. For example:

+ +

This will create an structure corresponding + to the Erlang term: +

+

The function returns an Erlang term, or NULL if + does not describe a valid Erlang term.

+
+
+ + interl_match(Pattern, Term) + Performs pattern matching + + ETERM *Pattern,*Term; + + +

This function is used to perform pattern matching similar + to that done in Erlang. Refer to an Erlang manual for matching + rules and more examples.

+

is an Erlang term, possibly containing unbound + variables.

+

is an Erlang term that we wish to match against + .

+

and are compared, and any + unbound variables in are bound to corresponding + values in .

+

If and can be matched, the + function returns a non-zero value and binds any unbound + variables in . If do + not match, the function returns 0. For example:

+ +

can be used to retrieve the + content of any variables bound as a result of a call to + .

+
+
+
+
+ diff --git a/lib/erl_interface/doc/src/erl_global.xml b/lib/erl_interface/doc/src/erl_global.xml new file mode 100644 index 0000000000..8f9a354b4f --- /dev/null +++ b/lib/erl_interface/doc/src/erl_global.xml @@ -0,0 +1,141 @@ + + + + +
+ + 19982009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + erl_global + Gordon Beaton + Gordon Beaton + + Gordon Beaton + Gordon Beaton + 980703 + A + erl_global.sgml +
+ erl_global + Access globally registered names + +

This module provides support for registering, looking + up and unregistering names in the Erlang Global module. For more + information, see the description of Global in the reference manual.

+

Note that the functions below perform an RPC using an open file + descriptor provided by the caller. This file descriptor must + not be used for other traffic during the global operation or the + function may receive unexpected data and fail.

+
+ + + char **erl_global_names(fd,count) + Obtain list of Global names + + int fd; + int *count; + + +

Retrieve a list of all known global names. +

+

is an open descriptor to an Erlang connection. +

+

is the address of an integer, or NULL. If + is not NULL, it will be set by the function to + the number of names found. +

+

On success, the function returns an array of strings, each + containing a single registered name, and sets to + the number of names found. The array is terminated + by a single NULL pointer. On failure, the function returns + NULL and is not modified. +

+ +

It is the caller's responsibility to free the array + afterwards. It has been allocated by the function with a + single call to , so a single is + all that is necessary.

+
+
+
+ + interl_global_register(fd,name,pid) + Register a name in Global + + int fd; + const char *name; + ETERM *pid; + + +

This function registers a name in Global. +

+

is an open descriptor to an Erlang connection. +

+

is the name to register in Global. +

+

is the pid that should be associated with + . This is the value that Global will return when + processes request the location of . +

+

The function returns 0 on success, or -1 on failure.

+
+
+ + interl_global_unregister(fd,name) + Unregister a name in Global + + int fd; + const char *name; + + +

This function unregisters a name from Global. +

+

is an open descriptor to an Erlang connection. +

+

is the name to unregister from Global. +

+

The function returns 0 on success, or -1 on failure.

+
+
+ + ETERM *erl_global_whereis(fd,name,node) + Look up a name in global + + int fd; + const char *name; + char *node; + + +

is an open descriptor to an Erlang connection. +

+

is the name that is to be looked up in Global. +

+

If is not NULL, it is a pointer to a buffer + where the function can fill in the name of the node where + is found. can be passed directly to + if necessary. +

+

On success, the function returns an Erlang Pid containing the address + of the given name, and node will be initialized to + the nodename where is found. On failure NULL will be + returned and will not be modified.

+
+
+
+
+ diff --git a/lib/erl_interface/doc/src/erl_interface.xml b/lib/erl_interface/doc/src/erl_interface.xml new file mode 100644 index 0000000000..850a4127f4 --- /dev/null +++ b/lib/erl_interface/doc/src/erl_interface.xml @@ -0,0 +1,625 @@ + + + + +
+ + 19962009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + The Erl_Interface Library + Torbjörn Törnkvist + Torbjörn Törnkvist + + Bjarne Däcker + K.Lundin + 990113 + A + erl_interface.sgml +
+

The Erl_Interface library contains functions. which help you + integrate programs written in C and Erlang. The functions in + Erl_Interface support the following:

+ + manipulation of data represented as Erlang data types + conversion of data between C and Erlang formats + encoding and decoding of Erlang data types for transmission or storage + communication between C nodes and Erlang processes + backup and restore of C node state to and from Mnesia + +

In the following sections, these topics are described:

+ + compiling your code for use with Erl_Interface + initializing Erl_Interface + encoding, decoding, and sending Erlang terms + building terms and patterns + pattern matching + connecting to a distributed Erlang node + using EPMD + sending and receiving Erlang messages + remote procedure calls + global names + the registry + + +
+ Compiling and Linking Your Code +

In order to use any of the Erl_Interface functions, include the + following lines in your code:

+ +

Determine where the top directory of your OTP installation is. You + can find this out by starting Erlang and entering the following + command at the Eshell prompt:

+ code:root_dir(). +/usr/local/otp ]]> +

To compile your code, make sure that your C compiler knows where + to find by specifying an appropriate + argument on the command line, or by adding it to the + definition in your . The correct value for this path is + Vsn, where is the path + reported by in the above example, and Vsn is + the version of the Erl_interface application, for example +

+ +

When linking, you will need to specify the path to + and with + , and you will need to specify the + name of the libraries with . You can do + this on the command line or by adding the flags to the + definition in your .

+ +

Also, on some systems it may be necessary to link with some + additional libraries (e.g. and on + Solaris, or on Windows) in order to use the + communication facilities of Erl_Interface.

+

If you are using Erl_Interface functions in a threaded + application based on POSIX threads or Solaris threads, then + Erl_Interface needs access to some of the synchronization + facilities in your threads package, and you will need to specify + additional compiler flags in order to indicate which of the packages + you are using. Define and either or + . The default is to use POSIX threads if + is specified.

+

Note that both single threaded and default versions of the Erl_interface + and Ei libraries are provided. (The single threaded versions are named + and ). Whether the default + versions of the libraries have support for threads or not is determined by if + the platform in question has support for POSIX or Solaris threads. To check this, + have a look in the file in the erl_interface src directory.

+
+ +
+ Initializing the erl_interface Library +

Before calling any of the other Erl_Interface functions, you + must call exactly once to initialize the library. + takes two arguments, however the arguments are no + longer used by Erl_Interface, and should therefore be specified + as .

+
+ +
+ Encoding, Decoding and Sending Erlang Terms +

Data sent between distributed Erlang nodes is encoded in the + Erlang external format. Consequently, you have to encode and decode + Erlang terms into byte streams if you want to use the distribution + protocol to communicate between a C program and Erlang.

+

The Erl_Interface library supports this activity. It has a + number of C functions which create and manipulate Erlang data + structures. The library also contains an encode and a decode function. + The example below shows how to create and encode an Erlang tuple + :

+ +

Alternatively, you can use and + , which handle the encoding and decoding of + messages transparently.

+

Refer to the Reference Manual for a complete description of the + following modules:

+ + the module for creating Erlang terms + the module for encoding and decoding routines. + +
+ +
+ Building Terms and Patterns +

The previous example can be simplified by using + to create an Erlang term.

+ +

Refer to the Reference Manual, the module, for a + full description of the different format directives. The following + example is more complex:

+ +

As in previous examples, it is your responsibility to free the + memory allocated for Erlang terms. In this example, + ensures that the complete term pointed to + by is released. This is necessary, because the pointer from + the second call to is lost.

+

The following + example shows a slightly different solution:

+ +

In this case, you free the two terms independently. The order in + which you free the terms and is not important, + because the Erl_Interface library uses reference counting to + determine when it is safe to actually remove objects.

+

If you are not sure whether you have freed the terms properly, you + can use the following function to see the status of the fixed term + allocator:

+ +

Refer to the Reference Manual, the module for more + information.

+
+ +
+ Pattern Matching +

An Erlang pattern is a term that may contain unbound variables or + symbols. Such a pattern can be matched against a + term and, if the match is successful, any unbound variables in the + pattern will be bound as a side effect. The content of a bound + variable can then be retrieved.

+ +

is used to perform pattern matching. It takes a + pattern and a term and tries to match them. As a side effect any unbound + variables in the pattern will be bound. In the following example, we + create a pattern with a variable Age which appears at two + positions in the tuple. The pattern match is performed as follows:

+ + will bind the contents of + Age to 21 the first time it reaches the variable + the second occurrence of Age will cause a test for + equality between the terms since Age is already bound to + 21. Since Age is bound to 21, the equality test will + succeed and the match continues until the end of the pattern. + if the end of the pattern is reached, the match succeeds and you + can retrieve the contents of the variable + + +

Refer to the Reference Manual, the function for + more information.

+
+ +
+ Connecting to a Distributed Erlang Node +

In order to connect to a distributed Erlang node you need to first + initialize the connection routine with , + which stores information such as the host name, node name, and IP + address for later use:

+ +

Refer to the Reference Manual, the module for more information.

+

After initialization, you set up the connection to the Erlang node. + Use to specify the Erlang node you want to + connect to. The following example sets up the connection and should + result in a valid socket file descriptor:

+ +

prints the specified string and terminates + the program. Refer to the Reference Manual, the + function for more information.

+
+ +
+ Using EPMD +

is the Erlang Port Mapper Daemon. Distributed Erlang nodes + register with on the localhost to indicate to other nodes that + they exist and can accept connections. maintains a register of + node and port number information, and when a node wishes to connect to + another node, it first contacts in order to find out the correct + port number to connect to.

+

When you use to connect to an Erlang node, a + connection is first made to and, if the node is known, a + connection is then made to the Erlang node.

+

C nodes can also register themselves with if they want other + nodes in the system to be able to find and connect to them.

+

Before registering with , you need to first create a listen socket + and bind it to a port. Then:

+ +

is a file descriptor now connected to . + monitors the other end of the connection, and if it detects that the + connection has been closed, the node will be unregistered. So, if you + explicitly close the descriptor or if your node fails, it will be + unregistered from .

+

Be aware that on some systems (such as VxWorks), a failed node will + not be detected by this mechanism since the operating system does not + automatically close descriptors that were left open when the node + failed. If a node has failed in this way, will prevent you from + registering a new node with the old name, since it thinks that the old + name is still in use. In this case, you must unregister the name + explicitly:

+ +

This will cause to close the connection from the far end. Note + that if the name was in fact still in use by a node, the results of + this operation are unpredictable. Also, doing this does not cause the + local end of the connection to close, so resources may be consumed.

+
+ +
+ Sending and Receiving Erlang Messages +

Use one of the following two functions to send messages:

+ + + + +

As in Erlang, it is possible to send messages to a + Pid or to a registered name. It is easier to send a + message to a registered name because it avoids the problem of finding + a suitable Pid.

+

Use one of the following two functions to receive messages:

+ + + + +

receives the message into a buffer, while + decodes the message into an Erlang term.

+ +
+ Example of Sending Messages +

In the following example, is + sent to a registered process . The message is encoded + by :

+ +

The first element of the tuple that is sent is your own + Pid. This enables to reply. Refer to the + Reference Manual, the module for more information + about send primitives.

+
+ +
+ Example of Receiving Messages +

In this example is received. The + received Pid is then used to return

+ +

In order to provide robustness, a distributed Erlang node + occasionally polls all its connected neighbours in an attempt to + detect failed nodes or communication links. A node which receives such + a message is expected to respond immediately with an message. + This is done automatically by , however when this + has occurred returns to the caller + without storing a message into the structure.

+

When a message has been received, it is the caller's responsibility + to free the received message as well as + or , depending on the type of message received.

+

Refer to the Reference Manual for additional information about the + following modules:

+ + + . + +
+
+ +
+ Remote Procedure Calls +

An Erlang node acting as a client to another Erlang node + typically sends a request and waits for a reply. Such a request is + included in a function call at a remote node and is called a remote + procedure call. The following example shows how the + Erl_Interface library supports remote procedure calls:

+ when compiling file: %s.erl !\ +", modname); +erl_free_term(ep); +ep = erl_format("{ok,_}"); +if (!erl_match(ep, reply)) + erl_err_msg(" compiler errors !\ +"); +erl_free_term(ep); +erl_free_term(reply); ]]> +

is called to compile the specified module on the + remote node. checks that the compilation was + successful by testing for the expected .

+

Refer to the Reference Manual, the module for + more information about , and its companions + and .

+
+ +
+ Using Global Names +

A C node has access to names registered through the Erlang Global + module. Names can be looked up, allowing the C node to send messages + to named Erlang services. C nodes can also register global names, + allowing them to provide named services to Erlang processes or other C + nodes.

+

Erl_Interface does not provide a native implementation of the global + service. Instead it uses the global services provided by a "nearby" + Erlang node. In order to use the services described in this section, + it is necessary to first open a connection to an Erlang node.

+

To see what names there are:

+ +

allocates and returns a buffer containing + all the names known to global. will be initialized to + indicate how many names are in the array. The array of strings in + names is terminated by a NULL pointer, so it is not necessary to use + to determine when the last name is reached.

+

It is the caller's responsibility to free the array. + allocates the array and all of the strings + using a single call to , so is all + that is necessary.

+

To look up one of the names:

+ +

If is known to global, an Erlang pid is returned + that can be used to send messages to the schedule service. + Additionally, will be initialized to contain the name of + the node where the service is registered, so that you can make a + connection to it by simply passing the variable to .

+

Before registering a name, you should already have registered your + port number with . This is not strictly necessary, but if you + neglect to do so, then other nodes wishing to communicate with your + service will be unable to find or connect to your process.

+

Create a pid that Erlang processes can use to communicate with your + service:

+ +

After registering the name, you should use to wait for + incoming connections.

+

Do not forget to free later with !

+

To unregister a name:

+ +
+ +
+ The Registry +

This section describes the use of the registry, a simple mechanism + for storing key-value pairs in a C-node, as well as backing them up or + restoring them from a Mnesia table on an Erlang node. More detailed + information about the individual API functions can be found in the + Reference Manual.

+

Keys are strings, i.e. 0-terminated arrays of characters, and values + are arbitrary objects. Although integers and floating point numbers + are treated specially by the registry, you can store strings or binary + objects of any type as pointers.

+

To start, you need to open a registry:

+ +

The number 45 in the example indicates the approximate number of + objects that you expect to store in the registry. Internally the + registry uses hash tables with collision chaining, so there is no + absolute upper limit on the number of objects that the registry can + contain, but if performance or memory usage are important, then you + should choose a number accordingly. The registry can be resized later.

+

You can open as many registries as you like (if memory permits).

+

Objects are stored and retrieved through set and get functions. In + the following examples you see how to store integers, floats, strings + and arbitrary binary objects:

+ l = 42; +b->m = 12; +ei_reg_setpval(reg,"jox",b,sizeof(*b)); ]]> +

If you attempt to store an object in the registry and there is an + existing object with the same key, the new value will replace the old + one. This is done regardless of whether the new object and the old one + have the same type, so you can, for example, replace a string with an + integer. If the existing value is a string or binary, it will be freed + before the new value is assigned.

+

Stored values are retrieved from the registry as follows:

+ +

In all of the above examples, the object must exist and it must be of + the right type for the specified operation. If you do not know the + type of a given object, you can ask:

+ +

Buf will be initialized to contain object attributes.

+

Objects can be removed from the registry:

+ +

When you are finished with a registry, close it to remove all the + objects and free the memory back to the system:

+ + +
+ Backing Up the Registry to Mnesia +

The contents of a registry can be backed up to Mnesia on a "nearby" + Erlang node. You need to provide an open connection to the Erlang node + (see ). Also, Mnesia 3.0 or later must be running + on the Erlang node before the backup is initiated:

+ +

The example above will backup the contents of the registry to the + specified Mnesia table . Once a registry has been backed + up to Mnesia in this manner, additional backups will only affect + objects that have been modified since the most recent backup, i.e. + objects that have been created, changed or deleted. The backup + operation is done as a single atomic transaction, so that the entire + backup will be performed or none of it will.

+

In the same manner, a registry can be restored from a Mnesia table:

+ +

This will read the entire contents of into the specified + registry. After the restore, all of the objects in the registry will + be marked as unmodified, so a subsequent backup will only affect + objects that you have modified since the restore.

+

Note that if you restore to a non-empty registry, objects in the + table will overwrite objects in the registry with the same keys. Also, + the entire contents of the registry is marked as unmodified + after the restore, including any modified objects that were not + overwritten by the restore operation. This may not be your intention.

+
+ +
+ Storing Strings and Binaries +

When string or binary objects are stored in the registry it is + important that a number of simple guidelines are followed.

+

Most importantly, the object must have been created with a single call + to (or similar), so that it can later be removed by a + single call to . Objects will be freed by the registry + when it is closed, or when you assign a new value to an object that + previously contained a string or binary.

+

You should also be aware that if you store binary objects that are + context-dependent (e.g. containing pointers or open file descriptors), + they will lose their meaning if they are backed up to a Mnesia table + and subsequently restored in a different context.

+

When you retrieve a stored string or binary value from the registry, + the registry maintains a pointer to the object and you are passed a + copy of that pointer. You should never free an object retrieved in + this manner because when the registry later attempts to free it, a + runtime error will occur that will likely cause the C-node to crash.

+

You are free to modify the contents of an object retrieved this way. + However when you do so, the registry will not be aware of the changes + you make, possibly causing it to be missed the next time you make a + Mnesia backup of the registry contents. This can be avoided if you + mark the object as dirty after any such changes with + , or pass appropriate flags to + .

+
+
+
+ diff --git a/lib/erl_interface/doc/src/erl_malloc.xml b/lib/erl_interface/doc/src/erl_malloc.xml new file mode 100644 index 0000000000..8c8750d62a --- /dev/null +++ b/lib/erl_interface/doc/src/erl_malloc.xml @@ -0,0 +1,200 @@ + + + + +
+ + 19962009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + erl_malloc + Torbjörn Törnkvist + Torbjörn Törnkvist + + Bjarne Däcker + Torbjörn Törnkvist + 980703 + A + erl_malloc.sgml +
+ erl_malloc + Memory Allocation Functions + +

This module provides functions for allocating and deallocating + memory.

+
+ + + ETERM *erl_alloc_eterm(etype) + Allocates an ETERM structure + + unsigned char etype; + + +

This function allocates an structure. + Specify as one of the following constants:

+ + +

ERL_INTEGER

+
+ +

ERL_U_INTEGER

+
+ +

ERL_ATOM

+
+ +

ERL_PID

+
+ +

ERL_PORT

+
+ +

ERL_REF

+
+ +

ERL_LIST

+
+ +

ERL_EMPTY_LIST

+
+ +

ERL_TUPLE

+
+ +

ERL_BINARY

+
+ +

ERL_FLOAT

+
+ +

ERL_VARIABLE

+
+ +

ERL_SMALL_BIG

+
+ +

ERL_U_SMALL_BIG

+
+
+

and are for + creating Erlang , which can contain integers of + arbitrary size. The size of an integer in Erlang is machine + dependent, but in general any integer larger than 2^28 + requires a bignum.

+
+
+ + voiderl_eterm_release(void) + Clears the ETERM freelist + +

Clears the + freelist, where blocks are placed when they are + released by and + .

+
+
+ + voiderl_eterm_statistics(allocated, freed) + Reports term allocation statistics + + long *allocated; + long *freed; + + +

and are initialized to + contain information about the fix-allocator used to allocate + ETERM components. is the number of blocks + currently allocated to ETERM objects. is the + length of the freelist, where blocks are placed when they are + released by and + .

+
+
+ + voiderl_free_array(array, size) + Frees an array of ETERM structures + + ETERM **array; + int size; + + +

This function frees an array of Erlang terms.

+

is an array of ETERM* objects. +

+

is the number of terms in the array.

+
+
+ + voiderl_free_term(t) + Frees an ETERM structure + + ETERM *t; + + +

Use this function to free an Erlang term.

+
+
+ + voiderl_free_compound(t) + Frees an array of ETERM structures + + ETERM *t; + + +

Normally it is the programmer's responsibility to free each + Erlang term that has been returned from any of the + functions. However since many of the + functions that build new Erlang terms in fact share objects + with other existing terms, it may be difficult for the + programmer to maintain pointers to all such terms in order to + free them individually. +

+

will recursively free all of the + sub-terms associated with a given Erlang term, regardless of + whether we are still holding pointers to the sub-terms. +

+

There is an example in the User Manual under "Building + Terms and Patterns" +

+
+
+ + voiderl_malloc(size) + Allocates some memory + + long size; + + +

This function calls the standard + function.

+
+
+ + voiderl_free(ptr) + Frees some memory + + void *ptr; + + +

This function calls the standard + function.

+
+
+
+
+ diff --git a/lib/erl_interface/doc/src/erl_marshal.xml b/lib/erl_interface/doc/src/erl_marshal.xml new file mode 100644 index 0000000000..a7eaf78f35 --- /dev/null +++ b/lib/erl_interface/doc/src/erl_marshal.xml @@ -0,0 +1,272 @@ + + + + +
+ + 19962009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + erl_marshal + Torbjörn Törnkvist + Torbjörn Törnkvist + + Bjarne Däcker + Torbjörn Törnkvist + 980703 + A + erl_marshal.sgml +
+ erl_marshal + Encoding and Decoding of Erlang terms + +

This module contains functions for encoding Erlang terms into + a sequence of bytes, and for decoding Erlang terms from a + sequence of bytes.

+
+ + + interl_compare_ext(bufp1, bufp2) + Compares encoded byte sequences + + unsigned char *bufp1,*bufp2; + + +

This function compares two encoded terms. +

+

is a buffer containing an encoded Erlang + term term1. +

+

is a buffer containing an encoded Erlang + term term2. +

+

The function returns 0 if the terms are equal, -1 if term1 + is less than term2, or 1 if term2 is less than term1. +

+
+
+ + ETERM *erl_decode(bufp) + ETERM *erl_decode_buf(bufpp) + Converts a term from Erlang external format + + unsigned char *bufp; + unsigned char **bufpp; + + +

and decode + the contents of a buffer and return the corresponding + Erlang term. provides a simple + mechanism for dealing with several encoded terms stored + consecutively in the buffer.

+

is a pointer to a buffer containing one or + more encoded Erlang terms. +

+

is the address of a buffer pointer. The buffer + contains one or more consecutively encoded Erlang terms. + Following a successful call to , + will be updated so that it points to the next + encoded term. +

+

returns an Erlang term + corresponding to the contents of on success, or + NULL on failure. returns an Erlang + term corresponding to the first of the consecutive terms in + and moves forward to point to the + next term in the buffer. On failure, each of the functions + returns NULL. +

+
+
+ + interl_encode(term, bufp) + interl_encode_buf(term, bufpp) + Converts a term into Erlang external format + + ETERM *term; + unsigned char *bufp; + unsigned char **bufpp; + + +

and encode + Erlang terms into external format for storage or transmission. + provides a simple mechanism for + encoding several terms consecutively in the same + buffer. +

+

term is an Erlang term to be encoded. +

+

bufp is a pointer to a buffer containing one or + more encoded Erlang terms. +

+

bufpp is a pointer to a pointer to a buffer + containing one or more consecutively encoded Erlang terms. + Following a successful call to , + bufpp will be updated so that it points to the + position for the next encoded term. +

+

+ These functions returns the number of bytes written to buffer + if successful, otherwise returns 0. +

+

Note that no bounds checking is done on the buffer. It is + the caller's responsibility to make sure that the buffer is + large enough to hold the encoded terms. You can either use a + static buffer that is large enough to hold the terms you + expect to need in your program, or use + to determine the exact requirements for a given term. +

+

The following can help you estimate the buffer + requirements for a term. Note that this information is + implementation specific, and may change in future versions. + If you are unsure, use . +

+

Erlang terms are encoded with a 1 byte tag that + identifies the type of object, a 2- or 4-byte length field, + and then the data itself. Specifically: +

+ + + need 5 bytes, plus the space for each element. + + need 5 bytes, plus the space for each element, and 1 + additional byte for the empty list at the end. + + need 3 bytes, plus 1 byte for each character (the + terminating 0 is not encoded). Really long strings (more + than 64k characters) are encoded as lists. Atoms cannot + contain more than 256 characters. + + need 5 bytes. + + (integers < 256) need 2 bytes. + + need 32 bytes. + + need 10 bytes, plus the space for the node name, which + is an atom. + + need 6 bytes, plus the space for the node name, which + is an atom. + +

The total space required will be the result calculated + from the information above, plus 1 additional byte for a + version identifier. +

+
+
+ + interl_ext_size(bufp) + Counts elements in encoded term + + unsigned char *bufp; + + +

This function returns the number of elements in an + encoded term.

+
+
+ + unsigned charerl_ext_type(bufp) + Determines type of an encoded byte sequence + + unsigned char *bufp; + + +

This function identifies and returns the type of Erlang term encoded + in a buffer. It will skip a trailing magic identifier. + Returns if the type can't be determined or one of

+ + +

ERL_INTEGER

+
+ +

ERL_ATOM

+
+ +

ERL_PID

+
+ +

ERL_PORT

+
+ +

ERL_REF

+
+ +

ERL_EMPTY_LIST

+
+ +

ERL_LIST

+
+ +

ERL_TUPLE

+
+ +

ERL_FLOAT

+
+ +

ERL_BINARY

+
+ +

ERL_FUNCTION

+
+
+
+
+ + unsigned char *erl_peek_ext(bufp, pos) + Steps over encoded term + + unsigned char *bufp; + int pos; + + +

This function is used for stepping over one or more + encoded terms in a buffer, in order to directly access a + later term. +

+

is a pointer to a buffer containing one or + more encoded Erlang terms. +

+

indicates how many terms to step over in the + buffer. +

+

The function returns a pointer to a sub-term that can be + used in a subsequent call to in order to retrieve + the term at that position. If there is no term, or + would exceed the size of the terms in the buffer, NULL is returned. +

+
+
+ + interl_term_len(t) + Determines encoded size of term + + ETERM *t; + + +

This function determines the buffer space that would be + needed by if it were encoded into Erlang external + format by . +

+

The size in bytes is returned. +

+
+
+
+
+ diff --git a/lib/erl_interface/doc/src/fascicules.xml b/lib/erl_interface/doc/src/fascicules.xml new file mode 100644 index 0000000000..3d6219a2bd --- /dev/null +++ b/lib/erl_interface/doc/src/fascicules.xml @@ -0,0 +1,24 @@ + + + + + + EI User's Guide + + + EI Library Reference + + + Erl_interface Library Reference + + + Command Reference + + + Release Notes + + + Off-Print + + + diff --git a/lib/erl_interface/doc/src/make.dep b/lib/erl_interface/doc/src/make.dep new file mode 100644 index 0000000000..3f43cf64fe --- /dev/null +++ b/lib/erl_interface/doc/src/make.dep @@ -0,0 +1,24 @@ +# ---------------------------------------------------- +# >>>> Do not edit this file <<<< +# This file was automaticly generated by +# /home/otp/bin//docdepend +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# TeX files that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: book.tex ei.tex ei_connect.tex ei_users_guide.tex \ + erl_call.tex erl_connect.tex erl_error.tex \ + erl_eterm.tex erl_format.tex erl_global.tex \ + erl_malloc.tex erl_marshal.tex part_ei.tex \ + ref_man.tex ref_man_ei.tex ref_man_erl_interface.tex \ + registry.tex + +# ---------------------------------------------------- +# Source inlined when transforming from source to LaTeX +# ---------------------------------------------------- + +book.tex: ref_man.xml ref_man_ei.xml ref_man_erl_interface.xml + diff --git a/lib/erl_interface/doc/src/note.gif b/lib/erl_interface/doc/src/note.gif new file mode 100644 index 0000000000..6fffe30419 Binary files /dev/null and b/lib/erl_interface/doc/src/note.gif differ diff --git a/lib/erl_interface/doc/src/notes.xml b/lib/erl_interface/doc/src/notes.xml new file mode 100644 index 0000000000..f2519fda0b --- /dev/null +++ b/lib/erl_interface/doc/src/notes.xml @@ -0,0 +1,535 @@ + + + + +
+ + 20042009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Erl_interface Release Notes + otp_appnotes + nil + nil + nil + notes.xml +
+

This document describes the changes made to the Erl_interface application.

+ +
Erl_Interface 3.6.4 + +
Improvements and New Features + + +

+ The documentation is now built with open source tools + (xsltproc and fop) that exists on most platforms. One + visible change is that the frames are removed.

+

+ Own Id: OTP-8201

+
+
+
+ +
+ +
Erl_Interface 3.6.3 + +
Fixed Bugs and Malfunctions + + +

+ The manual states that erl_receive() return the reason in + the ErlMessage struct. This was not the case and + the function is now corrected.

+

+ *** POTENTIAL INCOMPATIBILITY ***

+

+ Own Id: OTP-4969

+
+ +

+ In send_exit.c an errorneous size of memory + allocation could occur when reallocating a buffer.

+

+ In ei_decode_trace.c the index could be updated + when the decoding failed.

+

+ In ei_printterm.c the index could be updated when + the decoding failed in lists and tuples.

+

+ In ei_decode_term.c when decoding a double + (ERL_FLOAT_EXT) no check was done to ensure that the last + of the 31 bytes was null terminated.

+

+ In ei_decode_term.c when decoding references, only + the first 3 bytes are read, but the index did not + increment by the total size.

+

+ In ei_decode_fun.c no check of correct buffer + allocation or data length was done.

+

+ In ei_decode_string.c the integer list string case + did not decode the NIL tail correctly.

+

+ These errors has now been fixed. (Thanks to Romain + Lenglet, Paul Mineiro and Paul Guyot).

+

+ Own Id: OTP-6117

+
+ +

+ ei_decode_big could be decoded with a garbage + byte.

+

+ ei_encode_big and ei_x_encode_big is now + available.

+

+ Own Id: OTP-7554

+
+ +

+ The function erl_init_resolve() did not conform to + C99 standard which caused a build error on some + platforms. This has now been fixed.

+

+ Own Id: OTP-8093

+
+ +

+ Makefile.in has been updated to use the LDFLAGS + environment variable (if set). (Thanks to Davide + Pesavento.)

+

+ Own Id: OTP-8157

+
+
+
+ + +
Improvements and New Features + + +

+ Added support for 64-bit integers in encoding/decoding.

+

+ Added support for better printouts of binaries.

+

+ Own Id: OTP-6091

+
+
+
+ +
+ +
Erl_Interface 3.6.2 + +
Fixed Bugs and Malfunctions + + +

+ A problem with gethostbyname in erl_start.c + could cause a buffer overflow. This has now been fixed.

+

+ Clean up of code and removed compiler warnings.

+

+ Own Id: OTP-7978

+
+
+
+ +
+ +
Erl_Interface 3.6.1 + +
Fixed Bugs and Malfunctions + + +

A faulty validation in ei_reg_getpval caused it + to never return the key-value. This has now been fixed. + (Thanks to Matt Stancliff)

+

+ Own Id: OTP-7960

+
+
+
+ + +
Improvements and New Features + + +

Minor update to the configure script.

+

+ Own Id: OTP-7959

+
+
+
+ +
+ +
Erl_Interface 3.6.1 + +
Improvements and New Features + + +

Minor update to the configure script.

+

+ Own Id: OTP-7959

+
+
+
+ +
+ +
Erl_Interface 3.6 + +
Improvements and New Features + + +

+ Nodes belonging to different independent clusters can now + co-exist on the same host with the help of a new + environment variable setting ERL_EPMD_PORT.

+

+ Own Id: OTP-7826

+
+
+
+ +
+ +
Erl_Interface 3.5.9 + +
Fixed Bugs and Malfunctions + + +

+ A type-casting bug in ei_skip_term and ei_printterm on + 64bit platforms rendering undefined results is now + corrected.

+

+ Own Id: OTP-7577

+
+ +

+ A bug in the hostent copying code of erl_interface on + MacOS X/Darwin is now corrected.

+

+ Own Id: OTP-7593

+
+ +

A problem with building erl_interface on + FreeBSD has been fixed (Thanks to Akira Kitada).

+

+ Own Id: OTP-7611

+
+
+
+ +
+ +
Erl_Interface 3.5.8 + +
Fixed Bugs and Malfunctions + + +

+ Fixed bug in erl_interface when decoding broken data

+

+ Own Id: OTP-7448

+
+
+
+ +
+ + +
Erl_Interface 3.5.7 + +
Fixed Bugs and Malfunctions + + +

+ An erroneous freeing of memory could occur when using + ei_x_format_wo_ver in erl_interface, resulting in + a segmentation fault.

+

+ Own Id: OTP-6795

+
+ +

+ A faulty compare in erl_marshal has now been + fixed. (Thanks to Simon Cornish and Paul Mineiro)

+

+ Own Id: OTP-7368

+
+
+
+ +
+ +
Erl_Interface 3.5.6 + +
Fixed Bugs and Malfunctions + + +

+ Minor documentation fixes.

+

+ Own Id: OTP-7183 Aux Id: OTP-7118

+
+
+
+ +
+ +
Erl_Interface 3.5.5.4 + +
Fixed Bugs and Malfunctions + + +

+ The symbol __erl_errno was undefined in the single thread + version of the ei library, but is now defined.

+

+ Own Id: OTP-6887

+
+ +

+ Corrected FreeBSD build error.

+

+ Own Id: OTP-7093

+
+
+
+ +
+ +
+ Erl_Interface 3.5.5.3 + +
+ Improvements and New Features + + +

Calls to alloca in erl_marshal.c have been removed. A + static buffer is now used instead to store node names + temporarily.

+

Own Id: OTP-6331 Aux Id: seq10468

+
+ +

ei_print_term interprets a list of integers with values + from 0 to 255 as a string. If the original list contains + the integer 0, this is considered terminator of the + string. This is incorrect. The function has now been + modified to not look for '\\0' in a string, but always + print all characters.

+

Own Id: OTP-6339 Aux Id: seq10492

+
+
+
+
+ +
+ Erl_Interface 3.5.5.2 + +
+ Fixed Bugs and Malfunctions + + +

The combination of xeon processors with 64bit x86 + extensions and a 32bit linux could cause ei_decode_long + and ei_decode_longlong to fail for the value LONG_MIN and + LONGLONG_MIN. The conversion is now made more portable.

+

Own Id: OTP-6216

+
+
+
+
+ +
+ Erl_Interface 3.5.5.1 + +
+ Improvements and New Features + + +

Portability enhancements.

+

Own Id: OTP-6132

+
+
+
+
+ +
+ Erl_Interface 3.5.5 + +
+ Fixed Bugs and Malfunctions + + +

Different (and old) files in the + and applications would + cause build problems on the new Intel-based iMacs. + (Thanks to Sebastion Strollo.)

+

Own Id: OTP-5967

+
+ +

pthread header and library mismatch on linux systems (at + least some SuSE and Debian) with both NPTL and + Linuxthreads libraries installed.

+

Own Id: OTP-5981

+
+
+
+ +
+ Improvements and New Features + + +

Support for a C node to connect to an Erlang node on a + standalone host has been added.

+

Own Id: OTP-5883 Aux Id: seq10170

+
+
+
+
+ +
+ Erl_interface 3.5.2 + +
+ Improvements and New Features + + +

A configuration test error caused erl_interface to be + built without support for threads. This has been + corrected.

+

Own Id: OTP-5456

+
+
+
+
+ +
+ Erl_interface 3.5.1 + +
+ Improvements and New Features + + +

Changes and improvements have been made to the build and + test environment to solve problems with failing + erl_interface test cases.

+

Own Id: OTP-5295 Aux Id: OTP-5387

+
+
+
+
+ +
+ Erl_interface 3.5 + +
+ Improvements and New Features + + +

Process identifiers and port identifiers have been + made more unique. Previously 18 bits were used as id in + the internal representation of process and port + identifiers. Now 28 bits are used.

+

The maximum + limit on the number of concurrently existing processes + due to the representation of pids has been increased to + 268435456 processes. The same is true for ports. This + limit will at least on a 32-bit architecture be + impossible to reach due to memory shortage.

+

NOTE: By default, the , and the + , , and + libraries are now only guaranteed to be compatible with + other Erlang/OTP components from the same release. It is + possible to set each component in compatibility mode of + an earlier release, though. See the documentation for + respective component on how to set it in compatibility + mode.

+

*** POTENTIAL INCOMPATIBILITY ***

+

Own Id: OTP-4968 Aux Id: OTP-4196

+
+
+
+
+ +
+ Erl_interface 3.4.5 + +
+ Fixed Bugs and Malfunctions + + +

Corrections for mistakes done for patch erl_605/OTP-4874.

+

Own Id: OTP-4995 Aux Id: OTP-4874

+
+
+
+
+ +
+ Erl_interface 3.4.4 + +
+ Fixed Bugs and Malfunctions + + +

A small optimization in ei_rpc*() was added and a bug in + ei_decode_longlong() was corrected.

+

Own Id: OTP-4784

+
+
+
+
+ +
+ Erl_interface 3.4.2 + +
+ Fixed Bugs and Malfunctions + + +

Strings longer than 65535 bytes were encoded wrong in + ei/erl_interface.

+

Own Id: OTP-4865 Aux Id: EABln07451

+
+
+
+
+ +
+ Erl_interface 3.4.1 + +
+ Fixed Bugs and Malfunctions + + +

erl_call -a parsed erlang terms incorrectly due to a bug + in ei_format, which is now corrected.

+

Own Id: OTP-4777 Aux Id: seq8099

+
+
+
+
+
+ diff --git a/lib/erl_interface/doc/src/notes_history.xml b/lib/erl_interface/doc/src/notes_history.xml new file mode 100644 index 0000000000..f484f3c04e --- /dev/null +++ b/lib/erl_interface/doc/src/notes_history.xml @@ -0,0 +1,367 @@ + + + + +
+ + 20062009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Erl_Interface Release Notes History + + + + +
+ +
+ Erl_Interface 3.4 + +
+ Fixed Bugs and Malfunctions + + +

and could not + previously handle uints. This bug has now been fixed.

+

Own Id: OTP-4061 Aux Id: seq7079

+
+ +

was not working correctly for floating + point arguments on some platforms. This is now corrected.

+

Own Id: OTP-4379

+
+ +

did not compare the node parts of + pids, ports, and references. This has now been fixed. + Comparison between two pids, ports, or references does now + conform to the Erlang specification.

+

Own Id: OTP-4512 Aux Id: OTP-4511

+
+
+
+ +
+ Improvements and New Features + + +

Erl_Interface and EI now supports 64 bit architectures.

+

Own Id: OTP-4772

+
+ +

There are new functions that support the GCC and Visual + C++ 64 bit extended integer types.

+ +

Own Id: OTP-4772

+
+ +

If you compile the library from source you can use the ei + library together with GMP, the GNU multi precision + library, to convert integers larger than 64 bits from and + to the external format.

+ +

Own Id: OTP-4772

+
+ +

Some general code improvements where done like correcting + buffer sizes, added more error checking etc.

+

Own Id: OTP-4772

+
+ +

In order to conform to the Erlang specification, + comparison between two pids was changed in the R9B + release. This change did however break a deadlock + prevention algorithm used by Mnesia during release + upgrade. Therefore, comparison between two pids has been + changed back so that R9B nodes are compatible with Erlang + nodes running pre-R9 releases.

+

Pre-R9 comparison between two pids which now is used + again: If t1 and t2 are both pids, t1 will precede t2 if + and only if either

+ + the node local id of t1 precedes the node local id + of t2, or + the node local ids of t1 and t2 are equal, and + node(t1) precedes node(t2), or + the node local ids of t1 and t2 are equal, and also + node(t1) and node(t2) are equal, and node(t1) was + created before node(t2). + +

The node local id consist of two integers; serial which + is most significant, and number.

+

The Erlang specification states: If t1 and t2 are both + refs, both PIDs, or both ports, then t1 precedes t2 if + and only if either

+ + node(t1) precedes node(t2), or + node(t1) equals node(t2) and t1 was created before + t2. + +

Note that comparisons between two refs, or two ports will + still conform to the Erlang specification.

+

*** POTENTIAL INCOMPATIBILITY ***

+

Own Id: OTP-4715 Aux Id: OTP-4511, OTP-4512

+
+
+
+
+ +
+ ErlInterface 3.3 + +
+ Improvements and New Features + + +

Erl_Interface has been rewritten extensively. The library + is now documented and supported. The old + is considered obsolete, and provided + only for backward compatibility.

+
+ +

Erl_Interface is now thread-safe, and multiple C-nodes may + run from the same process.

+
+ +

New functions are added for connecting and accepting + connections from ; these are documented in + .

+
+ +

New functions are added for converting to and from Erlang + binary format; these are documented in .

+
+
+
+
+ +
+ Erl_Interface 3.2.9 + +
+ Fixed Bugs and Malfunctions + + +

Changed back the return values from and + to 1 (as they used to be). + Incompatible with plain R7, compatible with previous + versions.

+

*** INCOMPATIBILITY with R7B ***

+

Own Id: OTP-3772

+
+ +

A race-condition bug in the term allocation routines was + corrected.

+

Own Id: OTP-3809

+
+ +

Erl_Interface could not be linked with pthreads.

+

Own Id: OTP-3810 Aux Id: Seq 5032

+
+ +

The TCB of VxWorks processes no longer grows when + is accessed. On Pthreads platforms + the use of no longer crashes programs + using multithreading.

+

Own Id: OTP-3820

+
+ +

Name clashes between Erlang emulator and Erl_Interface + on VxWorks removed.

+

Own Id: OTP-3824

+
+
+
+
+ +
+ Erl_Interface 3.2.3 + +
+ Fixed Bugs and Malfunctions + + +

Memory lossage affecting pids, ports and refs fixed.

+
+
+
+
+ +
+ Erl_Interface 3.2.2 + +
+ Improvements and New Features + + +

An error reporting facility has been + introduced.

+

Own Id: OTP-3641

+
+ +

ETERMs are now shrunk to a more reasonable size.

+

Own Id: OTP-3648

+

+
+
+
+
+ +
+ Erl_Interface 3.2.1 + +
+ Fixed Errors and Malfunctions + + +

Lists containing negative numbers were incorrectly + encoded by . This has been corrected.

+

Own Id: OTP-3535

+
+
+
+
+ +
+ Erl_Interface 3.2 + +
+ Improvements and New Features + + +

The reference type has been extended from 18 bits to + 82 bits. For compatibility with older nodes, an R6 node + can send a ref to an older node; if the older node sends + it back, it has lost all but its 18 least significant + bits, but still compares equal to the original ref. + The external format has been extended to represent the new + longer refs; that means for example that binaries with + refs, produced on an R6 node, cannot be converted to a + term on an older node. + In , a function + has been added, and macros and + .

+

*** POTENTIAL INCOMPATIBILITY ***

+

Own Id: OTP-3140 Aux Id: OTP-3139

+
+ +

The function has the problem that + a fixed buffer must be given - a larger message than + expected is simply discarded. A function + has been introduced, which + dynamically resizes the buffer given to it, if needed.

+

Own Id: OTP-3313 Aux Id: OTP-2927

+
+
+
+
+ +
+ Erl_Interface 3.1.1 + +
+ Improvements and New Features + + +

is added to all the + and files in order to support + use from C++.

+

On Unix the object files are now produced with + the option to make it possible to include + them in a shared library.

+

Own Id: OTP-3138 Aux Id: Seq 1722

+
+
+
+
+ +
+ Erl_Interface 3.1 + +
+ Fixed Bugs and Malfunctions + + +

A buffer overflow in was causing + C-node crashes on Linux.

+

Own Id: OTP-2743

+
+ +

When decoding very long strings (more than 65535 + characters) the terminating 0 was left out.

+

Own Id: OTP-2744

+
+ +

was not handshaking properly with + Erlang, causing incoming connection attempts to fail.

+

Own Id: OTP-2862

+
+ +

Very large negative numbers are no longer encoded + incorrectly.

+

Own Id: OTP-2897

+
+ +

Atoms could sometimes contain an unterminated string. + This is fixed.

+

Own Id: OTP-2956

+
+ +

Erl_Interface now uses the SENS resolver functions if + they are available at runtime. This primarily concerns + use on the VxWorks platform.

+

Own Id: OTP-3034 Aux Id: Seq 1559

+
+ +

The documentation for no longer + makes erroneous reference to the remote node.

+

Own Id: OTP-3102 Aux Id: Seq 1671

+
+
+
+ +
+ Improvements and New Features + + +

Erl_Interface has been moved out of the Erlang runtime + system (ERTS) and is now a separate application. This has + implications for all users of Erl_Interface, who will + need to make changes to the Makefiles used to build + applications based on Erl_Interface. In particular, + header and library files are no longer in + . The and + directories are now located in the directory + (i.e. + the directory name is now version specific).

+

Own Id: OTP-3082

+
+
+
+
+
+ diff --git a/lib/erl_interface/doc/src/part.xml b/lib/erl_interface/doc/src/part.xml new file mode 100644 index 0000000000..e38b9164b8 --- /dev/null +++ b/lib/erl_interface/doc/src/part.xml @@ -0,0 +1,33 @@ + + + + +
+ + 20022009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + EI User's Guide + Gordon Beaton + + 1998-11-30 + 1.2 + part.xml +
+ +
+ diff --git a/lib/erl_interface/doc/src/part_erl_interface.xml b/lib/erl_interface/doc/src/part_erl_interface.xml new file mode 100644 index 0000000000..c69cc85c63 --- /dev/null +++ b/lib/erl_interface/doc/src/part_erl_interface.xml @@ -0,0 +1,33 @@ + + + + +
+ + 19962009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Erl_Interface User's Guide + Gordon Beaton + + 1998-11-30 + 1.2 + part_erl_interface.sgml +
+ +
+ diff --git a/lib/erl_interface/doc/src/part_notes.xml b/lib/erl_interface/doc/src/part_notes.xml new file mode 100644 index 0000000000..14c1de1d6e --- /dev/null +++ b/lib/erl_interface/doc/src/part_notes.xml @@ -0,0 +1,38 @@ + + + + +
+ + 20042009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Erl_Interface Release Notes + + + + +
+ +

Erl_Interface is a C interface library for communication + with Erlang.

+

For information about older versions, see + Release Notes History.

+
+ +
+ diff --git a/lib/erl_interface/doc/src/part_notes_history.xml b/lib/erl_interface/doc/src/part_notes_history.xml new file mode 100644 index 0000000000..612b4a9e1e --- /dev/null +++ b/lib/erl_interface/doc/src/part_notes_history.xml @@ -0,0 +1,36 @@ + + + + +
+ + 20062009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Erl_Interface Release Notes History + + + + +
+ +

Erl_Interface is a C interface library for communication + with Erlang.

+
+ +
+ diff --git a/lib/erl_interface/doc/src/ref_man.xml b/lib/erl_interface/doc/src/ref_man.xml new file mode 100644 index 0000000000..9ae4cf27f5 --- /dev/null +++ b/lib/erl_interface/doc/src/ref_man.xml @@ -0,0 +1,55 @@ + + + + +
+ + 19982009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + Erl_Interface Command Reference + Gordon Beaton + + 1998-11.30 + 1.2 + ref_man.xml +
+ +

The ei and erl_interface are C interface libraries for + communication with Erlang.

+ +

By default, the ei and erl_interface libraries are only guaranteed + to be compatible with other Erlang/OTP components from the same + release as the libraries themself. See the documentation of the + ei_set_compat_rel() and + erl_set_compat_rel() + functions on how to communicate with Erlang/OTP components from earlier + releases.

+
+
+ + + + + + + + + + + +
+ diff --git a/lib/erl_interface/doc/src/ref_man_ei.xml b/lib/erl_interface/doc/src/ref_man_ei.xml new file mode 100644 index 0000000000..ff161f9e7f --- /dev/null +++ b/lib/erl_interface/doc/src/ref_man_ei.xml @@ -0,0 +1,47 @@ + + + + +
+ + 20022009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + EI Library Reference + Gordon Beaton + + 1998-11-30 + 1.2 + ref_man_ei.xml +
+ +

The library is a interface library for + communication with .

+ +

By default, the library is only guaranteed + to be compatible with other Erlang/OTP components from the same + release as the library itself. See the documentation of the + ei_set_compat_rel() + function on how to communicate with Erlang/OTP components from earlier + releases.

+
+
+ + + +
+ diff --git a/lib/erl_interface/doc/src/ref_man_erl_interface.xml b/lib/erl_interface/doc/src/ref_man_erl_interface.xml new file mode 100644 index 0000000000..7ffa0cfb23 --- /dev/null +++ b/lib/erl_interface/doc/src/ref_man_erl_interface.xml @@ -0,0 +1,52 @@ + + + + +
+ + 19962009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Erl_Interface Library Reference + Gordon Beaton + + 1998-11-30 + 1.2 + ref_man_erl_interface.xml +
+ +

The erl_interface library is a C interface library + for communication with Erlang.

+ +

By default, the erl_interface library is only guaranteed + to be compatible with other Erlang/OTP components from the same + release as the erl_interface library. See the documentation + of the + erl_set_compat_rel() + function on how to communicate with Erlang/OTP components from earlier + releases.

+
+
+ + + + + + + +
+ diff --git a/lib/erl_interface/doc/src/registry.xml b/lib/erl_interface/doc/src/registry.xml new file mode 100644 index 0000000000..8aeb378d95 --- /dev/null +++ b/lib/erl_interface/doc/src/registry.xml @@ -0,0 +1,611 @@ + + + + +
+ + 19982009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + registry + Gordon Beaton + Gordon Beaton + + Gordon Beaton + Gordon Beaton + 980707 + A + registry.sgml +
+ registry + Store and backup key-value pairs + +

This module provides support for storing key-value + pairs in a table known as a registry, backing up registries to + Mnesia in an atomic manner, and later restoring the contents of a + registry from Mnesia.

+
+ + + ei_reg *ei_reg_open(size) + Create and open a registry + + int size; + + +

Open (create) a registry. The registry will be + initially empty. Use to close the registry + later. +

+

is the approximate number of objects you intend + to store in the registry. Since the registry uses a hash table + with collision chaining, there is no absolute upper limit on the + number of objects that can be stored in it. However for reasons + of efficiency, it is a good idea to choose a number that is + appropriate for your needs. It is possible to use + to change the size later. Note that the + number you provide will be increased to the nearest larger prime + number. +

+

On success, an empty registry will be returned. On failure, NULL + will be returned.

+
+
+ + intei_reg_resize(reg,newsize) + Resize a registry + + ei_reg *reg; + int newsize; + + +

Change the size of a registry. +

+

is the new size to make the registry. The + number will be increased to the nearest larger prime number. +

+

On success, the registry will be resized, all contents + rehashed, and the function will return 0. On failure, the + registry will be left unchanged and the function will return -1.

+
+
+ + intei_reg_close(reg) + Close a registry + + ei_reg *reg; + + +

A registry that has previously been created with + is closed, and all the objects it contains + are freed. +

+

is the registry to close. +

+

The function returns 0.

+
+
+ + intei_reg_setival(reg,key,i) + Assign an integer object + + ei_reg *reg; + const char *key; + int i; + + +

Create a key-value pair with the specified and integer + value . If an object already existed with the same + , the new value replaces the old one. If the previous + value was a binary or string, it is freed with . +

+

is the registry where the object should be placed. +

+

is the name of the object. +

+

is the integer value to assign. +

+

The function returns 0 on success, or -1 on failure.

+
+
+ + intei_reg_setfval(reg,key,f) + Assign a floating point object + + ei_reg *reg; + const char *key; + double f; + + +

Create a key-value pair with the specified and + floating point value . If an object already existed with + the same , the new value replaces the old one. If the + previous value was a binary or string, it is freed with . +

+

is the registry where the object should be placed. +

+

is the name of the object. +

+

is the floating point value to assign. +

+

The function returns 0 on success, or -1 on failure.

+
+
+ + intei_reg_setsval(reg,key,s) + Assign a string object + + ei_reg *reg; + const char *key; + const char *s; + + +

Create a key-value pair with the specified whose + "value" is the specified string . If an object already + existed with the same , the new value replaces the old + one. If the previous value was a binary or string, it is freed + with . +

+

is the registry where the object should be placed. +

+

is the name of the object. +

+

is the string to assign. The string itself + must have been created through a single call to or + similar function, so that the registry can later delete it if + necessary by calling . +

+

The function returns 0 on success, or -1 on failure.

+
+
+ + intei_reg_setpval(reg,key,p,size) + Assign a binary object + + ei_reg *reg; + const char *key; + const void *p; + int size; + + +

Create a key-value pair with the specified whose + "value" is the binary object pointed to by . If an + object already existed with the same , the new value + replaces the old one. If the previous value was a binary or + string, it is freed with . +

+

is the registry where the object should be placed. +

+

is the name of the object. +

+

is a pointer to the binary object. The object itself + must have been created through a single call to or + similar function, so that the registry can later delete it if + necessary by calling . +

+

is the length in bytes of the binary object. +

+

The function returns 0 on success, or -1 on failure.

+
+
+ + intei_reg_setval(reg,key,flags,v,...) + Assign a value to any object type + + ei_reg *reg; + const char *key; + int flags; + v (see below) + + +

Create a key-value pair with the specified whose + value is specified by . If an object already + existed with the same , the new value replaces the old + one. If the previous value was a binary or string, it is freed + with . +

+

is the registry where the object should be placed. +

+

is the name of the object. +

+

indicates the type of the object specified by + . Flags must be one of EI_INT, EI_FLT, EI_STR and + EI_BIN, indicating whether is , , + or . If is EI_BIN, then a + fifth argument is required, indicating the size + in bytes of the object pointed to by . +

+

If you wish to store an arbitrary pointer in the registry, + specify a of 0. In this case, the object itself will + not be transferred by an operation, just + the pointer value. +

+

The function returns 0 on success, or -1 on failure.

+
+
+ + intei_reg_getival(reg,key) + Get an integer object + + ei_reg *reg; + const char *key; + + +

Get the value associated with in the + registry. The value must be an integer. +

+

is the registry where the object will be looked + up. +

+

is the name of the object to look up. +

+

On success, the function returns the value associated with . + If the object was not found or it was not an integer + object, -1 is returned. To avoid problems with in-band error + reporting (i.e. if you cannot distinguish between -1 and a + valid result) use the more general function + instead.

+
+
+ + doubleei_reg_getfval(reg,key) + Get a floating point object + + ei_reg *reg; + const char *key; + + +

Get the value associated with in the + registry. The value must be a floating point type. +

+

is the registry where the object will be looked + up. +

+

is the name of the object to look up. +

+

On success, the function returns the value associated with . + If the object was not found or it was not a floating point + object, -1.0 is returned. To avoid problems with in-band error + reporting (i.e. if you cannot distinguish between -1.0 and a + valid result) use the more general function + instead.

+
+
+ + const char *ei_reg_getsval(reg,key) + Get a string object + + ei_reg *reg; + const char *key; + + +

Get the value associated with in the + registry. The value must be a string. +

+

is the registry where the object will be looked + up. +

+

is the name of the object to look up. +

+

On success, the function returns the value associated with + . If the object was not found or it was not a string, + NULL is returned. To avoid problems with in-band error + reporting (i.e. if you cannot distinguish between NULL and a + valid result) use the more general function + instead.

+
+
+ + const void *ei_reg_getpval(reg,key,size) + Get a binary object + + ei_reg *reg; + const char *key; + int size; + + +

Get the value associated with in the + registry. The value must be a binary (pointer) type. +

+

is the registry where the object will be looked + up. +

+

is the name of the object to look up. +

+

will be initialized to contain the length in + bytes of the object, if it is found. +

+

On success, the function returns the value associated with + and indicates its length in . + If the object was not found or it was not a binary object, + NULL is returned. To avoid problems with in-band error + reporting (i.e. if you cannot distinguish between NULL and a + valid result) use the more general function + instead.

+
+
+ + intei_reg_getval(reg,key,flags,v,...) + Get any object + + ei_reg *reg; + const char *key; + int flags; + void *v (see below) + + +

This is a general function for retrieving any kind of + object from the registry. +

+

is the registry where the object will be looked + up. +

+

is the name of the object to look up. +

+

indicates the type of object that you are + looking for. If is 0, then any kind of object will + be returned. If is one of EI_INT, EI_FLT, EI_STR or + EI_BIN, then only values of that kind will be returned. The + buffer pointed to by must be large enough to hold the return + data, i.e. it must be a pointer to one of , + , or , respectively. Also, + if is EI_BIN, then a fifth argument is required, so that the size of the object can be + returned. +

+

If the function succeeds, (and if the + object is binary) will be initialized with the value associated + with , and the function will return one of EI_INT, + EI_FLT, EI_STR or EI_BIN, indicating the type of object. On failure the + function will return -1 and the arguments will not be updated.

+
+
+ + intei_reg_markdirty(reg,key) + Mark an object as dirty + + ei_reg *reg; + const char *key; + + +

Mark a registry object as dirty. This will ensure that + it is included in the next backup to Mnesia. Normally this + operation will not be necessary since all of the normal registry + 'set' functions do this automatically. However if you have + retrieved the value of a string or binary object from the + registry and modified the contents, then the change will be + invisible to the registry and the object will be assumed to be + unmodified. This function allows you to make such modifications + and then let the registry know about them. +

+

is the registry containing the object. +

+

is the name of the object to mark. +

+

The function returns 0 on success, or -1 on failure.

+
+
+ + intei_reg_delete(reg,key) + Delete an object from the registry + + ei_reg *reg; + const char *key; + + +

Delete an object from the registry. The object is not + actually removed from the registry, it is only marked for later + removal so that on subsequent backups to Mnesia, the + corresponding object can be removed from the Mnesia table as + well. If another object is later created with the same key, the + object will be reused. +

+

The object will be removed from the registry after a call to + or . +

+

is the registry containing . +

+

is the object to remove. +

+

If the object was found, the function returns 0 indicating + success. Otherwise the function returns -1.

+
+
+ + intei_reg_stat(reg,key,obuf) + Get object information + + ei_reg *reg; + const char *key; + struct ei_reg_stat *obuf; + + +

Return information about an object. +

+

is the registry containing the object. +

+

is the name of the object. +

+

is a pointer to an structure, + defined below: +

+ +

In the object's attributes are stored as the logical + OR of its type (one of EI_INT, EI_FLT, EI_BIN and EI_STR), + whether it is marked for deletion (EI_DELET) and whether it has + been modified since the last backup to Mnesia (EI_DIRTY). +

+

The field indicates the size in bytes required to store + EI_STR (including the terminating 0) and EI_BIN objects, or 0 + for EI_INT and EI_FLT. +

+

The function returns 0 and initializes on + success, or returns -1 on failure.

+
+
+ + intei_reg_tabstat(reg,obuf) + Get registry information + + ei_reg *reg; + struct ei_reg_tabstat *obuf; + + +

Return information about a registry. Using information + returned by this function, you can see whether the size of the + registry is suitable for the amount of data it contains. +

+

is the registry to return information about. +

+

is a pointer to an structure, + defined below: +

+ +

The field indicates the number of hash positions + in the registry. This is the number you provided when you + created or last resized the registry, rounded up to the nearest + prime. +

+

indicates the number of elements stored in the + registry. It includes objects that are deleted but not purged. +

+

indicates the number of unique positions that are + occupied in the registry. +

+

indicates how many elements are sharing + positions in the registry. +

+

On success, the function returns 0 and is + initialized to contain table statistics. On failure, the function + returns -1.

+
+
+ + intei_reg_dump(fd,reg,mntab,flags) + Back up a registry to Mnesia + + int fd; + ei_reg *reg; + const char *mntab; + int flags; + + +

Dump the contents of a registry to a Mnesia table in an + atomic manner, i.e. either all data will be updated, or none of + it will. If any errors are encountered while backing up + the data, the entire operation is aborted. +

+

is an open connection to Erlang. + Mnesia 3.0 or later must be running on the Erlang node. +

+

is the registry to back up. +

+

is the name of the Mnesia table where the backed + up data should be placed. If the table does not exist, it will + be created automatically using configurable defaults. See your + Mnesia documentation for information about configuring this + behaviour. +

+

If is 0, the backup will include only those + objects which have been created, modified or deleted since the + last backup or restore (i.e. an incremental backup). After the + backup, any objects that were marked dirty are now clean, and any + objects that had been marked for deletion are deleted. +

+

Alternatively, setting flags to EI_FORCE will cause a full + backup to be done, and EI_NOPURGE will cause the deleted objects + to be left in the registry afterwards. These can be bitwise ORed + together if both behaviours are desired. If EI_NOPURGE was + specified, you can use to explicitly remove + the deleted items from the registry later. +

+

The function returns 0 on success, or -1 on failure.

+
+
+ + intei_reg_restore(fd,reg,mntab) + Restore a registry from Mnesia + + int fd; + ei_reg *reg; + const char *mntab; + + +

The contents of a Mnesia table are read into the + registry. +

+

is an open connection to Erlang. + Mnesia 3.0 or later must be running on the Erlang node. +

+

is the registry where the data should be placed. +

+

is the name of the Mnesia table to read data + from. +

+

Note that only tables of a certain format can be + restored, i.e. those that have been created and backed up to + with . If the registry was not empty before + the operation, then the contents of the table are added to the + contents of the registry. If the table contains objects with the + same keys as those already in the registry, the registry objects + will be overwritten with the new values. If the registry + contains objects that were not in the table, they will be + unchanged by this operation. +

+

After the restore operation, the entire contents of the + registry is marked as unmodified. Note that this includes any + objects that were modified before the restore and not + overwritten by the restore. +

+

The function returns 0 on success, or -1 on failure.

+
+
+ + intei_reg_purge(reg) + Remove deleted objects + + ei_reg *reg; + + +

Remove all objects marked for deletion. When objects + are deleted with they are not actually + removed from the registry, only marked for later removal. This + is so that on a subsequent backup to Mnesia, the + objects can also be removed from the Mnesia table. If you are + not backing up to Mnesia then you may wish to remove the objects + manually with this function. +

+

is a registry containing objects marked for + deletion. +

+

The function returns 0 on success, or -1 on failure.

+
+
+
+
+ diff --git a/lib/erl_interface/doc/src/warning.gif b/lib/erl_interface/doc/src/warning.gif new file mode 100644 index 0000000000..96af52360e Binary files /dev/null and b/lib/erl_interface/doc/src/warning.gif differ diff --git a/lib/erl_interface/include/ei.h b/lib/erl_interface/include/ei.h new file mode 100644 index 0000000000..01272244e1 --- /dev/null +++ b/lib/erl_interface/include/ei.h @@ -0,0 +1,785 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifndef EI_H +#define EI_H + +#define EI_HAVE_TIMEOUT 1 /* Flag to user code that we have them */ +#define USE_EI_UNDOCUMENTED /* Want declarations for undocumented */ + +/************************************************************************/ +/* This file defines the complete interface to ei */ +/************************************************************************/ + +/* -------------------------------------------------------------------- */ +/* Include types needed below */ +/* -------------------------------------------------------------------- */ + +#if defined(__WIN32__) +#include +#include +#include +#endif + +#include /* Need type FILE */ +#include /* Need EHOSTUNREACH, ENOMEM, ... */ + +#if !defined(__WIN32__) && !defined(VXWORKS) || (defined(VXWORKS) && defined(HAVE_SENS)) +# include +#endif + + +/* -------------------------------------------------------------------- */ +/* Defines part of API */ +/* -------------------------------------------------------------------- */ + +/* + * Some error codes might be missing, so here's a backstop definitions + * of the ones we use with `erl_errno': + */ + +#ifndef EMSGSIZE /* Message too long */ +#define EMSGSIZE EIO +#endif + +#ifndef ETIMEDOUT /* Connection timed out */ +#define ETIMEDOUT EIO +#endif + +#ifndef EHOSTUNREACH /* No route to host */ +#define EHOSTUNREACH EIO +#endif + +/* FIXME just a few are documented, does it mean they can't be returned? */ + +#define ERL_ERROR -1 /* Error of some kind */ +#define ERL_NO_DAEMON -2 /* No contact with EPMD */ +#define ERL_NO_PORT -3 /* No port received from EPMD */ +#define ERL_CONNECT_FAIL -4 /* Connect to Erlang Node failed */ +#define ERL_TIMEOUT -5 /* A timeout has expired */ +#define ERL_NO_REMOTE -6 /* Cannot execute rsh */ + +#define ERL_TICK 0 +#define ERL_MSG 1 + +#define ERL_NO_TIMEOUT -1 + +/* these are the control message types */ +#define ERL_LINK 1 +#define ERL_SEND 2 +#define ERL_EXIT 3 +#define ERL_UNLINK 4 +#define ERL_NODE_LINK 5 +#define ERL_REG_SEND 6 +#define ERL_GROUP_LEADER 7 +#define ERL_EXIT2 8 +#define ERL_PASS_THROUGH 'p' + +/* new ones for tracing, from Kenneth */ +#define ERL_SEND_TT 12 +#define ERL_EXIT_TT 13 +#define ERL_REG_SEND_TT 16 +#define ERL_EXIT2_TT 18 + + +/* -------------------------------------------------------------------- */ +/* Defines used for ei_get_type_internal() output */ +/* -------------------------------------------------------------------- */ +/* + * these are the term type indicators used in + * the external (distribution) format + */ + +/* FIXME we don't want to export these..... */ + +#define ERL_SMALL_INTEGER_EXT 'a' +#define ERL_INTEGER_EXT 'b' +#define ERL_FLOAT_EXT 'c' +#define ERL_ATOM_EXT 'd' +#define ERL_REFERENCE_EXT 'e' +#define ERL_NEW_REFERENCE_EXT 'r' +#define ERL_PORT_EXT 'f' +#define ERL_PID_EXT 'g' +#define ERL_SMALL_TUPLE_EXT 'h' +#define ERL_LARGE_TUPLE_EXT 'i' +#define ERL_NIL_EXT 'j' +#define ERL_STRING_EXT 'k' +#define ERL_LIST_EXT 'l' +#define ERL_BINARY_EXT 'm' +#define ERL_SMALL_BIG_EXT 'n' +#define ERL_LARGE_BIG_EXT 'o' +#define ERL_NEW_FUN_EXT 'p' +#define ERL_FUN_EXT 'u' + +#define ERL_NEW_CACHE 'N' /* c nodes don't know these two */ +#define ERL_CACHED_ATOM 'C' + + +/* -------------------------------------------------------------------- */ +/* Define the erl_errno macro */ +/* -------------------------------------------------------------------- */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * GCC's attributes are too useful to not use. Other compilers + * just lose opportunities to optimize and warn. + */ +#if !defined(__GNUC__) || __GNUC__ < 2 +# define __attribute__(foo) /* nothing */ +#endif + +/* + * Define the 'erl_errno' facility. Unfortunately this lives on in + * the 'ei' interface as well.... :-( + */ + +#if defined(_REENTRANT) || defined(VXWORKS) || defined(__WIN32__) + +/* 'erl_errno' as a function return value */ +volatile int* __erl_errno_place(void) __attribute__ ((__const__)); + +#define erl_errno (*__erl_errno_place ()) + +#else /* !_REENTRANT && !VXWORKS && !__WIN32__ */ + +extern volatile int __erl_errno; + +#define erl_errno __erl_errno + +#endif /* !_REENTRANT && !VXWORKS && !__WIN32__ */ + + +/* -------------------------------------------------------------------- */ +/* Type definitions */ +/* -------------------------------------------------------------------- */ + +/* + * To avoid confusion about the MAXHOSTNAMELEN when compiling the + * library and when using the library we set a value that we use + */ + +#define EI_MAXHOSTNAMELEN 64 +#define EI_MAXALIVELEN 63 +#define EI_MAX_COOKIE_SIZE 512 +#define MAXATOMLEN 255 +#define MAXNODELEN EI_MAXALIVELEN+1+EI_MAXHOSTNAMELEN + +/* a pid */ +typedef struct { + char node[MAXATOMLEN+1]; + unsigned int num; + unsigned int serial; + unsigned int creation; +} erlang_pid; + +/* a port */ +typedef struct { + char node[MAXATOMLEN+1]; + unsigned int id; + unsigned int creation; +} erlang_port; + +/* a ref */ +typedef struct { + char node[MAXATOMLEN+1]; + int len; + unsigned int n[3]; + unsigned int creation; +} erlang_ref; + +/* a trace token */ +typedef struct { + long serial; + long prev; + erlang_pid from; + long label; + long flags; +} erlang_trace; + +/* a message */ +typedef struct { + long msgtype; + erlang_pid from; + erlang_pid to; + char toname[MAXATOMLEN+1]; + char cookie[MAXATOMLEN+1]; + erlang_trace token; +} erlang_msg; + +/* a fun */ +typedef struct { + long arity; + char module[MAXATOMLEN+1]; + char md5[16]; + long index; + long old_index; + long uniq; + long n_free_vars; + erlang_pid pid; + long free_var_len; + char* free_vars; +} erlang_fun; + +/* a big */ +typedef struct { + unsigned int arity; + int is_neg; + void *digits; +} erlang_big; + +typedef struct { + char ei_type; + int arity; + int size; + union { + long i_val; + double d_val; + char atom_name[MAXATOMLEN+1]; + erlang_pid pid; + erlang_port port; + erlang_ref ref; + } value; +} ei_term; + +/* XXX */ + +typedef struct { + char ipadr[4]; /* stored in network byte order */ + char nodename[MAXNODELEN+1]; +} ErlConnect; + +typedef struct ei_cnode_s { + char thishostname[EI_MAXHOSTNAMELEN+1]; + char thisnodename[MAXNODELEN+1]; + char thisalivename[EI_MAXALIVELEN+1]; +/* Currently this_ipaddr isn't used */ +/* struct in_addr this_ipaddr; */ + char ei_connect_cookie[EI_MAX_COOKIE_SIZE+1]; + short creation; + erlang_pid self; +} ei_cnode; + +typedef struct in_addr *Erl_IpAddr; + + +/* A dynamic version of ei XX */ + +typedef struct ei_x_buff_TAG { + char* buff; + int buffsz; + int index; +} ei_x_buff; + + +/* -------------------------------------------------------------------- */ +/* Function definitions (listed in same order as documentation) */ +/* -------------------------------------------------------------------- */ + +/* Handle the connection */ + +int ei_connect_init(ei_cnode* ec, const char* this_node_name, + const char *cookie, short creation); +int ei_connect_xinit (ei_cnode* ec, const char *thishostname, + const char *thisalivename, const char *thisnodename, + Erl_IpAddr thisipaddr, const char *cookie, + const short creation); + +int ei_connect(ei_cnode* ec, char *nodename); +int ei_connect_tmo(ei_cnode* ec, char *nodename, unsigned ms); +int ei_xconnect(ei_cnode* ec, Erl_IpAddr adr, char *alivename); +int ei_xconnect_tmo(ei_cnode* ec, Erl_IpAddr adr, char *alivename, unsigned ms); + +int ei_receive(int fd, unsigned char *bufp, int bufsize); +int ei_receive_tmo(int fd, unsigned char *bufp, int bufsize, unsigned ms); +int ei_receive_msg(int fd, erlang_msg* msg, ei_x_buff* x); +int ei_receive_msg_tmo(int fd, erlang_msg* msg, ei_x_buff* x, unsigned ms); +int ei_xreceive_msg(int fd, erlang_msg* msg, ei_x_buff* x); +int ei_xreceive_msg_tmo(int fd, erlang_msg* msg, ei_x_buff* x, unsigned ms); + +int ei_send(int fd, erlang_pid* to, char* buf, int len); +int ei_send_tmo(int fd, erlang_pid* to, char* buf, int len, unsigned ms); +int ei_reg_send(ei_cnode* ec, int fd, char *server_name, char* buf, int len); +int ei_reg_send_tmo(ei_cnode* ec, int fd, char *server_name, char* buf, int len, unsigned ms); + +int ei_rpc(ei_cnode* ec, int fd, char *mod, char *fun, + const char* inbuf, int inbuflen, ei_x_buff* x); +int ei_rpc_to(ei_cnode* ec, int fd, char *mod, char *fun, + const char* buf, int len); +int ei_rpc_from(ei_cnode* ec, int fd, int timeout, erlang_msg* msg, + ei_x_buff* x); + +int ei_publish(ei_cnode* ec, int port); +int ei_publish_tmo(ei_cnode* ec, int port, unsigned ms); +int ei_accept(ei_cnode* ec, int lfd, ErlConnect *conp); +int ei_accept_tmo(ei_cnode* ec, int lfd, ErlConnect *conp, unsigned ms); +int ei_unpublish(ei_cnode* ec); +int ei_unpublish_tmo(const char *alive, unsigned ms); + +const char *ei_thisnodename(const ei_cnode* ec); +const char *ei_thishostname(const ei_cnode* ec); +const char *ei_thisalivename(const ei_cnode* ec); + +erlang_pid *ei_self(ei_cnode* ec); + +void ei_set_compat_rel(unsigned rel); + +/* + * We have erl_gethost*() so we include ei versions as well. + */ + +#if defined(VXWORKS) + +extern int h_errno; + +/* + * We need these definitions - if the user has SENS then he gets them + * from netdb.h, otherwise we define them ourselves. + * + * If you are getting "multiple definition" errors here, + * make sure you have included BEFORE "erl_interface.h" + * or define HAVE_SENS in your CFLAGS. + */ + +#if !defined(HAVE_SENS) && !defined(HOST_NOT_FOUND) /* just in case */ + +struct hostent { + char *h_name; /* official name of host */ + char **h_aliases; /* alias list */ + int h_addrtype; /* host address type */ + int h_length; /* length of address */ + char **h_addr_list; /* list of addresses from name server */ +#define h_addr h_addr_list[0] /* address, for backward compatiblity */ + unsigned int unused; /* SENS defines this as ttl */ +}; + +#define HOST_NOT_FOUND 1 /* Authoritative Answer Host not found */ +#define TRY_AGAIN 2 /* Non-Authoritive Host not found, or SERVERFAIL */ +#define NO_RECOVERY 3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */ +#define NO_DATA 4 /* Valid name, no data record of requested type */ +#define NO_ADDRESS NO_DATA /* no address, look for MX record */ + +#endif /* !HAVE_SENS && !HOST_NOT_FOUND */ +#endif /* VXWORKS */ + + +struct hostent *ei_gethostbyname(const char *name); +struct hostent *ei_gethostbyaddr(const char *addr, int len, int type); +struct hostent *ei_gethostbyname_r(const char *name, + struct hostent *hostp, + char *buffer, + int buflen, + int *h_errnop); +struct hostent *ei_gethostbyaddr_r(const char *addr, + int length, + int type, + struct hostent *hostp, + char *buffer, + int buflen, + int *h_errnop); + + +/* Encode/decode functions */ + +int ei_encode_version(char *buf, int *index); +int ei_x_encode_version(ei_x_buff* x); +int ei_encode_long(char *buf, int *index, long p); +int ei_x_encode_long(ei_x_buff* x, long n); +int ei_encode_ulong(char *buf, int *index, unsigned long p); +int ei_x_encode_ulong(ei_x_buff* x, unsigned long n); +int ei_encode_double(char *buf, int *index, double p); +int ei_x_encode_double(ei_x_buff* x, double dbl); +int ei_encode_boolean(char *buf, int *index, int p); +int ei_x_encode_boolean(ei_x_buff* x, int p); +int ei_encode_char(char *buf, int *index, char p); +int ei_x_encode_char(ei_x_buff* x, char p); +int ei_encode_string(char *buf, int *index, const char *p); +int ei_encode_string_len(char *buf, int *index, const char *p, int len); +int ei_x_encode_string(ei_x_buff* x, const char* s); +int ei_x_encode_string_len(ei_x_buff* x, const char* s, int len); +int ei_encode_atom(char *buf, int *index, const char *p); +int ei_encode_atom_len(char *buf, int *index, const char *p, int len); +int ei_x_encode_atom(ei_x_buff* x, const char* s); +int ei_x_encode_atom_len(ei_x_buff* x, const char* s, int len); +int ei_encode_binary(char *buf, int *index, const void *p, long len); +int ei_x_encode_binary(ei_x_buff* x, const void* s, int len); +int ei_encode_pid(char *buf, int *index, const erlang_pid *p); +int ei_x_encode_pid(ei_x_buff* x, const erlang_pid* pid); +int ei_encode_fun(char* buf, int* index, const erlang_fun* p); +int ei_x_encode_fun(ei_x_buff* x, const erlang_fun* fun); +int ei_encode_port(char *buf, int *index, const erlang_port *p); +int ei_x_encode_port(ei_x_buff* x, const erlang_port *p); +int ei_encode_ref(char *buf, int *index, const erlang_ref *p); +int ei_x_encode_ref(ei_x_buff* x, const erlang_ref *p); +int ei_encode_term(char *buf, int *index, void *t); /* ETERM* actually */ +int ei_x_encode_term(ei_x_buff* x, void* t); +int ei_encode_trace(char *buf, int *index, const erlang_trace *p); +int ei_x_encode_trace(ei_x_buff* x, const erlang_trace *p); +int ei_encode_tuple_header(char *buf, int *index, int arity); +int ei_x_encode_tuple_header(ei_x_buff* x, long n); +int ei_encode_list_header(char *buf, int *index, int arity); +int ei_x_encode_list_header(ei_x_buff* x, long n); +#define ei_encode_empty_list(buf,i) ei_encode_list_header(buf,i,0) +int ei_x_encode_empty_list(ei_x_buff* x); + +/* + * ei_get_type() returns the type and "size" of the item at + * buf[index]. For strings and atoms, size is the number of characters + * not including the terminating 0. For binaries, size is the number + * of bytes. For lists and tuples, size is the arity of the + * object. For other types, size is 0. In all cases, index is left + * unchanged. + */ + +int ei_get_type(const char *buf, const int *index, int *type, int *size); +int ei_get_type_internal(const char *buf, const int *index, int *type, + int *size); + +/* Step through buffer, decoding the given type into the buffer + * provided. On success, 0 is returned and index is updated to point + * to the start of the next item in the buffer. If the type of item at + * buf[index] is not the requested type, -1 is returned and index is + * not updated. The buffer provided by the caller must be sufficiently + * large to contain the decoded object. + */ +int ei_decode_version(const char *buf, int *index, int *version); +int ei_decode_long(const char *buf, int *index, long *p); +int ei_decode_ulong(const char *buf, int *index, unsigned long *p); +int ei_decode_double(const char *buf, int *index, double *p); +int ei_decode_boolean(const char *buf, int *index, int *p); +int ei_decode_char(const char *buf, int *index, char *p); +int ei_decode_string(const char *buf, int *index, char *p); +int ei_decode_atom(const char *buf, int *index, char *p); +int ei_decode_binary(const char *buf, int *index, void *p, long *len); +int ei_decode_fun(const char* buf, int* index, erlang_fun* p); +void free_fun(erlang_fun* f); +int ei_decode_pid(const char *buf, int *index, erlang_pid *p); +int ei_decode_port(const char *buf, int *index, erlang_port *p); +int ei_decode_ref(const char *buf, int *index, erlang_ref *p); +int ei_decode_term(const char *buf, int *index, void *t); /* ETERM** actually */ +int ei_decode_trace(const char *buf, int *index, erlang_trace *p); +int ei_decode_tuple_header(const char *buf, int *index, int *arity); +int ei_decode_list_header(const char *buf, int *index, int *arity); + +/* + * ei_decode_ei_term() returns 1 if term is decoded, 0 if term is OK, + * but not decoded here and -1 if something is wrong. ONLY changes + * index if term is decoded (return value 1)! + */ + +int ei_decode_ei_term(const char* buf, int* index, ei_term* term); + + +/* + * ei_print_term to print out a binary coded term + */ + +int ei_print_term(FILE *fp, const char* buf, int* index); +int ei_s_print_term(char** s, const char* buf, int* index); + +/* + * format to build binary format terms a bit like printf + */ + +int ei_x_format(ei_x_buff* x, const char* fmt, ...); +int ei_x_format_wo_ver(ei_x_buff* x, const char *fmt, ...); + +int ei_x_new(ei_x_buff* x); +int ei_x_new_with_version(ei_x_buff* x); +int ei_x_free(ei_x_buff* x); +int ei_x_append(ei_x_buff* x, const ei_x_buff* x2); +int ei_x_append_buf(ei_x_buff* x, const char* buf, int len); +int ei_skip_term(const char* buf, int* index); + +/*************************************************************************** + * + * Hash types needed by registry types + * + ***************************************************************************/ + +#define EI_SMALLKEY 32 + +typedef struct bucket_s { + int rawhash; + const char *key; + char keybuf[EI_SMALLKEY]; + const void *value; + struct bucket_s *next; +} ei_bucket; + +/* users of the package declare variables as pointers to this. */ +typedef struct { + ei_bucket **tab; + int (*hash)(const char *); /* hash function for this table */ + int size; /* size of table */ + int nelem; /* nr elements */ + int npos; /* nr occupied positions */ + ei_bucket *freelist; /* reuseable freed buckets */ +} ei_hash; + + +/*************************************************************************** + * + * Registry defines, types, functions + * + ***************************************************************************/ + +/* -------------------------------------------------------------------- */ +/* XXXXXXXXXXX */ +/* -------------------------------------------------------------------- */ + +/* registry object attributes */ +#define EI_DIRTY 0x01 /* dirty bit (object value differs from backup) */ +#define EI_DELET 0x02 /* object is deleted */ +#define EI_INT 0x10 /* object is an integer */ +#define EI_FLT 0x20 /* object is a float */ +#define EI_STR 0x40 /* object is a string */ +#define EI_BIN 0x80 /* object is a binary, i.e. pointer to arbitrary type */ + + +/* -------------------------------------------------------------------- */ +/* XXXXXXXXXXX */ +/* -------------------------------------------------------------------- */ + +typedef struct ei_reg_inode { + int attr; + int size; + union { + long i; + double f; + char *s; + void *p; + } val; + struct ei_reg_inode *next; +} ei_reg_obj; + +typedef struct { + ei_reg_obj *freelist; + ei_hash *tab; +} ei_reg; + +struct ei_reg_stat { + int attr; /* object attributes (see above) */ + int size; /* size in bytes (for STR and BIN) 0 for others */ +}; + +struct ei_reg_tabstat { + int size; /* size of table */ + int nelem; /* number of stored elements */ + int npos; /* number of occupied positions */ + int collisions; /* number of positions with more than one element */ +}; + + +/* -------------------------------------------------------------------- */ +/* XXXXXXXXXXX */ +/* -------------------------------------------------------------------- */ + +/* FIXME move comments to source */ + +/* open / close registry. On open, a descriptor is returned that must + * be specified in all subsequent calls to registry functions. You can + * open as many registries as you like. + */ +ei_reg *ei_reg_open(int size); +int ei_reg_resize(ei_reg *oldreg, int newsize); +int ei_reg_close(ei_reg *reg); + +/* set values... these routines assign values to keys. If the key + * exists, the previous value is discarded and the new one replaces + * it. + * + * BIN objects require an additional argument indicating the size in + * bytes of the stored object. This will be used when the object is + * backed up, since it will need to be copied at that time. Remember + * also that pointers are process-space specific and it is not + * meaningful to back them up for later recall. If you are storing + * binary objects for backup, make sure that they are self-contained + * (without references to other objects). + * + * On success the function returns 0, otherwise a value + * indicating the reason for failure will be returned. + */ +int ei_reg_setival(ei_reg *reg, const char *key, long i); +int ei_reg_setfval(ei_reg *reg, const char *key, double f); +int ei_reg_setsval(ei_reg *reg, const char *key, const char *s); +int ei_reg_setpval(ei_reg *reg, const char *key, const void *p, int size); + +/* general set function (specifiy type via flags) + * optional arguments are as for equivalent type-specific function, + * i.e.: + * ei_reg_setval(fd, path, EI_INT, int i); + * ei_reg_setval(fd, path, EI_FLT, float f); + * ei_reg_setval(fd, path, EI_STR, const char *s); + * ei_reg_setval(fd, path, EI_BIN, const void *p, int size); + */ +int ei_reg_setval(ei_reg *reg, const char *key, int flags, ...); + +/* get value of specific type object */ +/* warning: it may be difficult to detect errors when using these + * functions, since the error values are returned "in band" + */ +long ei_reg_getival(ei_reg *reg, const char *key); +double ei_reg_getfval(ei_reg *reg, const char *key); +const char *ei_reg_getsval(ei_reg *reg, const char *key); +const void *ei_reg_getpval(ei_reg *reg, const char *key, int *size); + +/* get value of any type object (must specify) + * Retrieve a value from an object. The type of value expected and a + * pointer to a large enough buffer must be provided. flags must be + * set to the appropriate type (see type constants above) and the + * object type must match. If (flags == 0) the pointer is *assumed* to + * be of the correct type for the object. In any case, the actual + * object type is always returned on success. + * + * The argument following flags must be one of int*, double*, const + * char** and const void**. + * + * for BIN objects an int* is needed to return the size of the object, i.e. + * int ei_reg_getval(ei_reg *reg, const char *path, int flags, void **p, int *size); + */ +int ei_reg_getval(ei_reg *reg, const char *key, int flags, ...); + +/* mark the object as dirty. Normally this operation will not be + * necessary, as it is done automatically by all of the above 'set' + * functions. However, if you modify the contents of an object pointed + * to by a STR or BIN object, then the registry will not be aware of + * the change. As a result, the object may be missed on a subsequent + * backup operation. Use this function to set the dirty bit on the + * object. + */ +int ei_reg_markdirty(ei_reg *reg, const char *key); + +/* remove objects. The value, if any, is discarded. For STR and BIN + * objects, the object itself is removed using free(). */ +int ei_reg_delete(ei_reg *reg, const char *key); + +/* get information about an object */ +int ei_reg_stat(ei_reg *reg, const char *key, struct ei_reg_stat *obuf); + +/* get information about table */ +int ei_reg_tabstat(ei_reg *reg, struct ei_reg_tabstat *obuf); + +/* dump to / restore from backup */ +/* fd is open descriptor to Erlang, mntab is Mnesia table name */ +/* flags here: */ +#define EI_FORCE 0x1 /* dump all records (not just dirty ones) */ +#define EI_NOPURGE 0x2 /* don't purge deleted records */ +int ei_reg_dump(int fd, ei_reg *reg, const char *mntab, int flags); +int ei_reg_restore(int fd, ei_reg *reg, const char *mntab); +int ei_reg_purge(ei_reg *reg); + + +/* -------------------------------------------------------------------- */ +/* Encoding/decoding bugnums to GNU MP format */ +/* -------------------------------------------------------------------- */ + +/* If the user included we supply some more functions */ + +#if defined(__GNU_MP_VERSION) \ + && __GNU_MP_VERSION == 4 && __GNU_MP_VERSION_MINOR >= 1 + +int ei_decode_bignum(const char *buf, int *index, mpz_t obj); +int ei_encode_bignum(char *buf, int *index, mpz_t obj); +int ei_x_encode_bignum(ei_x_buff *x, mpz_t obj); + +#endif /* __GNU_MP_VERSION */ + +/* -------------------------------------------------------------------- */ +/* Function definitions not documented FIXME */ +/* -------------------------------------------------------------------- */ + +/* FIXME replace this primitive type size code */ + +#ifdef __WIN32__ +#define EI_LONGLONG __int64 +#define EI_ULONGLONG unsigned __int64 +#else +#ifndef VXWORKS +#define EI_LONGLONG long long +#define EI_ULONGLONG unsigned long long +#endif +#endif + +#ifndef VXWORKS +int ei_decode_longlong(const char *buf, int *index, EI_LONGLONG *p); +int ei_decode_ulonglong(const char *buf, int *index, EI_ULONGLONG *p); +int ei_encode_longlong(char *buf, int *index, EI_LONGLONG p); +int ei_encode_ulonglong(char *buf, int *index, EI_ULONGLONG p); +int ei_x_encode_longlong(ei_x_buff* x, EI_LONGLONG n); +int ei_x_encode_ulonglong(ei_x_buff* x, EI_ULONGLONG n); +#endif + +#ifdef USE_EI_UNDOCUMENTED + +/* + * Decode a list of integers into an integer array (i.e. even if it is + * encoded as a string). count gets number of items in array. + * See "decode_intlist.c". + */ + +int ei_decode_intlist(const char *buf, int *index, long *a, int *count); + +/* + * FIXME: used in IC, document? + * bufp = address of pointer to dynamically allocated buffer - may be reallocated by + * this function if it is too small for the message + * bufsz = in/out value: in=user buffer size, out=new buffer size + * msglen = nr bytes in received message + */ +int ei_receive_encoded(int fd, char **bufp, int *bufsz, erlang_msg *to, + int *msglen); +int ei_receive_encoded_tmo(int fd, char **bufp, int *bufsz, erlang_msg *to, + int *msglen, unsigned ms); +int ei_send_encoded(int fd, const erlang_pid *to, char *msg, int msglen); +int ei_send_encoded_tmo(int fd, const erlang_pid *to, char *msg, int msglen, + unsigned ms); +int ei_send_reg_encoded(int fd, const erlang_pid *from, const char *to, + char *msg, int msglen); +int ei_send_reg_encoded_tmo(int fd, const erlang_pid *from, const char *to, + char *msg, int msglen, unsigned ms); + +/* + * Bacward compatibility with old undocumented but used interface... + * FIXME use wrapper function instead?! + */ +#define ei_send_encoded_timeout(Fd,To,Msg,MsgLen,Ms) \ + ei_send_encoded_tmo((Fd),(To),(Msg),(MsgLen),(Ms)) +#define ei_send_reg_encoded_timeout(Fd,From,To,Msg,MsgLen,Ms) \ + ei_send_reg_encoded_tmo((Fd),(From),(To),(Msg),(MsgLen),(Ms)) + + +/* FIXME: is this really the best way to handle bignums? */ +int ei_encode_big(char *buf, int *index, erlang_big* big); +int ei_x_encode_big(ei_x_buff* x, erlang_big* big); +int ei_decode_big(const char *buf, int *index, erlang_big* p); +int ei_big_comp(erlang_big *x, erlang_big *y); +int ei_big_to_double(erlang_big *b, double *resp); +int ei_small_to_big(int s, erlang_big *b); +erlang_big *ei_alloc_big(unsigned int arity); +void ei_free_big(erlang_big *b); + +#endif /* USE_EI_UNDOCUMENTED */ + +#ifdef __cplusplus +} +#endif + +#endif /* EI_H */ diff --git a/lib/erl_interface/include/ei_connect.h b/lib/erl_interface/include/ei_connect.h new file mode 100644 index 0000000000..02880e197c --- /dev/null +++ b/lib/erl_interface/include/ei_connect.h @@ -0,0 +1,26 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2003-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifndef EI_CONNECT_H +#define EI_CONNECT_H + +/* Dummy for now.... */ + +#include "ei.h" + +#endif /* EI_CONNECT_H */ diff --git a/lib/erl_interface/include/eicode.h b/lib/erl_interface/include/eicode.h new file mode 100644 index 0000000000..c35489e890 --- /dev/null +++ b/lib/erl_interface/include/eicode.h @@ -0,0 +1,26 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2003-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifndef EICODE_H +#define EICODE_H + +/* Dummy for now.... */ + +#include "ei.h" + +#endif /* EICODE_H */ diff --git a/lib/erl_interface/include/erl_interface.h b/lib/erl_interface/include/erl_interface.h new file mode 100644 index 0000000000..1c4a94700d --- /dev/null +++ b/lib/erl_interface/include/erl_interface.h @@ -0,0 +1,449 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1996-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifndef _ERL_INTERFACE_H +#define _ERL_INTERFACE_H + +/************************************************************************/ +/* This file defines the complete interface to erl_interface */ +/* Note: the 'ei' interface is the prefered C API. */ +/************************************************************************/ + +/* FIXME only include if needed? */ + +#include "ei.h" /* ei is the base */ + +/* -------------------------------------------------------------------- */ +/* Public defines */ +/* -------------------------------------------------------------------- */ + +#define ERL_COMPOUND (1 << 7) + +#define ERL_UNDEF 0 +#define ERL_INTEGER 1 +#define ERL_U_INTEGER 2 /* unsigned int */ +#define ERL_ATOM 3 +#define ERL_PID 4 +#define ERL_PORT 5 +#define ERL_REF 6 +#define ERL_CONS (7 | ERL_COMPOUND) +#define ERL_LIST ERL_CONS +#define ERL_NIL 8 +#define ERL_EMPTY_LIST ERL_NIL +#define ERL_TUPLE (9 | ERL_COMPOUND) +#define ERL_BINARY 10 +#define ERL_FLOAT 11 +#define ERL_VARIABLE (12 | ERL_COMPOUND) /* used in patterns */ +#define ERL_SMALL_BIG 13 +#define ERL_U_SMALL_BIG 14 +#define ERL_FUNCTION (15 | ERL_COMPOUND) +#define ERL_BIG 16 +#define ERL_LONGLONG 17 +#define ERL_U_LONGLONG 18 + + +#define ERL_TYPE(x) (ERL_HEADER(x)->type) + +/* FIXME some macros left in erl_eterm.h should probably be documented */ + +#define ERL_IS_INTEGER(x) (ERL_TYPE(x) == ERL_INTEGER) +#define ERL_IS_UNSIGNED_INTEGER(x) (ERL_TYPE(x) == ERL_U_INTEGER) +#define ERL_IS_LONGLONG(x) (ERL_TYPE(x) == ERL_LONGLONG) +#define ERL_IS_UNSIGNED_LONGLONG(x) (ERL_TYPE(x) == ERL_U_LONGLONG) +#define ERL_IS_FLOAT(x) (ERL_TYPE(x) == ERL_FLOAT) +#define ERL_IS_ATOM(x) (ERL_TYPE(x) == ERL_ATOM) +#define ERL_IS_PID(x) (ERL_TYPE(x) == ERL_PID) +#define ERL_IS_PORT(x) (ERL_TYPE(x) == ERL_PORT) +#define ERL_IS_REF(x) (ERL_TYPE(x) == ERL_REF) +#define ERL_IS_TUPLE(x) (ERL_TYPE(x) == ERL_TUPLE) +#define ERL_IS_BINARY(x) (ERL_TYPE(x) == ERL_BINARY) +#define ERL_IS_NIL(x) (ERL_TYPE(x) == ERL_NIL) +#define ERL_IS_EMPTY_LIST(x) ERL_IS_NIL(x) +#define ERL_IS_CONS(x) (ERL_TYPE(x) == ERL_CONS) +#define ERL_IS_LIST(x) (ERL_IS_CONS(x) || ERL_IS_EMPTY_LIST(x)) + +/* + * Macros used for XXXX + */ + +#define ERL_HEADER(x) ((Erl_Header *)x) +#define ERL_COUNT(x) (ERL_HEADER(x)->count) + +/* + * Macros used for retrieving values from Erlang terms. + */ + +#define ERL_INT_VALUE(x) ((x)->uval.ival.i) +#define ERL_INT_UVALUE(x) ((x)->uval.uival.u) +#define ERL_LL_VALUE(x) ((x)->uval.llval.i) +#define ERL_LL_UVALUE(x) ((x)->uval.ullval.u) + +#define ERL_FLOAT_VALUE(x) ((x)->uval.fval.f) + +#define ERL_ATOM_PTR(x) ((x)->uval.aval.a) +#define ERL_ATOM_SIZE(x) ((x)->uval.aval.len) + +#define ERL_PID_NODE(x) ((x)->uval.pidval.node) +#define ERL_PID_NUMBER(x) ((x)->uval.pidval.number) +#define ERL_PID_SERIAL(x) ((x)->uval.pidval.serial) +#define ERL_PID_CREATION(x) ((x)->uval.pidval.creation) + +#define ERL_PORT_NODE(x) ((x)->uval.portval.node) +#define ERL_PORT_NUMBER(x) ((x)->uval.portval.number) +#define ERL_PORT_CREATION(x) ((x)->uval.portval.creation) + +#define ERL_REF_NODE(x) ((x)->uval.refval.node) +#define ERL_REF_NUMBER(x) ((x)->uval.refval.n[0]) +#define ERL_REF_NUMBERS(x) ((x)->uval.refval.n) +#define ERL_REF_LEN(x) ((x)->uval.refval.len) +#define ERL_REF_CREATION(x) ((x)->uval.refval.creation) + +#define ERL_TUPLE_SIZE(x) ((x)->uval.tval.size) + +/* NOTE!!! This is 0-based!! (first item is number 0) + * Note too that element/2 (in Erlang) and + * erl_element() are both 1-based. + */ +#define ERL_TUPLE_ELEMS(x) ((x)->uval.tval.elems) +#define ERL_TUPLE_ELEMENT(x, i) (ERL_TUPLE_ELEMS(x)[(i)]) + +#define ERL_BIN_SIZE(x) ((x)->uval.bval.size) +#define ERL_BIN_PTR(x) ((x)->uval.bval.b) + +#define ERL_CONS_HEAD(x) ((x)->uval.lval.head) +#define ERL_CONS_TAIL(x) ((x)->uval.lval.tail) + +#define ERL_VAR_LEN(x) ((x)->uval.vval.len) +#define ERL_VAR_NAME(x) ((x)->uval.vval.name) +#define ERL_VAR_VALUE(x) ((x)->uval.vval.v) + +#define ERL_CLOSURE_SIZE(x) ((x)->uval.funcval.size) +#define ERL_FUN_CREATOR(x) ((x)->uval.funcval.creator) +#define ERL_FUN_MODULE(x) ((x)->uval.funcval.module) +#define ERL_FUN_UNIQ(x) ((x)->uval.funcval.uniq) +#define ERL_FUN_INDEX(x) ((x)->uval.funcval.index) +#define ERL_FUN_ARITY(x) ((x)->uval.funcval.arity) +#define ERL_FUN_NEW_INDEX(x) ((x)->uval.funcval.new_index) +#define ERL_FUN_MD5(x) ((x)->uval.funcval.md5) +#define ERL_CLOSURE(x) ((x)->uval.funcval.closure) +#define ERL_CLOSURE_ELEMENT(x,i) (ERL_CLOSURE(x)[(i)]) + + +#ifdef __cplusplus +extern "C" { +#endif + +/* -------------------------------------------------------------------- */ +/* Type definitions of Erlang terms in C */ +/* -------------------------------------------------------------------- */ + +typedef struct { + unsigned int count:24; /* reference counter */ + unsigned int type:8; /* type of Erlang term */ +} Erl_Header; + +typedef struct { + Erl_Header h; + int i; +} Erl_Integer; + +typedef struct { + Erl_Header h; + unsigned int u; +} Erl_Uinteger; + +typedef struct { + Erl_Header h; + long long i; +} Erl_LLInteger; + +typedef struct { + Erl_Header h; + unsigned long long u; +} Erl_ULLInteger; + +typedef struct { + Erl_Header h; + double f; +} Erl_Float; + +typedef struct { + Erl_Header h; + int len; + char *a; +} Erl_Atom; + +typedef struct { + Erl_Header h; + char * node; + unsigned int number; + unsigned int serial; + unsigned char creation; +} Erl_Pid; + +typedef struct { + Erl_Header h; + char * node; + unsigned int number; + unsigned char creation; +} Erl_Port; + +typedef struct { + Erl_Header h; + char * node; + int len; + unsigned int n[3]; + unsigned char creation; +} Erl_Ref; + +typedef struct { + Erl_Header h; + int arity; + int is_neg; + unsigned short *digits; +} Erl_Big; + +struct _eterm; /* forward */ + +typedef struct { + Erl_Header h; + struct _eterm *head; + struct _eterm *tail; +} Erl_List; + +typedef struct { + Erl_Header h; +} Erl_EmptyList; + +typedef struct { + Erl_Header h; + int size; + struct _eterm **elems; +} Erl_Tuple; + +typedef struct { + Erl_Header h; + int size; + unsigned char *b; +} Erl_Binary; + +/* Variables may only exist in patterns. + * Note: identical variable names in a pattern + * denotes the same value. + */ +typedef struct { + Erl_Header h; + int len; + char *name; + struct _eterm *v; +} Erl_Variable; + + +typedef struct { + Erl_Header h; + int size; /* size of closure */ + int arity; /* arity for new (post R7) external funs */ + unsigned char md5[16]; /* md5 for new funs */ + int new_index; /* new funs */ + struct _eterm* creator; /* pid */ + struct _eterm* module; /* module */ + struct _eterm* index; + struct _eterm* uniq; + struct _eterm** closure; +} Erl_Function; + +typedef struct _eterm { + union { + Erl_Integer ival; + Erl_Uinteger uival; + Erl_LLInteger llval; + Erl_ULLInteger ullval; + Erl_Float fval; + Erl_Atom aval; + Erl_Pid pidval; + Erl_Port portval; + Erl_Ref refval; + Erl_List lval; + Erl_EmptyList nval; + Erl_Tuple tval; + Erl_Binary bval; + Erl_Variable vval; + Erl_Function funcval; + Erl_Big bigval; + } uval; +} ETERM; + + +#define MAXREGLEN 255 /* max length of registered (atom) name */ + +typedef struct { + int type; /* one of the message type constants in eiext.h */ + ETERM *msg; /* the actual message */ + ETERM *from; + ETERM *to; + char to_name[MAXREGLEN+1]; +} ErlMessage; + +typedef unsigned char Erl_Heap; + + +/* -------------------------------------------------------------------- */ +/* The functions */ +/* -------------------------------------------------------------------- */ + +void erl_init(void *x, long y); +void erl_set_compat_rel(unsigned); +int erl_connect_init(int, char*,short); +int erl_connect_xinit(char*,char*,char*,struct in_addr*,char*,short); +int erl_connect(char*); +int erl_xconnect(struct in_addr*,char *); +int erl_close_connection(int); +int erl_receive(int, unsigned char*, int); +int erl_receive_msg(int, unsigned char*, int, ErlMessage*); +int erl_xreceive_msg(int, unsigned char**, int*, ErlMessage*); +int erl_send(int, ETERM*, ETERM*); +int erl_reg_send(int, char*, ETERM*); +ETERM *erl_rpc(int,char*,char*,ETERM*); +int erl_rpc_to(int,char*,char*,ETERM*); +int erl_rpc_from(int,int,ErlMessage*); + +/* erl_publish returns open descriptor on success, or -1 */ +int erl_publish(int port); +int erl_accept(int,ErlConnect*); + +const char *erl_thiscookie(void); +const char *erl_thisnodename(void); +const char *erl_thishostname(void); +const char *erl_thisalivename(void); +short erl_thiscreation(void); + +/* returns 0 on success, -1 if node not known to epmd or epmd not reached */ +int erl_unpublish(const char *alive); + +/* Report generic error to stderr. */ +void erl_err_msg(const char * __template, ...) + __attribute__ ((__format__ (printf, 1, 2))); +/* Report generic error to stderr and die. */ +void erl_err_quit(const char * __template, ...) + __attribute__ ((__format__ (printf, 1, 2), __noreturn__)); +/* Report system/libc error to stderr. */ +void erl_err_ret(const char * __template, ...) + __attribute__ ((__format__ (printf, 1, 2))); +/* Report system/libc error to stderr and die. */ +void erl_err_sys(const char * __template, ...) + __attribute__ ((__format__ (printf, 1, 2), __noreturn__)); + +ETERM *erl_cons(ETERM*,ETERM*); +ETERM *erl_copy_term(const ETERM*); +ETERM *erl_element(int,const ETERM*); + +ETERM *erl_hd(const ETERM*); +ETERM* erl_iolist_to_binary(const ETERM* term); +char* erl_iolist_to_string(const ETERM* term); +int erl_iolist_length(const ETERM*); +int erl_length(const ETERM*); +ETERM *erl_mk_atom(const char*); +ETERM *erl_mk_binary(const char*,int); +ETERM *erl_mk_empty_list(void); +ETERM *erl_mk_estring(const char*, int); +ETERM *erl_mk_float(double); +ETERM *erl_mk_int(int); +ETERM *erl_mk_longlong(long long); +ETERM *erl_mk_list(ETERM**,int); +ETERM *erl_mk_pid(const char*,unsigned int,unsigned int,unsigned char); +ETERM *erl_mk_port(const char*,unsigned int,unsigned char); +ETERM *erl_mk_ref(const char*,unsigned int,unsigned char); +ETERM *erl_mk_long_ref(const char*,unsigned int,unsigned int, + unsigned int,unsigned char); +ETERM *erl_mk_string(const char*); +ETERM *erl_mk_tuple(ETERM**,int); +ETERM *erl_mk_uint(unsigned int); +ETERM *erl_mk_ulonglong(unsigned long long); +ETERM *erl_mk_var(const char*); +int erl_print_term(FILE*,const ETERM*); +/* int erl_sprint_term(char*,const ETERM*); */ +int erl_size(const ETERM*); +ETERM *erl_tl(const ETERM*); +ETERM *erl_var_content(const ETERM*, const char*); + +ETERM *erl_format(char*, ... ); +int erl_match(ETERM*, ETERM*); + +char **erl_global_names(int fd, int *count); +int erl_global_register(int fd, const char *name, ETERM *pid); +int erl_global_unregister(int fd, const char *name); +ETERM *erl_global_whereis(int fd, const char *name, char *node); + +void erl_init_malloc(Erl_Heap*,long); +ETERM *erl_alloc_eterm(unsigned char); +void erl_eterm_release(void); +void erl_eterm_statistics(unsigned long*,unsigned long*); +void erl_free_array(ETERM**,int); +void erl_free_term(ETERM*); +void erl_free_compound(ETERM*); +void *erl_malloc(long); +void erl_free(void*); + +int erl_compare_ext(unsigned char*, unsigned char*); +ETERM *erl_decode(unsigned char*); +ETERM *erl_decode_buf(unsigned char**); +int erl_encode(ETERM*,unsigned char*t); +int erl_encode_buf(ETERM*,unsigned char**); +int erl_ext_size(unsigned char*); +unsigned char erl_ext_type(unsigned char*); /* Note: returned 'char' before R9C */ +unsigned char *erl_peek_ext(unsigned char*,int); +int erl_term_len(ETERM*); + + +/* -------------------------------------------------------------------- */ +/* Wrappers around ei functions */ +/* -------------------------------------------------------------------- */ + +/* + * Undocumented before R9C, included for compatibility with old code + */ + +struct hostent *erl_gethostbyname(const char *name); +struct hostent *erl_gethostbyaddr(const char *addr, int len, int type); +struct hostent *erl_gethostbyname_r(const char *name, + struct hostent *hostp, + char *buffer, + int buflen, + int *h_errnop); +struct hostent *erl_gethostbyaddr_r(const char *addr, + int length, + int type, + struct hostent *hostp, + char *buffer, + int buflen, + int *h_errnop); + +/* + * Undocumented, included for compatibility with old code + */ + +void erl_init_resolve(void); +int erl_distversion(int fd); +int erl_epmd_connect(struct in_addr *inaddr); +int erl_epmd_port(struct in_addr *inaddr, const char *alive, int *dist); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/erl_interface/info b/lib/erl_interface/info new file mode 100644 index 0000000000..9612b0b6d4 --- /dev/null +++ b/lib/erl_interface/info @@ -0,0 +1,2 @@ +group: comm Interface and Communication Applications +short: Low level interface to C diff --git a/lib/erl_interface/priv/.gitignore b/lib/erl_interface/priv/.gitignore new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lib/erl_interface/src/INSTALL b/lib/erl_interface/src/INSTALL new file mode 100644 index 0000000000..b42a17ac46 --- /dev/null +++ b/lib/erl_interface/src/INSTALL @@ -0,0 +1,182 @@ +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. diff --git a/lib/erl_interface/src/Makefile b/lib/erl_interface/src/Makefile new file mode 100644 index 0000000000..5f0367bec1 --- /dev/null +++ b/lib/erl_interface/src/Makefile @@ -0,0 +1,31 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1996-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +# Invoke with GNU make or clearmake -C gnu. +# + +# FIXME let configure put in this last part TARGET + +include $(ERL_TOP)/make/target.mk + +debug opt shared purify quantify purecov gcov: + $(MAKE) -f $(TARGET)/Makefile TYPE=$@ + +clean depend docs release release_docs tests release_tests check: + $(MAKE) -f $(TARGET)/Makefile $@ diff --git a/lib/erl_interface/src/Makefile.in b/lib/erl_interface/src/Makefile.in new file mode 100644 index 0000000000..b8ee5c83c7 --- /dev/null +++ b/lib/erl_interface/src/Makefile.in @@ -0,0 +1,903 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +########################################################################### +## +## This is a standalone make file for erl_interface. It is +## to be preprocessed by the configure script and the result +## is saved into the TARGER directory. +## +## We use 'vpath' to use plain C file names without the directory +## part in dependency rules. +## +########################################################################### + +.PHONY : debug opt release clean distclean depend + +TARGET = @TARGET@ + +# ---------------------------------------------------- +# Application version and release dir specification +# ---------------------------------------------------- +include ../vsn.mk +include $(TARGET)/eidefs.mk + +USING_MINGW=@MIXED_CYGWIN_MINGW@ +USING_VC=@MIXED_CYGWIN_VC@ + +ifdef TESTROOT +RELEASE_PATH=$(TESTROOT) +else +RELEASE_PATH=$(ERL_TOP)/release/$(TARGET) +endif +RELSYSDIR = $(RELEASE_PATH)/lib/erl_interface-$(EI_VSN) + +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ + +ifeq ($(TYPE),debug) +PURIFY = +TYPEMARKER = .debug +TYPE_FLAGS = -g -DDEBUG +ifeq ($(TARGET),win32) +LDFLAGS += -g +endif +else +ifeq ($(TYPE),purify) +PURIFY = purify +TYPEMARKER = .purify +TYPE_FLAGS = -DPURIFY -DNO_JUMP_TABLE +else +ifeq ($(TYPE),quantify) +PURIFY = quantify +TYPEMARKER = .quantify +TYPE_FLAGS = -g -O2 -DQUANTIFY +else +ifeq ($(TYPE),purecov) +PURIFY = purecov --follow-child-processes=yes +TYPEMARKER = .purecov +TYPE_FLAGS = -g -DPURECOV -DNO_JUMP_TABLE +else +ifeq ($(TYPE),gcov) +PURIFY = +TYPEMARKER = +TYPE_FLAGS = -DNO_JUMP_TABLE -fprofile-arcs -ftest-coverage +ifeq ($(TARGET),linux) +LIBS += -lgcov +endif +else +PURIFY = +TYPEMARKER = +TYPE_FLAGS = +endif +endif +endif +endif +endif + +CC = @CC@ +LD = @LD@ +AR = @AR@ +RANLIB = @RANLIB@ + +INCFLAGS = -I. -I../include -Iconnect -Iencode -Idecode -Imisc -Iepmd \ + -Iregistry -I$(TARGET) + +ifeq ($(USING_VC),yes) +WARNFLAGS = -Wall +else +WARNFLAGS = @WFLAGS@ +endif + +ifneq ($(findstring ose,$(TARGET)),ose) +CFLAGS = @DED_CFLAGS@ $(WARNFLAGS) $(INCFLAGS) $(TYPE_FLAGS) +else +CFLAGS = @CFLAGS@ $(INCFLAGS) +endif +PROG_CFLAGS = @CFLAGS@ $(WARNFLAGS) $(INCFLAGS) $(TYPE_FLAGS) -Ilegacy + +ifeq ($(findstring vxworks,$(TARGET)),vxworks) +PROG_CFLAGS += -nostartfiles -Wl,-r,-d +endif + + +INSTALL = @INSTALL@ +INSTALL_DIR = @INSTALL_DIR@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ + +# The default library (no extra extension in name) is for Unix with +# thread support if exists. For windows MD is the default. +# +# ST = single threaded (Unix without thread support) +# MT = multi threaded (on windows also static linking) +# MD = multithreaded dynamic (default for cygwin cc wrapper) +# MDD = multithreaded dynamic with debug symbols +# +ST_OBJDIR = $(ERL_TOP)/lib/erl_interface/obj.st$(TYPEMARKER)/$(TARGET) +MT_OBJDIR = $(ERL_TOP)/lib/erl_interface/obj.mt$(TYPEMARKER)/$(TARGET) +MD_OBJDIR = $(ERL_TOP)/lib/erl_interface/obj.md$(TYPEMARKER)/$(TARGET) +MDD_OBJDIR = $(ERL_TOP)/lib/erl_interface/obj.mdd$(TYPEMARKER)/$(TARGET) +OBJDIR = $(ERL_TOP)/lib/erl_interface/obj$(TYPEMARKER)/$(TARGET) +BINDIR = $(ERL_TOP)/lib/erl_interface/bin/$(TARGET) + +# FIXME maybe use this opt and remove (int) cast to is*() functions +# -Wno-char-subscripts +# -Wshadow + +vpath %.c connect:encode:decode:misc:epmd:legacy:registry + + +########################################################################### +# List targets +########################################################################### + +ifeq ($(TARGET),win32) +EXE=.exe +else +EXE= +endif + +ifeq ($(USING_VC),yes) +LIBEXT=.lib +LIBPRE= +MTFLAG=-MT + +else +LIBEXT=.a +LIBPRE=lib +MTFLAG= + +endif + +########################################################################### +# Specify targets names +########################################################################### + +ERL_CALL = $(BINDIR)/erl_call$(EXE) + +ifdef THR_DEFS +ST_EILIB = $(OBJDIR)/$(LIBPRE)ei_st$(LIBEXT) +ST_ERLLIB = $(OBJDIR)/$(LIBPRE)erl_interface_st$(LIBEXT) +MT_EILIB = $(OBJDIR)/$(LIBPRE)ei$(LIBEXT) +MT_ERLLIB = $(OBJDIR)/$(LIBPRE)erl_interface$(LIBEXT) +else +ST_EILIB = $(OBJDIR)/$(LIBPRE)ei$(LIBEXT) +ST_ERLLIB = $(OBJDIR)/$(LIBPRE)erl_interface$(LIBEXT) +endif +MD_EILIB = $(OBJDIR)/$(LIBPRE)ei_md$(LIBEXT) +MDD_EILIB = $(OBJDIR)/$(LIBPRE)ei_mdd$(LIBEXT) +MD_ERLLIB = $(OBJDIR)/$(LIBPRE)erl_interface_md$(LIBEXT) +MDD_ERLLIB = $(OBJDIR)/$(LIBPRE)erl_interface_mdd$(LIBEXT) + +########################################################################### +# Specify targets to build +########################################################################### + +ifneq ($(findstring ose,$(TARGET)),ose) +EXE_TARGETS = \ + $(ERL_CALL) +else +EXE_TARGETS = +endif + +ifeq ($(USING_VC),yes) + +# Windows targets + +TARGETS = \ + $(BINDIR) \ + $(OBJDIR) \ + $(MT_OBJDIR) \ + $(MD_OBJDIR) \ + $(MDD_OBJDIR) \ + $(OBJ_TARGETS) \ + $(EXE_TARGETS) + +OBJ_TARGETS = \ + $(MT_EILIB) \ + $(MD_EILIB) \ + $(MDD_EILIB) \ + $(MT_ERLLIB) \ + $(MD_ERLLIB) \ + $(MDD_ERLLIB) + +FAKE_TARGETS = \ + $(OBJDIR)/erl_fake_prog_mt$(EXE) \ + $(OBJDIR)/ei_fake_prog_mt$(EXE) \ + $(OBJDIR)/erl_fake_prog_mt_cxx$(EXE) \ + $(OBJDIR)/ei_fake_prog_mt_cxx$(EXE) \ + $(OBJDIR)/erl_fake_prog_md$(EXE) \ + $(OBJDIR)/ei_fake_prog_md$(EXE) \ + $(OBJDIR)/erl_fake_prog_cxx_md$(EXE) \ + $(OBJDIR)/ei_fake_prog_cxx_md$(EXE) \ + $(OBJDIR)/erl_fake_prog_mdd$(EXE) \ + $(OBJDIR)/ei_fake_prog_mdd$(EXE) \ + $(OBJDIR)/erl_fake_prog_cxx_mdd$(EXE) \ + $(OBJDIR)/ei_fake_prog_cxx_mdd$(EXE) \ + +else + +ifeq ($USING_MINGW,yes) +TARGETS = \ + $(BINDIR) \ + $(OBJDIR) \ + $(MD_OBJDIR) \ + $(OBJ_TARGETS) \ + $(EXE_TARGETS) + +OBJ_TARGETS = \ + $(MD_EILIB) \ + $(MD_ERLLIB) + +FAKE_TARGETS = \ + $(OBJDIR)/erl_fake_prog_md$(EXE) \ + $(OBJDIR)/ei_fake_prog_md$(EXE) \ + $(OBJDIR)/erl_fake_prog_cxx_md$(EXE) \ + $(OBJDIR)/ei_fake_prog_cxx_md$(EXE) +else +# Unix targets + +ifdef THR_DEFS + +TARGETS = \ + $(BINDIR) \ + $(OBJDIR) \ + $(ST_OBJDIR) \ + $(MT_OBJDIR) \ + $(OBJ_TARGETS) \ + $(EXE_TARGETS) + +OBJ_TARGETS = \ + $(ST_EILIB) \ + $(ST_ERLLIB) \ + $(MT_EILIB) \ + $(MT_ERLLIB) + +FAKE_TARGETS = \ + $(ST_OBJDIR)/erl_fake_prog_st$(EXE) \ + $(ST_OBJDIR)/ei_fake_prog_st$(EXE) \ + $(ST_OBJDIR)/erl_fake_prog_cxx_st$(EXE) \ + $(ST_OBJDIR)/ei_fake_prog_cxx_st$(EXE) \ + $(MT_OBJDIR)/erl_fake_prog_mt$(EXE) \ + $(MT_OBJDIR)/ei_fake_prog_mt$(EXE) \ + $(MT_OBJDIR)/erl_fake_prog_mt_cxx$(EXE) \ + $(MT_OBJDIR)/ei_fake_prog_mt_cxx$(EXE) + +else + +TARGETS = \ + $(BINDIR) \ + $(OBJDIR) \ + $(ST_OBJDIR) \ + $(OBJ_TARGETS) \ + $(EXE_TARGETS) + +OBJ_TARGETS = \ + $(ST_EILIB) \ + $(ST_ERLLIB) + +FAKE_TARGETS = \ + $(ST_OBJDIR)/erl_fake_prog_st$(EXE) \ + $(ST_OBJDIR)/ei_fake_prog_st$(EXE) \ + $(ST_OBJDIR)/erl_fake_prog_cxx_st$(EXE) \ + $(ST_OBJDIR)/ei_fake_prog_cxx_st$(EXE) + +endif + +endif + +endif +########################################################################### +# List all source files +########################################################################### + +# FIXME do we need dummy here for XX.h that was needed before?? + +HEADERS = \ + ../include/ei.h \ + ../include/ei_connect.h \ + ../include/eicode.h \ + ../include/erl_interface.h + +EISOURCES = \ + $(CONNECTSRC) \ + $(DECODESRC) \ + $(ENCODESRC) \ + $(EPMDSRC) \ + $(MISCSRC) \ + $(REGISTRYSRC) + +CONNECTSRC = \ + connect/ei_connect.c \ + connect/ei_resolve.c \ + connect/eirecv.c \ + connect/send.c \ + connect/send_exit.c \ + connect/send_reg.c + +DECODESRC = \ + decode/decode_atom.c \ + decode/decode_big.c \ + decode/decode_bignum.c \ + decode/decode_binary.c \ + decode/decode_boolean.c \ + decode/decode_char.c \ + decode/decode_double.c \ + decode/decode_fun.c \ + decode/decode_intlist.c \ + decode/decode_list_header.c \ + decode/decode_long.c \ + decode/decode_pid.c \ + decode/decode_port.c \ + decode/decode_ref.c \ + decode/decode_skip.c \ + decode/decode_string.c \ + decode/decode_trace.c \ + decode/decode_tuple_header.c \ + decode/decode_ulong.c \ + decode/decode_version.c \ + $(DECODESRC_LONGLONG) + +ifneq ($(findstring vxworks,$(TARGET)),vxworks) +DECODESRC_LONGLONG = \ + decode/decode_longlong.c \ + decode/decode_ulonglong.c +else +DECODESRC_LONGLONG = +endif + + +ENCODESRC = \ + encode/encode_atom.c \ + encode/encode_big.c \ + encode/encode_bignum.c \ + encode/encode_binary.c \ + encode/encode_boolean.c \ + encode/encode_char.c \ + encode/encode_double.c \ + encode/encode_fun.c \ + encode/encode_list_header.c \ + encode/encode_long.c \ + encode/encode_pid.c \ + encode/encode_port.c \ + encode/encode_ref.c \ + encode/encode_string.c \ + encode/encode_trace.c \ + encode/encode_tuple_header.c \ + encode/encode_ulong.c \ + encode/encode_version.c \ + $(ENCODESRC_LONGLONG) + +ifneq ($(findstring vxworks,$(TARGET)),vxworks) +ENCODESRC_LONGLONG = \ + encode/encode_longlong.c \ + encode/encode_ulonglong.c +else +ENCODESRC_LONGLONG = +endif + + +EPMDSRC = \ + epmd/epmd_port.c \ + epmd/epmd_publish.c \ + epmd/epmd_unpublish.c + +MISCSRC = \ + misc/ei_decode_term.c \ + misc/ei_format.c \ + misc/ei_locking.c \ + misc/ei_malloc.c \ + misc/ei_portio.c \ + misc/ei_printterm.c \ + misc/ei_pthreads.c \ + misc/ei_trace.c \ + misc/ei_x_encode.c \ + misc/eimd5.c \ + misc/get_type.c \ + misc/show_msg.c \ + misc/ei_compat.c + +REGISTRYSRC = \ + registry/hash_dohash.c \ + registry/hash_foreach.c \ + registry/hash_freetab.c \ + registry/hash_insert.c \ + registry/hash_isprime.c \ + registry/hash_lookup.c \ + registry/hash_newtab.c \ + registry/hash_remove.c \ + registry/hash_resize.c \ + registry/hash_rlookup.c \ + registry/reg_close.c \ + registry/reg_delete.c \ + registry/reg_dirty.c \ + registry/reg_dump.c \ + registry/reg_free.c \ + registry/reg_get.c \ + registry/reg_getf.c \ + registry/reg_geti.c \ + registry/reg_getp.c \ + registry/reg_gets.c \ + registry/reg_make.c \ + registry/reg_open.c \ + registry/reg_purge.c \ + registry/reg_resize.c \ + registry/reg_restore.c \ + registry/reg_set.c \ + registry/reg_setf.c \ + registry/reg_seti.c \ + registry/reg_setp.c \ + registry/reg_sets.c \ + registry/reg_stat.c \ + registry/reg_tabstat.c + +ERLSOURCES = \ + legacy/decode_term.c \ + legacy/encode_term.c \ + legacy/erl_connect.c \ + legacy/erl_error.c \ + legacy/erl_eterm.c \ + legacy/erl_fix_alloc.c \ + legacy/erl_format.c \ + legacy/erl_malloc.c \ + legacy/erl_marshal.c \ + legacy/erl_resolve.c \ + legacy/erl_timeout.c \ + legacy/global_names.c \ + legacy/global_register.c \ + legacy/global_unregister.c \ + legacy/global_whereis.c + +SOURCES = $(EISOURCES) $(ERLSOURCES) + +OSE_EISOURCES = \ + $(DECODESRC) \ + $(ENCODESRC) \ + misc/ei_decode_term.c \ + misc/ei_format.c \ + misc/ei_locking.c \ + misc/ei_malloc.c \ + misc/ei_printterm.c \ + misc/ei_pthreads.c \ + misc/ei_trace.c \ + misc/ei_x_encode.c \ + misc/eimd5.c \ + misc/get_type.c \ + misc/show_msg.c \ + misc/ei_compat.c \ + registry/hash_dohash.c \ + registry/hash_foreach.c \ + registry/hash_freetab.c \ + registry/hash_insert.c \ + registry/hash_isprime.c \ + registry/hash_lookup.c \ + registry/hash_newtab.c \ + registry/hash_remove.c \ + registry/hash_resize.c \ + registry/hash_rlookup.c + +OSE_ERLSOURCES = \ + legacy/decode_term.c \ + legacy/encode_term.c \ + legacy/erl_error.c \ + legacy/erl_eterm.c \ + legacy/erl_fix_alloc.c \ + legacy/erl_format.c \ + legacy/erl_malloc.c \ + legacy/erl_marshal.c + +OSE_SOURCES = $(OSE_EISOURCES) $(OSE_ERLSOURCES) + +NEVERUSED = \ + whereis.c \ + ei_send.c \ + ei_send_reg.c \ + send_link.c + +ERLCALL = \ + prog/erl_call.c \ + prog/erl_start.c + + +# Note that encode/decode_term.c defines ei functions that is +# located in the erl_interface library, not ei library. + +ifneq ($(findstring ose,$(TARGET)),ose) +ST_EIOBJECTS = $(addprefix $(ST_OBJDIR)/,$(notdir $(EISOURCES:.c=.o))) +ST_ERLOBJECTS = $(addprefix $(ST_OBJDIR)/,$(notdir $(ERLSOURCES:.c=.o))) +else +ST_EIOBJECTS = $(addprefix $(ST_OBJDIR)/,$(notdir $(OSE_EISOURCES:.c=.o))) +ST_ERLOBJECTS = $(addprefix $(ST_OBJDIR)/,$(notdir $(OSE_ERLSOURCES:.c=.o))) +endif +MT_EIOBJECTS = $(addprefix $(MT_OBJDIR)/,$(notdir $(EISOURCES:.c=.o))) +MT_ERLOBJECTS = $(addprefix $(MT_OBJDIR)/,$(notdir $(ERLSOURCES:.c=.o))) +MD_EIOBJECTS = $(addprefix $(MD_OBJDIR)/,$(notdir $(EISOURCES:.c=.o))) +MD_ERLOBJECTS = $(addprefix $(MD_OBJDIR)/,$(notdir $(ERLSOURCES:.c=.o))) +MDD_EIOBJECTS = $(addprefix $(MDD_OBJDIR)/,$(notdir $(EISOURCES:.c=.o))) +MDD_ERLOBJECTS = $(addprefix $(MDD_OBJDIR)/,$(notdir $(ERLSOURCES:.c=.o))) + +########################################################################### +# Main targets +########################################################################### + +# FIXME this assumes execution order +# FIXME move up and add exe prefix if needed.... + +debug opt: $(TARGETS) + +docs: + +tests: + +clean: + rm -f $(ST_EIOBJECTS) $(ST_ERLOBJECTS) $(ST_EILIB) $(ST_ERLLIB) + rm -f $(MT_EIOBJECTS) $(MT_ERLOBJECTS) $(MT_EILIB) $(MT_ERLLIB) + rm -f $(MD_EIOBJECTS) $(MD_ERLOBJECTS) $(MD_EILIB) $(MD_ERLLIB) + rm -f $(MDD_EIOBJECTS) $(MDD_ERLOBJECTS) $(MDD_EILIB) $(MDD_ERLLIB) + rm -f $(ERL_CALL) + rm -f $(FAKE_TARGETS) + +distclean: clean + rm -f config.h config.log config.status configure + + +########################################################################### +# FIXME move this VxWorks stuff to configure or something +########################################################################### + +# FIXME depend on $(TARGET)/Makefile ??? + +ifeq ($(findstring vxworks,$(TARGET)),vxworks) +$(TARGET)/config.h: + echo "/* Generated by Makefile */" > $@ + echo "#define HAVE_STRERROR 1" >> $@ +endif + +ifeq ($(findstring ose,$(TARGET)),ose) +$(TARGET)/config.h: + echo "/* Generated by Makefile */" > $@ + echo "#define HAVE_STRERROR 1" >> $@ +endif + +########################################################################### +# Default rules, normal and threaded +########################################################################### + +$(ST_OBJDIR)/%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(MT_OBJDIR)/%.o: %.c + $(CC) $(MTFLAG) $(CFLAGS) $(THR_DEFS) -c $< -o $@ + +$(MD_OBJDIR)/%.o: %.c + $(CC) -MD $(CFLAGS) $(THR_DEFS) -c $< -o $@ + +$(MD_OBJDIR)/%.o: %.c + $(CC) -MD $(CFLAGS) $(THR_DEFS) -c $< -o $@ + +$(MDD_OBJDIR)/%.o: %.c + $(CC) -MDd $(CFLAGS) $(THR_DEFS) -c $< -o $@ + +########################################################################### +# Create directories +########################################################################### + +$(BINDIR): + mkdir -p $(BINDIR) + +$(OBJDIR): + mkdir -p $(OBJDIR) + +$(ST_OBJDIR): + mkdir -p $(ST_OBJDIR) + +$(MT_OBJDIR): + mkdir -p $(MT_OBJDIR) + +$(MD_OBJDIR): + mkdir -p $(MD_OBJDIR) + +$(MDD_OBJDIR): + mkdir -p $(MDD_OBJDIR) + +########################################################################### +# Special rules +########################################################################### + +ifeq ($(TARGET),win32) + +# Windows archive creation + +$(ST_EILIB) : $(ST_EIOBJECTS) + $(AR) -out:$@ $(ST_EIOBJECTS) + $(RANLIB) $@ + +$(ST_ERLLIB) : $(ST_ERLOBJECTS) + $(AR) -out:$@ $(ST_ERLOBJECTS) + $(RANLIB) $@ + +$(MT_EILIB) : $(MT_EIOBJECTS) + $(AR) -out:$@ $(MT_EIOBJECTS) + $(RANLIB) $@ + +$(MT_ERLLIB) : $(MT_ERLOBJECTS) + $(AR) -out:$@ $(MT_ERLOBJECTS) + $(RANLIB) $@ + +$(MD_EILIB) : $(MD_EIOBJECTS) + $(AR) -out:$@ $(MD_EIOBJECTS) + $(RANLIB) $@ + +$(MD_ERLLIB) : $(MD_ERLOBJECTS) + $(AR) -out:$@ $(MD_ERLOBJECTS) + $(RANLIB) $@ + +$(MDD_EILIB) : $(MDD_EIOBJECTS) + $(AR) -out:$@ $(MDD_EIOBJECTS) + $(RANLIB) $@ + +$(MDD_ERLLIB) : $(MDD_ERLOBJECTS) + $(AR) -out:$@ $(MDD_ERLOBJECTS) + $(RANLIB) $@ + +else + +# Unix archive creation + +$(ST_EILIB) : $(ST_EIOBJECTS) + rm -f $@ + $(AR) rcv $@ $(ST_EIOBJECTS) +ifdef RANLIB + $(RANLIB) $@ +endif + +$(ST_ERLLIB) : $(ST_ERLOBJECTS) + rm -f $@ + $(AR) rcv $@ $(ST_ERLOBJECTS) +ifdef RANLIB + $(RANLIB) $@ +endif + +$(MT_EILIB) : $(MT_EIOBJECTS) + rm -f $@ + $(AR) rcv $@ $(MT_EIOBJECTS) +ifdef RANLIB + $(RANLIB) $@ +endif + +$(MT_ERLLIB) : $(MT_ERLOBJECTS) + rm -f $@ + $(AR) rcv $@ $(MT_ERLOBJECTS) +ifdef RANLIB + $(RANLIB) $@ +endif + +endif + +########################################################################### +# erl_call FIXME how to avoid explicit -lsocket on winows??? +########################################################################### + +ifeq ($(TARGET),win32) +$(ERL_CALL): $(ERLCALL) ../include/ei.h $(MD_EILIB) + $(PURIFY) $(CC) -MD $(PROG_CFLAGS) $(THR_DEFS) -o $@ $(ERLCALL) \ + -L$(OBJDIR) -lei_md $(THR_LIBS) $(LIBS) -lsocket +else +ifeq ($(findstring vxworks,$(TARGET)),vxworks) +$(ERL_CALL): $(ST_OBJDIR)/erl_call.o $(ST_OBJDIR)/erl_start.o ../include/ei.h $(ST_EILIB) + $(LD) -r -d -o $@ $(ST_OBJDIR)/erl_call.o $(ST_OBJDIR)/erl_start.o -L$(OBJDIR) -lei $(LIBS) + +$(ST_OBJDIR)/erl_call.o: prog/erl_call.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(ST_OBJDIR)/erl_start.o: prog/erl_start.c + $(CC) $(CFLAGS) -c $< -o $@ + +else +ifeq ($(findstring ose,$(TARGET)),ose) +$(ERL_CALL): +else +ifdef THR_DEFS +$(ERL_CALL): $(ERLCALL) ../include/ei.h $(MT_EILIB) + $(PURIFY) $(CC) $(PROG_CFLAGS) $(THR_DEFS) $(LDFLAGS) -o $@ $(ERLCALL) \ + -L$(OBJDIR) -lei $(THR_LIBS) $(LIBS) +else +$(ERL_CALL): $(ERLCALL) ../include/ei.h $(ST_EILIB) + $(PURIFY) $(CC) $(PROG_CFLAGS) $(LDFLAGS) -o $@ $(ERLCALL) \ + -L$(OBJDIR) -lei $(LIBS) +endif +endif +endif +endif + +########################################################################### +# Fake application targets used to test header files and linking +########################################################################### + +check: $(FAKE_TARGETS) + +ifndef THR_DEFS +$(ST_OBJDIR)/erl_fake_prog_st$(EXE): prog/erl_fake_prog.c $(ST_ERLLIB) $(ST_EILIB) + $(CC) $(PROG_CFLAGS) -o $@ $< -L$(OBJDIR) -lerl_interface -lei \ + $(LIBS) + +$(ST_OBJDIR)/ei_fake_prog_st$(EXE): prog/ei_fake_prog.c $(ST_EILIB) + $(CC) $(PROG_CFLAGS) -o $@ $< -L$(OBJDIR) -lei $(LIBS) + +$(ST_OBJDIR)/erl_fake_prog_cxx_st$(EXE): prog/erl_fake_prog.c \ + $(ST_ERLLIB) $(ST_EILIB) + $(CC) $(PROG_CFLAGS) -o $@ -xc++ $< -L$(OBJDIR) \ + -lerl_interface -lei $(LIBS) + +$(ST_OBJDIR)/ei_fake_prog_cxx_st$(EXE): prog/ei_fake_prog.c $(ST_EILIB) + $(CC) $(PROG_CFLAGS) -o $@ -xc++ $< -L$(OBJDIR) -lei $(LIBS) + +else + +$(ST_OBJDIR)/erl_fake_prog_st$(EXE): prog/erl_fake_prog.c $(ST_ERLLIB) $(ST_EILIB) + $(CC) $(PROG_CFLAGS) -o $@ $< -L$(OBJDIR) -lerl_interface_st -lei_st \ + $(LIBS) + +$(ST_OBJDIR)/ei_fake_prog_st$(EXE): prog/ei_fake_prog.c $(ST_EILIB) + $(CC) $(PROG_CFLAGS) -o $@ $< -L$(OBJDIR) -lei_st $(LIBS) + +$(ST_OBJDIR)/erl_fake_prog_cxx_st$(EXE): prog/erl_fake_prog.c \ + $(ST_ERLLIB) $(ST_EILIB) + $(CC) $(PROG_CFLAGS) -o $@ -xc++ $< -L$(OBJDIR) \ + -lerl_interface_st -lei_st $(LIBS) + +$(ST_OBJDIR)/ei_fake_prog_cxx_st$(EXE): prog/ei_fake_prog.c $(ST_EILIB) + $(CC) $(PROG_CFLAGS) -o $@ -xc++ $< -L$(OBJDIR) -lei_st $(LIBS) + +endif + +#### + +$(MT_OBJDIR)/erl_fake_prog_mt$(EXE): prog/erl_fake_prog.c \ + $(MT_ERLLIB) $(MT_EILIB) + $(CC) $(MTFLAG) $(PROG_CFLAGS) $(THR_DEFS) -o $@ $< -L$(OBJDIR) \ + -lerl_interface -lei $(THR_LIBS) $(LIBS) + +$(MT_OBJDIR)/ei_fake_prog_mt$(EXE): prog/ei_fake_prog.c $(MT_EILIB) + $(CC) $(MTFLAG) $(PROG_CFLAGS) $(THR_DEFS) -o $@ $< \ + -L$(OBJDIR) -lei $(THR_LIBS) $(LIBS) + +$(MT_OBJDIR)/erl_fake_prog_mt_cxx$(EXE): prog/erl_fake_prog.c \ + $(MT_ERLLIB) $(MT_EILIB) + $(CC) $(MTFLAG) $(PROG_CFLAGS) $(THR_DEFS) -o $@ -xc++ $< \ + -L$(OBJDIR) -lerl_interface -lei \ + $(THR_LIBS) $(LIBS) + +$(MT_OBJDIR)/ei_fake_prog_mt_cxx$(EXE): prog/ei_fake_prog.c $(MT_EILIB) + $(CC) $(MTFLAG) $(PROG_CFLAGS) $(THR_DEFS) -o $@ -xc++ $< \ + -L$(OBJDIR) -lei $(THR_LIBS) $(LIBS) + +#### + +$(MD_OBJDIR)/erl_fake_prog_md$(EXE): prog/erl_fake_prog.c \ + $(MD_ERLLIB) $(MD_EILIB) + $(CC) -MD $(PROG_CFLAGS) $(THR_DEFS) -o $@ $< -L$(OBJDIR) \ + -lerl_interface_r -lei_r $(THR_LIBS) $(LIBS) + +$(MD_OBJDIR)/ei_fake_prog_md$(EXE): prog/ei_fake_prog.c $(MD_EILIB) + $(CC) -MD $(PROG_CFLAGS) $(THR_DEFS) -o $@ $< \ + -L$(OBJDIR) -lei_r $(THR_LIBS) $(LIBS) + +$(MD_OBJDIR)/erl_fake_prog_md_cxx$(EXE): prog/erl_fake_prog.c \ + $(MD_ERLLIB) $(MD_EILIB) + $(CC) -MD $(PROG_CFLAGS) $(THR_DEFS) -o $@ -xc++ $< \ + -L$(OBJDIR) -lerl_interface_r -lei_r \ + $(THR_LIBS) $(LIBS) + +$(MD_OBJDIR)/ei_fake_prog_md_cxx$(EXE): prog/ei_fake_prog.c $(MD_EILIB) + $(CC) -MD $(PROG_CFLAGS) $(THR_DEFS) -o $@ -xc++ $< \ + -L$(OBJDIR) -lei_r $(THR_LIBS) $(LIBS) + +#### + +$(MDD_OBJDIR)/erl_fake_prog_mdd$(EXE): prog/erl_fake_prog.c \ + $(MDD_ERLLIB) $(MDD_EILIB) + $(CC) -MDD $(PROG_CFLAGS) $(THR_DEFS) -o $@ $< -L$(OBJDIR) \ + -lerl_interface_r -lei_r $(THR_LIBS) $(LIBS) + +$(MDD_OBJDIR)/ei_fake_prog_mdd$(EXE): prog/ei_fake_prog.c $(MDD_EILIB) + $(CC) -MDD $(PROG_CFLAGS) $(THR_DEFS) -o $@ $< \ + -L$(OBJDIR) -lei_r $(THR_LIBS) $(LIBS) + +$(MDD_OBJDIR)/erl_fake_prog_mdd_cxx$(EXE): prog/erl_fake_prog.c \ + $(MDD_ERLLIB) $(MDD_EILIB) + $(CC) -MDD $(PROG_CFLAGS) $(THR_DEFS) -o $@ -xc++ $< \ + -L$(OBJDIR) -lerl_interface_r -lei_r \ + $(THR_LIBS) $(LIBS) + +$(MDD_OBJDIR)/ei_fake_prog_mdd_cxx$(EXE): prog/ei_fake_prog.c $(MDD_EILIB) + $(CC) -MDD $(PROG_CFLAGS) $(THR_DEFS) -o $@ -xc++ $< \ + -L$(OBJDIR) -lei_r $(THR_LIBS) $(LIBS) + +########################################################################### +# Create dependency file using gcc -MM +########################################################################### + +depend: + @echo "Generating dependency file depend.mk..." + @echo "# Generated dependency rules" > depend.mk; \ + $(CC) $(CFLAGS) -MM $(SOURCES) | \ + sed 's&$(TARGET)&\$$\(TARGET\)&g' | \ + sed 's/^.*:/\$$\(ST_OBJDIR\)\/&/' >> depend.mk; \ + echo >> depend.mk; \ + $(CC) $(CFLAGS) -MM $(SOURCES) | \ + sed 's&$(TARGET)&\$$\(TARGET\)&g' | \ + sed 's/^.*:/\$$\(MT_OBJDIR\)\/&/' >> depend.mk; \ + echo >> depend.mk; \ + $(CC) $(CFLAGS) -MM $(SOURCES) | \ + sed 's&$(TARGET)&\$$\(TARGET\)&g' | \ + sed 's/^.*:/\$$\(MD_OBJDIR\)\/&/' >> depend.mk; \ + echo >> depend.mk; \ + $(CC) $(CFLAGS) -MM $(SOURCES) | \ + sed 's&$(TARGET)&\$$\(TARGET\)&g' | \ + sed 's/^.*:/\$$\(MDD_OBJDIR\)\/&/' >> depend.mk; \ + echo >> depend.mk + +# For some reason this has to be after 'opt' target +include depend.mk + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- + +EXTRA = \ + INSTALL \ + Makefile \ + Makefile.in \ + README \ + README.internal \ + $(TARGET)/eidefs.mk + +release: opt + $(INSTALL_DIR) $(RELSYSDIR)/include + $(INSTALL_DIR) $(RELSYSDIR)/lib + $(INSTALL_DIR) $(RELSYSDIR)/bin + $(INSTALL_DIR) $(RELSYSDIR)/src/auxdir + $(INSTALL_DIR) $(RELSYSDIR)/src/connect + $(INSTALL_DIR) $(RELSYSDIR)/src/decode + $(INSTALL_DIR) $(RELSYSDIR)/src/encode + $(INSTALL_DIR) $(RELSYSDIR)/src/epmd + $(INSTALL_DIR) $(RELSYSDIR)/src/legacy + $(INSTALL_DIR) $(RELSYSDIR)/src/misc + $(INSTALL_DIR) $(RELSYSDIR)/src/prog + $(INSTALL_DIR) $(RELSYSDIR)/src/registry + $(INSTALL_DATA) $(HEADERS) $(RELSYSDIR)/include + $(INSTALL_DATA) $(OBJ_TARGETS) $(RELSYSDIR)/lib +ifneq ($(EXE_TARGETS),) + $(INSTALL_PROGRAM) $(EXE_TARGETS) $(RELSYSDIR)/bin +endif + $(INSTALL_DATA) $(EXTRA) $(RELSYSDIR)/src + $(INSTALL_DATA) connect/*.[ch] $(RELSYSDIR)/src/connect + $(INSTALL_DATA) decode/*.[ch] $(RELSYSDIR)/src/decode + $(INSTALL_DATA) encode/*.[ch] $(RELSYSDIR)/src/encode + $(INSTALL_DATA) epmd/*.[ch] $(RELSYSDIR)/src/epmd + $(INSTALL_DATA) misc/*.[ch] $(RELSYSDIR)/src/misc + $(INSTALL_DATA) registry/*.[ch] $(RELSYSDIR)/src/registry + $(INSTALL_DATA) legacy/*.[ch] $(RELSYSDIR)/src/legacy + $(INSTALL_DATA) prog/*.[ch] $(RELSYSDIR)/src/prog + +release_docs: + +release_tests: diff --git a/lib/erl_interface/src/README b/lib/erl_interface/src/README new file mode 100644 index 0000000000..feee2e48e8 --- /dev/null +++ b/lib/erl_interface/src/README @@ -0,0 +1,186 @@ +Erl_interface README July 2, 1997. +Bjorn Gustavsson +---------------------------------- + +About the erl_interface library +------------------------------- + +The pre-release version of erl_interface provided in this package +is compiled for use of DNS and with symbol information. +Also, assertions are enabled, meaning that the code will be a +little bit slower. In the final release, there will be two +alternative libraries shipped, with and without assertions. + +If an assertion triggers, there will be a printout similiar to this +one: + + Assertion failed: ep != NULL in erl_eterm.c, line 694 + Abort (core dumped) + +The cause of an assertion can be either errors in the application +program (for instance, passing NULL pointers to any function that +expects an ETERM pointer) or in erl_interface itself. + +If you encounter any assertion failures which think you originate in +erl_interface, I'll need the following information to track it down: + +1a) The printout from the assertion, especially filename and line number. + +1b) A dump of the stack, obtained by running a debugger. + + - OR - + +2) The source for a small test program which triggers the assertion. + +Changes in this version +----------------------- + +There is now *one* representation for an empty list, not two as is used +to be. An empty list is represented by the Erl_EmptyList structure. +There are new macros, ERL_IS_EMPTY_LIST(ep), to test for an empty list, +and ERL_IS_CONS(ep) to test for a cons cell (more on that below). + +None of the type checking macros (ERL_IS_LIST(ep), ERL_IS_TUPLE(ep), etc), +accept NULL pointers any longer. Make sure to only pass valid ETERM +pointers. + +erl_cons(head, tail) now requires tail to be a non-NULL pointer. +To represent the end of a list, use the return value from +erl_mk_empty_list(). + +erl_length() now only works for a proper list; i.e. for the +the term [a|b], erl_length() returns -1. + +erl_tl(), erl_hd() is now silent if given a bad list +(but still returns NULL). + +The string data type has been removed, including the macro ERL_IS_STRING(). +The functions erl_mk_string() and erl_mk_estring() still exists, but builds +lists instead of strings. + +There are two new functions to convert I/O lists (= deep lists of +byte-sized integers and binaries): + + char* erl_iolist_to_string(ETERM* term); + ETERM* erl_iolist_to_binary(ETERM* term); + +The erl_iolist_to_string() function converts an I/O list to a +'\0' terminated string. + +Known bugs +---------- + +The term erl_mk_small_int(-0x10000000) will be incorrectly represented +if decoded and sent to the Erlang side. + +Calling erl_mk_int() on an integer whose value is represented +in more than 28 bits, will result in an ETERM which is not an integer +(i.e. ERL_IS_INTEGER() will fail). + +Planned future changes +---------------------- + +Support for heap allocation of Erlang terms will be dropped. +It will be assumed that malloc()/free() functions are available. + +There will be one header file, erl_interface.h, not one for each +"module". + +The type checking macros for lists +---------------------------------- + +In this version of erl_interface, there are three macros for testing +types of lists: + +ERL_IS_LIST(term) +ERL_IS_CONS(term) +ERL_IS_EMPTY_LIST(term) + +They behave as follows: + +ERL_IS_LIST(term) is used like a list/1 guard function in Erlang: + +function(List) when list(List) -> + .... + +It is true if its argument is a list, even an empty list. + +ERL_IS_EMPTY(term) is true only for an empty list; thus it can be +used like the following function head: + +function([]) -> + .... + +ERL_IS_CONS(term) only if the list is not empty; it is similar to the +following function head: + +function([H|T] -> + .... + +Documentation for new functions +------------------------------- + +/*********************************************************************** + * I o l i s t f u n c t i o n s + * + * The following functions handles I/O lists. + * + * Informally, an I/O list is a deep list of characters and binaries, + * which can be sent to an Erlang port. + * + * Formally, in BNF, an I/O list is defined as: + * + * iolist ::= [] + * | Binary + * | [iohead | iolist] + * ; + * + * iohead ::= Binary + * | Byte (integer in the range [0..255]) + * | iolist + * ; + * + * Note that versions of Erlang/OTP prior to R2 had a slightly more + * restricted definition of I/O lists, in that the tail of a an I/O list + * was not allowed to be a binary. The erl_interface functions + * for I/O lists follows the more liberal rules described by the BNF + * description above. + ***********************************************************************/ + +/* + * This function converts an I/O list to a '\0' terminated C string. + * The I/O list must not contain any occurrences of the integer 0. + * + * The string will be in memory allocated by erl_malloc(). It is the + * responsibility of the caller to eventually call erl_free() to free + * the memory. + * + * Returns: NULL if the list was not an I/O list or contained + * the integer 0, otherwise a pointer to '\0' terminated string. + */ + +char* +erl_iolist_to_string(term) + ETERM* term; /* Term to convert to a string. */ + +/* + * This function converts an I/O list to a binary term. + * + * Returns: NULL if the list was not an I/O list, otherwise + * an ETERM pointer pointing to a binary term. + */ + +ETERM* +erl_iolist_to_binary(term) + ETERM* term; /* Term to convert to a binary. */ + +/* + * Returns the length of an I/O list. + * + * Returns: -1 if the term if the given term is not a I/O list, + * or the length otherwise. + */ + +int +erl_iolist_length(term) + ETERM* term; diff --git a/lib/erl_interface/src/README.internal b/lib/erl_interface/src/README.internal new file mode 100644 index 0000000000..c1f2d6863f --- /dev/null +++ b/lib/erl_interface/src/README.internal @@ -0,0 +1,285 @@ +****************************************************************************** + General +****************************************************************************** + +There are two different interfaces, the old 'erl_interface' and 'ei'. +The old interface is to depend on the new one, not the other way arount. + +Erl_interface should be "thread safe", i.e. you should be able to +handle connections, convert data etc from different threads. + +Ei should be "reentrant" or "async safe", i.e. no locks should be set +so that if an ei function is called inside an signal handler there +could be a deadlock. + +VxWorks call the operating processes "tasks". These are to be handled the +same way as Unix threads, i.e. there can only be one C node for all tasks +using the old interface. + +Try to keep the documented functions, variables and symbols in sync +between + + * Documentation + + * ei.h and erl_interface.h + + * prog/ei_fake_prog.c and prog/erl_fake_prog.c + +From time to time do a + + % (cd src; gmake check) + +(FIXME this check should be rewritten to a test case) + + +****************************************************************************** + Directories +****************************************************************************** + + * src/aux/ + + Support files for configure described in the next section + + * src/legacy/ + + Old erl_interface stuff FIXME what about thread support etc....? + + * src/connect/ + + Create nodes, connections, communication with the other node etc + + * src/decode/ + + Simple decode functions + + * src/encode/ + + Simple encode functions + + * src/epmd/ + + Handle communication with epmd + + * src/registry/ + + Key/value database with optional mnesia back up + + * src/misc/ + + The rest of the library + + * src/prog/ + + erl_call and some test programs for compiling and linking + + * src/not_used/ + + Strange, some files are not used.... + + +****************************************************************************** + Configuration support files +****************************************************************************** + +The build uses GNU configure and libtool. The libtool and autoconf +package don't need to be installed to configure and build the +sources. But in "maintainer mode" you need them to update some files +in the source distribution. + + * configure.in + + Used in maintainer mode together with "aclocal.m4" to create + "configure". "configure.in" is hand written and only need to + be updated when you change the sources to use new header files + or C compiler features. You may get some hints about what to + update using a recent autoconf package and do + + % cd erl_inteface + % autoscan src + + The result to compare with the current "configure.in" will be + stored in "src/configure.scan". + + * aclocal.m4 + + This file contains macros generated by ??? appended + with the content of "libtool.m4" in the installed libtool + package. (FIXME don't know when this is to be updated and + why it contains so much). + + * src/aux/config.guess + * src/aux/config.sub + + Used by "configure" to form the subdirectory name + "cpu-vendor-os". + + * src/aux/install-sh* + + Used if no other BSD compatible install script is found. + + * src/aux/config.h.in + + Used by "configure" as a template for the resulting + "src/config.h". The file "config.h.in" should be + updated when "configure.in" is updated because the + new macros used in your source and this is the file + where they are listed. You can find out what to update + using + + % autoheader + + * ltmain.sh + + This is XXX (FIXME what?) + +The base for the configure.in script was created with 'autoscan'. +The base for the config.h.in file was created with 'autoheader'. + + +****************************************************************************** + Writing source +****************************************************************************** + +C files in "registry" are considered users of 'ei' and should not +include "eidef.h" or "config.h", only "ei.h". + +C files in "prog" could include "config.h" directly. + +Other C files should include "eidef.h" as the first line of +source. "eidef.h" contains some common constants and macros and +also includes config.h. + +In general avoid including other header files from header files. +The exception is to make the protoypes complete to the user of +this library, i.e. to include to defined FILE or +to include "ei_x_encode" to define the type ei_x_buff. + +The function ei_decode_term() (FIXME encode_term?) work on ETERM, +i.e. it converts between the old erl_interface format and ei. +Because of this it is really part of the erl_interface library, +not the ei library. + +Use uint8, uint16, uint32, int8, int16, and int32 for types +where size matters ;-) Use uint8 for buffers where we construct +messages. + +NOTE!!!! Sending a "char" to macros like isupper(), isalpha() where +the character is > 127 will cause serios problems on some +machines/OS. The reason is that + + 'char' may be unsigned, i.e. the Swedish char 'ä' will + as a number be negativ. + + The implementation of isupper() and others will on some + machines use an array that is indexed with the incoming + character code. The Swedish 'ä' will then create an access + on memory outside the array! + +This may give a random value as a result or a segmentation +violation error. + + +****************************************************************************** + Global variables +****************************************************************************** + +There are two reasons we avoid global variables: + + - It is much easier to support threads without them + + - On operating systems like VxWorks the global variable is global + to all operating system processes. + +There are a few global variables that are ok + + ei_x_extra This is set to 100 in "ei_x_encode.c" but can be + changed for debugging the memory allocation. + + ei_trace_distribution Enable verbose tracing on stderr. + + errno In the non threaded version of the lib this + is a global variable. + + __erl_errno This is a global handled by "ei_pthreads.c" + +You can check for globals using something like + + % nm -g ei_fake_prog | fgrep OBJT + +Global variables but with local scope + + erl_if_ec Global state, is ok + + +****************************************************************************** + The "long long" story +****************************************************************************** + +There are some functions in the 'ei' library that uses the GCC and +VC++ "long long" type. Unfortunately this can lead to some trouble. + +When user code is linked with the "libei.a" the linker will extract +all objects files needed for resolving all symbol referenses +found. This means that you want to follow the rule that + + * To reduce executable code size we use resonably small C source + files. One C file is one object file. + + * We try to avoid unessesary dependency. For example currently almost all + ei_x_encode*() functions are in the same object file. Because they all + use the corresponding ei_encode*() function this means using one ei_x + function we will link in "ei_x_encode.o" object file but also all the + "ei_encode*.o" object files even if they are not used. + +But the above is not the real trouble, memory and disk is cheap these +days. The real trouble is if we compile the 'ei' library using one +compiler, usually GNU cc, and link with another linker than GNU ld or +miss some runtime libraries that the GNU cc generated object files +assume is on the target. For example currently on Solaris some "long +long" operations will create a dependency to a "hidden" library +"libgcc.a". For example in a library not released got references to +"libgcc.a" '__ashldi3' + + % nm -A libei.a | grep '__ashldi3' + libei.a[decode_longlong.o]: [6] | 0| 0|NOTY |GLOB |0 |UNDEF |__ashldi3 + libei.a[decode_ulonglong.o]: [5] | 0| 0|NOTY |GLOB |0 |UNDEF |__ashldi3 + +We can accept that a dependecy is created for code linked with +"libei.a" that actually use 'ei' long long functions. But if we +arrange the 'ei' source badly using a non "long long" functions from +'ei' will still link in an object file that need "libgcc.a". One +example is that in plain R9C the ei_x_encode_longlong() function is +located in the file "ei_x_encode.c". So if any "long long" ei_x +function is used we have an unessesary dependency on +"ei_encode_longlong.o" and then need to link with GNU ld on with the +user code or explicitely link with "libgcc.a". The situation can be +visible in in plain R9C using + + % nm -A erl_interface-3.4/lib/libei.a | \ + grep 'longlong' | fgrep -v 'longlong.o' + +As an possibly alternative to the current solution we may include the +object files inside the "libgcc.a" archive in the "libei.a" archive. +The "libgcc.a" that is assumed to be used when linking can be found +using + + % gcc -print-libgcc-file-name + +Some links about problems and solutions using "libgcc.a" + + http://www.gnu.org/software/gcc/gcc-3.0/libgcc.html + http://www.gnu.org/software/libc/FAQ.html + +The license for "libgcc.a" is a bit special and not located on the +official sites. You have to look in the source file for the "libgcc.a" +you use. The file is named "libgcc.c". If you don't know what gcc that +was used for the build of for example 'r9c' you can use + + % otp_build_env -o r9c | perl -ne '/(gcc-[\d\.]+)/ and print "$1\n"' + +Then to view the lincense do + + % less `find /usr/local/share/src/gcc-REL/ -name "libgcc*.c"` + + +********************************* EOF **************************************** diff --git a/lib/erl_interface/src/auxdir/config.guess b/lib/erl_interface/src/auxdir/config.guess new file mode 120000 index 0000000000..fefabd7dd0 --- /dev/null +++ b/lib/erl_interface/src/auxdir/config.guess @@ -0,0 +1 @@ +../../../../erts/autoconf/config.guess \ No newline at end of file diff --git a/lib/erl_interface/src/auxdir/config.h.in b/lib/erl_interface/src/auxdir/config.h.in new file mode 100644 index 0000000000..523c766993 --- /dev/null +++ b/lib/erl_interface/src/auxdir/config.h.in @@ -0,0 +1,277 @@ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. + */ +#undef CRAY_STACKSEG_END + +/* Define to 1 if using `alloca.c'. */ +#undef C_ALLOCA + +/* Define to 1 if you have `alloca', as a function or macro. */ +#undef HAVE_ALLOCA + +/* Define to 1 if you have and it should be used (not on Ultrix). + */ +#undef HAVE_ALLOCA_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ARPA_INET_H + +/* Define to 1 if you have the `clock_gettime' function. */ +#undef HAVE_CLOCK_GETTIME + +/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you + don't. */ +#undef HAVE_DECL_STRERROR_R + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +#undef HAVE_DOPRNT + +/* Define to 1 if you have the `dup2' function. */ +#undef HAVE_DUP2 + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the `fork' function. */ +#undef HAVE_FORK + +/* Define to 1 if you have the `gethostbyaddr' function. */ +#undef HAVE_GETHOSTBYADDR + +/* Define to 1 if you have the `gethostbyname' function. */ +#undef HAVE_GETHOSTBYNAME + +/* Define to 1 if you have the `gethostbyname_r' function. */ +#undef HAVE_GETHOSTBYNAME_R + +/* Define to 1 if you have the `gethostname' function. */ +#undef HAVE_GETHOSTNAME + +/* Define to 1 if you have the `gethrtime' function. */ +#undef HAVE_GETHRTIME + +/* Define to 1 if you have the `gettimeofday' function. */ +#undef HAVE_GETTIMEOFDAY + +/* Define to 1 if you have the header file. */ +#undef HAVE_GMP_H + +/* Define to 1 if you have the `inet_ntoa' function. */ +#undef HAVE_INET_NTOA + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `gmp' library (-lgmp). */ +#undef HAVE_LIBGMP + +/* Define to 1 if you have the `m' library (-lm). */ +#undef HAVE_LIBM + +/* Define to 1 if you have the `nsl' library (-lnsl). */ +#undef HAVE_LIBNSL + +/* Define to 1 if you have the `resolv' library (-lresolv). */ +#undef HAVE_LIBRESOLV + +/* Define to 1 if you have the `socket' library (-lsocket). */ +#undef HAVE_LIBSOCKET + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#undef HAVE_MALLOC + +/* Define to 1 if you have the header file. */ +#undef HAVE_MALLOC_H + +/* Define to 1 if you have the `memchr' function. */ +#undef HAVE_MEMCHR + +/* Define to 1 if you have the `memmove' function. */ +#undef HAVE_MEMMOVE + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#undef HAVE_MEMSET + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETDB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MIT_PTHREAD_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_PTHREAD_H + +/* Define to 1 if your system has a GNU libc compatible `realloc' function, + and to 0 otherwise. */ +#undef HAVE_REALLOC + +/* Define if you have the res_gethostbyname function. */ +#undef HAVE_RES_GETHOSTBYNAME + +/* Define to 1 if you have the `select' function. */ +#undef HAVE_SELECT + +/* Define to 1 if you have the `socket' function. */ +#undef HAVE_SOCKET + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDDEF_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strchr' function. */ +#undef HAVE_STRCHR + +/* Define to 1 if you have the `strerror' function. */ +#undef HAVE_STRERROR + +/* Define to 1 if you have the `strerror_r' function. */ +#undef HAVE_STRERROR_R + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strrchr' function. */ +#undef HAVE_STRRCHR + +/* Define to 1 if you have the `strstr' function. */ +#undef HAVE_STRSTR + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define to 1 if you have the `uname' function. */ +#undef HAVE_UNAME + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `vfork' function. */ +#undef HAVE_VFORK + +/* Define to 1 if you have the header file. */ +#undef HAVE_VFORK_H + +/* Define to 1 if you have the `vprintf' function. */ +#undef HAVE_VPRINTF + +/* Define to 1 if `fork' works. */ +#undef HAVE_WORKING_FORK + +/* Define to 1 if `vfork' works. */ +#undef HAVE_WORKING_VFORK + +/* Define if you have the writev function. */ +#undef HAVE_WRITEV + +/* Define if you have the socklen_t datatype */ +#undef HAVE_SOCKLEN_T + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define as the return type of signal handlers (`int' or `void'). */ +#undef RETSIGTYPE + +/* Define to the type of arg 1 for `select'. */ +#undef SELECT_TYPE_ARG1 + +/* Define to the type of args 2, 3 and 4 for `select'. */ +#undef SELECT_TYPE_ARG234 + +/* Define to the type of arg 5 for `select'. */ +#undef SELECT_TYPE_ARG5 + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +#undef STACK_DIRECTION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to 1 if strerror_r returns char *. */ +#undef STRERROR_R_CHAR_P + +/* Define to 1 if you can safely include both and . */ +#undef TIME_WITH_SYS_TIME + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `int' if doesn't define. */ +#undef gid_t + +/* Define to rpl_malloc if the replacement function should be used. */ +#undef malloc + +/* Define to `int' if does not define. */ +#undef pid_t + +/* Define to rpl_realloc if the replacement function should be used. */ +#undef realloc + +/* Define to `unsigned' if does not define. */ +#undef size_t + +/* Define to `int' if doesn't define. */ +#undef uid_t + +/* Define as `fork' if `vfork' does not work. */ +#undef vfork + +/* Define to empty if the keyword `volatile' does not work. Warning: valid + code using `volatile' can become incorrect without. Disable with care. */ +#undef volatile diff --git a/lib/erl_interface/src/auxdir/config.sub b/lib/erl_interface/src/auxdir/config.sub new file mode 120000 index 0000000000..90979e8924 --- /dev/null +++ b/lib/erl_interface/src/auxdir/config.sub @@ -0,0 +1 @@ +../../../../erts/autoconf/config.sub \ No newline at end of file diff --git a/lib/erl_interface/src/auxdir/install-sh b/lib/erl_interface/src/auxdir/install-sh new file mode 120000 index 0000000000..9422c370df --- /dev/null +++ b/lib/erl_interface/src/auxdir/install-sh @@ -0,0 +1 @@ +../../../../erts/autoconf/install-sh \ No newline at end of file diff --git a/lib/erl_interface/src/connect/ei_connect.c b/lib/erl_interface/src/connect/ei_connect.c new file mode 100644 index 0000000000..9ac5a93c5a --- /dev/null +++ b/lib/erl_interface/src/connect/ei_connect.c @@ -0,0 +1,1738 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2000-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Purpose: Connect to any node at any host. (EI version) + */ + +#include "eidef.h" + +#include +#include +#include + +#ifdef __WIN32__ +#include +#include +#include + +#elif VXWORKS +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define getpid() taskIdSelf() + +#else /* some other unix */ +#include +#include +#include + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#include +#include +#include +#include +#include +#include /* for gen_challenge (NEED FIX?) */ +#include +#endif + +/* common includes */ +#include +#include +#include +#include +#include + +#include "eiext.h" +#include "ei_portio.h" +#include "ei_internal.h" +#include "ei_connect_int.h" +#include "ei_locking.h" +#include "eisend.h" +#include "eirecv.h" +#include "eimd5.h" +#include "putget.h" +#include "ei_resolve.h" +#include "ei_epmd.h" +#include "ei_internal.h" + +int ei_tracelevel = 0; + +#define COOKIE_FILE "/.erlang.cookie" +#define EI_MAX_HOME_PATH 1024 + +/* FIXME why not macro? */ +static char *null_cookie = ""; + +static int get_cookie(char *buf, int len); +static int get_home(char *buf, int size); + +/* forwards */ +static unsigned gen_challenge(void); +static void gen_digest(unsigned challenge, char cookie[], + unsigned char digest[16]); +static int send_status(int fd, char *status, unsigned ms); +static int recv_status(int fd, unsigned ms); +static int send_challenge(int fd, char *nodename, + unsigned challenge, unsigned version, unsigned ms); +static int recv_challenge(int fd, unsigned *challenge, + unsigned *version, + unsigned *flags, ErlConnect *namebuf, unsigned ms); +static int send_challenge_reply(int fd, unsigned char digest[16], + unsigned challenge, unsigned ms); +static int recv_challenge_reply(int fd, + unsigned our_challenge, + char cookie[], + unsigned *her_challenge, unsigned ms); +static int send_challenge_ack(int fd, unsigned char digest[16], unsigned ms); +static int recv_challenge_ack(int fd, + unsigned our_challenge, + char cookie[], unsigned ms); +static int send_name(int fd, char *nodename, + unsigned version, unsigned ms); + +/* Common for both handshake types */ +static int recv_name(int fd, + unsigned *version, + unsigned *flags, ErlConnect *namebuf, unsigned ms); + + +/*************************************************************************** + * + * For each file descriptor returned from ei_connect() we save information + * about distribution protocol version, node information for this node + * and the cookie. + * + ***************************************************************************/ + +typedef struct ei_socket_info_s { + int socket; + int dist_version; + ei_cnode cnode; /* A copy, not a pointer. We don't know when freed */ + char cookie[EI_MAX_COOKIE_SIZE+1]; +} ei_socket_info; + +int ei_n_sockets = 0, ei_sz_sockets = 0; +ei_socket_info *ei_sockets = NULL; +#ifdef _REENTRANT +ei_mutex_t* ei_sockets_lock = NULL; +#endif /* _REENTRANT */ + + +/*************************************************************************** + * + * XXX + * + ***************************************************************************/ + +static int put_ei_socket_info(int fd, int dist_version, char* cookie, ei_cnode *ec) +{ + int i; + +#ifdef _REENTRANT + ei_mutex_lock(ei_sockets_lock, 0); +#endif /* _REENTRANT */ + for (i = 0; i < ei_n_sockets; ++i) { + if (ei_sockets[i].socket == fd) { + if (dist_version == -1) { + memmove(&ei_sockets[i], &ei_sockets[i+1], + sizeof(ei_sockets[0])*(ei_n_sockets-i-1)); + } else { + ei_sockets[i].dist_version = dist_version; + /* Copy the content, see ei_socket_info */ + ei_sockets[i].cnode = *ec; + strcpy(ei_sockets[i].cookie, cookie); + } +#ifdef _REENTRANT + ei_mutex_unlock(ei_sockets_lock); +#endif /* _REENTRANT */ + return 0; + } + } + if (ei_n_sockets == ei_sz_sockets) { + ei_sz_sockets += 5; + ei_sockets = realloc(ei_sockets, + sizeof(ei_sockets[0])*ei_sz_sockets); + if (ei_sockets == NULL) { + ei_sz_sockets = ei_n_sockets = 0; +#ifdef _REENTRANT + ei_mutex_unlock(ei_sockets_lock); +#endif /* _REENTRANT */ + return -1; + } + ei_sockets[ei_n_sockets].socket = fd; + ei_sockets[ei_n_sockets].dist_version = dist_version; + ei_sockets[i].cnode = *ec; + strcpy(ei_sockets[ei_n_sockets].cookie, cookie); + ++ei_n_sockets; + } +#ifdef _REENTRANT + ei_mutex_unlock(ei_sockets_lock); +#endif /* _REENTRANT */ + return 0; +} + +#if 0 +/* FIXME not used ?! */ +static int remove_ei_socket_info(int fd, int dist_version, char* cookie) +{ + return put_ei_socket_info(fd, -1, NULL); +} +#endif + +static ei_socket_info* get_ei_socket_info(int fd) +{ + int i; +#ifdef _REENTRANT + ei_mutex_lock(ei_sockets_lock, 0); +#endif /* _REENTRANT */ + for (i = 0; i < ei_n_sockets; ++i) + if (ei_sockets[i].socket == fd) { + /*fprintf("get_ei_socket_info %d %d \"%s\"\n", + fd, ei_sockets[i].dist_version, ei_sockets[i].cookie);*/ +#ifdef _REENTRANT + ei_mutex_unlock(ei_sockets_lock); +#endif /* _REENTRANT */ + return &ei_sockets[i]; + } +#ifdef _REENTRANT + ei_mutex_unlock(ei_sockets_lock); +#endif /* _REENTRANT */ + return NULL; +} + +ei_cnode *ei_fd_to_cnode(int fd) +{ + ei_socket_info *sockinfo = get_ei_socket_info(fd); + if (sockinfo == NULL) return NULL; + return &sockinfo->cnode; +} + +/*************************************************************************** + * XXXX + ***************************************************************************/ + +int ei_distversion(int fd) +{ + ei_socket_info* e = get_ei_socket_info(fd); + if (e == NULL) + return -1; + else + return e->dist_version; +} + +static const char* ei_cookie(int fd) +{ + ei_socket_info* e = get_ei_socket_info(fd); + if (e == NULL) + return NULL; + else + return e->cookie; +} + +const char *ei_thisnodename(const ei_cnode* ec) +{ + return ec->thisnodename; +} + +const char *ei_thishostname(const ei_cnode* ec) +{ + return ec->thishostname; +} + +const char *ei_thisalivename(const ei_cnode* ec) +{ + return ec->thisalivename; +} + +short ei_thiscreation(const ei_cnode* ec) +{ + return ec->creation; +} + +/* FIXME: this function is not an api, why not? */ +const char *ei_thiscookie(const ei_cnode* ec) +{ + return (const char *)ec->ei_connect_cookie; +} + +erlang_pid *ei_self(ei_cnode* ec) +{ + return &ec->self; +} + +/* two internal functions that will let us support different cookies +* (to be able to connect to other nodes that don't have the same +* cookie as each other or us) +*/ +const char *ei_getfdcookie(int fd) +{ + const char* r = ei_cookie(fd); + if (r == NULL) r = ""; + return r; +} + +/* call with cookie to set value to use on descriptor fd, +* or specify NULL to use default +*/ +/* FIXME why defined but not used? */ +#if 0 +static int ei_setfdcookie(ei_cnode* ec, int fd, char *cookie) +{ + int dist_version = ei_distversion(fd); + + if (cookie == NULL) + cookie = ec->ei_connect_cookie; + return put_ei_socket_info(fd, dist_version, cookie); +} +#endif + +static int get_int32(unsigned char *s) +{ + return ((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | (s[3] )); +} + + +#ifdef __WIN32__ +void win32_error(char *buf, int buflen) +{ + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, + 0, /* n/a */ + WSAGetLastError(), /* error code */ + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* language */ + buf, + buflen, + NULL); + return; +} + +static int initWinSock(void) +{ + WORD wVersionRequested; + WSADATA wsaData; + int i; + /* FIXME problem for threaded ? */ + static int initialized = 0; + + wVersionRequested = MAKEWORD(1, 1); + if (!initialized) { + initialized = 1; + /* FIXME not terminate, just a message?! */ + if ((i = WSAStartup(wVersionRequested, &wsaData))) { + EI_TRACE_ERR1("ei_connect_init", + "ERROR: can't initialize windows sockets: %d",i); + return 0; + } + + if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { + EI_TRACE_ERR0("initWinSock","ERROR: this version of windows " + "sockets not supported"); + WSACleanup(); + return 0; + } + } + return 1; +} +#endif + +/* +* Perhaps run this routine instead of ei_connect_init/2 ? +* Initailize by setting: +* thishostname, thisalivename, thisnodename and thisipaddr +*/ +int ei_connect_xinit(ei_cnode* ec, const char *thishostname, + const char *thisalivename, const char *thisnodename, + Erl_IpAddr thisipaddr, const char *cookie, + const short creation) +{ + char *dbglevel; + +/* FIXME this code was enabled for 'erl'_connect_xinit(), why not here? */ +#if 0 +#ifdef __WIN32__ + if (!initWinSock()) { + EI_TRACE_ERR0("ei_connect_xinit","can't initiate winsock"); + return ERL_ERROR; + } +#endif +#endif + +#ifdef _REENTRANT + if (ei_sockets_lock == NULL) { + ei_sockets_lock = ei_mutex_create(); + } +#endif /* _REENTRANT */ + + ec->creation = creation; + + if (cookie) { + if (strlen(cookie) >= sizeof(ec->ei_connect_cookie)) { + EI_TRACE_ERR0("ei_connect_xinit", + "ERROR: Cookie size too large"); + return ERL_ERROR; + } else { + strcpy(ec->ei_connect_cookie, cookie); + } + } else if (!get_cookie(ec->ei_connect_cookie, sizeof(ec->ei_connect_cookie))) { + return ERL_ERROR; + } + + if (strlen(thishostname) >= sizeof(ec->thishostname)) { + EI_TRACE_ERR0("ei_connect_xinit","ERROR: Thishostname too long"); + return ERL_ERROR; + } + strcpy(ec->thishostname, thishostname); + + if (strlen(thisalivename) >= sizeof(ec->thisalivename)) { + EI_TRACE_ERR0("ei_connect_init","Thisalivename too long"); + return ERL_ERROR; + } + + strcpy(ec->thisalivename, thisalivename); + + if (strlen(thisnodename) >= sizeof(ec->thisnodename)) { + EI_TRACE_ERR0("ei_connect_init","Thisnodename too long"); + return ERL_ERROR; + } + strcpy(ec->thisnodename, thisnodename); + +/* FIXME right now this_ipaddr is never used */ +/* memmove(&ec->this_ipaddr, thisipaddr, sizeof(ec->this_ipaddr)); */ + + strcpy(ec->self.node,thisnodename); + ec->self.num = 0; + ec->self.serial = 0; + ec->self.creation = creation; + + if ((dbglevel = getenv("EI_TRACELEVEL")) != NULL || + (dbglevel = getenv("ERL_DEBUG_DIST")) != NULL) + ei_tracelevel = atoi(dbglevel); + + return 0; +} + + +/* +* Initialize by set: thishostname, thisalivename, +* thisnodename and thisipaddr. At success return 0, +* otherwise return -1. +*/ +int ei_connect_init(ei_cnode* ec, const char* this_node_name, + const char *cookie, short creation) +{ + struct hostent *hp; + char thishostname[EI_MAXHOSTNAMELEN+1]; + char thisnodename[MAXNODELEN+1]; + char thisalivename[EI_MAXALIVELEN+1]; + +#ifdef __WIN32__ + if (!initWinSock()) { + EI_TRACE_ERR0("ei_connect_xinit","can't initiate winsock"); + return ERL_ERROR; + } +#endif /* win32 */ +#ifdef _REENTRANT + if (ei_sockets_lock == NULL) { + ei_sockets_lock = ei_mutex_create(); + } +#endif /* _REENTRANT */ + + if (gethostname(thishostname, EI_MAXHOSTNAMELEN) == -1) { +#ifdef __WIN32__ + EI_TRACE_ERR1("ei_connect_init","Failed to get host name: %d", + WSAGetLastError()); +#else + EI_TRACE_ERR1("ei_connect_init","Failed to get host name: %d", errno); +#endif /* win32 */ + return ERL_ERROR; + } + + if (this_node_name == NULL) + sprintf(thisalivename, "c%d", (int) getpid()); + else + strcpy(thisalivename, this_node_name); + + if ((hp = ei_gethostbyname(thishostname)) == 0) { + /* Looking up IP given hostname fails. We must be on a standalone + host so let's use loopback for communication instead. */ + if ((hp = ei_gethostbyname("localhost")) == 0) { +#ifdef __WIN32__ + char reason[1024]; + + win32_error(reason,sizeof(reason)); + EI_TRACE_ERR2("ei_connect_init", + "Can't get ip address for host %s: %s", + thishostname, reason); +#else + EI_TRACE_ERR2("ei_connect_init", + "Can't get ip address for host %s: %d", + thishostname, h_errno); +#endif /* win32 */ + return ERL_ERROR; + } + } + { + char* ct; + if (strcmp(hp->h_name, "localhost") == 0) { + /* We use a short node name */ + if ((ct = strchr(thishostname, '.')) != NULL) *ct = '\0'; + sprintf(thisnodename, "%s@%s", this_node_name, thishostname); + } else { + /* We use a short node name */ + if ((ct = strchr(hp->h_name, '.')) != NULL) *ct = '\0'; + strcpy(thishostname, hp->h_name); + sprintf(thisnodename, "%s@%s", this_node_name, hp->h_name); + } + } + return ei_connect_xinit(ec, thishostname, thisalivename, thisnodename, + (struct in_addr *)*hp->h_addr_list, cookie, creation); +} + + +/* connects to port at ip-address ip_addr +* and returns fd to socket +* port has to be in host byte order +*/ +static int cnct(uint16 port, struct in_addr *ip_addr, int addr_len, unsigned ms) +{ + int s, res; + struct sockaddr_in iserv_addr; + + if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + erl_errno = errno; + return ERL_ERROR; + } + + memset((char*)&iserv_addr, 0, sizeof(struct sockaddr_in)); + memcpy((char*)&iserv_addr.sin_addr, (char*)ip_addr, addr_len); + iserv_addr.sin_family = AF_INET; + iserv_addr.sin_port = htons(port); + + if ((res = ei_connect_t(s, (struct sockaddr*)&iserv_addr, + sizeof(iserv_addr),ms)) < 0) { + erl_errno = (res == -2) ? ETIMEDOUT : EIO; + closesocket(s); + return ERL_ERROR; + } + + return s; +} /* cnct */ + + /* + * Set up a connection to a given Node, and + * interchange hand shake messages with it. + * Returns a valid file descriptor at success, + * otherwise a negative error code. +*/ +int ei_connect_tmo(ei_cnode* ec, char *nodename, unsigned ms) +{ + char *hostname, alivename[BUFSIZ]; + struct hostent *hp; +#if !defined (__WIN32__) + /* these are needed for the call to gethostbyname_r */ + struct hostent host; + char buffer[1024]; + int ei_h_errno; +#endif /* !win32 */ + + /* extract the host and alive parts from nodename */ + if (!(hostname = strchr(nodename,'@'))) { + EI_TRACE_ERR0("ei_connect","Node name has no @ in name"); + return ERL_ERROR; + } else { + strncpy(alivename, nodename, hostname - nodename); + alivename[hostname - nodename] = 0x0; + hostname++; + } + +#ifndef __WIN32__ + hp = ei_gethostbyname_r(hostname,&host,buffer,1024,&ei_h_errno); + if (hp == NULL) { + char thishostname[EI_MAXHOSTNAMELEN+1]; + if (gethostname(thishostname,EI_MAXHOSTNAMELEN) < 0) { + EI_TRACE_ERR0("ei_connect_tmo", + "Failed to get name of this host"); + erl_errno = EHOSTUNREACH; + return ERL_ERROR; + } else { + char *ct; + /* We use a short node name */ + if ((ct = strchr(thishostname, '.')) != NULL) *ct = '\0'; + } + if (strcmp(hostname,thishostname) == 0) + /* Both nodes on same standalone host, use loopback */ + hp = ei_gethostbyname_r("localhost",&host,buffer,1024,&ei_h_errno); + if (hp == NULL) { + EI_TRACE_ERR2("ei_connect", + "Can't find host for %s: %d\n",nodename,ei_h_errno); + erl_errno = EHOSTUNREACH; + return ERL_ERROR; + } + } +#else /* __WIN32__ */ + if ((hp = ei_gethostbyname(hostname)) == NULL) { + char thishostname[EI_MAXHOSTNAMELEN+1]; + if (gethostname(thishostname,EI_MAXHOSTNAMELEN) < 0) { + EI_TRACE_ERR1("ei_connect_tmo", + "Failed to get name of this host: %d", + WSAGetLastError()); + erl_errno = EHOSTUNREACH; + return ERL_ERROR; + } else { + char *ct; + /* We use a short node name */ + if ((ct = strchr(thishostname, '.')) != NULL) *ct = '\0'; + } + if (strcmp(hostname,thishostname) == 0) + /* Both nodes on same standalone host, use loopback */ + hp = ei_gethostbyname("localhost"); + if (hp == NULL) { + char reason[1024]; + win32_error(reason,sizeof(reason)); + EI_TRACE_ERR2("ei_connect", + "Can't find host for %s: %s",nodename,reason); + erl_errno = EHOSTUNREACH; + return ERL_ERROR; + } + } +#endif /* win32 */ + return ei_xconnect_tmo(ec, (Erl_IpAddr) *hp->h_addr_list, alivename, ms); +} /* ei_connect */ + +int ei_connect(ei_cnode* ec, char *nodename) +{ + return ei_connect_tmo(ec, nodename, 0); +} + + + /* ip_addr is now in network byte order + * + * first we have to get hold of the portnumber to + * the node through epmd at that host + * +*/ +int ei_xconnect_tmo(ei_cnode* ec, Erl_IpAddr adr, char *alivename, unsigned ms) +{ + struct in_addr *ip_addr=(struct in_addr *) adr; + int rport = 0; /*uint16 rport = 0;*/ + int sockd; + int one = 1; + int dist = 0; + ErlConnect her_name; + unsigned her_flags, her_version; + + erl_errno = EIO; /* Default error code */ + + EI_TRACE_CONN1("ei_xconnect","-> CONNECT attempt to connect to %s", + alivename); + + if ((rport = ei_epmd_port_tmo(ip_addr,alivename,&dist, ms)) < 0) { + EI_TRACE_ERR0("ei_xconnect","-> CONNECT can't get remote port"); + /* ei_epmd_port_tmo() has set erl_errno */ + return ERL_NO_PORT; + } + + /* we now have port number to enode, try to connect */ + if((sockd = cnct((uint16)rport, ip_addr, sizeof(struct in_addr),ms)) < 0) { + EI_TRACE_ERR0("ei_xconnect","-> CONNECT socket connect failed"); + /* cnct() has set erl_errno */ + return ERL_CONNECT_FAIL; + } + + EI_TRACE_CONN0("ei_xconnect","-> CONNECT connected to remote"); + + /* FIXME why connect before checking 'dist' output from ei_epmd_port() ?! */ + if (dist <= 4) { + EI_TRACE_ERR0("ei_xconnect","-> CONNECT remote version not compatible"); + goto error; + } + else { + unsigned our_challenge, her_challenge; + unsigned char our_digest[16]; + + if (send_name(sockd, ec->thisnodename, (unsigned) dist, ms)) + goto error; + if (recv_status(sockd, ms)) + goto error; + if (recv_challenge(sockd, &her_challenge, &her_version, + &her_flags, &her_name, ms)) + goto error; + our_challenge = gen_challenge(); + gen_digest(her_challenge, ec->ei_connect_cookie, our_digest); + if (send_challenge_reply(sockd, our_digest, our_challenge, ms)) + goto error; + if (recv_challenge_ack(sockd, our_challenge, + ec->ei_connect_cookie, ms)) + goto error; + put_ei_socket_info(sockd, dist, null_cookie, ec); /* FIXME check == 0 */ + } + + setsockopt(sockd, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one)); + setsockopt(sockd, SOL_SOCKET, SO_KEEPALIVE, (char *)&one, sizeof(one)); + + EI_TRACE_CONN1("ei_xconnect","-> CONNECT (ok) remote = %s",alivename); + + erl_errno = 0; + return sockd; + +error: + EI_TRACE_ERR0("ei_xconnect","-> CONNECT failed"); + closesocket(sockd); + return ERL_ERROR; +} /* ei_xconnect */ + +int ei_xconnect(ei_cnode* ec, Erl_IpAddr adr, char *alivename) +{ + return ei_xconnect_tmo(ec, adr, alivename, 0); +} + + + /* + * For symmetry reasons +*/ +#if 0 +int ei_close_connection(int fd) +{ + return closesocket(fd); +} /* ei_close_connection */ +#endif + + /* + * Accept and initiate a connection from an other + * Erlang node. Return a file descriptor at success, + * otherwise -1; +*/ +int ei_accept(ei_cnode* ec, int lfd, ErlConnect *conp) +{ + return ei_accept_tmo(ec, lfd, conp, 0); +} + +int ei_accept_tmo(ei_cnode* ec, int lfd, ErlConnect *conp, unsigned ms) +{ + int fd; + struct sockaddr_in cli_addr; + int cli_addr_len=sizeof(struct sockaddr_in); + unsigned her_version, her_flags; + ErlConnect her_name; + + erl_errno = EIO; /* Default error code */ + + EI_TRACE_CONN0("ei_accept","<- ACCEPT waiting for connection"); + + if ((fd = ei_accept_t(lfd, (struct sockaddr*) &cli_addr, + &cli_addr_len, ms )) < 0) { + EI_TRACE_ERR0("ei_accept","<- ACCEPT socket accept failed"); + erl_errno = (fd == -2) ? ETIMEDOUT : EIO; + goto error; + } + + EI_TRACE_CONN0("ei_accept","<- ACCEPT connected to remote"); + + if (recv_name(fd, &her_version, &her_flags, &her_name, ms)) { + EI_TRACE_ERR0("ei_accept","<- ACCEPT initial ident failed"); + goto error; + } + + if (her_version <= 4) { + EI_TRACE_ERR0("ei_accept","<- ACCEPT remote version not compatible"); + goto error; + } + else { + unsigned our_challenge; + unsigned her_challenge; + unsigned char our_digest[16]; + + if (send_status(fd,"ok", ms)) + goto error; + our_challenge = gen_challenge(); + if (send_challenge(fd, ec->thisnodename, + our_challenge, her_version, ms)) + goto error; + if (recv_challenge_reply(fd, our_challenge, + ec->ei_connect_cookie, + &her_challenge, ms)) + goto error; + gen_digest(her_challenge, ec->ei_connect_cookie, our_digest); + if (send_challenge_ack(fd, our_digest, ms)) + goto error; + put_ei_socket_info(fd, her_version, null_cookie, ec); + } + if (conp) + *conp = her_name; + + EI_TRACE_CONN1("ei_accept","<- ACCEPT (ok) remote = %s",her_name.nodename); + + erl_errno = 0; /* No error */ + return fd; + +error: + EI_TRACE_ERR0("ei_accept","<- ACCEPT failed"); + closesocket(fd); + return ERL_ERROR; +} /* ei_accept */ + + +/* Receives a message from an Erlang socket. + * If the message was a TICK it is immediately + * answered. Returns: ERL_ERROR, ERL_TICK or + * the number of bytes read. + */ +int ei_receive_tmo(int fd, unsigned char *bufp, int bufsize, unsigned ms) +{ + int len; + unsigned char fourbyte[4]={0,0,0,0}; + int res; + + if ((res = ei_read_fill_t(fd, (char *) bufp, 4, ms)) != 4) { + erl_errno = (res == -2) ? ETIMEDOUT : EIO; + return ERL_ERROR; + } + + /* Tick handling */ + if ((len = get_int32(bufp)) == ERL_TICK) + { + ei_write_fill_t(fd, (char *) fourbyte, 4, ms); + /* FIXME ok to ignore error or timeout? */ + erl_errno = EAGAIN; + return ERL_TICK; + } + else if (len > bufsize) + { + /* FIXME: We should drain the message. */ + erl_errno = EMSGSIZE; + return ERL_ERROR; + } + else if ((res = ei_read_fill_t(fd, (char *) bufp, len, ms)) != len) + { + erl_errno = (res == -2) ? ETIMEDOUT : EIO; + return ERL_ERROR; + } + + return len; + +} + +int ei_receive(int fd, unsigned char *bufp, int bufsize) +{ + return ei_receive_tmo(fd, bufp, bufsize, 0); +} + +int ei_reg_send_tmo(ei_cnode* ec, int fd, char *server_name, + char* buf, int len, unsigned ms) +{ + erlang_pid *self = ei_self(ec); + self->num = fd; + + /* erl_errno and return code is set by ei_reg_send_encoded_tmo() */ + return ei_send_reg_encoded_tmo(fd, self, server_name, buf, len, ms); +} + + +int ei_reg_send(ei_cnode* ec, int fd, char *server_name, char* buf, int len) +{ + return ei_reg_send_tmo(ec,fd,server_name,buf,len,0); +} + +/* +* Sends an Erlang message to a process at an Erlang node +*/ +int ei_send_tmo(int fd, erlang_pid* to, char* buf, int len, unsigned ms) +{ + /* erl_errno and return code is set by ei_reg_send_encoded_tmo() */ + return ei_send_encoded_tmo(fd, to, buf, len, ms); +} + +int ei_send(int fd, erlang_pid* to, char* buf, int len) +{ + return ei_send_tmo(fd, to, buf, len, 0); +} + + +/* +* Try to receive an Erlang message on a given socket. Returns +* ERL_TICK, ERL_MSG, or ERL_ERROR. Sets `erl_errno' on ERL_ERROR and +* ERL_TICK (to EAGAIN in the latter case). +*/ + +int ei_do_receive_msg(int fd, int staticbuffer_p, + erlang_msg* msg, ei_x_buff* x, unsigned ms) +{ + int msglen; + int i; + + if (!(i=ei_recv_internal(fd, &x->buff, &x->buffsz, msg, &msglen, + staticbuffer_p, ms))) { + erl_errno = EAGAIN; + return ERL_TICK; + } + if (i<0) { + /* erl_errno set by ei_recv_internal() */ + return ERL_ERROR; + } + if (staticbuffer_p && msglen > x->buffsz) + { + erl_errno = EMSGSIZE; + return ERL_ERROR; + } + x->index = x->buffsz; + switch (msg->msgtype) { /* FIXME are these all? */ + case ERL_SEND: + case ERL_REG_SEND: + case ERL_LINK: + case ERL_UNLINK: + case ERL_GROUP_LEADER: + case ERL_EXIT: + case ERL_EXIT2: + case ERL_NODE_LINK: + return ERL_MSG; + + default: + /*if (emsg->to) 'erl'_free_term(emsg->to); + if (emsg->from) 'erl'_free_term(emsg->from); + if (emsg->msg) 'erl'_free_term(emsg->msg); + emsg->to = NULL; + emsg->from = NULL; + emsg->msg = NULL;*/ + + erl_errno = EIO; + return ERL_ERROR; + } +} /* do_receive_msg */ + + +int ei_receive_msg(int fd, erlang_msg* msg, ei_x_buff* x) +{ + return ei_do_receive_msg(fd, 1, msg, x, 0); +} + +int ei_xreceive_msg(int fd, erlang_msg *msg, ei_x_buff *x) +{ + return ei_do_receive_msg(fd, 0, msg, x, 0); +} + +int ei_receive_msg_tmo(int fd, erlang_msg* msg, ei_x_buff* x, unsigned ms) +{ + return ei_do_receive_msg(fd, 1, msg, x, ms); +} + +int ei_xreceive_msg_tmo(int fd, erlang_msg *msg, ei_x_buff *x, unsigned ms) +{ + return ei_do_receive_msg(fd, 0, msg, x, ms); +} + +/* +* The RPC consists of two parts, send and receive. +* Here is the send part ! +* { PidFrom, { call, Mod, Fun, Args, user }} +*/ +/* +* Now returns non-negative number for success, negative for failure. +*/ +int ei_rpc_to(ei_cnode *ec, int fd, char *mod, char *fun, + const char *buf, int len) +{ + + ei_x_buff x; + erlang_pid *self = ei_self(ec); + self->num = fd; + + /* encode header */ + ei_x_new_with_version(&x); + ei_x_encode_tuple_header(&x, 2); /* A */ + + self->num = fd; + ei_x_encode_pid(&x, self); /* A 1 */ + + ei_x_encode_tuple_header(&x, 5); /* B A 2 */ + ei_x_encode_atom(&x, "call"); /* B 1 */ + ei_x_encode_atom(&x, mod); /* B 2 */ + ei_x_encode_atom(&x, fun); /* B 3 */ + ei_x_append_buf(&x, buf, len); /* B 4 */ + ei_x_encode_atom(&x, "user"); /* B 5 */ + + /* ei_x_encode_atom(&x,"user"); */ + ei_send_reg_encoded(fd, self, "rex", x.buff, x.index); + ei_x_free(&x); + + return 0; +} /* rpc_to */ + + /* + * And here is the rpc receiving part. A negative + * timeout means 'infinity'. Returns either of: ERL_MSG, + * ERL_TICK, ERL_ERROR or ERL_TIMEOUT. +*/ +int ei_rpc_from(ei_cnode *ec, int fd, int timeout, erlang_msg *msg, + ei_x_buff *x) +{ + fd_set readmask; + struct timeval tv; + struct timeval *t = NULL; + + if (timeout >= 0) { + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + t = &tv; + } + + FD_ZERO(&readmask); + FD_SET(fd,&readmask); + + switch (select(fd+1, &readmask, NULL, NULL, t)) { + case -1: + erl_errno = EIO; + return ERL_ERROR; + + case 0: + erl_errno = ETIMEDOUT; + return ERL_TIMEOUT; + + default: + if (FD_ISSET(fd, &readmask)) { + return ei_xreceive_msg(fd, msg, x); + } else { + erl_errno = EIO; + return ERL_ERROR; + } + } +} /* rpc_from */ + + /* + * A true RPC. It return a NULL pointer + * in case of failure, otherwise a valid + * (ETERM *) pointer containing the reply + */ +int ei_rpc(ei_cnode* ec, int fd, char *mod, char *fun, + const char* inbuf, int inbuflen, ei_x_buff* x) +{ + int i, index; + ei_term t; + erlang_msg msg; + char rex[MAXATOMLEN+1]; + + if (ei_rpc_to(ec, fd, mod, fun, inbuf, inbuflen) < 0) { + return -1; + } + /* FIXME are we not to reply to the tick? */ + while ((i = ei_rpc_from(ec, fd, ERL_NO_TIMEOUT, &msg, x)) == ERL_TICK) + ; + + if (i == ERL_ERROR) return -1; + /*ep = 'erl'_element(2,emsg.msg);*/ /* {RPC_Tag, RPC_Reply} */ + index = 0; + if (ei_decode_version(x->buff, &index, &i) < 0 + || ei_decode_ei_term(x->buff, &index, &t) < 0) + return -1; /* FIXME ei_decode_version don't set erl_errno as before */ + /* FIXME this is strange, we don't check correct "rex" atom + and we let it pass if not ERL_SMALL_TUPLE_EXT and arity == 2 */ + if (t.ei_type == ERL_SMALL_TUPLE_EXT && t.arity == 2) + if (ei_decode_atom(x->buff, &index, rex) < 0) + return -1; + /* remove header */ + x->index -= index; + memmove(x->buff, &x->buff[index], x->index); + return 0; +} + + + /* + ** Handshake +*/ + + +/* FROM RTP RFC 1889 (except that we use all bits, bug in RFC?) */ +static unsigned int md_32(char* string, int length) +{ + MD5_CTX ctx; + union { + char c[16]; + unsigned x[4]; + } digest; + ei_MD5Init(&ctx); + ei_MD5Update(&ctx, (unsigned char *) string, + (unsigned) length); + ei_MD5Final((unsigned char *) digest.c, &ctx); + return (digest.x[0] ^ digest.x[1] ^ digest.x[2] ^ digest.x[3]); +} + +#if defined(__WIN32__) +unsigned int gen_challenge(void) +{ + struct { + SYSTEMTIME tv; + DWORD cpu; + int pid; + } s; + GetSystemTime(&s.tv); + s.cpu = GetTickCount(); + s.pid = getpid(); + return md_32((char*) &s, sizeof(s)); +} + +#elif defined(VXWORKS) + +static unsigned int gen_challenge(void) +{ + struct { + struct timespec tv; + clock_t cpu; + int pid; + } s; + s.cpu = clock(); + clock_gettime(CLOCK_REALTIME, &s.tv); + s.pid = getpid(); + return md_32((char*) &s, sizeof(s)); +} + +#else /* some unix */ + +static unsigned int gen_challenge(void) +{ + struct { + struct timeval tv; + clock_t cpu; + pid_t pid; + u_long hid; + uid_t uid; + gid_t gid; + struct utsname name; + } s; + + gettimeofday(&s.tv, 0); + uname(&s.name); + s.cpu = clock(); + s.pid = getpid(); + s.hid = gethostid(); + s.uid = getuid(); + s.gid = getgid(); + + return md_32((char*) &s, sizeof(s)); +} +#endif + +static void gen_digest(unsigned challenge, char cookie[], + unsigned char digest[16]) +{ + MD5_CTX c; + + char chbuf[21]; + + sprintf(chbuf,"%u", challenge); + ei_MD5Init(&c); + ei_MD5Update(&c, (unsigned char *) cookie, + (unsigned) strlen(cookie)); + ei_MD5Update(&c, (unsigned char *) chbuf, + (unsigned) strlen(chbuf)); + ei_MD5Final(digest, &c); +} + + +static char *hex(char digest[16], char buff[33]) +{ + static char tab[] = "0123456789abcdef"; + unsigned char *d = (unsigned char *) digest; + //static char buff[sizeof(digest)*2 + 1]; + char *p = buff; + int i; + + for (i = 0; i < sizeof(digest); ++i) { + *p++ = tab[(int)((*d) >> 4)]; + *p++ = tab[(int)((*d++) & 0xF)]; + } + *p = '\0'; + return buff; +} + +static int read_2byte_package(int fd, char **buf, int *buflen, + int *is_static, unsigned ms) +{ + unsigned char nbuf[2]; + unsigned char *x = nbuf; + unsigned len; + int res; + + if((res = ei_read_fill_t(fd, (char *)nbuf, 2, ms)) != 2) { + erl_errno = (res == -2) ? ETIMEDOUT : EIO; + return -1; + } + len = get16be(x); + + if (len > *buflen) { + if (*is_static) { + char *tmp = malloc(len); + if (!tmp) { + erl_errno = ENOMEM; + return -1; + } + *buf = tmp; + *is_static = 0; + *buflen = len; + } else { + char *tmp = realloc(*buf, len); + if (!tmp) { + erl_errno = ENOMEM; + return -1; + } + *buf = tmp; + *buflen = len; + } + } + if ((res = ei_read_fill_t(fd, *buf, len, ms)) != len) { + erl_errno = (res == -2) ? ETIMEDOUT : EIO; + return -1; + } + return len; +} + + +static int send_status(int fd, char *status, unsigned ms) +{ + char *buf, *s; + char dbuf[DEFBUF_SIZ]; + int siz = strlen(status) + 1 + 2; + int res; + + buf = (siz > DEFBUF_SIZ) ? malloc(siz) : dbuf; + if (!buf) { + erl_errno = ENOMEM; + return -1; + } + s = buf; + put16be(s,siz - 2); + put8(s, 's'); + memcpy(s, status, strlen(status)); + if ((res = ei_write_fill_t(fd, buf, siz, ms)) != siz) { + EI_TRACE_ERR0("send_status","-> SEND_STATUS socket write failed"); + if (buf != dbuf) + free(buf); + erl_errno = (res == -2) ? ETIMEDOUT : EIO; + return -1; + } + EI_TRACE_CONN1("send_status","-> SEND_STATUS (%s)",status); + + if (buf != dbuf) + free(buf); + return 0; +} + +static int recv_status(int fd, unsigned ms) +{ + char dbuf[DEFBUF_SIZ]; + char *buf = dbuf; + int is_static = 1; + int buflen = DEFBUF_SIZ; + int rlen; + + if ((rlen = read_2byte_package(fd, &buf, &buflen, &is_static, ms)) <= 0) { + EI_TRACE_ERR1("recv_status", + "<- RECV_STATUS socket read failed (%d)", rlen); + goto error; + } + if (rlen == 3 && buf[0] == 's' && buf[1] == 'o' && + buf[2] == 'k') { + if (!is_static) + free(buf); + EI_TRACE_CONN0("recv_status","<- RECV_STATUS (ok)"); + return 0; + } +error: + if (!is_static) + free(buf); + return -1; +} + +/* FIXME fix the signed/unsigned mess..... */ + +static int send_name_or_challenge(int fd, char *nodename, + int f_chall, + unsigned challenge, + unsigned version, + unsigned ms) +{ + char *buf; + unsigned char *s; + char dbuf[DEFBUF_SIZ]; + int siz = 2 + 1 + 2 + 4 + strlen(nodename); + const char* function[] = {"SEND_NAME", "SEND_CHALLENGE"}; + int res; + + if (f_chall) + siz += 4; + buf = (siz > DEFBUF_SIZ) ? malloc(siz) : dbuf; + if (!buf) { + erl_errno = ENOMEM; + return -1; + } + s = (unsigned char *)buf; + put16be(s,siz - 2); + put8(s, 'n'); + put16be(s, version); + put32be(s, (DFLAG_EXTENDED_REFERENCES + | DFLAG_EXTENDED_PIDS_PORTS + | DFLAG_FUN_TAGS + | DFLAG_NEW_FUN_TAGS)); + if (f_chall) + put32be(s, challenge); + memcpy(s, nodename, strlen(nodename)); + + if ((res = ei_write_fill_t(fd, buf, siz, ms)) != siz) { + EI_TRACE_ERR1("send_name_or_challenge", + "-> %s socket write failed", function[f_chall]); + if (buf != dbuf) + free(buf); + erl_errno = (res == -2) ? ETIMEDOUT : EIO; + return -1; + } + + if (buf != dbuf) + free(buf); + return 0; +} + +static int recv_challenge(int fd, unsigned *challenge, + unsigned *version, + unsigned *flags, ErlConnect *namebuf, unsigned ms) +{ + char dbuf[DEFBUF_SIZ]; + char *buf = dbuf; + int is_static = 1; + int buflen = DEFBUF_SIZ; + int rlen; + char *s; + struct sockaddr_in sin; + socklen_t sin_len = sizeof(sin); + char tag; + + erl_errno = EIO; /* Default */ + + if ((rlen = read_2byte_package(fd, &buf, &buflen, &is_static, ms)) <= 0) { + EI_TRACE_ERR1("recv_challenge", + "<- RECV_CHALLENGE socket read failed (%d)",rlen); + goto error; + } + if ((rlen - 11) > MAXNODELEN) { + EI_TRACE_ERR1("recv_challenge", + "<- RECV_CHALLENGE nodename too long (%d)",rlen - 11); + goto error; + } + s = buf; + if ((tag = get8(s)) != 'n') { + EI_TRACE_ERR2("recv_challenge", + "<- RECV_CHALLENGE incorrect tag, " + "expected 'n' got '%c' (%u)",tag,tag); + goto error; + } + *version = get16be(s); + *flags = get32be(s); + *challenge = get32be(s); + + if (!(*flags & DFLAG_EXTENDED_REFERENCES)) { + EI_TRACE_ERR0("recv_challenge","<- RECV_CHALLENGE peer cannot " + "handle extended references"); + goto error; + } + + if (!(*flags & DFLAG_EXTENDED_PIDS_PORTS) + && !ei_internal_use_r9_pids_ports()) { + EI_TRACE_ERR0("recv_challenge","<- RECV_CHALLENGE peer cannot " + "handle extended pids and ports"); + erl_errno = EIO; + goto error; + } + + + if (getpeername(fd, (struct sockaddr *) &sin, &sin_len) < 0) { + EI_TRACE_ERR0("recv_challenge","<- RECV_CHALLENGE can't get peername"); + erl_errno = errno; + goto error; + } + memcpy(namebuf->ipadr, &(sin.sin_addr.s_addr), + sizeof(sin.sin_addr.s_addr)); + memcpy(namebuf->nodename, s, rlen - 11); + namebuf->nodename[rlen - 11] = '\0'; + if (!is_static) + free(buf); + EI_TRACE_CONN4("recv_challenge","<- RECV_CHALLENGE (ok) node = %s, " + "version = %u, " + "flags = %u, " + "challenge = %d", + namebuf->nodename, + *version, + *flags, + *challenge + ); + erl_errno = 0; + return 0; +error: + if (!is_static) + free(buf); + return -1; +} + +static int send_challenge_reply(int fd, unsigned char digest[16], + unsigned challenge, unsigned ms) +{ + char *s; + char buf[DEFBUF_SIZ]; + int siz = 2 + 1 + 4 + 16; + int res; + + s = buf; + put16be(s,siz - 2); + put8(s, 'r'); + put32be(s, challenge); + memcpy(s, digest, 16); + + if ((res = ei_write_fill_t(fd, buf, siz, ms)) != siz) { + EI_TRACE_ERR0("send_challenge_reply", + "-> SEND_CHALLENGE_REPLY socket write failed"); + erl_errno = (res == -2) ? ETIMEDOUT : EIO; + return -1; + } + + if (ei_tracelevel >= 3) { + char buffer[33]; + EI_TRACE_CONN2("send_challenge_reply", + "-> SEND_CHALLENGE_REPLY (ok) challenge = %d, digest = %s", + challenge,hex((char*)digest, buffer)); + } + return 0; +} + +static int recv_challenge_reply (int fd, + unsigned our_challenge, + char cookie[], + unsigned *her_challenge, + unsigned ms) +{ + char dbuf[DEFBUF_SIZ]; + char *buf = dbuf; + int is_static = 1; + int buflen = DEFBUF_SIZ; + int rlen; + char *s; + char tag; + char her_digest[16], expected_digest[16]; + + erl_errno = EIO; /* Default */ + + if ((rlen = read_2byte_package(fd, &buf, &buflen, &is_static, ms)) != 21) { + EI_TRACE_ERR1("recv_challenge_reply", + "<- RECV_CHALLENGE_REPLY socket read failed (%d)",rlen); + goto error; + } + + s = buf; + if ((tag = get8(s)) != 'r') { + EI_TRACE_ERR2("recv_challenge_reply", + "<- RECV_CHALLENGE_REPLY incorrect tag, " + "expected 'r' got '%c' (%u)",tag,tag); + goto error; + } + *her_challenge = get32be(s); + memcpy(her_digest, s, 16); + gen_digest(our_challenge, cookie, (unsigned char*)expected_digest); + if (memcmp(her_digest, expected_digest, 16)) { + EI_TRACE_ERR0("recv_challenge_reply", + "<- RECV_CHALLENGE_REPLY authorization failure"); + goto error; + } + if (!is_static) + free(buf); + + + if (ei_tracelevel >= 3) { + char buffer[33]; + EI_TRACE_CONN2("recv_challenge_reply", + "<- RECV_CHALLENGE_REPLY (ok) challenge = %u, digest = %s", + *her_challenge,hex(her_digest,buffer)); + } + erl_errno = 0; + return 0; + +error: + if (!is_static) + free(buf); + return -1; +} + +static int send_challenge_ack(int fd, unsigned char digest[16], unsigned ms) +{ + char *s; + char buf[DEFBUF_SIZ]; + int siz = 2 + 1 + 16; + int res; + + s = buf; + + put16be(s,siz - 2); + put8(s, 'a'); + memcpy(s, digest, 16); + + if ((res = ei_write_fill_t(fd, buf, siz, ms)) != siz) { + EI_TRACE_ERR0("recv_challenge_reply", + "-> SEND_CHALLENGE_ACK socket write failed"); + erl_errno = (res == -2) ? ETIMEDOUT : EIO; + return -1; + } + + if (ei_tracelevel >= 3) { + char buffer[33]; + EI_TRACE_CONN1("recv_challenge_reply", + "-> SEND_CHALLENGE_ACK (ok) digest = %s",hex((char *)digest,buffer)); + } + + return 0; +} + +static int recv_challenge_ack(int fd, + unsigned our_challenge, + char cookie[], unsigned ms) +{ + char dbuf[DEFBUF_SIZ]; + char *buf = dbuf; + int is_static = 1; + int buflen = DEFBUF_SIZ; + int rlen; + char *s; + char tag; + char her_digest[16], expected_digest[16]; + + erl_errno = EIO; /* Default */ + + if ((rlen = read_2byte_package(fd, &buf, &buflen, &is_static, ms)) != 17) { + EI_TRACE_ERR1("recv_challenge_ack", + "<- RECV_CHALLENGE_ACK socket read failed (%d)",rlen); + goto error; + } + + s = buf; + if ((tag = get8(s)) != 'a') { + EI_TRACE_ERR2("recv_challenge_ack", + "<- RECV_CHALLENGE_ACK incorrect tag, " + "expected 'a' got '%c' (%u)",tag,tag); + goto error; + } + memcpy(her_digest, s, 16); + gen_digest(our_challenge, cookie, (unsigned char *)expected_digest); + if (memcmp(her_digest, expected_digest, 16)) { + EI_TRACE_ERR0("recv_challenge_ack", + "<- RECV_CHALLENGE_ACK authorization failure"); + goto error; + } + if (!is_static) + free(buf); + + if (ei_tracelevel >= 3) { + char buffer[33]; + EI_TRACE_CONN1("recv_challenge_ack", + "<- RECV_CHALLENGE_ACK (ok) digest = %s",hex(her_digest,buffer)); + } + erl_errno = 0; + return 0; + +error: + if (!is_static) + free(buf); + return -1; +} + +static int send_name(int fd, char *nodename, unsigned version, unsigned ms) +{ + return send_name_or_challenge(fd, nodename, 0, 0, version, ms); +} + +static int send_challenge(int fd, char *nodename, + unsigned challenge, unsigned version, unsigned ms) +{ + return send_name_or_challenge(fd, nodename, 1, challenge, version, ms); +} + +static int recv_name(int fd, + unsigned *version, + unsigned *flags, ErlConnect *namebuf, unsigned ms) +{ + char dbuf[DEFBUF_SIZ]; + char *buf = dbuf; + int is_static = 1; + int buflen = DEFBUF_SIZ; + int rlen; + char *s; + struct sockaddr_in sin; + socklen_t sin_len = sizeof(sin); + char tag; + + erl_errno = EIO; /* Default */ + + if ((rlen = read_2byte_package(fd, &buf, &buflen, &is_static, ms)) <= 0) { + EI_TRACE_ERR1("recv_name","<- RECV_NAME socket read failed (%d)",rlen); + goto error; + } + if ((rlen - 7) > MAXNODELEN) { + EI_TRACE_ERR1("recv_name","<- RECV_NAME nodename too long (%d)",rlen-7); + goto error; + } + s = buf; + tag = get8(s); + if (tag != 'n') { + EI_TRACE_ERR2("recv_name","<- RECV_NAME incorrect tag, " + "expected 'n' got '%c' (%u)",tag,tag); + goto error; + } + *version = get16be(s); + *flags = get32be(s); + + if (!(*flags & DFLAG_EXTENDED_REFERENCES)) { + EI_TRACE_ERR0("recv_name","<- RECV_NAME peer cannot handle" + "extended references"); + goto error; + } + + if (!(*flags & DFLAG_EXTENDED_PIDS_PORTS) + && !ei_internal_use_r9_pids_ports()) { + EI_TRACE_ERR0("recv_name","<- RECV_NAME peer cannot " + "handle extended pids and ports"); + erl_errno = EIO; + goto error; + } + + if (getpeername(fd, (struct sockaddr *) &sin, &sin_len) < 0) { + EI_TRACE_ERR0("recv_name","<- RECV_NAME can't get peername"); + erl_errno = errno; + goto error; + } + memcpy(namebuf->ipadr, &(sin.sin_addr.s_addr), + sizeof(sin.sin_addr.s_addr)); + memcpy(namebuf->nodename, s, rlen - 7); + namebuf->nodename[rlen - 7] = '\0'; + if (!is_static) + free(buf); + EI_TRACE_CONN3("recv_name", + "<- RECV_NAME (ok) node = %s, version = %u, flags = %u", + namebuf->nodename,*version,*flags); + erl_errno = 0; + return 0; + +error: + if (!is_static) + free(buf); + return -1; +} + +/*************************************************************************** + * + * Returns 1 on success and 0 on failure. + * + ***************************************************************************/ + + +/* size is the buffer size, e.i. string length + 1 */ + +static int get_home(char *buf, int size) +{ + char* homedrive; + char* homepath; + +#ifdef __WIN32__ + homedrive = getenv("HOMEDRIVE"); + homepath = getenv("HOMEPATH"); +#else + homedrive = ""; + homepath = getenv("HOME"); +#endif + + if (!homedrive || !homepath) { + buf[0] = '.'; + buf[1] = '\0'; + return 1; + } else if (strlen(homedrive)+strlen(homepath) < size-1) { + strcpy(buf, homedrive); + strcat(buf, homepath); + return 1; + } + + return 0; +} + + +static int get_cookie(char *buf, int bufsize) +{ + char fname[EI_MAX_HOME_PATH + sizeof(COOKIE_FILE) + 1]; + int fd; + int len; + unsigned char next_c; + + if (!get_home(fname, EI_MAX_HOME_PATH+1)) { + fprintf(stderr," get_cookie: too long path to home"); + return 0; + } + + strcat(fname, COOKIE_FILE); + if ((fd = open(fname, O_RDONLY, 0777)) < 0) { + fprintf(stderr," get_cookie: can't open cookie file"); + return 0; + } + + if ((len = read(fd, buf, bufsize-1)) < 0) { + fprintf(stderr," get_cookie: reading cookie file"); + close(fd); + return 0; + } + + /* If more to read it is too long. Not 100% correct test but will do. */ + if (read(fd, &next_c, 1) > 0 && !isspace(next_c)) { + fprintf(stderr," get_cookie: cookie in %s is too long",fname); + close(fd); + return 0; + } + + close(fd); + + /* Remove all newlines after the first newline */ + buf[len] = '\0'; /* Terminate string */ + len = strcspn(buf,"\r\n"); + buf[len] = '\0'; /* Terminate string again */ + + return 1; /* Success! */ +} diff --git a/lib/erl_interface/src/connect/ei_connect_int.h b/lib/erl_interface/src/connect/ei_connect_int.h new file mode 100644 index 0000000000..9926f799df --- /dev/null +++ b/lib/erl_interface/src/connect/ei_connect_int.h @@ -0,0 +1,114 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* +* Purpose: Connect to any node at any host. (EI version) +*/ + +/* FIXME far to many includes here... */ + +/* some send() functions use buffer on heap for "small" messages */ +/* messages larger than this require call to malloc() */ + +#ifndef _EI_CONNECT_H +#define _EI_CONNECT_H + +#include +#include +#include + +#ifdef __WIN32__ +#include +#include +#include + +#elif VXWORKS +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define getpid() taskIdSelf() +extern int h_errno; + +#else /* some other unix */ +#include +#include +#include + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#include +#include +#include +#include +#include +#include /* for gen_challenge (NEED FIX?) */ +#endif + +/* FIXME remove duplicate defintions */ + +#define DEFBUF_SIZ 100 + +/* rpc_from() uses a buffer this size */ +#ifndef MAX_RECEIVE_BUF +# define MAX_RECEIVE_BUF 32*1024 +#endif + +/* Distribution capability flags */ +#define DFLAG_PUBLISHED 1 +#define DFLAG_ATOM_CACHE 2 +#define DFLAG_EXTENDED_REFERENCES 4 +#define DFLAG_DIST_MONITOR 8 +#define DFLAG_FUN_TAGS 16 +#define DFLAG_NEW_FUN_TAGS 0x80 +#define DFLAG_EXTENDED_PIDS_PORTS 0x100 + +ei_cnode *ei_fd_to_cnode(int fd); +int ei_distversion(int fd); +const char* ei_getfdcookie(int fd); +short ei_thiscreation(const ei_cnode* ec); +const char *ei_thiscookie(const ei_cnode* ec); + +int ei_do_receive_msg(int fd, int staticbuffer_p, + erlang_msg* msg, ei_x_buff* x, unsigned ms); + +#endif /* _EI_CONNECT_H */ diff --git a/lib/erl_interface/src/connect/ei_resolve.c b/lib/erl_interface/src/connect/ei_resolve.c new file mode 100644 index 0000000000..42aeab22b1 --- /dev/null +++ b/lib/erl_interface/src/connect/ei_resolve.c @@ -0,0 +1,645 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1997-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Interface functions to different versions of gethostbyname + */ + +#ifdef VXWORKS +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#elif __WIN32__ +#include +#include +#include + +#else /* unix of some kind */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +/* common to all platforms */ +#include "eidef.h" +#include "ei_resolve.h" +#include "ei_locking.h" + +#ifdef HAVE_GETHOSTBYNAME_R + +void ei_init_resolve(void) +{ + return; /* Do nothing */ +} + +#else /* !HAVE_GETHOSTBYNAME_R */ + +/* we have our own in that case */ + +/* Make sure this semaphore has been initialized somewhere first. This + * should probably be done from 'erl'_init() but we do it in the first + * call to gethostbyname_r() or gethostbyaddr_r(). + */ +/* FIXME we don't want globals here, but maybe ok? */ +#ifdef _REENTRANT +static ei_mutex_t *ei_gethost_sem = NULL; +#endif /* _REENTRANT */ +static int ei_resolve_initialized = 0; +#ifndef __WIN32__ +int h_errno; +#endif + +#ifdef DEBUG +#define DEBUGF(X) fprintf X +#else +#define DEBUGF(X) /* Nothing */ +#endif + +#ifdef VXWORKS +/* FIXME problem for threaded ? */ +static struct hostent *(*sens_gethostbyname)(const char *name, + char *, int) = NULL; +static struct hostent *(*sens_gethostbyaddr)(const char *addr, + char *, int) = NULL; +#endif + +#ifdef VXWORKS +static int verify_dns_configuration(void); +#endif + +/* + * If we find SENS resolver, use the functions found there, i.e. + * resolvGetHostByName() and resolvGetHostByAddr(). Otherwise we use + * our own, which are just wrappers around hostGetByName() and + * hostGetByAddr(). Here we look up the functions. + */ +void ei_init_resolve(void) +{ + +#ifdef VXWORKS + void *sym; + SYM_TYPE symtype; + + if (symFindByName(sysSymTbl,"resolvGetHostByName", + (char **)&sym,&symtype) == OK && + verify_dns_configuration()) { + sens_gethostbyname = sym; + DEBUGF((stderr,"found SENS resolver - using it for gethostbyname()\n")); + if (symFindByName(sysSymTbl,"resolvGetHostByAddr", + (char **)&sym,&symtype) == OK) { + sens_gethostbyaddr = sym; + DEBUGF((stderr,"found SENS resolver - " + "using it for gethostbyaddr()\n")); + } + else { + DEBUGF((stderr,"SENS resolver not found - " + "using default gethostbyaddr()\n")); + } + } + else { + DEBUGF((stderr,"SENS resolver not found - " + "using default gethostbyname()\n")); + } +#endif /* VXWORKS */ + +#ifdef _REENTRANT + ei_gethost_sem = ei_mutex_create(); +#endif /* _REENTRANT */ + + ei_resolve_initialized = 1; +} + +#ifdef VXWORKS +/* +** Function to verify the DNS configuration on VwXorks SENS. +** Actually configures to a default value if unconfigured... +*/ +static int verify_dns_configuration(void) +{ + /* FIXME problem for threaded ? */ + static char resolv_params[sizeof(RESOLV_PARAMS_S)]; + void (*rpg)(char *); + STATUS (*rps)(char *); + SYM_TYPE dummy; + int get_result, set_result; + + get_result = symFindByName(sysSymTbl,"resolvParamsGet", (char **) &rpg, &dummy); + set_result = symFindByName(sysSymTbl,"resolvParamsSet", (char **) &rps, &dummy); + + if (!(get_result == OK && + set_result == OK)) + return -1; + (*rpg)(resolv_params); + if (*resolv_params == '\0') { + /* It exists, but is not configured, ei_connect would fail + if we left it this way... The best we can do is to configure + it to use the local host database on the card, as a fallback */ + *resolv_params = (char) 1; + fprintf(stderr,"Trying to fix up DNS configuration.\n"); + if (((*rps)(resolv_params)) != OK) + return -1; + } + return 0; +} + +#endif + +/* + * Copy the contents of one struct hostent to another, i.e. don't just + * copy the pointers, copy all the data and create new pointers, etc. + * User must provide a secondary buffer to which the host data can be copied. + * + * Returns 0 on success or -1 if buffer is too small for host data +*/ + +/* a couple of helpers + * align: increment buf until it is dword-aligned, reduce len by same amount. + * advance: increment buf by n bytes, reduce len by same amount . + */ +#define align_buf(buf,len) for (;(((unsigned)buf)&0x3); (buf)++, len--) +#define advance_buf(buf,len,n) ((buf)+=(n),(len)-=(n)) + +/* "and now the tricky part..." */ +static int copy_hostent(struct hostent *dest, const struct hostent *src, char *buffer, int buflen) +{ + char **pptr; + int len; + char **src_aliases = NULL; + char **src_addr_list = NULL; + + /* fix initial buffer alignment */ + align_buf(buffer, buflen); + + /* copy the data into our buffer... */ + /* first the easy ones! */ + dest->h_length = src->h_length; + dest->h_addrtype = src->h_addrtype; + + /* h_name */ + dest->h_name = buffer; + len = strlen(src->h_name); + if (buflen < len+1) return -1; + memmove((char *)dest->h_name,src->h_name,len); + buffer[len] = (char)0; + advance_buf(buffer,buflen,len+1); + + /* traverse alias list, collecting the pointers */ + align_buf(buffer, buflen); + pptr = (char **)buffer; + dest->h_aliases = pptr; /* save head of pointer array */ + + src_aliases = src->h_aliases; + + while(*(src_aliases)) { + if (buflen < sizeof(*pptr)) return -1; + *pptr = src_aliases; + advance_buf(buffer,buflen,sizeof(*pptr)); + src_aliases++; + pptr++; + } + if (buflen < sizeof(*pptr)) return -1; + *pptr = NULL; + advance_buf(buffer,buflen,sizeof(*pptr)); + + /* go back to saved position & transfer the alias data */ + pptr = dest->h_aliases; + while (*pptr) { + len = strlen(*pptr); + if (buflen < len+1) return -1; + memmove(buffer,*pptr,len); /* copy data to local buffer */ + buffer[len] = (char)0; + *pptr = buffer; /* point to own copy now */ + advance_buf(buffer,buflen,len+1); + pptr++; + } + + /* traverse address list, collecting the pointers */ + align_buf(buffer, buflen); + pptr = (char **)buffer; + dest->h_addr_list = pptr; /* save head of pointer array */ + + src_addr_list = src->h_addr_list; + + while(*(src_addr_list)) { + if (buflen < sizeof(*pptr)) return -1; + *pptr = *src_addr_list; + advance_buf(buffer,buflen,sizeof(*pptr)); + src_addr_list++; + pptr++; + } + if (buflen < sizeof(*pptr)) return -1; + *pptr = NULL; + advance_buf(buffer,buflen,sizeof(*pptr)); + + /* go back to saved position & transfer the addresses */ + /* align_buf(buffer, buflen); */ + pptr = dest->h_addr_list; + while (*pptr) { + len = src->h_length; + if (buflen < len+1) return -1; + memmove(buffer,*pptr,len); /* copy data to local buffer */ + buffer[len]=(char)0; /* not sure if termination is necessary */ + *pptr = buffer; /* point to own copy now */ + advance_buf(buffer,buflen,len+1); + pptr++; + } + + if (buflen < 0) return -1; + return 0; +} + +/* This function is a pseudo-reentrant version of gethostbyname(). It + * uses locks to serialize the call to the regular (non-reentrant) + * gethostbyname() and then copies the data into the user-provided + * buffers. It's not pretty but it works. + * + * name - name of host to look up + * hostp - user-supplied structure for returning host entry + * buffer - user-supplied buffer: storage for the copied host data + * buflen - length of user-supplied buffer + * h_errnop - buffer for return status + * + * Returns values as for gethostbyname(). Additionally, sets + * errno=ERANGE and returns NULL if buffer is too small for host data. + */ + +static struct hostent *my_gethostbyname_r(const char *name, + struct hostent *hostp, + char *buffer, + int buflen, + int *h_errnop) +{ + struct hostent dest; + struct hostent *src; + struct hostent *rval = NULL; + + /* FIXME this should have been done in 'erl'_init()? */ + if (!ei_resolve_initialized) ei_init_resolve(); + +#ifdef _REENTRANT + /* === BEGIN critical section === */ + if (ei_mutex_lock(ei_gethost_sem,0) != 0) { + *h_errnop = NO_RECOVERY; + return NULL; + } +#endif /* _REENTRANT */ + + /* lookup the data */ + if ((src = ei_gethostbyname(name))) { + /* copy to caller's buffer */ + if (!copy_hostent(&dest,src,buffer,buflen)) { + /* success */ + *hostp = dest; + *h_errnop = 0; + rval = hostp; + } + + else { + /* failure - buffer size */ +#ifdef __WIN32__ + SetLastError(ERROR_INSUFFICIENT_BUFFER); +#else + errno = ERANGE; +#endif + *h_errnop = 0; + } + } + + else { + /* failure - lookup */ +#ifdef __WIN32__ + *h_errnop = WSAGetLastError(); +#else + *h_errnop = h_errno; +#endif + } + +#ifdef _REENTRANT + /* === END critical section === */ + ei_mutex_unlock(ei_gethost_sem); +#endif /* _REENTRANT */ + return rval; +} + +static struct hostent *my_gethostbyaddr_r(const char *addr, + int length, + int type, + struct hostent *hostp, + char *buffer, + int buflen, + int *h_errnop) +{ + struct hostent dest; + struct hostent *src; + struct hostent *rval = NULL; + + /* FIXME this should have been done in 'erl'_init()? */ + if (!ei_resolve_initialized) ei_init_resolve(); + +#ifdef _REENTRANT + /* === BEGIN critical section === */ + if (ei_mutex_lock(ei_gethost_sem,0) != 0) { + *h_errnop = NO_RECOVERY; + return NULL; + } +#endif /* _REENTRANT */ + + /* lookup the data */ + if ((src = ei_gethostbyaddr(addr,length,type))) { + /* copy to caller's buffer */ + if (!copy_hostent(&dest,src,buffer,buflen)) { + /* success */ + *hostp = dest; + *h_errnop = 0; + rval = hostp; + } + + else { + /* failure - buffer size */ +#ifdef __WIN32__ + SetLastError(ERROR_INSUFFICIENT_BUFFER); +#else + errno = ERANGE; +#endif + *h_errnop = 0; + } + } + + else { + /* failure - lookup */ +#ifdef __WIN32__ + *h_errnop = WSAGetLastError(); +#else + *h_errnop = h_errno; +#endif + } + + +#ifdef _REENTRANT + /* === END critical section === */ + ei_mutex_unlock(ei_gethost_sem); +#endif /* _REENTRANT */ + return rval; +} + + +#endif /* !HAVE_GETHOSTBYNAME_R */ + + +#ifdef __WIN32__ +struct hostent *ei_gethostbyname(const char *name) +{ + return gethostbyname(name); +} + +struct hostent *ei_gethostbyaddr(const char *addr, int len, int type) +{ + return gethostbyaddr(addr, len, type); +} + +#elif VXWORKS + + +/* these are a couple of substitutes for the real thing when we run on + * stock vxworks (i.e. no sens). + * + * len and type are ignored, but we make up some reasonable values and + * insert them + */ +static struct hostent *my_gethostbyname(const char *name) +{ + /* FIXME problem for threaded ? */ + static struct hostent h; + static char hostname[EI_MAXHOSTNAMELEN+1]; + static char *aliases[1] = {NULL}; + static char *addrp[2] = {NULL,NULL}; + static unsigned long addr = 0; + + strcpy(hostname,name); + if ((addr = (unsigned long)hostGetByName(hostname)) == ERROR) { + h_errno = HOST_NOT_FOUND; + return NULL; + } + + h_errno = 0; + h.h_name = hostname; + h.h_aliases = aliases; + h.h_length = 4; + h.h_addrtype = AF_INET; + addrp[0] = (char *)&addr; + h.h_addr_list = addrp; + + return &h; +} + +static struct hostent *my_gethostbyaddr(const char *addr, int len, int type) +{ + /* FIXME problem for threaded ? */ + static struct hostent h; + static char hostname[EI_MAXHOSTNAMELEN+1]; + static char *aliases[1] = { NULL }; + static unsigned long inaddr; + static char *addrp[2] = {(char *)&inaddr, NULL}; + + memmove(&inaddr,addr,sizeof(inaddr)); + + if ((hostGetByAddr(inaddr,hostname)) == ERROR) { + h_errno = HOST_NOT_FOUND; + return NULL; + } + + h_errno = 0; + h.h_name = hostname; + h.h_aliases = aliases; + h.h_length = 4; + h.h_addrtype = AF_INET; + h.h_addr_list = addrp; + + return &h; +} + +/* use sens functions for these, if found. */ +struct hostent *ei_gethostbyname(const char *name) +{ + struct hostent *h = NULL; + + if (!sens_gethostbyname) { + h = my_gethostbyname(name); + } + else { + /* FIXME problem for threaded ? */ + static char buf[1024]; + h = sens_gethostbyname(name,buf,1024); + } + + return h; +} + +struct hostent *ei_gethostbyaddr(const char *addr, int len, int type) +{ + struct hostent *h = NULL; + + if (!sens_gethostbyaddr) { + h = my_gethostbyaddr(addr,len,type); + } + else { + /* FIXME problem for threaded ? */ + static char buf[1024]; + h = sens_gethostbyaddr(addr,buf,1024); + } + + return h; +} + +struct hostent *ei_gethostbyaddr_r(const char *addr, + int length, + int type, + struct hostent *hostp, + char *buffer, + int buflen, + int *h_errnop) +{ + struct hostent *h = NULL; + + /* use own func if sens function not available */ + if (!sens_gethostbyaddr) { + h = my_gethostbyaddr_r(addr,length,type,hostp,buffer,buflen,h_errnop); + } + else { + if (!(h = sens_gethostbyaddr(addr,buffer,buflen))) { + /* sens returns status via errno */ + *h_errnop = errno; + } + else { + *hostp = *h; + *h_errnop = 0; + } + } + + return h; +} + +struct hostent *ei_gethostbyname_r(const char *name, + struct hostent *hostp, + char *buffer, + int buflen, + int *h_errnop) +{ + struct hostent *h = NULL; + + /* use own func if sens function not available */ + if (!sens_gethostbyname) { + h = my_gethostbyname_r(name,hostp,buffer,buflen,h_errnop); + } + else { + if (!(h = sens_gethostbyname(name,buffer,buflen))) { + /* sens returns status via errno */ + *h_errnop = errno; + } + else { + *hostp = *h; + *h_errnop = 0; + } + } + + return h; +} + +#else /* unix of some kind */ + +struct hostent *ei_gethostbyname(const char *name) +{ + return gethostbyname(name); +} + +struct hostent *ei_gethostbyaddr(const char *addr, int len, int type) +{ + return gethostbyaddr(addr, len, type); +} + +struct hostent *ei_gethostbyaddr_r(const char *addr, + int length, + int type, + struct hostent *hostp, + char *buffer, + int buflen, + int *h_errnop) +{ +#if (EI_THREADS == false) + /* threads disabled, no need to call reentrant function */ + return gethostbyaddr(addr, length, type); +#else +#ifndef HAVE_GETHOSTBYNAME_R + return my_gethostbyaddr_r(addr,length,type,hostp,buffer,buflen,h_errnop); +#else +#if (defined(__GLIBC__) || (__FreeBSD_version >= 602000)) + struct hostent *result; + + gethostbyaddr_r(addr, length, type, hostp, buffer, buflen, &result, + h_errnop); + + return result; +#else + return gethostbyaddr_r(addr,length,type,hostp,buffer,buflen,h_errnop); +#endif +#endif +#endif +} + +struct hostent *ei_gethostbyname_r(const char *name, + struct hostent *hostp, + char *buffer, + int buflen, + int *h_errnop) +{ +#ifndef _REENTRANT + /* threads disabled, no need to call reentrant function */ + return gethostbyname(name); +#else +#ifndef HAVE_GETHOSTBYNAME_R + return my_gethostbyname_r(name,hostp,buffer,buflen,h_errnop); +#else +#if (defined(__GLIBC__) || (__FreeBSD_version >= 602000)) + struct hostent *result; + + gethostbyname_r(name, hostp, buffer, buflen, &result, h_errnop); + + return result; +#else + return gethostbyname_r(name,hostp,buffer,buflen,h_errnop); +#endif +#endif +#endif +} + +#endif /* vxworks, win, unix */ + diff --git a/lib/erl_interface/src/connect/ei_resolve.h b/lib/erl_interface/src/connect/ei_resolve.h new file mode 100644 index 0000000000..4cb8aff338 --- /dev/null +++ b/lib/erl_interface/src/connect/ei_resolve.h @@ -0,0 +1,24 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1997-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifndef _EI_RESOLVE_H +#define _EI_RESOLVE_H + +void ei_init_resolve(void); + +#endif /* _EI_RESOLVE_H */ diff --git a/lib/erl_interface/src/connect/eirecv.c b/lib/erl_interface/src/connect/eirecv.c new file mode 100644 index 0000000000..51fc32d65c --- /dev/null +++ b/lib/erl_interface/src/connect/eirecv.c @@ -0,0 +1,280 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifdef __WIN32__ +# include +# include +# include +#else /* Unix/VxWorks */ +# include +#endif + +/* common */ +#include +#include +#include + +#include "eidef.h" +#include "eiext.h" +#include "eirecv.h" +#include "ei_portio.h" +#include "ei_internal.h" +#include "putget.h" +#include "ei_trace.h" +#include "show_msg.h" + +#include + +#define EIRECVBUF 2048 /* largest possible header is approx 1300 bytes */ + +/* length (4), PASS_THOUGH (1), header, message */ +int +ei_recv_internal (int fd, + char **mbufp, int *bufsz, + erlang_msg *msg, int *msglenp, + int staticbufp, unsigned ms) +{ + char header[EIRECVBUF]; + char *s=header; + char *mbuf=*mbufp; + int len = 0; + int msglen = 0; + int bytesread = 0; + int remain; + int arity; + int version; + int index = 0; + int i = 0; + int res; + int show_this_msg = 0; + + /* get length field */ + if ((res = ei_read_fill_t(fd, header, 4, ms)) != 4) + { + erl_errno = (res == -2) ? ETIMEDOUT : EIO; + return -1; + } + len = get32be(s); + + /* got tick - respond and return */ + if (!len) { + char tock[] = {0,0,0,0}; + ei_write_fill_t(fd, tock, sizeof(tock), ms); /* Failure no problem */ + *msglenp = 0; + return 0; /* maybe flag ERL_EAGAIN [sverkerw] */ + } + + /* turn off tracing on each receive. it will be turned back on if + * we receive a trace token. + */ + ei_trace(-1,NULL); + + /* read enough to get at least entire header */ + bytesread = (len > EIRECVBUF ? EIRECVBUF : len); + if ((i = ei_read_fill_t(fd,header,bytesread,ms)) != bytesread) { + erl_errno = (i == -2) ? ETIMEDOUT : EIO; + return -1; + } + + /* now decode header */ + /* pass-through, version, control tuple header, control message type */ + s = header; + index = 1; + if ((get8(s) != ERL_PASS_THROUGH) + || ei_decode_version(header,&index,&version) + || (version != ERL_VERSION_MAGIC) + || ei_decode_tuple_header(header,&index,&arity) + || ei_decode_long(header,&index,&msg->msgtype)) + { + erl_errno = EIO; /* Maybe another code for decoding errors */ + return -1; + } + + switch (msg->msgtype) { + case ERL_SEND: /* { SEND, Cookie, ToPid } */ + if (ei_tracelevel > 0) show_this_msg = 1; + if (ei_decode_atom(header,&index,msg->cookie) + || ei_decode_pid(header,&index,&msg->to)) + { + erl_errno = EIO; + return -1; + } + + break; + + case ERL_REG_SEND: /* { REG_SEND, From, Cookie, ToName } */ + if (ei_tracelevel > 0) show_this_msg = 1; + if (ei_decode_pid(header,&index,&msg->from) + || ei_decode_atom(header,&index,msg->cookie) + || ei_decode_atom(header,&index,msg->toname)) + { + erl_errno = EIO; + return -1; + } + + /* actual message is remaining part of headerbuf, plus any unread bytes */ + break; + + case ERL_LINK: /* { LINK, From, To } */ + case ERL_UNLINK: /* { UNLINK, From, To } */ + case ERL_GROUP_LEADER: /* { GROUP_LEADER, From, To } */ + if (ei_tracelevel > 1) show_this_msg = 1; + if (ei_decode_pid(header,&index,&msg->from) + || ei_decode_pid(header,&index,&msg->to)) + { + erl_errno = EIO; + return -1; + } + + break; + + case ERL_EXIT: /* { EXIT, From, To, Reason } */ + case ERL_EXIT2: /* { EXIT2, From, To, Reason } */ + if (ei_tracelevel > 1) show_this_msg = 1; + if (ei_decode_pid(header,&index,&msg->from) + || ei_decode_pid(header,&index,&msg->to)) + { + erl_errno = EIO; + return -1; + } + + break; + + case ERL_SEND_TT: /* { SEND_TT, Cookie, ToPid, TraceToken } */ + if (ei_tracelevel > 0) show_this_msg = 1; + if (ei_decode_atom(header,&index,msg->cookie) + || ei_decode_pid(header,&index,&msg->to) + || ei_decode_trace(header,&index,&msg->token)) + { + erl_errno = EIO; + return -1; + } + + ei_trace(1,&msg->token); /* turn on tracing */ + break; + + case ERL_REG_SEND_TT: /* { REG_SEND_TT, From, Cookie, ToName, TraceToken } */ + if (ei_tracelevel > 0) show_this_msg = 1; + if (ei_decode_pid(header,&index,&msg->from) + || ei_decode_atom(header,&index,msg->cookie) + || ei_decode_atom(header,&index,msg->toname) + || ei_decode_trace(header,&index,&msg->token)) + { + erl_errno = EIO; + return -1; + } + + ei_trace(1,&msg->token); /* turn on tracing */ + break; + + case ERL_EXIT_TT: /* { EXIT_TT, From, To, TraceToken, Reason } */ + case ERL_EXIT2_TT: /* { EXIT2_TT, From, To, TraceToken, Reason } */ + if (ei_tracelevel > 1) show_this_msg = 1; + if (ei_decode_pid(header,&index,&msg->from) + || ei_decode_pid(header,&index,&msg->to) + || ei_decode_trace(header,&index,&msg->token)) + { + erl_errno = EIO; + return -1; + } + + ei_trace(1,&msg->token); /* turn on tracing */ + break; + + case ERL_NODE_LINK: /* { NODE_LINK } */ + if (ei_tracelevel > 1) show_this_msg = 1; + break; + + default: + /* unknown type, just put any remaining bytes into buffer */ + break; + } + + /* actual message is remaining part of headerbuf, plus any unread bytes */ + msglen = len - index; /* message size (payload) */ + remain = len - bytesread; /* bytes left to read */ + + /* if callers buffer is too small, we flush in the rest of the + * message and discard it, unless we know that we can reallocate + * the buffer in which case we do that and read the message. + */ + if (msglen > *bufsz) { + if (staticbufp) { + int sz = EIRECVBUF; + /* flush in rest of packet */ + while (remain > 0) { + if (remain < sz) sz = remain; + if ((i=ei_read_fill_t(fd,header,sz,ms)) <= 0) break; + remain -= i; + } + erl_errno = EMSGSIZE; + return -1; + } + else { + /* Dynamic buffer --- grow it. */ +#ifdef DEBUG + fprintf(stderr, "Growing buffer from %d bytes to %d bytes\n", + *bufsz, msglen); +#endif + if ((mbuf = realloc(*mbufp, msglen)) == NULL) + { + erl_errno = ENOMEM; + return -1; + } + + *mbufp = mbuf; + *bufsz = msglen; + } + } + + /* move remaining bytes to callers buffer */ + memmove(mbuf,header+index,bytesread-index); + + /* let the caller know how big the message is in his buffer */ + *msglenp = msglen; + + /* read the rest of the message into callers buffer */ + if (remain > 0) { + if ((i = ei_read_fill_t(fd,mbuf+bytesread-index,remain,ms)) != remain) { + *msglenp = bytesread-index+1; /* actual bytes in users buffer */ + erl_errno = (i == -2) ? ETIMEDOUT : EIO; + return -1; + } + } + + if (show_this_msg) + ei_show_recmsg(stderr,msg,mbuf); + + /* the caller only sees "untraced" message types */ + /* the trace token is buried in the message struct */ + if (msg->msgtype > 10) msg->msgtype -= 10; + + return msg->msgtype; +} + +int ei_receive_encoded(int fd, char **mbufp, int *bufsz, + erlang_msg *msg, int *msglen) +{ + return ei_recv_internal(fd, mbufp, bufsz, msg, msglen, 0, 0); +} + +int ei_receive_encoded_tmo(int fd, char **mbufp, int *bufsz, erlang_msg *msg, int *msglen, unsigned ms) +{ + return ei_recv_internal(fd, mbufp, bufsz, msg, msglen, 0, ms); +} + diff --git a/lib/erl_interface/src/connect/eirecv.h b/lib/erl_interface/src/connect/eirecv.h new file mode 100644 index 0000000000..b66eaeeb56 --- /dev/null +++ b/lib/erl_interface/src/connect/eirecv.h @@ -0,0 +1,26 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2002-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifndef _EIRECV_H +#define _EIRECV_H + +/* Internal interface */ +int ei_recv_internal(int fd, char **mbufp, int *bufsz, erlang_msg *msg, + int *msglenp, int staticbufp, unsigned ms); + +#endif /* _EIRECV_H */ diff --git a/lib/erl_interface/src/connect/eisend.h b/lib/erl_interface/src/connect/eisend.h new file mode 100644 index 0000000000..d83caf1352 --- /dev/null +++ b/lib/erl_interface/src/connect/eisend.h @@ -0,0 +1,41 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifndef _EISEND_H +#define _EISEND_H + +/* FIXME strange, is this for debugging?! */ +#define EI_HAVE_TIMEOUT 1 + +int ei_send_exit(int fd, const erlang_pid *from, const erlang_pid *to, + const char *msg); +int ei_send_exit_tmo(int fd, const erlang_pid *from, + const erlang_pid *to, + const char *msg, unsigned ms); + +/* FIXME ei_send_*() functions not used */ +#if 0 +int ei_send_link(int fd, const erlang_pid *from, const erlang_pid *to); +int ei_send_unlink(int fd, const erlang_pid *from, const erlang_pid *to); +int ei_send_link_tmo(int fd, const erlang_pid *from, + const erlang_pid *to, unsigned ms); +int ei_send_unlink_tmo(int fd, const erlang_pid *from, + const erlang_pid *to, unsigned ms); +#endif /* Not used */ + +#endif /* _EISEND_H */ diff --git a/lib/erl_interface/src/connect/send.c b/lib/erl_interface/src/connect/send.c new file mode 100644 index 0000000000..cd832db4ea --- /dev/null +++ b/lib/erl_interface/src/connect/send.c @@ -0,0 +1,125 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +#ifdef __WIN32__ + +# include +# include +# include + +#elif VXWORKS + +# include +# include +# include +# include + +#else /* unix */ + +# include +# include +# include + +#endif + +#include + +#include "eidef.h" +#include "eiext.h" +#include "eisend.h" +#include "putget.h" +#include "ei_connect_int.h" +#include "ei_internal.h" +#include "ei_trace.h" +#include "ei_portio.h" +#include "show_msg.h" + + +int ei_send_encoded_tmo(int fd, const erlang_pid *to, + char *msg, int msglen, unsigned ms) +{ + char *s, header[1200]; /* see size calculation below */ + erlang_trace *token = NULL; + int index = 5; /* reserve 5 bytes for control message */ + int res; +#ifdef HAVE_WRITEV + struct iovec v[2]; +#endif + + /* are we tracing? */ + /* check that he can receive trace tokens first */ + if (ei_distversion(fd) > 0) token = ei_trace(0,NULL); + + /* header = SEND, cookie, to max sizes: */ + ei_encode_version(header,&index); /* 1 */ + if (token) { + ei_encode_tuple_header(header,&index,4); /* 2 */ + ei_encode_long(header,&index,ERL_SEND_TT); /* 2 */ + } else { + ei_encode_tuple_header(header,&index,3); + ei_encode_long(header,&index,ERL_SEND); + } + ei_encode_atom(header,&index,ei_getfdcookie(fd)); /* 258 */ + ei_encode_pid(header,&index,to); /* 268 */ + + if (token) ei_encode_trace(header,&index,token); /* 534 */ + + /* control message (precedes header actually) */ + /* length = 1 ('p') + header len + message len */ + s = header; + put32be(s, index + msglen - 4); /* 4 */ + put8(s, ERL_PASS_THROUGH); /* 1 */ + /*** sum: 1070 */ + + /* FIXME incorrect level */ + if (ei_tracelevel > 0) + ei_show_sendmsg(stderr,header,msg); + +#ifdef HAVE_WRITEV + + v[0].iov_base = (char *)header; + v[0].iov_len = index; + v[1].iov_base = (char *)msg; + v[1].iov_len = msglen; + + if ((res = ei_writev_fill_t(fd,v,2,ms)) != index+msglen) { + erl_errno = (res == -2) ? ETIMEDOUT : EIO; + return -1; + } + +#else /* !HAVE_WRITEV */ + + if ((res = ei_write_fill_t(fd,header,index,ms)) != index) { + erl_errno = (res == -2) ? ETIMEDOUT : EIO; + return -1; + } + if ((res = ei_write_fill_t(fd,msg,msglen,ms)) != msglen) { + erl_errno = (res == -2) ? ETIMEDOUT : EIO; + return -1; + } + +#endif /* !HAVE_WRITEV */ + + return 0; +} + +int ei_send_encoded(int fd, const erlang_pid *to, char *msg, int msglen) +{ + return ei_send_encoded_tmo(fd, to, msg, msglen, 0); +} diff --git a/lib/erl_interface/src/connect/send_exit.c b/lib/erl_interface/src/connect/send_exit.c new file mode 100644 index 0000000000..098797c96d --- /dev/null +++ b/lib/erl_interface/src/connect/send_exit.c @@ -0,0 +1,101 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifdef __WIN32__ +# include +# include +# include +#else /* Unix/VxWorks */ +#include +#endif + +#include +#include +#include "eidef.h" +#include "eiext.h" +#include "eisend.h" +#include "ei_connect_int.h" +#include "ei_trace.h" +#include "ei_internal.h" +#include "putget.h" +#include "ei_portio.h" +#include "show_msg.h" + +/* use this to break a link */ +int ei_send_exit(int fd, const erlang_pid *from, + const erlang_pid *to, const char *reason) +{ + return ei_send_exit_tmo(fd,from,to,reason,0); +} + + +int ei_send_exit_tmo(int fd, const erlang_pid *from, const erlang_pid *to, + const char *reason, unsigned ms) +{ + char sbuf[EISMALLBUF]; + erlang_trace *token = NULL; + char *dbuf = NULL; + char *msgbuf; + char *s; + int index = 0; + int len = strlen(reason) + 1080; /* see below */ + + if (len > EISMALLBUF) + if (!(dbuf = malloc(len))) + return -1; + msgbuf = (dbuf ? dbuf : sbuf); + + + /* are we tracing? */ + /* check that he can receive trace tokens first */ + if (ei_distversion(fd) > 0) token = ei_trace(0,NULL); + + index = 5; /* max sizes: */ + ei_encode_version(msgbuf,&index); /* 1 */ + if (token) { + ei_encode_tuple_header(msgbuf,&index,5); /* 2 */ + ei_encode_long(msgbuf,&index,ERL_EXIT_TT); /* 2 */ + } + else { + ei_encode_tuple_header(msgbuf,&index,4); + ei_encode_long(msgbuf,&index,ERL_EXIT); + } + ei_encode_pid(msgbuf,&index,from); /* 268 */ + ei_encode_pid(msgbuf,&index,to); /* 268 */ + + if (token) ei_encode_trace(msgbuf,&index,token); /* 534 */ + + /* Reason */ + ei_encode_string(msgbuf,&index,reason); /* len */ + + /* 5 byte header missing */ + s = msgbuf; + put32be(s, index - 4); /* 4 */ + put8(s, ERL_PASS_THROUGH); /* 1 */ + /*** sum: len + 1080 */ + /* FIXME incorrect level */ + if (ei_tracelevel > 1) + ei_show_sendmsg(stderr,msgbuf,NULL); + + ei_write_fill_t(fd,msgbuf,index,ms); + /* FIXME ignore timeout etc? erl_errno?! */ + + if (dbuf) free(dbuf); + return 0; +} + diff --git a/lib/erl_interface/src/connect/send_reg.c b/lib/erl_interface/src/connect/send_reg.c new file mode 100644 index 0000000000..8f0e40309c --- /dev/null +++ b/lib/erl_interface/src/connect/send_reg.c @@ -0,0 +1,122 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifdef __WIN32__ +#include +#include +#include + +#elif VXWORKS +#include +#include + +#else /* unix */ +#include +#include +#include +#endif + +#include + +#include "eidef.h" +#include "eiext.h" +#include "eisend.h" +#include "putget.h" +#include "ei_connect_int.h" +#include "ei_internal.h" +#include "ei_trace.h" +#include "ei_portio.h" +#include "show_msg.h" + +int ei_send_reg_encoded_tmo(int fd, const erlang_pid *from, + const char *to, char *msg, int msglen, + unsigned ms) +{ + char *s, header[1400]; /* see size calculation below */ + erlang_trace *token = NULL; + int index = 5; /* reserve 5 bytes for control message */ + int res; + +#ifdef HAVE_WRITEV + struct iovec v[2]; +#endif + + /* are we tracing? */ + /* check that he can receive trace tokens first */ + if (ei_distversion(fd) > 0) + token = ei_trace(0,NULL); + + /* header = REG_SEND, from, cookie, toname max sizes: */ + ei_encode_version(header,&index); /* 1 */ + if (token) { + ei_encode_tuple_header(header,&index,5); /* 2 */ + ei_encode_long(header,&index,ERL_REG_SEND_TT); /* 2 */ + } else { + ei_encode_tuple_header(header,&index,4); + ei_encode_long(header,&index,ERL_REG_SEND); + } + ei_encode_pid(header, &index, from); /* 268 */ + ei_encode_atom(header, &index, ei_getfdcookie(fd)); /* 258 */ + ei_encode_atom(header, &index, to); /* 268 */ + + if (token) ei_encode_trace(header,&index,token); /* 534 */ + + /* control message (precedes header actually) */ + /* length = 1 ('p') + header len + message len */ + s = header; + put32be(s, index + msglen - 4); /* 4 */ + put8(s, ERL_PASS_THROUGH); /* 1 */ + /*** sum: 1336 */ + /* FIXME incorrect level.... */ + if (ei_tracelevel > 0) + ei_show_sendmsg(stderr,header,msg); + +#ifdef HAVE_WRITEV + + v[0].iov_base = (char *)header; + v[0].iov_len = index; + v[1].iov_base = (char *)msg; + v[1].iov_len = msglen; + + if ((res = ei_writev_fill_t(fd,v,2,ms)) != index+msglen) { + erl_errno = (res == -2) ? ETIMEDOUT : EIO; + return -1; + } +#else + + /* no writev() */ + if ((res = ei_write_fill_t(fd,header,index,ms)) != index) { + erl_errno = (res == -2) ? ETIMEDOUT : EIO; + return -1; + } + if ((res = ei_write_fill_t(fd,msg,msglen,ms)) != msglen) { + erl_errno = (res == -2) ? ETIMEDOUT : EIO; + return -1; + } +#endif + + return 0; +} + + +int ei_send_reg_encoded(int fd, const erlang_pid *from, const char *to, + char *msg, int msglen) +{ + return ei_send_reg_encoded_tmo(fd, from, to, msg, msglen, 0); +} + diff --git a/lib/erl_interface/src/decode/decode_atom.c b/lib/erl_interface/src/decode/decode_atom.c new file mode 100644 index 0000000000..b247bd4e17 --- /dev/null +++ b/lib/erl_interface/src/decode/decode_atom.c @@ -0,0 +1,42 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +int ei_decode_atom(const char *buf, int *index, char *p) +{ + const char *s = buf + *index; + const char *s0 = s; + int len; + + if (get8(s) != ERL_ATOM_EXT) return -1; + + len = get16be(s); + + if (p) { + memmove(p,s,len); + p[len] = (char)0; + } + s += len; + *index += s-s0; + + return 0; +} diff --git a/lib/erl_interface/src/decode/decode_big.c b/lib/erl_interface/src/decode/decode_big.c new file mode 100644 index 0000000000..efe9c6e5d9 --- /dev/null +++ b/lib/erl_interface/src/decode/decode_big.c @@ -0,0 +1,331 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2002-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include +#include + +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +int ei_decode_big(const char *buf, int *index, erlang_big *b) { + unsigned int digit_bytes; + const unsigned char *s = (unsigned char*) buf + *index; + const unsigned char *s0 = s; + + switch ( get8(s) ) { + case ERL_SMALL_BIG_EXT: + digit_bytes = get8(s); + break; + case ERL_LARGE_BIG_EXT: + digit_bytes = get32be(s); + break; + default: + return -1; + } + if ( b ) { + unsigned short *dt = b->digits; + unsigned int n = (digit_bytes+1)/2; + int i; + + if ( digit_bytes != b->arity ) { + return -1; + } + + b->is_neg = get8(s); + + for (i = 0; i < n; ++i) { + dt[i] = s[i*2]; + if ((i*2 + 1) < digit_bytes) { + dt[i] |= ((unsigned short) s[(i*2)+1]) << 8; + } + } + } else { + s++; /* skip sign byte */ + } + + s += digit_bytes; + + *index += s-s0; + + return 0; +} + +erlang_big *ei_alloc_big(unsigned int digit_bytes) { + erlang_big *b; + unsigned int n = (digit_bytes+1)/2; + + if ( (b = malloc(sizeof(erlang_big))) == NULL) return NULL; + memset(b,(char)0,sizeof(erlang_big)); + if ( (b->digits = malloc(2*n)) == NULL) { + free(b); + return 0; + } + + b->arity = digit_bytes; + memset(b->digits,(char)0, 2*n); + return b; +} + +void ei_free_big(erlang_big *b) +{ + if (!b) return; + if (b->digits) free(b->digits); + free(b); +} + +/* big compare functions */ + +typedef unsigned short Uint16; +typedef unsigned int Uint; + +typedef Uint16 digit_t; +typedef Uint dsize_t; + +static int I_comp(digit_t *x, dsize_t xl, digit_t *y, dsize_t yl) +{ + if (xlyl) { + return 1; + } else { + if ( x == y ) return 0; + x += (xl-1); + y += (yl-1); + while( (xl>0) && (*x==*y) ) { + x--; + y--; + xl--; + } + if ( xl == 0 ) return 0; + return ( *x < *y ) ? -1 : 1; + } +} + +int ei_big_comp(erlang_big *x, erlang_big *y) +{ + if ( x->is_neg == y->is_neg ) { + int c = I_comp(x->digits,(x->arity+1)/2,y->digits,(y->arity+1)/2); + if ( x->is_neg ) + return -c; + else + return c; + } else { + return x->is_neg ? -1 : 1; + } +} + +#define D_EXP 16 +#define D_BASE (1<> D_EXP)) + +/* + * Handling of floating point exceptions. + */ + +#if defined(VXWORKS) && CPU == PPC860 +#undef NO_FPE_SIGNALS +#define NO_FPE_SIGNALS 1 +#undef INLINED_FP_CONVERSION +#define INLINED_FP_CONVERSION 1 +#endif + +#ifdef USE_ISINF_ISNAN /* simulate finite() */ +# define finite(f) (!isinf(f) && !isnan(f)) +# define HAVE_FINITE +#endif + +#ifdef NO_FPE_SIGNALS +# define ERTS_FP_CHECK_INIT() do {} while (0) +# define ERTS_FP_ERROR(f, Action) if (!finite(f)) { Action; } else {} +# define ERTS_SAVE_FP_EXCEPTION() +# define ERTS_RESTORE_FP_EXCEPTION() +#else +/* extern volatile int erl_fp_exception; */ +static volatile int erl_fp_exception; +# define ERTS_FP_CHECK_INIT() do {erl_fp_exception = 0;} while (0) +# if defined(__i386__) && defined(__GNUC__) +/* extern void erts_restore_x87(void); */ + +static void unmask_fpe(void) +{ + unsigned short cw; + __asm__ __volatile__("fstcw %0" : "=m"(cw)); + cw &= ~(0x01|0x04|0x08); /* unmask IM, ZM, OM */ + __asm__ __volatile__("fldcw %0" : : "m"(cw)); +} + +static void erts_restore_x87(void) +{ + __asm__ __volatile__("fninit"); + unmask_fpe(); +} + +static int erts_check_x87(double f) +{ + __asm__ __volatile__("fwait" : "=m"(erl_fp_exception) : "m"(f)); + if( !erl_fp_exception ) + return 0; + erts_restore_x87(); + return 1; +} +# define ERTS_FP_ERROR(f, Action) do { if( erts_check_x87((f)) ) { Action; } } while (0) +# else +# define ERTS_FP_ERROR(f, Action) if (erl_fp_exception) { Action; } else {} +# endif +# define ERTS_SAVE_FP_EXCEPTION() int old_erl_fp_exception = erl_fp_exception +# define ERTS_RESTORE_FP_EXCEPTION() \ + do {erl_fp_exception = old_erl_fp_exception;} while (0) +#endif + + +#ifdef INLINED_FP_CONVERSION +static void join(unsigned d_split[4], unsigned *d) +{ + d[0] = (d_split[0] << 31) | /* Sign bit */ + ((d_split[1] & 0x7FFU) << 20) | /* Exponent */ + (d_split[2] & 0xFFFFFU); /* Mantissa MS bits */ + d[1] = d_split[3]; /* Mantissa LS bits */ +} + +static int blength(unsigned long l) +{ + int i; + for(i = 0; l; ++i) + l >>= 1; + return i; +} + +static int bblength(erlang_big *b) +{ + unsigned int wholebytes = (b->arity+1)/2; + digit_t *dp = b->digits; + + while(wholebytes > 0 && dp[--wholebytes] == 0U) + ; + + return (wholebytes * sizeof(digit_t) * 8) + blength(dp[wholebytes]); +} + +static unsigned long bindex(erlang_big *b, int ndx) { + digit_t *dp = b->digits; + int skipdigits; + int dnum; + + if (ndx < 0) + return 0; + + skipdigits = ndx / (sizeof(digit_t) * 8); + dnum = ndx % (sizeof(digit_t) * 8); + return !!(dp[skipdigits] & (1UL << dnum)); +} + + +#endif + + +int ei_big_to_double(erlang_big *b, double *resp) +{ +#ifdef INLINED_FP_CONVERSION + unsigned d_split[4]; + unsigned *uresp = (unsigned *) resp; + unsigned len = bblength(b); + int i; + unsigned long msm = 0, lsm = 0; + + /* OK, this is not the most efficient conversion in the world, especially + not the bit-by-bit copying to the mantissa.... Simple, working and + only for vxworks ppc860 where no sane person would use floating + point anyway, eh? /Patrik */ + + if (!len) { + memset(d_split,0,sizeof(d_split)); /* 0 */ + } else { + --len; + if (len > 1023) { /* Infinite */ + d_split[1] = 2047; + d_split[2] = d_split[3] = 0; + } else { + d_split[1] = 1023 + len; + --len; /* skip the implicit binary 1. */ + for (i = 0; i < 20; ++i, --len) { + msm <<= 1; + msm |= bindex(b,len); + } + for (i = 0; i < 32; ++i, --len) { + lsm <<= 1; + lsm |= bindex(b,len); + } + d_split[2] = msm; + d_split[3] = lsm; + } + } + d_split[0] = (unsigned) !!(b->is_neg); + join(d_split,uresp); + return 0; +#else + double d = 0.0; + double d_base = 1.0; + + digit_t* s = (digit_t *)b->digits; + dsize_t xl = (b->arity + 1)/2; + short xsgn = b->is_neg; + ERTS_SAVE_FP_EXCEPTION(); + + ERTS_FP_CHECK_INIT(); + while(xl--) { + digit_t ds = *s; + double d_next = ds * d_base + d; + + ERTS_FP_ERROR(d_next, ERTS_RESTORE_FP_EXCEPTION(); {fprintf(stderr,"\r\n### fp exception ###\r\n"); return -1;}); + s++; + d = d_next; + d_base *= D_BASE; + } + + /* + * Note: The last multiplication in the loop could trigger an exception, + * which we will ignore because the result will never be used. + */ + + *resp = xsgn ? -d : d; + ERTS_FP_ERROR(*resp,;); + ERTS_RESTORE_FP_EXCEPTION(); + return 0; +#endif +} + +int ei_small_to_big(int s, erlang_big *b) +{ + digit_t *d; + unsigned int n = (b->arity+1)/2; + + if ( n < 2 ) return -1; + + b->is_neg = ( s < 0 ); + d = (digit_t *)b->digits; + d[0] = DLOW(s); + d[1] = DHIGH(s); + + return 0; +} diff --git a/lib/erl_interface/src/decode/decode_bignum.c b/lib/erl_interface/src/decode/decode_bignum.c new file mode 100644 index 0000000000..f10052f9fe --- /dev/null +++ b/lib/erl_interface/src/decode/decode_bignum.c @@ -0,0 +1,75 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2002-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +#include "eidef.h" + +#if defined(HAVE_GMP_H) && defined(HAVE_LIBGMP) + +#include + +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + + +int ei_decode_bignum(const char *buf, int *index, mpz_t obj) +{ + const char *s = buf + *index; + const char *s0 = s; + int arity; + int sign; + unsigned long n; + + switch (get8(s)) { + case ERL_SMALL_INTEGER_EXT: + n = get8(s); + mpz_set_ui(obj, n); + break; + + case ERL_INTEGER_EXT: + n = get32be(s); + mpz_set_ui(obj, n); + break; + + case ERL_SMALL_BIG_EXT: + arity = get8(s); + goto decode_bytes; + + case ERL_LARGE_BIG_EXT: + arity = get32be(s); + decode_bytes: + sign = get8(s); + mpz_import(obj, arity, -1, 1, 0, 0, s); + s += arity; + if (sign) { + mpz_neg(obj, obj); + } + + break; + + default: + return -1; + } + + *index += s-s0; + + return 0; +} + +#endif /* HAVE_GMP_H && HAVE_LIBGMP */ diff --git a/lib/erl_interface/src/decode/decode_binary.c b/lib/erl_interface/src/decode/decode_binary.c new file mode 100644 index 0000000000..713e621e60 --- /dev/null +++ b/lib/erl_interface/src/decode/decode_binary.c @@ -0,0 +1,42 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +int ei_decode_binary(const char *buf, int *index, void *p, long *lenp) +{ + const char *s = buf + *index; + const char *s0 = s; + long len; + + if (get8(s) != ERL_BINARY_EXT) return -1; + + len = get32be(s); + if (p) memmove(p,s,len); + s += len; + + if (lenp) *lenp = len; + *index += s-s0; + + return 0; +} + + diff --git a/lib/erl_interface/src/decode/decode_boolean.c b/lib/erl_interface/src/decode/decode_boolean.c new file mode 100644 index 0000000000..9fd09c63f1 --- /dev/null +++ b/lib/erl_interface/src/decode/decode_boolean.c @@ -0,0 +1,57 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +/* c non-zero -> erlang "true" atom, otherwise "false" */ +int ei_decode_boolean(const char *buf, int *index, int *p) +{ + const char *s = buf + *index; + const char *s0 = s; + int len; + int t; + + if (get8(s) != ERL_ATOM_EXT) return -1; + + len = get16be(s); + + switch (len) { + case 4: + /* typecast makes ansi happy */ + if (strncmp((char*)s,"true",4)) return -1; + t = 1; + break; + + case 5: + if (strncmp((char*)s,"false",5)) return -1; + t = 0; + break; + + default: + return -1; + } + + s += len; + if (p) *p = t; + *index += s-s0; + + return 0; +} diff --git a/lib/erl_interface/src/decode/decode_char.c b/lib/erl_interface/src/decode/decode_char.c new file mode 100644 index 0000000000..0f9b3f6cff --- /dev/null +++ b/lib/erl_interface/src/decode/decode_char.c @@ -0,0 +1,69 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +int ei_decode_char(const char *buf, int *index, char *p) +{ + const char *s = buf + *index; + const char *s0 = s; + long n; + int arity; + + switch (get8(s)) { + case ERL_SMALL_INTEGER_EXT: + n = get8(s); + break; + + case ERL_INTEGER_EXT: + n = get32be(s); + if (n < 0 || n > 255) + return -1; + break; + + case ERL_SMALL_BIG_EXT: + arity = get8(s); + goto decode_big; + case ERL_LARGE_BIG_EXT: + arity = get32be(s); + decode_big: + { + int sign = get8(s); + int i; + + if (sign) return -1; /* Char is always > 0 */ + + n = get8(s); /* First byte is our value */ + + for (i = 1; i < arity; i++) { + if (*(s++) != 0) return -1; /* All but first byte have to be 0 */ + } + } + break; + + default: + return -1; + } + + if (p) *p = n; + *index += s-s0; + + return 0; +} diff --git a/lib/erl_interface/src/decode/decode_double.c b/lib/erl_interface/src/decode/decode_double.c new file mode 100644 index 0000000000..66dbe474ec --- /dev/null +++ b/lib/erl_interface/src/decode/decode_double.c @@ -0,0 +1,39 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + + +int ei_decode_double(const char *buf, int *index, double *p) +{ + const char *s = buf + *index; + const char *s0 = s; + double f; + + if (get8(s) != ERL_FLOAT_EXT) return -1; + + if (sscanf(s, "%lf", &f) != 1) return -1; + + s += 31; + if (p) *p = f; + *index += s-s0; + return 0; +} diff --git a/lib/erl_interface/src/decode/decode_fun.c b/lib/erl_interface/src/decode/decode_fun.c new file mode 100644 index 0000000000..64fb9e86d8 --- /dev/null +++ b/lib/erl_interface/src/decode/decode_fun.c @@ -0,0 +1,123 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include +#include + +#include "eidef.h" +#include "eiext.h" +#include "ei_malloc.h" +#include "decode_skip.h" +#include "putget.h" + +int ei_decode_fun(const char *buf, int *index, erlang_fun *p) +{ + const char *s = buf + *index; + const char *s0 = s; + int i, ix, ix0, n; + + switch (get8(s)) { + case ERL_FUN_EXT: + /* mark as old (R7 and older) external fun */ + if (p != NULL) p->arity = -1; + /* first number of free vars (environment) */ + n = get32be(s); + /* then the pid */ + ix = 0; + if (ei_decode_pid(s, &ix, (p == NULL ? (erlang_pid*)NULL : &p->pid)) < 0) + return -1; + /* then the module (atom) */ + if (ei_decode_atom(s, &ix, (p == NULL ? (char*)NULL : p->module)) < 0) + return -1; + /* then the index */ + if (ei_decode_long(s, &ix, (p == NULL ? (long*)NULL : &p->index)) < 0) + return -1; + /* then the uniq */ + if (ei_decode_long(s, &ix, (p == NULL ? (long*)NULL : &p->uniq)) < 0) + return -1; + /* finally the free vars */ + ix0 = ix; + for (i = 0; i < n; ++i) { + if (ei_skip_term(s, &ix) < 0) + return -1; + } + if (p != NULL) { + p->n_free_vars = n; + p->free_var_len = ix - ix0; + p->free_vars = ei_malloc(ix - ix0); + if (!(p->free_vars)) return -1; + memcpy(p->free_vars, s + ix0, ix - ix0); + } + s += ix; + *index += s-s0; + return 0; + break; + case ERL_NEW_FUN_EXT: + /* first total size */ + n = get32be(s); + /* then the arity */ + i = get8(s); + if (p != NULL) p->arity = i; + /* then md5 */ + if (p != NULL) memcpy(p->md5, s, 16); + s += 16; + /* then index */ + i = get32be(s); + if (p != NULL) p->index = i; + /* then the number of free vars (environment) */ + i = get32be(s); + if (p != NULL) p->n_free_vars = i; + /* then the module (atom) */ + ix = 0; + if (ei_decode_atom(s, &ix, (p == NULL ? (char*)NULL : p->module)) < 0) + return -1; + /* then the old_index */ + if (ei_decode_long(s, &ix, (p == NULL ? (long*)NULL : &p->old_index)) < 0) + return -1; + /* then the old_uniq */ + if (ei_decode_long(s, &ix, (p == NULL ? (long*)NULL : &p->uniq)) < 0) + return -1; + /* the the pid */ + if (ei_decode_pid(s, &ix, (p == NULL ? (erlang_pid*)NULL : &p->pid)) < 0) + return -1; + /* finally the free vars */ + s += ix; + n = n - (s - s0) + 1; + if (n < 0) return -1; + if (p != NULL) { + p->free_var_len = n; + if (n > 0) { + p->free_vars = malloc(n); + if (!(p->free_vars)) return -1; + memcpy(p->free_vars, s, n); + } + } + s += n; + *index += s-s0; + return 0; + break; + default: + return -1; + } +} + +void free_fun(erlang_fun* f) +{ + if (f->free_var_len > 0) + ei_free(f->free_vars); +} diff --git a/lib/erl_interface/src/decode/decode_intlist.c b/lib/erl_interface/src/decode/decode_intlist.c new file mode 100644 index 0000000000..65552a4ed4 --- /dev/null +++ b/lib/erl_interface/src/decode/decode_intlist.c @@ -0,0 +1,82 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* since Erlang sends int-lists as either lists or strings, this + * function can be used when the caller needs an array but doesn't + * know which type to decode + */ +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +int ei_decode_intlist(const char *buf, int *index, long *a, int *count) +{ + const unsigned char *s = (const unsigned char *)(buf + *index); + const unsigned char *s0 = s; + int idx; + int len; + int i; + + switch (get8(s)) { + case ERL_STRING_EXT: + len = get16be(s); + + /* transfer and cast chars one at a time into array */ + if (a) { + for (i=0; i 0x80000000UL) { + return -1; + } + n = -((long)u); + } else { + if (u > 0x7FFFFFFF) { + return -1; + } + n = (long)u; + } + } + break; + + default: + return -1; + } + + if (p) *p = n; + *index += s-s0; + + return 0; +} +#endif /* !EI_64BIT */ diff --git a/lib/erl_interface/src/decode/decode_longlong.c b/lib/erl_interface/src/decode/decode_longlong.c new file mode 100644 index 0000000000..8ec9f76995 --- /dev/null +++ b/lib/erl_interface/src/decode/decode_longlong.c @@ -0,0 +1,100 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2002-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +#ifdef EI_64BIT +int ei_decode_long(const char *buf, int *index, long *p) +{ + return ei_decode_longlong(buf, index, (EI_LONGLONG *)p); +} +#endif + +#ifdef _MSC_VER +#define MAX_TO_NEGATE 0x8000000000000000Ui64 +#define MAX_TO_NOT_NEGATE 0x7FFFFFFFFFFFFFFFUi64 +#else +#define MAX_TO_NEGATE 0x8000000000000000ULL +#define MAX_TO_NOT_NEGATE 0x7FFFFFFFFFFFFFFFULL +#endif + +int ei_decode_longlong(const char *buf, int *index, EI_LONGLONG *p) +{ + const char *s = buf + *index; + const char *s0 = s; + EI_LONGLONG n; + int arity; + + switch (get8(s)) { + case ERL_SMALL_INTEGER_EXT: + n = get8(s); + break; + + case ERL_INTEGER_EXT: + n = get32be(s); + break; + + case ERL_SMALL_BIG_EXT: + arity = get8(s); + goto decode_big; + + case ERL_LARGE_BIG_EXT: + arity = get32be(s); + + decode_big: + { + int sign = get8(s); + int i; + EI_ULONGLONG u = 0; + + /* Little Endian, and n always positive, except for LONG_MIN */ + for (i = 0; i < arity; i++) { + if (i < 8) { + /* Use ULONGLONG not to get a negative integer if > 127 */ + u |= ((EI_ULONGLONG)get8(s)) << (i * 8); + } else if (get8(s) != 0) { + return -1; /* All but first byte have to be 0 */ + } + } + + /* check for overflow */ + if (sign) { + if (u > MAX_TO_NEGATE) { + return -1; + } + n = -((EI_LONGLONG) u); + } else { + if (u > MAX_TO_NOT_NEGATE) { + return -1; + } + n = (EI_LONGLONG) u; + } + } + break; + + default: + return -1; + } + + if (p) *p = n; + *index += s-s0; + + return 0; +} diff --git a/lib/erl_interface/src/decode/decode_pid.c b/lib/erl_interface/src/decode/decode_pid.c new file mode 100644 index 0000000000..5f2aec3b44 --- /dev/null +++ b/lib/erl_interface/src/decode/decode_pid.c @@ -0,0 +1,54 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +int ei_decode_pid(const char *buf, int *index, erlang_pid *p) +{ + const char *s = buf + *index; + const char *s0 = s; + int len; + + if (get8(s) != ERL_PID_EXT) return -1; + + /* first the nodename */ + if (get8(s) != ERL_ATOM_EXT) return -1; + + len = get16be(s); + + if (p) { + memmove(p->node, s, len); + p->node[len] = (char)0; + } + s += len; + + /* now the numbers: num (4), serial (4), creation (1) */ + if (p) { + p->num = get32be(s) & 0x7fff; /* 15 bits */ + p->serial = get32be(s) & 0x1fff; /* 13 bits */ + p->creation = get8(s) & 0x03; /* 2 bits */ + } + else s+= 9; + + *index += s-s0; + + return 0; +} diff --git a/lib/erl_interface/src/decode/decode_port.c b/lib/erl_interface/src/decode/decode_port.c new file mode 100644 index 0000000000..7fb7d8d414 --- /dev/null +++ b/lib/erl_interface/src/decode/decode_port.c @@ -0,0 +1,53 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +int ei_decode_port(const char *buf, int *index, erlang_port *p) +{ + const char *s = buf + *index; + const char *s0 = s; + int len; + + if (get8(s) != ERL_PORT_EXT) return -1; + + /* first the nodename */ + if (get8(s) != ERL_ATOM_EXT) return -1; + + len = get16be(s); + + if (p) { + memmove(p->node, s, len); + p->node[len] = (char)0; + } + s += len; + + /* now the numbers: num (4), creation (1) */ + if (p) { + p->id = get32be(s) & 0x0fffffff /* 28 bits */; + p->creation = get8(s) & 0x03; + } + else s += 5; + + *index += s-s0; + + return 0; +} diff --git a/lib/erl_interface/src/decode/decode_ref.c b/lib/erl_interface/src/decode/decode_ref.c new file mode 100644 index 0000000000..6fc2cd6533 --- /dev/null +++ b/lib/erl_interface/src/decode/decode_ref.c @@ -0,0 +1,94 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +int ei_decode_ref(const char *buf, int *index, erlang_ref *p) +{ + const char *s = buf + *index; + const char *s0 = s; + int count, len, i; + + switch (get8(s)) { + case ERL_REFERENCE_EXT: + + /* first the nodename */ + if (get8(s) != ERL_ATOM_EXT) return -1; + + len = get16be(s); + + if (p) { + memmove(p->node, s, len); + p->node[len] = (char)0; + } + s += len; + + /* now the numbers: num (4), creation (1) */ + if (p) { + p->n[0] = get32be(s); + p->len = 1; + p->creation = get8(s) & 0x03; + } + else s += 5; + + *index += s-s0; + + return 0; + break; + + case ERL_NEW_REFERENCE_EXT: + /* first the integer count */ + count = get16be(s); + if (p) p->len = count; + + /* then the nodename */ + if (get8(s) != ERL_ATOM_EXT) return -1; + len = get16be(s); + + if (p) { + memmove(p->node, s, len); + p->node[len] = (char)0; + } + s += len; + + /* creation */ + if (p) { + p->creation = get8(s) & 0x03; + } + else s += 1; + + /* finally the id integers */ + if (p) { + for (i = 0; (in[i] = get32be(s); + } + } + else s += 4 * count; + + *index += s-s0; + + return 0; + break; + + default: + return -1; + } +} diff --git a/lib/erl_interface/src/decode/decode_skip.c b/lib/erl_interface/src/decode/decode_skip.c new file mode 100644 index 0000000000..2fc68a3601 --- /dev/null +++ b/lib/erl_interface/src/decode/decode_skip.c @@ -0,0 +1,90 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2002-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include "eidef.h" +#include "eiext.h" +#include "decode_skip.h" + +int ei_skip_term(const char* buf, int* index) +{ + int i, n, ty; + + /* ASSERT(ep != NULL); */ + + ei_get_type_internal(buf, index, &ty, &n); + switch (ty) { + case ERL_ATOM_EXT: + /* FIXME: what if some weird locale is in use? */ + if (ei_decode_atom(buf, index, NULL) < 0) return -1; + break; + case ERL_PID_EXT: + if (ei_decode_pid(buf, index, NULL) < 0) return -1; + break; + case ERL_PORT_EXT: + if (ei_decode_port(buf, index, NULL) < 0) return -1; + break; + case ERL_NEW_REFERENCE_EXT: + case ERL_REFERENCE_EXT: + if (ei_decode_ref(buf, index, NULL) < 0) return -1; + break; + case ERL_NIL_EXT: + if (ei_decode_list_header(buf, index, &n) < 0) return -1; + break; + case ERL_LIST_EXT: + if (ei_decode_list_header(buf, index, &n) < 0) return -1; + for (i = 0; i < n; ++i) + ei_skip_term(buf, index); + if (ei_get_type_internal(buf, index, &ty, &n) < 0) return -1; + if (ty != ERL_NIL_EXT) + ei_skip_term(buf, index); + else + if (ei_decode_list_header(buf, index, &n) < 0) return -1; + break; + case ERL_STRING_EXT: + if (ei_decode_string(buf, index, NULL) < 0) return -1; + break; + case ERL_SMALL_TUPLE_EXT: + case ERL_LARGE_TUPLE_EXT: + if (ei_decode_tuple_header(buf, index, &n) < 0) return -1; + for (i = 0; i < n; ++i) + ei_skip_term(buf, index); + break; + case ERL_BINARY_EXT: + if (ei_decode_binary(buf, index, NULL, NULL) < 0) + return -1; + break; + case ERL_SMALL_INTEGER_EXT: + case ERL_INTEGER_EXT: + if (ei_decode_long(buf, index, NULL) < 0) return -1; + break; + case ERL_SMALL_BIG_EXT: + case ERL_LARGE_BIG_EXT: + if (ei_decode_big(buf, index, NULL) < 0) return -1; + break; + case ERL_FLOAT_EXT: + if (ei_decode_double(buf, index, NULL) < 0) return -1; + break; + case ERL_FUN_EXT: + if (ei_decode_fun(buf, index, NULL) < 0) return -1; + break; + default: + return -1; + } + return 0; +} + diff --git a/lib/erl_interface/src/decode/decode_skip.h b/lib/erl_interface/src/decode/decode_skip.h new file mode 100644 index 0000000000..b6c7b09fe4 --- /dev/null +++ b/lib/erl_interface/src/decode/decode_skip.h @@ -0,0 +1,27 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2002-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Function: + * ei_print_term to print out a binary coded term + */ + +#ifndef _DECODE_SKIP_H +#define _DECODE_SKIP_H + +#endif /* _DECODE_SKIP_H */ diff --git a/lib/erl_interface/src/decode/decode_string.c b/lib/erl_interface/src/decode/decode_string.c new file mode 100644 index 0000000000..bcbdca0438 --- /dev/null +++ b/lib/erl_interface/src/decode/decode_string.c @@ -0,0 +1,85 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +/* FIXME fix or document that special requirements on + the in data.... */ + +int ei_decode_string(const char *buf, int *index, char *p) +{ + const char *s = buf + *index; + const char *s0 = s; + int len; + int i; + int etype; + + switch (get8(s)) { + case ERL_STRING_EXT: + len = get16be(s); + + if (p) { + memmove(p,s,len); + p[len] = (char)0; + } + s += len; + break; + + case ERL_LIST_EXT: + /* Really long strings are represented as lists of small integers. + * We don't know in advance if the whole list is small integers, + * but we decode as much as we can, exiting early if we run into a + * non-character in the list. + */ + len = get32be(s); + if (p) { + for (i=0; iflags) + || ei_decode_long(buf, &tindex, &p->label) + || ei_decode_long(buf, &tindex, &p->serial) + || ei_decode_pid( buf, &tindex, &p->from) + || ei_decode_long(buf, &tindex, &p->prev)) return -1; + + /* index is updated by the functions we called */ + + *index = tindex; + + return 0; +} diff --git a/lib/erl_interface/src/decode/decode_tuple_header.c b/lib/erl_interface/src/decode/decode_tuple_header.c new file mode 100644 index 0000000000..c0ba14ea47 --- /dev/null +++ b/lib/erl_interface/src/decode/decode_tuple_header.c @@ -0,0 +1,47 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +int ei_decode_tuple_header(const char *buf, int *index, int *arity) +{ + const char *s = buf + *index; + const char *s0 = s; + int i; + + switch ((i=get8(s))) { + case ERL_SMALL_TUPLE_EXT: + if (arity) *arity = get8(s); + else s++; + break; + + case ERL_LARGE_TUPLE_EXT: + if (arity) *arity = get32be(s); + else s += 4; + break; + + default: + return -1; + } + + *index += s-s0; + + return 0; +} diff --git a/lib/erl_interface/src/decode/decode_ulong.c b/lib/erl_interface/src/decode/decode_ulong.c new file mode 100644 index 0000000000..dcf3703be7 --- /dev/null +++ b/lib/erl_interface/src/decode/decode_ulong.c @@ -0,0 +1,78 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +#ifndef EI_64BIT +int ei_decode_ulong(const char *buf, int *index, unsigned long *p) +{ + const char *s = buf + *index; + const char *s0 = s; + unsigned long n; + long sn; + int arity; + + switch (get8(s)) { + case ERL_SMALL_INTEGER_EXT: + n = get8(s); + break; + + case ERL_INTEGER_EXT: + sn = get32be(s); + if (sn < 0) return -1; + n = (unsigned long)sn; + break; + + case ERL_SMALL_BIG_EXT: + arity = get8(s); + goto decode_big; + + case ERL_LARGE_BIG_EXT: + arity = get32be(s); + + decode_big: + { + int sign = get8(s); + int i; + n = 0; + + if (sign) return -1; + + /* Little Endian, up to four bytes always fit into unsigned long */ + for (i = 0; i < arity; i++) { + if (i < 4) { + n |= get8(s) << (i * 8); + } else if (get8(s) != 0) { + return -1; /* All but first byte have to be 0 */ + } + } + } + break; + + default: + return -1; + } + + if (p) *p = (unsigned long)n; + *index += s-s0; + + return 0; +} +#endif /* EI_64BIT */ diff --git a/lib/erl_interface/src/decode/decode_ulonglong.c b/lib/erl_interface/src/decode/decode_ulonglong.c new file mode 100644 index 0000000000..17ecea848d --- /dev/null +++ b/lib/erl_interface/src/decode/decode_ulonglong.c @@ -0,0 +1,83 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2002-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +#ifdef EI_64BIT +int ei_decode_ulong(const char *buf, int *index, unsigned long *p) +{ + return ei_decode_ulonglong(buf, index, (EI_ULONGLONG *)p); +} +#endif + +int ei_decode_ulonglong(const char *buf, int *index, EI_ULONGLONG *p) +{ + const char *s = buf + *index; + const char *s0 = s; + EI_ULONGLONG n; + int arity; + int sn; + + switch (get8(s)) { + case ERL_SMALL_INTEGER_EXT: + n = get8(s); + break; + + case ERL_INTEGER_EXT: + sn = get32be(s); + if (sn < 0) return -1; + n = (EI_ULONGLONG)sn; + break; + + case ERL_SMALL_BIG_EXT: + arity = get8(s); + goto decode_big; + + case ERL_LARGE_BIG_EXT: + arity = get32be(s); + + decode_big: + { + int sign = get8(s); + int i; + n = 0; + + if (sign) return -1; + + /* Little Endian, up to four bytes always fit into unsigned long */ + for (i = 0; i < arity; i++) { + if (i < 8) { + n |= ((EI_ULONGLONG)get8(s)) << (i * 8); + } else if (get8(s) != 0) { + return -1; /* All but first byte have to be 0 */ + } + } + } + break; + + default: + return -1; + } + + if (p) *p = n; + *index += s-s0; + + return 0; +} diff --git a/lib/erl_interface/src/decode/decode_version.c b/lib/erl_interface/src/decode/decode_version.c new file mode 100644 index 0000000000..124d7272f4 --- /dev/null +++ b/lib/erl_interface/src/decode/decode_version.c @@ -0,0 +1,38 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +/* remove version identifier from the start of the buffer */ +int ei_decode_version(const char *buf, int *index, int *version) +{ + const char *s = buf + *index; + const char *s0 = s; + int v; + + v = get8(s); + if (version) *version = v; + if (v != ERL_VERSION_MAGIC) + return -1; + + *index += s-s0; + + return 0; +} diff --git a/lib/erl_interface/src/depend.mk b/lib/erl_interface/src/depend.mk new file mode 100644 index 0000000000..af753046e5 --- /dev/null +++ b/lib/erl_interface/src/depend.mk @@ -0,0 +1,1133 @@ +# Generated dependency rules +$(ST_OBJDIR)/ei_connect.o: connect/ei_connect.c $(TARGET)/config.h \ + misc/eidef.h ../include/ei.h misc/eiext.h misc/ei_portio.h \ + misc/ei_internal.h connect/ei_connect_int.h misc/ei_locking.h \ + connect/eisend.h connect/eirecv.h misc/eimd5.h misc/putget.h \ + connect/ei_resolve.h epmd/ei_epmd.h +$(ST_OBJDIR)/ei_resolve.o: connect/ei_resolve.c $(TARGET)/config.h \ + misc/eidef.h ../include/ei.h connect/ei_resolve.h misc/ei_locking.h +$(ST_OBJDIR)/eirecv.o: connect/eirecv.c misc/eidef.h $(TARGET)/config.h \ + ../include/ei.h misc/eiext.h connect/eirecv.h misc/ei_portio.h \ + misc/ei_internal.h misc/putget.h misc/ei_trace.h misc/show_msg.h +$(ST_OBJDIR)/send.o: connect/send.c misc/eidef.h $(TARGET)/config.h \ + ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \ + connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \ + misc/show_msg.h +$(ST_OBJDIR)/send_exit.o: connect/send_exit.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + connect/eisend.h connect/ei_connect_int.h misc/ei_trace.h \ + misc/ei_internal.h misc/putget.h misc/show_msg.h +$(ST_OBJDIR)/send_reg.o: connect/send_reg.c misc/eidef.h $(TARGET)/config.h \ + ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \ + connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \ + misc/show_msg.h +$(ST_OBJDIR)/decode_atom.o: decode/decode_atom.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/decode_big.o: decode/decode_big.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/decode_bignum.o: decode/decode_bignum.c $(TARGET)/config.h +$(ST_OBJDIR)/decode_binary.o: decode/decode_binary.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/decode_boolean.o: decode/decode_boolean.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/decode_char.o: decode/decode_char.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/decode_double.o: decode/decode_double.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/decode_fun.o: decode/decode_fun.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/ei_malloc.h decode/decode_skip.h misc/putget.h +$(ST_OBJDIR)/decode_intlist.o: decode/decode_intlist.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/decode_list_header.o: decode/decode_list_header.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/decode_long.o: decode/decode_long.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/decode_pid.o: decode/decode_pid.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/decode_port.o: decode/decode_port.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/decode_ref.o: decode/decode_ref.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/decode_skip.o: decode/decode_skip.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + decode/decode_skip.h +$(ST_OBJDIR)/decode_string.o: decode/decode_string.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/decode_trace.o: decode/decode_trace.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/putget.h +$(ST_OBJDIR)/decode_tuple_header.o: decode/decode_tuple_header.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/decode_ulong.o: decode/decode_ulong.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/decode_version.o: decode/decode_version.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/decode_longlong.o: decode/decode_longlong.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/decode_ulonglong.o: decode/decode_ulonglong.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/encode_atom.o: encode/encode_atom.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/encode_bignum.o: encode/encode_bignum.c $(TARGET)/config.h +$(ST_OBJDIR)/encode_binary.o: encode/encode_binary.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/encode_boolean.o: encode/encode_boolean.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/encode_char.o: encode/encode_char.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/encode_double.o: encode/encode_double.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/encode_fun.o: encode/encode_fun.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/encode_list_header.o: encode/encode_list_header.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/encode_long.o: encode/encode_long.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/encode_pid.o: encode/encode_pid.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/encode_port.o: encode/encode_port.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/encode_ref.o: encode/encode_ref.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/encode_string.o: encode/encode_string.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/encode_trace.o: encode/encode_trace.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/putget.h +$(ST_OBJDIR)/encode_tuple_header.o: encode/encode_tuple_header.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/encode_ulong.o: encode/encode_ulong.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/encode_version.o: encode/encode_version.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(ST_OBJDIR)/encode_longlong.o: encode/encode_longlong.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h misc/ei_x_encode.h +$(ST_OBJDIR)/encode_ulonglong.o: encode/encode_ulonglong.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h misc/ei_x_encode.h +$(ST_OBJDIR)/epmd_port.o: epmd/epmd_port.c misc/ei_internal.h epmd/ei_epmd.h \ + misc/putget.h +$(ST_OBJDIR)/epmd_publish.o: epmd/epmd_publish.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \ + misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h +$(ST_OBJDIR)/epmd_unpublish.o: epmd/epmd_unpublish.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \ + misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h +$(ST_OBJDIR)/ei_decode_term.o: misc/ei_decode_term.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/ei_decode_term.h misc/putget.h +$(ST_OBJDIR)/ei_format.o: misc/ei_format.c misc/eidef.h $(TARGET)/config.h \ + ../include/ei.h misc/ei_malloc.h misc/ei_format.h +$(ST_OBJDIR)/ei_locking.o: misc/ei_locking.c $(TARGET)/config.h \ + misc/ei_malloc.h misc/ei_locking.h +$(ST_OBJDIR)/ei_malloc.o: misc/ei_malloc.c misc/ei_malloc.h +$(ST_OBJDIR)/ei_portio.o: misc/ei_portio.c misc/ei_portio.h misc/ei_internal.h +$(ST_OBJDIR)/ei_printterm.o: misc/ei_printterm.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/ei_printterm.h misc/ei_malloc.h +$(ST_OBJDIR)/ei_pthreads.o: misc/ei_pthreads.c $(TARGET)/config.h \ + ../include/ei.h misc/ei_locking.h +$(ST_OBJDIR)/ei_trace.o: misc/ei_trace.c misc/eidef.h $(TARGET)/config.h \ + ../include/ei.h misc/ei_trace.h +$(ST_OBJDIR)/ei_x_encode.o: misc/ei_x_encode.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/ei_x_encode.h \ + misc/ei_malloc.h +$(ST_OBJDIR)/eimd5.o: misc/eimd5.c misc/eimd5.h +$(ST_OBJDIR)/get_type.o: misc/get_type.c misc/eidef.h $(TARGET)/config.h \ + ../include/ei.h misc/eiext.h misc/putget.h +$(ST_OBJDIR)/show_msg.o: misc/show_msg.c misc/eidef.h $(TARGET)/config.h \ + ../include/ei.h misc/eiext.h misc/putget.h misc/ei_printterm.h \ + misc/ei_internal.h misc/show_msg.h +$(ST_OBJDIR)/ei_compat.o: misc/ei_compat.c ../include/ei.h misc/ei_internal.h +$(ST_OBJDIR)/hash_dohash.o: registry/hash_dohash.c registry/hash.h ../include/ei.h +$(ST_OBJDIR)/hash_foreach.o: registry/hash_foreach.c registry/hash.h ../include/ei.h +$(ST_OBJDIR)/hash_freetab.o: registry/hash_freetab.c registry/hash.h ../include/ei.h +$(ST_OBJDIR)/hash_insert.o: registry/hash_insert.c registry/hash.h ../include/ei.h +$(ST_OBJDIR)/hash_isprime.o: registry/hash_isprime.c registry/hash.h ../include/ei.h +$(ST_OBJDIR)/hash_lookup.o: registry/hash_lookup.c registry/hash.h ../include/ei.h +$(ST_OBJDIR)/hash_newtab.o: registry/hash_newtab.c registry/hash.h ../include/ei.h +$(ST_OBJDIR)/hash_remove.o: registry/hash_remove.c registry/hash.h ../include/ei.h +$(ST_OBJDIR)/hash_resize.o: registry/hash_resize.c registry/hash.h ../include/ei.h +$(ST_OBJDIR)/hash_rlookup.o: registry/hash_rlookup.c registry/hash.h ../include/ei.h +$(ST_OBJDIR)/reg_close.o: registry/reg_close.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(ST_OBJDIR)/reg_delete.o: registry/reg_delete.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(ST_OBJDIR)/reg_dirty.o: registry/reg_dirty.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(ST_OBJDIR)/reg_dump.o: registry/reg_dump.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \ + connect/ei_connect_int.h +$(ST_OBJDIR)/reg_free.o: registry/reg_free.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(ST_OBJDIR)/reg_get.o: registry/reg_get.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(ST_OBJDIR)/reg_getf.o: registry/reg_getf.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(ST_OBJDIR)/reg_geti.o: registry/reg_geti.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(ST_OBJDIR)/reg_getp.o: registry/reg_getp.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(ST_OBJDIR)/reg_gets.o: registry/reg_gets.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(ST_OBJDIR)/reg_make.o: registry/reg_make.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(ST_OBJDIR)/reg_open.o: registry/reg_open.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(ST_OBJDIR)/reg_purge.o: registry/reg_purge.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(ST_OBJDIR)/reg_resize.o: registry/reg_resize.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(ST_OBJDIR)/reg_restore.o: registry/reg_restore.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \ + connect/ei_connect_int.h +$(ST_OBJDIR)/reg_set.o: registry/reg_set.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(ST_OBJDIR)/reg_setf.o: registry/reg_setf.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(ST_OBJDIR)/reg_seti.o: registry/reg_seti.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(ST_OBJDIR)/reg_setp.o: registry/reg_setp.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(ST_OBJDIR)/reg_sets.o: registry/reg_sets.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(ST_OBJDIR)/reg_stat.o: registry/reg_stat.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(ST_OBJDIR)/reg_tabstat.o: registry/reg_tabstat.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(ST_OBJDIR)/decode_term.o: legacy/decode_term.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h ../include/erl_interface.h +$(ST_OBJDIR)/encode_term.o: legacy/encode_term.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h misc/ei_x_encode.h ../include/erl_interface.h \ + legacy/erl_marshal.h legacy/erl_eterm.h legacy/portability.h +$(ST_OBJDIR)/erl_connect.o: legacy/erl_connect.c $(TARGET)/config.h \ + ../include/erl_interface.h ../include/ei.h legacy/erl_config.h \ + legacy/erl_connect.h legacy/erl_eterm.h legacy/portability.h \ + legacy/erl_malloc.h misc/putget.h connect/ei_connect_int.h \ + misc/ei_locking.h epmd/ei_epmd.h misc/ei_internal.h +$(ST_OBJDIR)/erl_error.o: legacy/erl_error.c $(TARGET)/config.h \ + ../include/erl_interface.h ../include/ei.h legacy/erl_error.h +$(ST_OBJDIR)/erl_eterm.o: legacy/erl_eterm.c misc/ei_locking.h \ + $(TARGET)/config.h connect/ei_resolve.h \ + ../include/erl_interface.h ../include/ei.h legacy/erl_eterm.h \ + legacy/portability.h legacy/erl_malloc.h legacy/erl_marshal.h \ + legacy/erl_error.h legacy/erl_internal.h misc/ei_internal.h +$(ST_OBJDIR)/erl_fix_alloc.o: legacy/erl_fix_alloc.c $(TARGET)/config.h \ + misc/ei_locking.h ../include/erl_interface.h ../include/ei.h \ + legacy/erl_error.h legacy/erl_malloc.h legacy/erl_fix_alloc.h \ + legacy/erl_eterm.h legacy/portability.h +$(ST_OBJDIR)/erl_format.o: legacy/erl_format.c ../include/erl_interface.h \ + ../include/ei.h legacy/erl_eterm.h legacy/portability.h \ + legacy/erl_malloc.h legacy/erl_error.h legacy/erl_internal.h +$(ST_OBJDIR)/erl_malloc.o: legacy/erl_malloc.c ../include/erl_interface.h \ + ../include/ei.h legacy/erl_fix_alloc.h legacy/erl_malloc.h \ + legacy/erl_internal.h legacy/erl_eterm.h legacy/portability.h \ + misc/ei_malloc.h +$(ST_OBJDIR)/erl_marshal.o: legacy/erl_marshal.c $(TARGET)/config.h \ + ../include/erl_interface.h ../include/ei.h legacy/erl_marshal.h \ + legacy/erl_eterm.h legacy/portability.h legacy/erl_malloc.h \ + legacy/erl_error.h legacy/erl_internal.h misc/eiext.h misc/putget.h +$(ST_OBJDIR)/erl_timeout.o: legacy/erl_timeout.c $(TARGET)/config.h \ + legacy/erl_timeout.h +$(ST_OBJDIR)/global_names.o: legacy/global_names.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \ + ../include/erl_interface.h legacy/erl_connect.h +$(ST_OBJDIR)/global_register.o: legacy/global_register.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + connect/eisend.h connect/eirecv.h ../include/erl_interface.h +$(ST_OBJDIR)/global_unregister.o: legacy/global_unregister.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \ + ../include/erl_interface.h legacy/erl_connect.h +$(ST_OBJDIR)/global_whereis.o: legacy/global_whereis.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \ + ../include/erl_interface.h legacy/erl_connect.h + +$(MT_OBJDIR)/ei_connect.o: connect/ei_connect.c $(TARGET)/config.h \ + misc/eidef.h ../include/ei.h misc/eiext.h misc/ei_portio.h \ + misc/ei_internal.h connect/ei_connect_int.h misc/ei_locking.h \ + connect/eisend.h connect/eirecv.h misc/eimd5.h misc/putget.h \ + connect/ei_resolve.h epmd/ei_epmd.h +$(MT_OBJDIR)/ei_resolve.o: connect/ei_resolve.c $(TARGET)/config.h \ + misc/eidef.h ../include/ei.h connect/ei_resolve.h misc/ei_locking.h +$(MT_OBJDIR)/eirecv.o: connect/eirecv.c misc/eidef.h $(TARGET)/config.h \ + ../include/ei.h misc/eiext.h connect/eirecv.h misc/ei_portio.h \ + misc/ei_internal.h misc/putget.h misc/ei_trace.h misc/show_msg.h +$(MT_OBJDIR)/send.o: connect/send.c misc/eidef.h $(TARGET)/config.h \ + ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \ + connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \ + misc/show_msg.h +$(MT_OBJDIR)/send_exit.o: connect/send_exit.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + connect/eisend.h connect/ei_connect_int.h misc/ei_trace.h \ + misc/ei_internal.h misc/putget.h misc/show_msg.h +$(MT_OBJDIR)/send_reg.o: connect/send_reg.c misc/eidef.h $(TARGET)/config.h \ + ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \ + connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \ + misc/show_msg.h +$(MT_OBJDIR)/decode_atom.o: decode/decode_atom.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/decode_big.o: decode/decode_big.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/decode_bignum.o: decode/decode_bignum.c $(TARGET)/config.h +$(MT_OBJDIR)/decode_binary.o: decode/decode_binary.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/decode_boolean.o: decode/decode_boolean.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/decode_char.o: decode/decode_char.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/decode_double.o: decode/decode_double.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/decode_fun.o: decode/decode_fun.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/ei_malloc.h decode/decode_skip.h misc/putget.h +$(MT_OBJDIR)/decode_intlist.o: decode/decode_intlist.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/decode_list_header.o: decode/decode_list_header.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/decode_long.o: decode/decode_long.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/decode_pid.o: decode/decode_pid.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/decode_port.o: decode/decode_port.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/decode_ref.o: decode/decode_ref.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/decode_skip.o: decode/decode_skip.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + decode/decode_skip.h +$(MT_OBJDIR)/decode_string.o: decode/decode_string.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/decode_trace.o: decode/decode_trace.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/putget.h +$(MT_OBJDIR)/decode_tuple_header.o: decode/decode_tuple_header.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/decode_ulong.o: decode/decode_ulong.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/decode_version.o: decode/decode_version.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/decode_longlong.o: decode/decode_longlong.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/decode_ulonglong.o: decode/decode_ulonglong.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/encode_atom.o: encode/encode_atom.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/encode_bignum.o: encode/encode_bignum.c $(TARGET)/config.h +$(MT_OBJDIR)/encode_binary.o: encode/encode_binary.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/encode_boolean.o: encode/encode_boolean.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/encode_char.o: encode/encode_char.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/encode_double.o: encode/encode_double.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/encode_fun.o: encode/encode_fun.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/encode_list_header.o: encode/encode_list_header.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/encode_long.o: encode/encode_long.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/encode_pid.o: encode/encode_pid.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/encode_port.o: encode/encode_port.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/encode_ref.o: encode/encode_ref.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/encode_string.o: encode/encode_string.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/encode_trace.o: encode/encode_trace.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/putget.h +$(MT_OBJDIR)/encode_tuple_header.o: encode/encode_tuple_header.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/encode_ulong.o: encode/encode_ulong.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/encode_version.o: encode/encode_version.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MT_OBJDIR)/encode_longlong.o: encode/encode_longlong.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h misc/ei_x_encode.h +$(MT_OBJDIR)/encode_ulonglong.o: encode/encode_ulonglong.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h misc/ei_x_encode.h +$(MT_OBJDIR)/epmd_port.o: epmd/epmd_port.c misc/ei_internal.h epmd/ei_epmd.h \ + misc/putget.h +$(MT_OBJDIR)/epmd_publish.o: epmd/epmd_publish.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \ + misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h +$(MT_OBJDIR)/epmd_unpublish.o: epmd/epmd_unpublish.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \ + misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h +$(MT_OBJDIR)/ei_decode_term.o: misc/ei_decode_term.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/ei_decode_term.h misc/putget.h +$(MT_OBJDIR)/ei_format.o: misc/ei_format.c misc/eidef.h $(TARGET)/config.h \ + ../include/ei.h misc/ei_malloc.h misc/ei_format.h +$(MT_OBJDIR)/ei_locking.o: misc/ei_locking.c $(TARGET)/config.h \ + misc/ei_malloc.h misc/ei_locking.h +$(MT_OBJDIR)/ei_malloc.o: misc/ei_malloc.c misc/ei_malloc.h +$(MT_OBJDIR)/ei_portio.o: misc/ei_portio.c misc/ei_portio.h misc/ei_internal.h +$(MT_OBJDIR)/ei_printterm.o: misc/ei_printterm.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/ei_printterm.h misc/ei_malloc.h +$(MT_OBJDIR)/ei_pthreads.o: misc/ei_pthreads.c $(TARGET)/config.h \ + ../include/ei.h misc/ei_locking.h +$(MT_OBJDIR)/ei_trace.o: misc/ei_trace.c misc/eidef.h $(TARGET)/config.h \ + ../include/ei.h misc/ei_trace.h +$(MT_OBJDIR)/ei_x_encode.o: misc/ei_x_encode.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/ei_x_encode.h \ + misc/ei_malloc.h +$(MT_OBJDIR)/eimd5.o: misc/eimd5.c misc/eimd5.h +$(MT_OBJDIR)/get_type.o: misc/get_type.c misc/eidef.h $(TARGET)/config.h \ + ../include/ei.h misc/eiext.h misc/putget.h +$(MT_OBJDIR)/show_msg.o: misc/show_msg.c misc/eidef.h $(TARGET)/config.h \ + ../include/ei.h misc/eiext.h misc/putget.h misc/ei_printterm.h \ + misc/ei_internal.h misc/show_msg.h +$(MT_OBJDIR)/ei_compat.o: misc/ei_compat.c ../include/ei.h misc/ei_internal.h +$(MT_OBJDIR)/hash_dohash.o: registry/hash_dohash.c registry/hash.h ../include/ei.h +$(MT_OBJDIR)/hash_foreach.o: registry/hash_foreach.c registry/hash.h ../include/ei.h +$(MT_OBJDIR)/hash_freetab.o: registry/hash_freetab.c registry/hash.h ../include/ei.h +$(MT_OBJDIR)/hash_insert.o: registry/hash_insert.c registry/hash.h ../include/ei.h +$(MT_OBJDIR)/hash_isprime.o: registry/hash_isprime.c registry/hash.h ../include/ei.h +$(MT_OBJDIR)/hash_lookup.o: registry/hash_lookup.c registry/hash.h ../include/ei.h +$(MT_OBJDIR)/hash_newtab.o: registry/hash_newtab.c registry/hash.h ../include/ei.h +$(MT_OBJDIR)/hash_remove.o: registry/hash_remove.c registry/hash.h ../include/ei.h +$(MT_OBJDIR)/hash_resize.o: registry/hash_resize.c registry/hash.h ../include/ei.h +$(MT_OBJDIR)/hash_rlookup.o: registry/hash_rlookup.c registry/hash.h ../include/ei.h +$(MT_OBJDIR)/reg_close.o: registry/reg_close.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MT_OBJDIR)/reg_delete.o: registry/reg_delete.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MT_OBJDIR)/reg_dirty.o: registry/reg_dirty.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MT_OBJDIR)/reg_dump.o: registry/reg_dump.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \ + connect/ei_connect_int.h +$(MT_OBJDIR)/reg_free.o: registry/reg_free.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MT_OBJDIR)/reg_get.o: registry/reg_get.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MT_OBJDIR)/reg_getf.o: registry/reg_getf.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MT_OBJDIR)/reg_geti.o: registry/reg_geti.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MT_OBJDIR)/reg_getp.o: registry/reg_getp.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MT_OBJDIR)/reg_gets.o: registry/reg_gets.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MT_OBJDIR)/reg_make.o: registry/reg_make.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MT_OBJDIR)/reg_open.o: registry/reg_open.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MT_OBJDIR)/reg_purge.o: registry/reg_purge.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MT_OBJDIR)/reg_resize.o: registry/reg_resize.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MT_OBJDIR)/reg_restore.o: registry/reg_restore.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \ + connect/ei_connect_int.h +$(MT_OBJDIR)/reg_set.o: registry/reg_set.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MT_OBJDIR)/reg_setf.o: registry/reg_setf.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MT_OBJDIR)/reg_seti.o: registry/reg_seti.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MT_OBJDIR)/reg_setp.o: registry/reg_setp.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MT_OBJDIR)/reg_sets.o: registry/reg_sets.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MT_OBJDIR)/reg_stat.o: registry/reg_stat.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MT_OBJDIR)/reg_tabstat.o: registry/reg_tabstat.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MT_OBJDIR)/decode_term.o: legacy/decode_term.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h ../include/erl_interface.h +$(MT_OBJDIR)/encode_term.o: legacy/encode_term.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h misc/ei_x_encode.h ../include/erl_interface.h \ + legacy/erl_marshal.h legacy/erl_eterm.h legacy/portability.h +$(MT_OBJDIR)/erl_connect.o: legacy/erl_connect.c $(TARGET)/config.h \ + ../include/erl_interface.h ../include/ei.h legacy/erl_config.h \ + legacy/erl_connect.h legacy/erl_eterm.h legacy/portability.h \ + legacy/erl_malloc.h misc/putget.h connect/ei_connect_int.h \ + misc/ei_locking.h epmd/ei_epmd.h misc/ei_internal.h +$(MT_OBJDIR)/erl_error.o: legacy/erl_error.c $(TARGET)/config.h \ + ../include/erl_interface.h ../include/ei.h legacy/erl_error.h +$(MT_OBJDIR)/erl_eterm.o: legacy/erl_eterm.c misc/ei_locking.h \ + $(TARGET)/config.h connect/ei_resolve.h \ + ../include/erl_interface.h ../include/ei.h legacy/erl_eterm.h \ + legacy/portability.h legacy/erl_malloc.h legacy/erl_marshal.h \ + legacy/erl_error.h legacy/erl_internal.h misc/ei_internal.h +$(MT_OBJDIR)/erl_fix_alloc.o: legacy/erl_fix_alloc.c $(TARGET)/config.h \ + misc/ei_locking.h ../include/erl_interface.h ../include/ei.h \ + legacy/erl_error.h legacy/erl_malloc.h legacy/erl_fix_alloc.h \ + legacy/erl_eterm.h legacy/portability.h +$(MT_OBJDIR)/erl_format.o: legacy/erl_format.c ../include/erl_interface.h \ + ../include/ei.h legacy/erl_eterm.h legacy/portability.h \ + legacy/erl_malloc.h legacy/erl_error.h legacy/erl_internal.h +$(MT_OBJDIR)/erl_malloc.o: legacy/erl_malloc.c ../include/erl_interface.h \ + ../include/ei.h legacy/erl_fix_alloc.h legacy/erl_malloc.h \ + legacy/erl_internal.h legacy/erl_eterm.h legacy/portability.h \ + misc/ei_malloc.h +$(MT_OBJDIR)/erl_marshal.o: legacy/erl_marshal.c $(TARGET)/config.h \ + ../include/erl_interface.h ../include/ei.h legacy/erl_marshal.h \ + legacy/erl_eterm.h legacy/portability.h legacy/erl_malloc.h \ + legacy/erl_error.h legacy/erl_internal.h misc/eiext.h misc/putget.h +$(MT_OBJDIR)/erl_timeout.o: legacy/erl_timeout.c $(TARGET)/config.h \ + legacy/erl_timeout.h +$(MT_OBJDIR)/global_names.o: legacy/global_names.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \ + ../include/erl_interface.h legacy/erl_connect.h +$(MT_OBJDIR)/global_register.o: legacy/global_register.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + connect/eisend.h connect/eirecv.h ../include/erl_interface.h +$(MT_OBJDIR)/global_unregister.o: legacy/global_unregister.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \ + ../include/erl_interface.h legacy/erl_connect.h +$(MT_OBJDIR)/global_whereis.o: legacy/global_whereis.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \ + ../include/erl_interface.h legacy/erl_connect.h + +$(MD_OBJDIR)/ei_connect.o: connect/ei_connect.c $(TARGET)/config.h \ + misc/eidef.h ../include/ei.h misc/eiext.h misc/ei_portio.h \ + misc/ei_internal.h connect/ei_connect_int.h misc/ei_locking.h \ + connect/eisend.h connect/eirecv.h misc/eimd5.h misc/putget.h \ + connect/ei_resolve.h epmd/ei_epmd.h +$(MD_OBJDIR)/ei_resolve.o: connect/ei_resolve.c $(TARGET)/config.h \ + misc/eidef.h ../include/ei.h connect/ei_resolve.h misc/ei_locking.h +$(MD_OBJDIR)/eirecv.o: connect/eirecv.c misc/eidef.h $(TARGET)/config.h \ + ../include/ei.h misc/eiext.h connect/eirecv.h misc/ei_portio.h \ + misc/ei_internal.h misc/putget.h misc/ei_trace.h misc/show_msg.h +$(MD_OBJDIR)/send.o: connect/send.c misc/eidef.h $(TARGET)/config.h \ + ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \ + connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \ + misc/show_msg.h +$(MD_OBJDIR)/send_exit.o: connect/send_exit.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + connect/eisend.h connect/ei_connect_int.h misc/ei_trace.h \ + misc/ei_internal.h misc/putget.h misc/show_msg.h +$(MD_OBJDIR)/send_reg.o: connect/send_reg.c misc/eidef.h $(TARGET)/config.h \ + ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \ + connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \ + misc/show_msg.h +$(MD_OBJDIR)/decode_atom.o: decode/decode_atom.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/decode_big.o: decode/decode_big.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/decode_bignum.o: decode/decode_bignum.c $(TARGET)/config.h +$(MD_OBJDIR)/decode_binary.o: decode/decode_binary.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/decode_boolean.o: decode/decode_boolean.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/decode_char.o: decode/decode_char.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/decode_double.o: decode/decode_double.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/decode_fun.o: decode/decode_fun.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/ei_malloc.h decode/decode_skip.h misc/putget.h +$(MD_OBJDIR)/decode_intlist.o: decode/decode_intlist.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/decode_list_header.o: decode/decode_list_header.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/decode_long.o: decode/decode_long.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/decode_pid.o: decode/decode_pid.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/decode_port.o: decode/decode_port.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/decode_ref.o: decode/decode_ref.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/decode_skip.o: decode/decode_skip.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + decode/decode_skip.h +$(MD_OBJDIR)/decode_string.o: decode/decode_string.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/decode_trace.o: decode/decode_trace.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/putget.h +$(MD_OBJDIR)/decode_tuple_header.o: decode/decode_tuple_header.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/decode_ulong.o: decode/decode_ulong.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/decode_version.o: decode/decode_version.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/decode_longlong.o: decode/decode_longlong.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/decode_ulonglong.o: decode/decode_ulonglong.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/encode_atom.o: encode/encode_atom.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/encode_bignum.o: encode/encode_bignum.c $(TARGET)/config.h +$(MD_OBJDIR)/encode_binary.o: encode/encode_binary.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/encode_boolean.o: encode/encode_boolean.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/encode_char.o: encode/encode_char.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/encode_double.o: encode/encode_double.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/encode_fun.o: encode/encode_fun.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/encode_list_header.o: encode/encode_list_header.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/encode_long.o: encode/encode_long.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/encode_pid.o: encode/encode_pid.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/encode_port.o: encode/encode_port.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/encode_ref.o: encode/encode_ref.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/encode_string.o: encode/encode_string.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/encode_trace.o: encode/encode_trace.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/putget.h +$(MD_OBJDIR)/encode_tuple_header.o: encode/encode_tuple_header.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/encode_ulong.o: encode/encode_ulong.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/encode_version.o: encode/encode_version.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MD_OBJDIR)/encode_longlong.o: encode/encode_longlong.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h misc/ei_x_encode.h +$(MD_OBJDIR)/encode_ulonglong.o: encode/encode_ulonglong.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h misc/ei_x_encode.h +$(MD_OBJDIR)/epmd_port.o: epmd/epmd_port.c misc/ei_internal.h epmd/ei_epmd.h \ + misc/putget.h +$(MD_OBJDIR)/epmd_publish.o: epmd/epmd_publish.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \ + misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h +$(MD_OBJDIR)/epmd_unpublish.o: epmd/epmd_unpublish.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \ + misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h +$(MD_OBJDIR)/ei_decode_term.o: misc/ei_decode_term.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/ei_decode_term.h misc/putget.h +$(MD_OBJDIR)/ei_format.o: misc/ei_format.c misc/eidef.h $(TARGET)/config.h \ + ../include/ei.h misc/ei_malloc.h misc/ei_format.h +$(MD_OBJDIR)/ei_locking.o: misc/ei_locking.c $(TARGET)/config.h \ + misc/ei_malloc.h misc/ei_locking.h +$(MD_OBJDIR)/ei_malloc.o: misc/ei_malloc.c misc/ei_malloc.h +$(MD_OBJDIR)/ei_portio.o: misc/ei_portio.c misc/ei_portio.h misc/ei_internal.h +$(MD_OBJDIR)/ei_printterm.o: misc/ei_printterm.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/ei_printterm.h misc/ei_malloc.h +$(MD_OBJDIR)/ei_pthreads.o: misc/ei_pthreads.c $(TARGET)/config.h \ + ../include/ei.h misc/ei_locking.h +$(MD_OBJDIR)/ei_trace.o: misc/ei_trace.c misc/eidef.h $(TARGET)/config.h \ + ../include/ei.h misc/ei_trace.h +$(MD_OBJDIR)/ei_x_encode.o: misc/ei_x_encode.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/ei_x_encode.h \ + misc/ei_malloc.h +$(MD_OBJDIR)/eimd5.o: misc/eimd5.c misc/eimd5.h +$(MD_OBJDIR)/get_type.o: misc/get_type.c misc/eidef.h $(TARGET)/config.h \ + ../include/ei.h misc/eiext.h misc/putget.h +$(MD_OBJDIR)/show_msg.o: misc/show_msg.c misc/eidef.h $(TARGET)/config.h \ + ../include/ei.h misc/eiext.h misc/putget.h misc/ei_printterm.h \ + misc/ei_internal.h misc/show_msg.h +$(MD_OBJDIR)/ei_compat.o: misc/ei_compat.c ../include/ei.h misc/ei_internal.h +$(MD_OBJDIR)/hash_dohash.o: registry/hash_dohash.c registry/hash.h ../include/ei.h +$(MD_OBJDIR)/hash_foreach.o: registry/hash_foreach.c registry/hash.h ../include/ei.h +$(MD_OBJDIR)/hash_freetab.o: registry/hash_freetab.c registry/hash.h ../include/ei.h +$(MD_OBJDIR)/hash_insert.o: registry/hash_insert.c registry/hash.h ../include/ei.h +$(MD_OBJDIR)/hash_isprime.o: registry/hash_isprime.c registry/hash.h ../include/ei.h +$(MD_OBJDIR)/hash_lookup.o: registry/hash_lookup.c registry/hash.h ../include/ei.h +$(MD_OBJDIR)/hash_newtab.o: registry/hash_newtab.c registry/hash.h ../include/ei.h +$(MD_OBJDIR)/hash_remove.o: registry/hash_remove.c registry/hash.h ../include/ei.h +$(MD_OBJDIR)/hash_resize.o: registry/hash_resize.c registry/hash.h ../include/ei.h +$(MD_OBJDIR)/hash_rlookup.o: registry/hash_rlookup.c registry/hash.h ../include/ei.h +$(MD_OBJDIR)/reg_close.o: registry/reg_close.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MD_OBJDIR)/reg_delete.o: registry/reg_delete.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MD_OBJDIR)/reg_dirty.o: registry/reg_dirty.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MD_OBJDIR)/reg_dump.o: registry/reg_dump.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \ + connect/ei_connect_int.h +$(MD_OBJDIR)/reg_free.o: registry/reg_free.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MD_OBJDIR)/reg_get.o: registry/reg_get.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MD_OBJDIR)/reg_getf.o: registry/reg_getf.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MD_OBJDIR)/reg_geti.o: registry/reg_geti.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MD_OBJDIR)/reg_getp.o: registry/reg_getp.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MD_OBJDIR)/reg_gets.o: registry/reg_gets.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MD_OBJDIR)/reg_make.o: registry/reg_make.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MD_OBJDIR)/reg_open.o: registry/reg_open.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MD_OBJDIR)/reg_purge.o: registry/reg_purge.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MD_OBJDIR)/reg_resize.o: registry/reg_resize.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MD_OBJDIR)/reg_restore.o: registry/reg_restore.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \ + connect/ei_connect_int.h +$(MD_OBJDIR)/reg_set.o: registry/reg_set.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MD_OBJDIR)/reg_setf.o: registry/reg_setf.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MD_OBJDIR)/reg_seti.o: registry/reg_seti.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MD_OBJDIR)/reg_setp.o: registry/reg_setp.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MD_OBJDIR)/reg_sets.o: registry/reg_sets.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MD_OBJDIR)/reg_stat.o: registry/reg_stat.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MD_OBJDIR)/reg_tabstat.o: registry/reg_tabstat.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MD_OBJDIR)/decode_term.o: legacy/decode_term.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h ../include/erl_interface.h +$(MD_OBJDIR)/encode_term.o: legacy/encode_term.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h misc/ei_x_encode.h ../include/erl_interface.h \ + legacy/erl_marshal.h legacy/erl_eterm.h legacy/portability.h +$(MD_OBJDIR)/erl_connect.o: legacy/erl_connect.c $(TARGET)/config.h \ + ../include/erl_interface.h ../include/ei.h legacy/erl_config.h \ + legacy/erl_connect.h legacy/erl_eterm.h legacy/portability.h \ + legacy/erl_malloc.h misc/putget.h connect/ei_connect_int.h \ + misc/ei_locking.h epmd/ei_epmd.h misc/ei_internal.h +$(MD_OBJDIR)/erl_error.o: legacy/erl_error.c $(TARGET)/config.h \ + ../include/erl_interface.h ../include/ei.h legacy/erl_error.h +$(MD_OBJDIR)/erl_eterm.o: legacy/erl_eterm.c misc/ei_locking.h \ + $(TARGET)/config.h connect/ei_resolve.h \ + ../include/erl_interface.h ../include/ei.h legacy/erl_eterm.h \ + legacy/portability.h legacy/erl_malloc.h legacy/erl_marshal.h \ + legacy/erl_error.h legacy/erl_internal.h misc/ei_internal.h +$(MD_OBJDIR)/erl_fix_alloc.o: legacy/erl_fix_alloc.c $(TARGET)/config.h \ + misc/ei_locking.h ../include/erl_interface.h ../include/ei.h \ + legacy/erl_error.h legacy/erl_malloc.h legacy/erl_fix_alloc.h \ + legacy/erl_eterm.h legacy/portability.h +$(MD_OBJDIR)/erl_format.o: legacy/erl_format.c ../include/erl_interface.h \ + ../include/ei.h legacy/erl_eterm.h legacy/portability.h \ + legacy/erl_malloc.h legacy/erl_error.h legacy/erl_internal.h +$(MD_OBJDIR)/erl_malloc.o: legacy/erl_malloc.c ../include/erl_interface.h \ + ../include/ei.h legacy/erl_fix_alloc.h legacy/erl_malloc.h \ + legacy/erl_internal.h legacy/erl_eterm.h legacy/portability.h \ + misc/ei_malloc.h +$(MD_OBJDIR)/erl_marshal.o: legacy/erl_marshal.c $(TARGET)/config.h \ + ../include/erl_interface.h ../include/ei.h legacy/erl_marshal.h \ + legacy/erl_eterm.h legacy/portability.h legacy/erl_malloc.h \ + legacy/erl_error.h legacy/erl_internal.h misc/eiext.h misc/putget.h +$(MD_OBJDIR)/erl_timeout.o: legacy/erl_timeout.c $(TARGET)/config.h \ + legacy/erl_timeout.h +$(MD_OBJDIR)/global_names.o: legacy/global_names.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \ + ../include/erl_interface.h legacy/erl_connect.h +$(MD_OBJDIR)/global_register.o: legacy/global_register.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + connect/eisend.h connect/eirecv.h ../include/erl_interface.h +$(MD_OBJDIR)/global_unregister.o: legacy/global_unregister.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \ + ../include/erl_interface.h legacy/erl_connect.h +$(MD_OBJDIR)/global_whereis.o: legacy/global_whereis.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \ + ../include/erl_interface.h legacy/erl_connect.h + +$(MDD_OBJDIR)/ei_connect.o: connect/ei_connect.c $(TARGET)/config.h \ + misc/eidef.h ../include/ei.h misc/eiext.h misc/ei_portio.h \ + misc/ei_internal.h connect/ei_connect_int.h misc/ei_locking.h \ + connect/eisend.h connect/eirecv.h misc/eimd5.h misc/putget.h \ + connect/ei_resolve.h epmd/ei_epmd.h +$(MDD_OBJDIR)/ei_resolve.o: connect/ei_resolve.c $(TARGET)/config.h \ + misc/eidef.h ../include/ei.h connect/ei_resolve.h misc/ei_locking.h +$(MDD_OBJDIR)/eirecv.o: connect/eirecv.c misc/eidef.h $(TARGET)/config.h \ + ../include/ei.h misc/eiext.h connect/eirecv.h misc/ei_portio.h \ + misc/ei_internal.h misc/putget.h misc/ei_trace.h misc/show_msg.h +$(MDD_OBJDIR)/send.o: connect/send.c misc/eidef.h $(TARGET)/config.h \ + ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \ + connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \ + misc/show_msg.h +$(MDD_OBJDIR)/send_exit.o: connect/send_exit.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + connect/eisend.h connect/ei_connect_int.h misc/ei_trace.h \ + misc/ei_internal.h misc/putget.h misc/show_msg.h +$(MDD_OBJDIR)/send_reg.o: connect/send_reg.c misc/eidef.h $(TARGET)/config.h \ + ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \ + connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \ + misc/show_msg.h +$(MDD_OBJDIR)/decode_atom.o: decode/decode_atom.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/decode_big.o: decode/decode_big.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/decode_bignum.o: decode/decode_bignum.c $(TARGET)/config.h +$(MDD_OBJDIR)/decode_binary.o: decode/decode_binary.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/decode_boolean.o: decode/decode_boolean.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/decode_char.o: decode/decode_char.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/decode_double.o: decode/decode_double.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/decode_fun.o: decode/decode_fun.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/ei_malloc.h decode/decode_skip.h misc/putget.h +$(MDD_OBJDIR)/decode_intlist.o: decode/decode_intlist.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/decode_list_header.o: decode/decode_list_header.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/decode_long.o: decode/decode_long.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/decode_pid.o: decode/decode_pid.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/decode_port.o: decode/decode_port.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/decode_ref.o: decode/decode_ref.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/decode_skip.o: decode/decode_skip.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + decode/decode_skip.h +$(MDD_OBJDIR)/decode_string.o: decode/decode_string.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/decode_trace.o: decode/decode_trace.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/putget.h +$(MDD_OBJDIR)/decode_tuple_header.o: decode/decode_tuple_header.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/decode_ulong.o: decode/decode_ulong.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/decode_version.o: decode/decode_version.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/decode_longlong.o: decode/decode_longlong.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/decode_ulonglong.o: decode/decode_ulonglong.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/encode_atom.o: encode/encode_atom.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/encode_bignum.o: encode/encode_bignum.c $(TARGET)/config.h +$(MDD_OBJDIR)/encode_binary.o: encode/encode_binary.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/encode_boolean.o: encode/encode_boolean.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/encode_char.o: encode/encode_char.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/encode_double.o: encode/encode_double.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/encode_fun.o: encode/encode_fun.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/encode_list_header.o: encode/encode_list_header.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/encode_long.o: encode/encode_long.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/encode_pid.o: encode/encode_pid.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/encode_port.o: encode/encode_port.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/encode_ref.o: encode/encode_ref.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/encode_string.o: encode/encode_string.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/encode_trace.o: encode/encode_trace.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/putget.h +$(MDD_OBJDIR)/encode_tuple_header.o: encode/encode_tuple_header.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/encode_ulong.o: encode/encode_ulong.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/encode_version.o: encode/encode_version.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h +$(MDD_OBJDIR)/encode_longlong.o: encode/encode_longlong.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h misc/ei_x_encode.h +$(MDD_OBJDIR)/encode_ulonglong.o: encode/encode_ulonglong.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h misc/ei_x_encode.h +$(MDD_OBJDIR)/epmd_port.o: epmd/epmd_port.c misc/ei_internal.h epmd/ei_epmd.h \ + misc/putget.h +$(MDD_OBJDIR)/epmd_publish.o: epmd/epmd_publish.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \ + misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h +$(MDD_OBJDIR)/epmd_unpublish.o: epmd/epmd_unpublish.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \ + misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h +$(MDD_OBJDIR)/ei_decode_term.o: misc/ei_decode_term.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/ei_decode_term.h misc/putget.h +$(MDD_OBJDIR)/ei_format.o: misc/ei_format.c misc/eidef.h $(TARGET)/config.h \ + ../include/ei.h misc/ei_malloc.h misc/ei_format.h +$(MDD_OBJDIR)/ei_locking.o: misc/ei_locking.c $(TARGET)/config.h \ + misc/ei_malloc.h misc/ei_locking.h +$(MDD_OBJDIR)/ei_malloc.o: misc/ei_malloc.c misc/ei_malloc.h +$(MDD_OBJDIR)/ei_portio.o: misc/ei_portio.c misc/ei_portio.h misc/ei_internal.h +$(MDD_OBJDIR)/ei_printterm.o: misc/ei_printterm.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/ei_printterm.h misc/ei_malloc.h +$(MDD_OBJDIR)/ei_pthreads.o: misc/ei_pthreads.c $(TARGET)/config.h \ + ../include/ei.h misc/ei_locking.h +$(MDD_OBJDIR)/ei_trace.o: misc/ei_trace.c misc/eidef.h $(TARGET)/config.h \ + ../include/ei.h misc/ei_trace.h +$(MDD_OBJDIR)/ei_x_encode.o: misc/ei_x_encode.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/ei_x_encode.h \ + misc/ei_malloc.h +$(MDD_OBJDIR)/eimd5.o: misc/eimd5.c misc/eimd5.h +$(MDD_OBJDIR)/get_type.o: misc/get_type.c misc/eidef.h $(TARGET)/config.h \ + ../include/ei.h misc/eiext.h misc/putget.h +$(MDD_OBJDIR)/show_msg.o: misc/show_msg.c misc/eidef.h $(TARGET)/config.h \ + ../include/ei.h misc/eiext.h misc/putget.h misc/ei_printterm.h \ + misc/ei_internal.h misc/show_msg.h +$(MDD_OBJDIR)/ei_compat.o: misc/ei_compat.c ../include/ei.h misc/ei_internal.h +$(MDD_OBJDIR)/hash_dohash.o: registry/hash_dohash.c registry/hash.h ../include/ei.h +$(MDD_OBJDIR)/hash_foreach.o: registry/hash_foreach.c registry/hash.h ../include/ei.h +$(MDD_OBJDIR)/hash_freetab.o: registry/hash_freetab.c registry/hash.h ../include/ei.h +$(MDD_OBJDIR)/hash_insert.o: registry/hash_insert.c registry/hash.h ../include/ei.h +$(MDD_OBJDIR)/hash_isprime.o: registry/hash_isprime.c registry/hash.h ../include/ei.h +$(MDD_OBJDIR)/hash_lookup.o: registry/hash_lookup.c registry/hash.h ../include/ei.h +$(MDD_OBJDIR)/hash_newtab.o: registry/hash_newtab.c registry/hash.h ../include/ei.h +$(MDD_OBJDIR)/hash_remove.o: registry/hash_remove.c registry/hash.h ../include/ei.h +$(MDD_OBJDIR)/hash_resize.o: registry/hash_resize.c registry/hash.h ../include/ei.h +$(MDD_OBJDIR)/hash_rlookup.o: registry/hash_rlookup.c registry/hash.h ../include/ei.h +$(MDD_OBJDIR)/reg_close.o: registry/reg_close.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MDD_OBJDIR)/reg_delete.o: registry/reg_delete.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MDD_OBJDIR)/reg_dirty.o: registry/reg_dirty.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MDD_OBJDIR)/reg_dump.o: registry/reg_dump.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \ + connect/ei_connect_int.h +$(MDD_OBJDIR)/reg_free.o: registry/reg_free.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MDD_OBJDIR)/reg_get.o: registry/reg_get.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MDD_OBJDIR)/reg_getf.o: registry/reg_getf.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MDD_OBJDIR)/reg_geti.o: registry/reg_geti.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MDD_OBJDIR)/reg_getp.o: registry/reg_getp.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MDD_OBJDIR)/reg_gets.o: registry/reg_gets.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MDD_OBJDIR)/reg_make.o: registry/reg_make.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MDD_OBJDIR)/reg_open.o: registry/reg_open.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MDD_OBJDIR)/reg_purge.o: registry/reg_purge.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MDD_OBJDIR)/reg_resize.o: registry/reg_resize.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MDD_OBJDIR)/reg_restore.o: registry/reg_restore.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \ + connect/ei_connect_int.h +$(MDD_OBJDIR)/reg_set.o: registry/reg_set.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MDD_OBJDIR)/reg_setf.o: registry/reg_setf.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MDD_OBJDIR)/reg_seti.o: registry/reg_seti.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MDD_OBJDIR)/reg_setp.o: registry/reg_setp.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MDD_OBJDIR)/reg_sets.o: registry/reg_sets.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MDD_OBJDIR)/reg_stat.o: registry/reg_stat.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MDD_OBJDIR)/reg_tabstat.o: registry/reg_tabstat.c registry/reg.h ../include/ei.h \ + registry/hash.h +$(MDD_OBJDIR)/decode_term.o: legacy/decode_term.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h ../include/erl_interface.h +$(MDD_OBJDIR)/encode_term.o: legacy/encode_term.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + misc/putget.h misc/ei_x_encode.h ../include/erl_interface.h \ + legacy/erl_marshal.h legacy/erl_eterm.h legacy/portability.h +$(MDD_OBJDIR)/erl_connect.o: legacy/erl_connect.c $(TARGET)/config.h \ + ../include/erl_interface.h ../include/ei.h legacy/erl_config.h \ + legacy/erl_connect.h legacy/erl_eterm.h legacy/portability.h \ + legacy/erl_malloc.h misc/putget.h connect/ei_connect_int.h \ + misc/ei_locking.h epmd/ei_epmd.h misc/ei_internal.h +$(MDD_OBJDIR)/erl_error.o: legacy/erl_error.c $(TARGET)/config.h \ + ../include/erl_interface.h ../include/ei.h legacy/erl_error.h +$(MDD_OBJDIR)/erl_eterm.o: legacy/erl_eterm.c misc/ei_locking.h \ + $(TARGET)/config.h connect/ei_resolve.h \ + ../include/erl_interface.h ../include/ei.h legacy/erl_eterm.h \ + legacy/portability.h legacy/erl_malloc.h legacy/erl_marshal.h \ + legacy/erl_error.h legacy/erl_internal.h misc/ei_internal.h +$(MDD_OBJDIR)/erl_fix_alloc.o: legacy/erl_fix_alloc.c $(TARGET)/config.h \ + misc/ei_locking.h ../include/erl_interface.h ../include/ei.h \ + legacy/erl_error.h legacy/erl_malloc.h legacy/erl_fix_alloc.h \ + legacy/erl_eterm.h legacy/portability.h +$(MDD_OBJDIR)/erl_format.o: legacy/erl_format.c ../include/erl_interface.h \ + ../include/ei.h legacy/erl_eterm.h legacy/portability.h \ + legacy/erl_malloc.h legacy/erl_error.h legacy/erl_internal.h +$(MDD_OBJDIR)/erl_malloc.o: legacy/erl_malloc.c ../include/erl_interface.h \ + ../include/ei.h legacy/erl_fix_alloc.h legacy/erl_malloc.h \ + legacy/erl_internal.h legacy/erl_eterm.h legacy/portability.h \ + misc/ei_malloc.h +$(MDD_OBJDIR)/erl_marshal.o: legacy/erl_marshal.c $(TARGET)/config.h \ + ../include/erl_interface.h ../include/ei.h legacy/erl_marshal.h \ + legacy/erl_eterm.h legacy/portability.h legacy/erl_malloc.h \ + legacy/erl_error.h legacy/erl_internal.h misc/eiext.h misc/putget.h +$(MDD_OBJDIR)/erl_timeout.o: legacy/erl_timeout.c $(TARGET)/config.h \ + legacy/erl_timeout.h +$(MDD_OBJDIR)/global_names.o: legacy/global_names.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \ + ../include/erl_interface.h legacy/erl_connect.h +$(MDD_OBJDIR)/global_register.o: legacy/global_register.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + connect/eisend.h connect/eirecv.h ../include/erl_interface.h +$(MDD_OBJDIR)/global_unregister.o: legacy/global_unregister.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \ + ../include/erl_interface.h legacy/erl_connect.h +$(MDD_OBJDIR)/global_whereis.o: legacy/global_whereis.c misc/eidef.h \ + $(TARGET)/config.h ../include/ei.h misc/eiext.h \ + connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \ + ../include/erl_interface.h legacy/erl_connect.h + diff --git a/lib/erl_interface/src/eidefs.mk.in b/lib/erl_interface/src/eidefs.mk.in new file mode 100644 index 0000000000..05f61236c3 --- /dev/null +++ b/lib/erl_interface/src/eidefs.mk.in @@ -0,0 +1,31 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2004-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +# ---------------------------------------------------------------------- + +# Have the ei and erl_interface libs been compiled for threads? +EI_THREADS=@EI_THREADS@ + +# Threads flags +THR_DEFS=@THR_DEFS@ + +# Threads libs +THR_LIBS=@THR_LIBS@ + +# ---------------------------------------------------------------------- diff --git a/lib/erl_interface/src/encode/eicode.h b/lib/erl_interface/src/encode/eicode.h new file mode 100644 index 0000000000..cf008b7fa9 --- /dev/null +++ b/lib/erl_interface/src/encode/eicode.h @@ -0,0 +1,69 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifndef _EICODE_H +#define _EICODE_H + +/* + * The following functions are used to encode from c native types directly into + * Erlang external format. To use them, you need + * + * - a destination buffer + * - an index counter + * - some data + * - an idea of how you want to represent the data as an Erlang term. + * + * You can encode exactly one (1) term into the buffer if you are + * going to transmit it to Erlang. Do the following: + * + * 1. Set your index to 0 + * 2. Encode the version into the buffer: ei_encode_version(buf,&index); + * The function has now advanced index so the next item can be encoded. + * 3. Encode your term: + * + * Encoding non-compound types (i.e. not lists or tuples) is + * straightforward. Just do it! + * + * Encoding tuples is done by first encoding the tuple header (it + * contains the arity) and then encoding the tuple elements in + * sequence. + * + * Encoding lists is done by first encoding the list header (it + * contains the arity) and then encoding the list elements in + * sequence, and finally encoding an empty list. + * + * After all this, the index counter will tell you how much buffer you + * used. If you really need to know in advance how big the buffer + * should be, go through the same steps but with a NULL buffer. No + * attempt will be made to modify the buffer, but index will be + * updated as though you really did encode something. + */ + +/* encode the given object into buf[index] as 'type'. 0 is + * returned and index is updated to the position for the next item. if + * buf == NULL, no data is actually copied, but index is updated to + * indicate the number of bytes that would have been necessary. + */ + +/* FIXME where do we put these..... */ + +erlang_big *ei_alloc_big(int arity); +void ei_free_big(erlang_big *b); + + +#endif /* _EICODE_H */ diff --git a/lib/erl_interface/src/encode/encode_atom.c b/lib/erl_interface/src/encode/encode_atom.c new file mode 100644 index 0000000000..69f2d1451c --- /dev/null +++ b/lib/erl_interface/src/encode/encode_atom.c @@ -0,0 +1,51 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +int ei_encode_atom(char *buf, int *index, const char *p) +{ + return ei_encode_atom_len(buf, index, p, strlen(p)); +} + +int ei_encode_atom_len(char *buf, int *index, const char *p, int len) +{ + char *s = buf + *index; + char *s0 = s; + + /* This function is documented to truncate at MAXATOMLEN (256) */ + if (len > MAXATOMLEN) + len = MAXATOMLEN; + + if (!buf) s += 3; + else { + put8(s,ERL_ATOM_EXT); + put16be(s,len); + + memmove(s,p,len); /* unterminated string */ + } + s += len; + + *index += s-s0; + + return 0; +} + diff --git a/lib/erl_interface/src/encode/encode_big.c b/lib/erl_interface/src/encode/encode_big.c new file mode 100644 index 0000000000..25abf424b7 --- /dev/null +++ b/lib/erl_interface/src/encode/encode_big.c @@ -0,0 +1,84 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +#include +#include "eidef.h" +#include "eiext.h" +#include "putget.h" +#include "ei_x_encode.h" + +int ei_encode_big(char *buf, int *index, erlang_big* big) { + unsigned char *s = (unsigned char *)buf + *index; + unsigned char *s0 = s; + unsigned int digit_bytes = big->arity; + unsigned int n = (digit_bytes+1)/2; + + if (digit_bytes < 256) { + if (buf) { + put8(s, ERL_SMALL_BIG_EXT); + put8(s, digit_bytes); + } else { + s += 2; + } + } else { + if (buf) { + put8(s, ERL_LARGE_BIG_EXT); + put32be(s, digit_bytes); + } else { + s += 5; + } + } + + if (buf) { + int i; + unsigned char hi, lo; + unsigned short *dt = big->digits; + put8(s, big->is_neg); + + for (i = 0; i < n; ++i) { + + hi = (unsigned char) (dt[i] >> 8); + lo = (unsigned char) (dt[i]); + + s[i*2] = lo; + if ((i*2 + 1) < digit_bytes) { + s[i*2 + 1] = hi; + } + } + + } else { + s ++; /* skip sign bit */ + } + + s += digit_bytes; + + *index += s-s0; + + return 0; +} + +int ei_x_encode_big(ei_x_buff* x, erlang_big* big) { + int i = x->index; + + ei_encode_big(NULL, &i, big); + if (!x_fix_buff(x, i)) + return -1; + return ei_encode_big(x->buff, &x->index, big); +} + diff --git a/lib/erl_interface/src/encode/encode_bignum.c b/lib/erl_interface/src/encode/encode_bignum.c new file mode 100644 index 0000000000..6850cb86a6 --- /dev/null +++ b/lib/erl_interface/src/encode/encode_bignum.c @@ -0,0 +1,81 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2002-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +#include "eidef.h" + +#if defined(HAVE_GMP_H) && defined(HAVE_LIBGMP) + +#include + +#include "eidef.h" +#include "eiext.h" +#include "putget.h" +#include "ei_x_encode.h" + +int ei_encode_bignum(char *buf, int *index, mpz_t obj) +{ + char *s = buf + *index; + char *s0 = s; + size_t count; + int mpz_sign = mpz_sgn(obj); + + /* + * FIXME we could code into ERL_[SMALL_]INTEGER_EXT but to make + * this code simple for now we always code into ERL_SMALL_BIG_EXT + */ + + if (mpz_sign == 0) { /* Special case, bignum is zero */ + if (!buf) s += 2; + else { + put8(s,ERL_SMALL_INTEGER_EXT); + put8(s,0); + } + } else { + + if (!buf) { + int numb = 8; /* # bits in each external format limb */ + s += (mpz_sizeinbase(obj, 2) + numb-1) / numb; + } else { + char *arityp; + + put8(s,ERL_LARGE_BIG_EXT); + arityp = s; /* fill in later */ + s += 4; + put8(s, mpz_sign == 1); /* save sign separately */ + mpz_export(s, &count, -1, 1, 0, 0, obj); + s += count; + put32le(arityp, count); + } + } + + *index += s-s0; + + return 0; +} + +int ei_x_encode_bignum(ei_x_buff* x, mpz_t n) +{ + int i = x->index; + ei_encode_bignum(NULL, &i, n); + if (!x_fix_buff(x, i)) + return -1; + return ei_encode_bignum(x->buff, &x->index, n); +} + +#endif /* HAVE_GMP_H && HAVE_LIBGMP */ diff --git a/lib/erl_interface/src/encode/encode_binary.c b/lib/erl_interface/src/encode/encode_binary.c new file mode 100644 index 0000000000..67a4dc1219 --- /dev/null +++ b/lib/erl_interface/src/encode/encode_binary.c @@ -0,0 +1,41 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +int ei_encode_binary(char *buf, int *index, const void *p, long len) +{ + char *s = buf + *index; + char *s0 = s; + + if (!buf) s += 5; + else { + put8(s,ERL_BINARY_EXT); + put32be(s,len); + memmove(s,p,len); + } + s += len; + + *index += s-s0; + + return 0; +} + diff --git a/lib/erl_interface/src/encode/encode_boolean.c b/lib/erl_interface/src/encode/encode_boolean.c new file mode 100644 index 0000000000..51a166bea5 --- /dev/null +++ b/lib/erl_interface/src/encode/encode_boolean.c @@ -0,0 +1,47 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +int ei_encode_boolean(char *buf, int *index, int p) +{ + char *s = buf + *index; + char *s0 = s; + char *val; + int len; + + val = p ? "true" : "false"; + len = strlen(val); + + if (!buf) s += 3; + else { + put8(s,ERL_ATOM_EXT); + put16be(s,len); + + memmove(s,val,len); /* unterminated string */ + } + s += len; + + *index += s-s0; + + return 0; +} + diff --git a/lib/erl_interface/src/encode/encode_char.c b/lib/erl_interface/src/encode/encode_char.c new file mode 100644 index 0000000000..a7d27c5261 --- /dev/null +++ b/lib/erl_interface/src/encode/encode_char.c @@ -0,0 +1,38 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +int ei_encode_char(char *buf, int *index, char p) +{ + char *s = buf + *index; + char *s0 = s; + + if (!buf) s += 2; + else { + put8(s,ERL_SMALL_INTEGER_EXT); + put8(s,(p & 0xff)); + } + + *index += s-s0; + + return 0; +} + diff --git a/lib/erl_interface/src/encode/encode_double.c b/lib/erl_interface/src/encode/encode_double.c new file mode 100644 index 0000000000..53f3d52ba6 --- /dev/null +++ b/lib/erl_interface/src/encode/encode_double.c @@ -0,0 +1,42 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include +#include +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +int ei_encode_double(char *buf, int *index, double p) +{ + char *s = buf + *index; + char *s0 = s; + + if (!buf) s ++; + else { + put8(s,ERL_FLOAT_EXT); + memset(s, 0, 31); + sprintf(s, "%.20e", p); + } + s += 31; + + *index += s-s0; + + return 0; +} + diff --git a/lib/erl_interface/src/encode/encode_fun.c b/lib/erl_interface/src/encode/encode_fun.c new file mode 100644 index 0000000000..54ee2083d6 --- /dev/null +++ b/lib/erl_interface/src/encode/encode_fun.c @@ -0,0 +1,82 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +int ei_encode_fun(char *buf, int *index, const erlang_fun *p) +{ + int ix = *index; + + if (p->arity == -1) { + /* ERL_FUN_EXT */ + if (buf != NULL) { + char* s = buf + ix; + put8(s, ERL_FUN_EXT); + put32be(s, p->n_free_vars); + } + ix += sizeof(char) + 4; + if (ei_encode_pid(buf, &ix, &p->pid) < 0) + return -1; + if (ei_encode_atom(buf, &ix, p->module) < 0) + return -1; + if (ei_encode_long(buf, &ix, p->index) < 0) + return -1; + if (ei_encode_long(buf, &ix, p->uniq) < 0) + return -1; + if (buf != NULL) + memcpy(buf + ix, p->free_vars, p->free_var_len); + ix += p->free_var_len; + } else { + char *size_p; + /* ERL_NEW_FUN_EXT */ + if (buf != NULL) { + char* s = buf + ix; + put8(s, ERL_NEW_FUN_EXT); + size_p = s; + s += 4; + put8(s, p->arity); + memcpy(s, p->md5, sizeof(p->md5)); + s += sizeof(p->md5); + put32be(s, p->index); + put32be(s, p->n_free_vars); + } else + size_p = NULL; + ix += 1 + 4 + 1 + sizeof(p->md5) + 4 + 4; + if (ei_encode_atom(buf, &ix, p->module) < 0) + return -1; + if (ei_encode_long(buf, &ix, p->old_index) < 0) + return -1; + if (ei_encode_long(buf, &ix, p->uniq) < 0) + return -1; + if (ei_encode_pid(buf, &ix, &p->pid) < 0) + return -1; + if (buf != NULL) + memcpy(buf + ix, p->free_vars, p->free_var_len); + ix += p->free_var_len; + if (size_p != NULL) { + int sz = buf + ix - size_p; + put32be(size_p, sz); + } + } + *index = ix; + return 0; +} + diff --git a/lib/erl_interface/src/encode/encode_list_header.c b/lib/erl_interface/src/encode/encode_list_header.c new file mode 100644 index 0000000000..27da70ae15 --- /dev/null +++ b/lib/erl_interface/src/encode/encode_list_header.c @@ -0,0 +1,45 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +int ei_encode_list_header(char *buf, int *index, int arity) +{ + char *s = buf + *index; + char *s0 = s; + + if (arity < 0) return -1; + else if (arity > 0) { + if (!buf) s += 5; + else { + put8(s,ERL_LIST_EXT); + put32be(s,arity); + } + } + else { + /* empty list */ + if (!buf) s++; + else put8(s,ERL_NIL_EXT); + } + + *index += s-s0; + + return 0; +} diff --git a/lib/erl_interface/src/encode/encode_long.c b/lib/erl_interface/src/encode/encode_long.c new file mode 100644 index 0000000000..d616bb6e47 --- /dev/null +++ b/lib/erl_interface/src/encode/encode_long.c @@ -0,0 +1,64 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +#define abs(p) (((p)<0) ? -(p) : p) + +/* long -> erl_integer */ +/* note that this is the only place where data is stored Little Endian */ + +#ifndef EI_64BIT +int ei_encode_long(char *buf, int *index, long p) +{ + char *s = buf + *index; + char *s0 = s; + + if ((p < 256) && (p >= 0)) { + if (!buf) s += 2; + else { + put8(s,ERL_SMALL_INTEGER_EXT); + put8(s,(p & 0xff)); + } + } + else if ((p <= ERL_MAX) && (p >= ERL_MIN)) { + /* FIXME: Non optimal, could use (p <= LONG_MAX) && (p >= LONG_MIN) + and skip next case */ + if (!buf) s += 5; + else { + put8(s,ERL_INTEGER_EXT); + put32be(s,p); + } + } + else { + if (!buf) s += 7; + else { + put8(s,ERL_SMALL_BIG_EXT); + put8(s,4); /* len = four bytes */ + put8(s, p < 0); /* save sign separately */ + put32le(s, abs(p)); /* OBS: Little Endian, and p now positive */ + } + } + + *index += s-s0; + + return 0; +} +#endif /* EI_64BIT */ diff --git a/lib/erl_interface/src/encode/encode_longlong.c b/lib/erl_interface/src/encode/encode_longlong.c new file mode 100644 index 0000000000..aff24e2478 --- /dev/null +++ b/lib/erl_interface/src/encode/encode_longlong.c @@ -0,0 +1,103 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2002-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include "eidef.h" +#include "eiext.h" +#include "putget.h" +#include "ei_x_encode.h" + +#define abs(p) (((p)<0) ? -(p) : p) + +/* long -> erl_integer */ +/* note that this is the only place where data is stored Little Endian */ + +/* + * For some 64 bit operations on some operating systems code + * compiled with GNU cc depends on "libgcc" for some 64 bit + * operations missing in hardware (or because of gcc bugs). + * If user code was linked together with the ei lib + * using other linkers than GNU ld this may cause problems. + * We moved ei_x_encode_longlong() here from "ei_x_encode.c" + * to limit this problem to users that actually use the ei + * longlong operations, not all ei_x users. + */ +int ei_x_encode_longlong(ei_x_buff* x, EI_LONGLONG n) +{ + int i = x->index; + ei_encode_longlong(NULL, &i, n); + if (!x_fix_buff(x, i)) + return -1; + return ei_encode_longlong(x->buff, &x->index, n); +} + +#ifdef EI_64BIT +int ei_encode_long(char *buf, int *index, long p) +{ + return ei_encode_longlong(buf, index, p); +} +#endif + +int ei_encode_longlong(char *buf, int *index, EI_LONGLONG p) +{ + char *s = buf + *index; + char *s0 = s; + + if ((p < 256) && (p >= 0)) { + if (!buf) s += 2; + else { + put8(s,ERL_SMALL_INTEGER_EXT); + put8(s,(p & 0xff)); + } + } else if ((p <= ERL_MAX) && (p >= ERL_MIN)) { + /* FIXME: Non optimal, could use (p <= LONG_MAX) && (p >= LONG_MIN) + and skip next case */ + if (!buf) s += 5; + else { + put8(s,ERL_INTEGER_EXT); + put32be(s,p); + } + } else { + /* We know 28-64 bits needed, i.e four to eight bytes */ + EI_ULONGLONG up = abs(p); /* FIXME name uabs(x) not to confuse with abs */ + if (buf) { + char *arityp; + int arity = 0; + + put8(s,ERL_SMALL_BIG_EXT); + arityp = s++; /* fill in later */ + put8(s, p < 0); /* save sign separately */ + while (up) { + *s++ = up & 0xff; /* take lowest byte */ + up >>= 8; /* shift unsigned */ + arity++; + } + put8(arityp,arity); + } else { + s += 3; /* Type, arity and sign */ + while (up) { + s++; /* take lowest byte */ + up >>= 8; /* shift unsigned */ + } + } + } + + *index += s-s0; + + return 0; +} + diff --git a/lib/erl_interface/src/encode/encode_pid.c b/lib/erl_interface/src/encode/encode_pid.c new file mode 100644 index 0000000000..ee7f235c17 --- /dev/null +++ b/lib/erl_interface/src/encode/encode_pid.c @@ -0,0 +1,52 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +int ei_encode_pid(char *buf, int *index, const erlang_pid *p) +{ + char *s = buf + *index; + char *s0 = s; + int len = strlen(p->node); + + if (!buf) s += 13 + len; + else { + put8(s,ERL_PID_EXT); + + /* first the nodename */ + put8(s,ERL_ATOM_EXT); + + put16be(s,len); + + memmove(s, p->node, len); + s += len; + + /* now the integers */ + put32be(s,p->num & 0x7fff); /* 15 bits */ + put32be(s,p->serial & 0x1fff); /* 13 bits */ + put8(s,(p->creation & 0x03)); /* 2 bits */ + } + + *index += s-s0; + + return 0; +} + diff --git a/lib/erl_interface/src/encode/encode_port.c b/lib/erl_interface/src/encode/encode_port.c new file mode 100644 index 0000000000..fbbb33182e --- /dev/null +++ b/lib/erl_interface/src/encode/encode_port.c @@ -0,0 +1,51 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +int ei_encode_port(char *buf, int *index, const erlang_port *p) +{ + char *s = buf + *index; + char *s0 = s; + int len = strlen(p->node); + + if (!buf) s += 9 + len; + else { + put8(s,ERL_PORT_EXT); + + /* first the nodename */ + put8(s,ERL_ATOM_EXT); + + put16be(s,len); + + memmove(s, p->node, len); + s += len; + + /* now the integers */ + put32be(s,p->id & 0x0fffffff /* 28 bits */); + put8(s,(p->creation & 0x03)); + } + + *index += s-s0; + + return 0; +} + diff --git a/lib/erl_interface/src/encode/encode_ref.c b/lib/erl_interface/src/encode/encode_ref.c new file mode 100644 index 0000000000..292b452864 --- /dev/null +++ b/lib/erl_interface/src/encode/encode_ref.c @@ -0,0 +1,59 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +int ei_encode_ref(char *buf, int *index, const erlang_ref *p) +{ + char *s = buf + *index; + char *s0 = s; + int len = strlen(p->node); + int i; + + /* Always encode as an extended reference; all participating parties + are now expected to be able to decode extended references. */ + if (!buf) s += 1 + 2 + (3+len) + p->len*4 + 1; + else { + put8(s,ERL_NEW_REFERENCE_EXT); + + /* first, number of integers */ + put16be(s, p->len); + + /* then the nodename */ + put8(s,ERL_ATOM_EXT); + + put16be(s,len); + + memmove(s, p->node, len); + s += len; + + /* now the integers */ + put8(s,(p->creation & 0x03)); + for (i = 0; i < p->len; i++) + put32be(s,p->n[i]); + + } + + *index += s-s0; + + return 0; +} + diff --git a/lib/erl_interface/src/encode/encode_string.c b/lib/erl_interface/src/encode/encode_string.c new file mode 100644 index 0000000000..1d342cb605 --- /dev/null +++ b/lib/erl_interface/src/encode/encode_string.c @@ -0,0 +1,77 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + + +int ei_encode_string(char *buf, int *index, const char *p) +{ + return ei_encode_string_len(buf, index, p, strlen(p)); +} + +int ei_encode_string_len(char *buf, int *index, const char *p, int len) +{ + char *s = buf + *index; + char *s0 = s; + int i; + + if (len == 0) { + + if (!buf) { + s += 1; + } else { + put8(s,ERL_NIL_EXT); + } + + } else if (len <= 0xffff) { + + if (!buf) { + s += 3; + } else { + put8(s,ERL_STRING_EXT); + put16be(s,len); + memmove(s,p,len); /* unterminated string */ + } + s += len; + + } else { + + if (!buf) { + s += 5 + (2*len) + 1; + } else { + /* strings longer than 65535 are encoded as lists */ + put8(s,ERL_LIST_EXT); + put32be(s,len); + + for (i=0; iflags); + ei_encode_long(buf,index,p->label); + ei_encode_long(buf,index,p->serial); + ei_encode_pid(buf,index,&p->from); + ei_encode_long(buf,index,p->prev); + + /* index is updated by the functions we called */ + + return 0; +} + diff --git a/lib/erl_interface/src/encode/encode_tuple_header.c b/lib/erl_interface/src/encode/encode_tuple_header.c new file mode 100644 index 0000000000..97a3d1f808 --- /dev/null +++ b/lib/erl_interface/src/encode/encode_tuple_header.c @@ -0,0 +1,49 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +int ei_encode_tuple_header(char *buf, int *index, int arity) +{ + char *s = buf + *index; + char *s0 = s; + + if (arity < 0) return -1; + + if (arity <= 0xff) { + if (!buf) s += 2; + else { + put8(s,ERL_SMALL_TUPLE_EXT); + put8(s,arity); + } + } + else { + if (!buf) s += 5; + else { + put8(s,ERL_LARGE_TUPLE_EXT); + put32be(s,arity); + } + } + + *index += s-s0; + + return 0; +} + diff --git a/lib/erl_interface/src/encode/encode_ulong.c b/lib/erl_interface/src/encode/encode_ulong.c new file mode 100644 index 0000000000..c4ff34e493 --- /dev/null +++ b/lib/erl_interface/src/encode/encode_ulong.c @@ -0,0 +1,57 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +#ifndef EI_64BIT +int ei_encode_ulong(char *buf, int *index, unsigned long p) +{ + char *s = buf + *index; + char *s0 = s; + + if (p > ERL_MAX) { + if (!buf) s += 7; + else { + put8(s,ERL_SMALL_BIG_EXT); + put8(s,4); /* len = four bytes */ + put8(s, 0); /* save sign separately */ + put32le(s,p); /* OBS: Little Endian, and p now positive */ + } + } + else if ((p < 256) && (p >= 0)) { + if (!buf) s += 2; + else { + put8(s,ERL_SMALL_INTEGER_EXT); + put8(s,(p & 0xff)); + } + } + else { + if (!buf) s += 5; + else { + put8(s,ERL_INTEGER_EXT); + put32be(s,p); + } + } + + *index += s-s0; + + return 0; +} +#endif /* EI_64BIT */ diff --git a/lib/erl_interface/src/encode/encode_ulonglong.c b/lib/erl_interface/src/encode/encode_ulonglong.c new file mode 100644 index 0000000000..0f21af2a91 --- /dev/null +++ b/lib/erl_interface/src/encode/encode_ulonglong.c @@ -0,0 +1,94 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2002-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include "eidef.h" +#include "eiext.h" +#include "putget.h" +#include "ei_x_encode.h" + +/* + * For some 64 bit operations on some operating systems code + * compiled with GNU cc depends on "libgcc" for some 64 bit + * operations missing in hardware (or because of gcc bugs). + * If user code was linked together with the ei lib + * using other linkers than GNU ld this may cause problems. + * We moved ei_x_encode_ulonglong() here from "ei_x_encode.c" + * to limit this problem to users that actually use the ei + * longlong operations, not all ei_x users. + */ +int ei_x_encode_ulonglong(ei_x_buff* x, EI_ULONGLONG n) +{ + int i = x->index; + ei_encode_ulonglong(NULL, &i, n); + if (!x_fix_buff(x, i)) + return -1; + return ei_encode_ulonglong(x->buff, &x->index, n); +} + +#ifdef EI_64BIT +int ei_encode_ulong(char *buf, int *index, unsigned long p) +{ + return ei_encode_ulonglong(buf, index, p); +} +#endif + +int ei_encode_ulonglong(char *buf, int *index, EI_ULONGLONG p) +{ + char *s = buf + *index; + char *s0 = s; + + if ((p < 256) && (p >= 0)) { + if (!buf) s += 2; + else { + put8(s,ERL_SMALL_INTEGER_EXT); + put8(s,(p & 0xff)); + } + } else if (p <= ERL_MAX) { + if (!buf) s += 5; + else { + put8(s,ERL_INTEGER_EXT); + put32be(s,p); + } + } else { + /* We know 28-64 bits needed, i.e four to eight bytes */ + if (buf) { + char *arityp; + int arity = 0; + put8(s,ERL_SMALL_BIG_EXT); + arityp = s++; /* fill in later */ + put8(s, 0); /* save sign separately */ + while (p) { + *s++ = p & 0xff; /* take lowest byte */ + p >>= 8; /* shift unsigned */ + arity++; + } + put8(arityp,arity); + } else { + s += 3; /* Type, arity and sign */ + while (p) { + s++; /* take lowest byte */ + p >>= 8; /* shift unsigned */ + } + } + } + + *index += s-s0; + + return 0; +} + diff --git a/lib/erl_interface/src/encode/encode_version.c b/lib/erl_interface/src/encode/encode_version.c new file mode 100644 index 0000000000..3fd9fdabd4 --- /dev/null +++ b/lib/erl_interface/src/encode/encode_version.c @@ -0,0 +1,35 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +/* add the version identifier to the start of the buffer */ +int ei_encode_version(char *buf, int *index) +{ + char *s = buf + *index; + char *s0 = s; + + if (!buf) s ++; + else put8(s,(unsigned char)ERL_VERSION_MAGIC); + *index += s-s0; + + return 0; +} + diff --git a/lib/erl_interface/src/epmd/ei_epmd.h b/lib/erl_interface/src/epmd/ei_epmd.h new file mode 100644 index 0000000000..40e5ece572 --- /dev/null +++ b/lib/erl_interface/src/epmd/ei_epmd.h @@ -0,0 +1,66 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifndef _EI_EPMD_H +#define _EI_EPMD_H + +#ifndef INADDR_LOOPBACK +#define INADDR_LOOPBACK ((u_long) 0x7F000001) +#endif + +#ifndef EI_DIST_HIGH +#define EI_DIST_HIGH 5 /* R4 and later */ +#define EI_DIST_LOW 1 /* R3 and earlier */ +#endif + +#ifndef EPMD_PORT +#define EPMD_PORT 4369 +#endif + +#ifndef EPMDBUF +#define EPMDBUF 512 +#endif + +#ifndef EI_MYPROTO +#define EI_MYPROTO 0 /* tcp/ip */ +#endif + +/* epmd r3 protocol */ +#ifndef EI_EPMD_ALIVE_REQ +#define EI_EPMD_ALIVE_REQ 'a' +#define EI_EPMD_ALIVE_OK_RESP 'Y' +#define EI_EPMD_PORT_REQ 'p' +#define EI_EPMD_STOP_REQ 's' +#endif + +/* epmd r4 */ +#ifndef EI_EPMD_ALIVE2_REQ +#define EI_EPMD_ALIVE2_REQ 120 +#define EI_EPMD_ALIVE2_RESP 121 +#define EI_EPMD_PORT2_REQ 122 +#define EI_EPMD_PORT2_RESP 119 +#endif + +/* internal functions */ +int ei_epmd_connect_tmo(struct in_addr *inaddr, unsigned ms); +int ei_epmd_publish(int port, const char *alive); +int ei_epmd_publish_tmo(int port, const char *alive, unsigned ms); +int ei_epmd_port(struct in_addr *inaddr, const char *alive, int *dist); +int ei_epmd_port_tmo(struct in_addr *inaddr, const char *alive, int *dist, unsigned ms); + +#endif /* _EI_EPMD_H */ diff --git a/lib/erl_interface/src/epmd/epmd_port.c b/lib/erl_interface/src/epmd/epmd_port.c new file mode 100644 index 0000000000..663b38d2d4 --- /dev/null +++ b/lib/erl_interface/src/epmd/epmd_port.c @@ -0,0 +1,299 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +#include "eidef.h" + +#ifdef __WIN32__ +#include +#include +#include + +#elif VXWORKS +#include +#include +#include +#include +#include +#include +#include +#include + +#else +#include +#include +#include +#include +#include +#include + +#endif + +#include +#include + +#include "ei.h" +#include "ei_internal.h" +#include "ei_epmd.h" +#include "ei_portio.h" +#include "putget.h" + + +/* connect to epmd on given host (use NULL for localhost) */ +/* + * FIXME: Expects IPv4 addresses (excludes IPv6, Appletalk, IRDA and + * whatever) */ +int ei_epmd_connect_tmo(struct in_addr *inaddr, unsigned ms) +{ + static unsigned int epmd_port = 0; + struct sockaddr_in saddr; + int sd; + int res; + + if (epmd_port == 0) { + char* port_str = getenv("ERL_EPMD_PORT"); + epmd_port = (port_str != NULL) ? atoi(port_str) : EPMD_PORT; + } + memset(&saddr, 0, sizeof(saddr)); + saddr.sin_port = htons(epmd_port); + saddr.sin_family = AF_INET; + + if (!inaddr) saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + else memmove(&saddr.sin_addr,inaddr,sizeof(saddr.sin_addr)); + + if (((sd = socket(PF_INET, SOCK_STREAM, 0)) < 0)) + { + erl_errno = errno; + return -1; + } + + if ((res = ei_connect_t(sd,(struct sockaddr *)&saddr,sizeof(saddr),ms)) < 0) + { + erl_errno = (res == -2) ? ETIMEDOUT : errno; + closesocket(sd); + return -1; + } + + return sd; +} + +/* get the given node's listen port using old epmd protocol */ +static int ei_epmd_r3_port (struct in_addr *addr, const char *alive, + unsigned ms) +{ + char buf[EPMDBUF]; + char *s = buf; + int len = strlen(alive) + 1; + int fd; + int port; + int res; +#if defined(VXWORKS) + char ntoabuf[32]; +#endif + + put16be(s,len); + put8(s,EI_EPMD_PORT_REQ); + strcpy(s,alive); + + /* connect to epmd */ + if ((fd = ei_epmd_connect_tmo(addr,ms)) < 0) + { + /* ei_epmd_connect_tmo() sets erl_errno */ + return -1; + } + + if ((res = ei_write_fill_t(fd, buf, len+2, ms)) != len+2) { + closesocket(fd); + erl_errno = (res == -2) ? ETIMEDOUT : EIO; + return -1; + } + +#ifdef VXWORKS + /* FIXME use union/macro for level. Correct level? */ + if (ei_tracelevel > 2) { + inet_ntoa_b(*addr,ntoabuf); + EI_TRACE_CONN2("ei_epmd_r3_port", + "-> PORT_REQ alive=%s ip=%s",alive,ntoabuf); + } +#else + EI_TRACE_CONN2("ei_epmd_r3_port", + "-> PORT_REQ alive=%s ip=%s",alive,inet_ntoa(*addr)); +#endif + + if ((res = ei_read_fill_t(fd, buf, 2, ms)) != 2) { + EI_TRACE_ERR0("ei_epmd_r3_port","<- CLOSE"); + closesocket(fd); + erl_errno = (res == -2) ? ETIMEDOUT : EIO; + return -1; + } + closesocket(fd); + s = buf; + port = get16be(s); + + EI_TRACE_CONN1("ei_epmd_r3_port","<- PORT_RESP port=%d",port); + + return port; +} + +static int ei_epmd_r4_port (struct in_addr *addr, const char *alive, + int *dist, unsigned ms) +{ + char buf[EPMDBUF]; + char *s = buf; + int len = strlen(alive) + 1; + int fd; + int ntype; + int port; + int dist_high, dist_low, proto; + int res; +#if defined(VXWORKS) + char ntoabuf[32]; +#endif + + put16be(s,len); + put8(s,EI_EPMD_PORT2_REQ); + strcpy(s,alive); + + /* connect to epmd */ + if ((fd = ei_epmd_connect_tmo(addr,ms)) < 0) + { + return -1; + } + + if ((res = ei_write_fill_t(fd, buf, len+2, ms)) != len+2) { + closesocket(fd); + erl_errno = (res == -2) ? ETIMEDOUT : EIO; + return -1; + } + +#ifdef VXWORKS + /* FIXME use union/macro for level. Correct level? */ + if (ei_tracelevel > 2) { + inet_ntoa_b(*addr,ntoabuf); + EI_TRACE_CONN2("ei_epmd_r4_port", + "-> PORT2_REQ alive=%s ip=%s",alive,ntoabuf); + } +#else + EI_TRACE_CONN2("ei_epmd_r4_port", + "-> PORT2_REQ alive=%s ip=%s",alive,inet_ntoa(*addr)); +#endif + + /* read first two bytes (response type, response) */ + if ((res = ei_read_fill_t(fd, buf, 2, ms)) != 2) { + EI_TRACE_ERR0("ei_epmd_r4_port","<- CLOSE"); + erl_errno = (res == -2) ? ETIMEDOUT : EIO; + closesocket(fd); + return -2; /* version mismatch */ + } + + s = buf; + res = get8(s); + + if (res != EI_EPMD_PORT2_RESP) { /* response type */ + EI_TRACE_ERR1("ei_epmd_r4_port","<- unknown (%d)",res); + EI_TRACE_ERR0("ei_epmd_r4_port","-> CLOSE"); + closesocket(fd); + erl_errno = EIO; + return -1; + } + + + + /* got negative response */ + if ((res = get8(s))) { + /* got negative response */ + EI_TRACE_ERR1("ei_epmd_r4_port","<- PORT2_RESP result=%d (failure)",res); + closesocket(fd); + erl_errno = EIO; + return -1; + } + + EI_TRACE_CONN1("ei_epmd_r4_port","<- PORT2_RESP result=%d (ok)",res); + + /* expecting remaining 8 bytes */ + if ((res = ei_read_fill_t(fd,buf,8,ms)) != 8) { + EI_TRACE_ERR0("ei_epmd_r4_port","<- CLOSE"); + erl_errno = (res == -2) ? ETIMEDOUT : EIO; + closesocket(fd); + return -1; + } + + closesocket(fd); + s = buf; + + port = get16be(s); + ntype = get8(s); + proto = get8(s); + dist_high = get16be(s); + dist_low = get16be(s); + + EI_TRACE_CONN5("ei_epmd_r4_port", + " port=%d ntype=%d proto=%d dist-high=%d dist-low=%d", + port,ntype,proto,dist_high,dist_low); + + /* right network protocol? */ + if (EI_MYPROTO != proto) + { + erl_errno = EIO; + return -1; + } + + /* is there overlap in our distribution versions? */ + if ((EI_DIST_HIGH < dist_low) || (EI_DIST_LOW > dist_high)) + { + erl_errno = EIO; + return -1; + } + + /* choose the highest common version */ + /* i.e. min(his-max, my-max) */ + *dist = (dist_high > EI_DIST_HIGH ? EI_DIST_HIGH : dist_high); + + /* ignore the remaining fields */ + return port; +} + +/* lookup the port number of the given node. 'dist' is an out-argument + * which, if the lookup is successful, will be initialized to contain + * the highest distribution version that is common to the calling node + * and the node looked up. The function will attempt to contact epmd + * version 4 before trying version 3. R3 (and earlier) nodes have + * dist=0. + */ +int ei_epmd_port (struct in_addr *addr, const char *alive, int *dist) +{ + return ei_epmd_port_tmo (addr, alive, dist, 0); +} + +int ei_epmd_port_tmo (struct in_addr *addr, const char *alive, int *dist, + unsigned ms) +{ + int i; + + /* try the new one first, then the old one */ + i = ei_epmd_r4_port(addr,alive,dist,ms); + + /* -2: new protocol not understood */ + if (i == -2) { + *dist = 0; + i = ei_epmd_r3_port(addr,alive,ms); + } + + return i; +} + diff --git a/lib/erl_interface/src/epmd/epmd_publish.c b/lib/erl_interface/src/epmd/epmd_publish.c new file mode 100644 index 0000000000..09b3dce43b --- /dev/null +++ b/lib/erl_interface/src/epmd/epmd_publish.c @@ -0,0 +1,228 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +#include "eidef.h" + +#ifdef __WIN32__ +#include +#include +#include + +#elif VXWORKS +#include +#include +#include +#include +#include +#include +#include +#include + +#else +#include +#include +#include +#include +#include +#include + +#endif + +#include +#include + +#include "ei_internal.h" +#include "putget.h" +#include "ei_epmd.h" +#include "ei_portio.h" + + +/* publish our listen port and alive name */ +/* return the (useless) creation number */ +static int ei_epmd_r3_publish (int port, const char *alive, unsigned ms) +{ + char buf[EPMDBUF]; + char *s = buf; + int fd; + int len = strlen(alive) + 3; + int res,creation; + + s = buf; + put16be(s,len); + put8(s,EI_EPMD_ALIVE_REQ); + put16be(s,port); + strcpy(s, alive); + + if ((fd = ei_epmd_connect_tmo(NULL,ms)) < 0) return fd; + + if ((res = ei_write_fill_t(fd, buf, len+2, ms)) != len+2) { + closesocket(fd); + erl_errno = (res == -2) ? ETIMEDOUT : EIO; + return -1; + } + + EI_TRACE_CONN2("ei_epmd_r3_publish", + "-> ALIVE_REQ alive=%s port=%d",alive,port); + + if ((res = ei_read_fill_t(fd, buf, 3, ms)) != 3) { + closesocket(fd); + erl_errno = (res == -2) ? ETIMEDOUT : EIO; + return -1; + } + + s = buf; + if ((res=get8(s)) != EI_EPMD_ALIVE_OK_RESP) { + EI_TRACE_ERR1("ei_epmd_r3_publish", + "<- ALIVE_NOK result=%d (failure)",res); + closesocket(fd); + erl_errno = EIO; + return -1; + } + + creation = get16be(s); + + EI_TRACE_CONN1("ei_epmd_r3_publish","<- ALIVE_OK creation=%d",creation); + + /* Don't close fd here! It keeps us registered with epmd */ + + /* probably should save fd so we can close it later... */ + /* epmd_saveconn(OPEN,fd,alive); */ + + /* return the creation number, for no good reason */ + /* return creation; */ + + /* no! return the descriptor */ + return fd; +} + +/* publish our listen port and alive name */ +/* return the (useless) creation number */ +/* this protocol is a lot more complex than the old one */ +static int ei_epmd_r4_publish (int port, const char *alive, unsigned ms) +{ + char buf[EPMDBUF]; + char *s = buf; + int fd; + int elen = 0; + int nlen = strlen(alive); + int len = elen + nlen + 13; /* hard coded: be careful! */ + int n; + int res, creation; + + s = buf; + put16be(s,len); + + put8(s,EI_EPMD_ALIVE2_REQ); + put16be(s,port); /* port number */ + put8(s,'h'); /* h = r4 hidden node */ + put8(s, EI_MYPROTO); /* protocol 0 ?? */ + put16be(s,EI_DIST_HIGH); /* highest understood version: 1 = R4 */ + put16be(s,EI_DIST_LOW); /* lowest: 0 = R3 */ + put16be(s,nlen); /* length of alivename */ + strcpy(s, alive); + s += nlen; + put16be(s,elen); /* length of extra string = 0 */ + /* no extra string */ + + if ((fd = ei_epmd_connect_tmo(NULL,ms)) < 0) return fd; + + if ((res = ei_write_fill_t(fd, buf, len+2, ms)) != len+2) { + closesocket(fd); + erl_errno = (res == -2) ? ETIMEDOUT : EIO; + return -1; + } + + EI_TRACE_CONN6("ei_epmd_r4_publish", + "-> ALIVE2_REQ alive=%s port=%d ntype=%d " + "proto=%d dist-high=%d dist-low=%d", + alive,port,'H',EI_MYPROTO,EI_DIST_HIGH,EI_DIST_LOW); + + if ((n = ei_read_fill_t(fd, buf, 4, ms)) != 4) { + EI_TRACE_ERR0("ei_epmd_r4_publish","<- CLOSE"); + closesocket(fd); + erl_errno = (n == -2) ? ETIMEDOUT : EIO; + return -2; /* version mismatch */ + } + /* Don't close fd here! It keeps us registered with epmd */ + s = buf; + if (((res=get8(s)) != EI_EPMD_ALIVE2_RESP)) { /* response */ + EI_TRACE_ERR1("ei_epmd_r4_publish","<- unknown (%d)",res); + EI_TRACE_ERR0("ei_epmd_r4_publish","-> CLOSE"); + closesocket(fd); + erl_errno = EIO; + return -1; + } + + EI_TRACE_CONN0("ei_epmd_r4_publish","<- ALIVE2_RESP"); + + if (((res=get8(s)) != 0)) { /* 0 == success */ + EI_TRACE_ERR1("ei_epmd_r4_publish"," result=%d (fail)",res); + closesocket(fd); + erl_errno = EIO; + return -1; + } + + creation = get16be(s); + + EI_TRACE_CONN2("ei_epmd_r4_publish", + " result=%d (ok) creation=%d",res,creation); + + /* probably should save fd so we can close it later... */ + /* epmd_saveconn(OPEN,fd,alive); */ + + /* return the creation number, for no good reason */ + /* return creation;*/ + + /* no - return the descriptor */ + return fd; +} + +int ei_epmd_publish(int port, const char *alive) +{ + return ei_epmd_publish_tmo(port, alive, 0); +} + +int ei_epmd_publish_tmo(int port, const char *alive, unsigned ms) +{ + int i; + + /* try the new one first, then the old one */ + i = ei_epmd_r4_publish(port,alive, ms); + + /* -2: new protocol not understood */ + if (i == -2) i = ei_epmd_r3_publish(port,alive, ms); + + return i; +} + + +/* + * Publish a name for our C-node. + * a file descriptor is returned - close it to unpublish. + * + */ +int ei_publish(ei_cnode* ec, int port) +{ + return ei_epmd_publish(port, ei_thisalivename(ec)); +} + +int ei_publish_tmo(ei_cnode* ec, int port, unsigned ms) +{ + return ei_epmd_publish_tmo(port, ei_thisalivename(ec), ms); +} diff --git a/lib/erl_interface/src/epmd/epmd_unpublish.c b/lib/erl_interface/src/epmd/epmd_unpublish.c new file mode 100644 index 0000000000..08662fe1ec --- /dev/null +++ b/lib/erl_interface/src/epmd/epmd_unpublish.c @@ -0,0 +1,106 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifdef __WIN32__ +#include +#include +#include + +#elif VXWORKS +#include +#include +#include +#include +#include +#include +#include +#include + +#else +#include +#include +#include +#include +#include +#include + +#endif + +#include +#include + +#include "eidef.h" +#include "ei_internal.h" +#include "putget.h" +#include "ei_epmd.h" +#include "ei_portio.h" + + +/* stop the specified node */ +int ei_unpublish_tmo(const char *alive, unsigned ms) +{ + char buf[EPMDBUF]; + char *s = (char*)buf; + int len = 1 + strlen(alive); + int fd, res; + + put16be(s,len); + put8(s,EI_EPMD_STOP_REQ); + strcpy(s, alive); + + /* FIXME can't connect, return success?! At least commen whats up */ + if ((fd = ei_epmd_connect_tmo(NULL,ms)) < 0) return fd; + + if ((res = ei_write_fill_t(fd, buf, len+2,ms)) != len+2) { + closesocket(fd); + erl_errno = (res == -2) ? ETIMEDOUT : EIO; + return -1; + } + + EI_TRACE_CONN1("ei_unpublish_tmo","-> STOP %s",alive); + + if ((res = ei_read_fill_t(fd, buf, 7, ms)) != 7) { + closesocket(fd); + erl_errno = (res == -2) ? ETIMEDOUT : EIO; + return -1; + } + closesocket(fd); + buf[7]=(char)0; /* terminate the string */ + + if (!strcmp("STOPPED",(char *)buf)) { + EI_TRACE_CONN0("ei_unpublish_tmo","<- STOPPED (success)"); + return 0; + } + else if (!strcmp("NOEXIST",(char *)buf)) { + EI_TRACE_ERR0("ei_unpublish_tmo","<- NOEXIST (failure)"); + erl_errno = EIO; + return -1; + } + else { + EI_TRACE_ERR0("ei_unpublish_tmo","<- unknown (failure)"); + erl_errno = EIO; + return -1; /* this shouldn't happen */ + } + return 0; +} + + +int ei_unpublish(ei_cnode* ec) +{ + return ei_unpublish_tmo(ei_thisalivename(ec),0); +} diff --git a/lib/erl_interface/src/legacy/decode_term.c b/lib/erl_interface/src/legacy/decode_term.c new file mode 100644 index 0000000000..ef29d6f57d --- /dev/null +++ b/lib/erl_interface/src/legacy/decode_term.c @@ -0,0 +1,142 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include "eidef.h" +#include "eiext.h" +#include "putget.h" +#include "erl_interface.h" + +/* + * This file is actually part of the erl_interface library, + * not the newer 'ei' library. The header file is still in "ei.h" + */ + +/* FIXME: is this to be completed? */ + +#if (0) +int ei_decode_term(const char *buf, int *index, void *t) +{ + const char *s = buf + *index; + const char *s0 = s; + + if (t) { + ETERM *tmp; + + /* this decodes and advances s */ + if (!(tmp = erl_decode_buf((unsigned char **)&s))) return -1; + + *(ETERM **)t = tmp; + *index += s - s0; + + return 0; + } + else { + int tmpindex = *index; + long ttype; + int arity; + int i; + + /* these are all the external types */ + switch ((ttype = get8(s))) { + case ERL_SMALL_INTEGER_EXT: + case ERL_INTEGER_EXT: + case ERL_SMALL_BIG_EXT: + return ei_decode_long(buf,index,NULL); + + case ERL_FLOAT_EXT: + return ei_decode_double(buf,index,NULL); + + case ERL_ATOM_EXT: + return ei_decode_atom(buf,index,NULL); + + case ERL_REFERENCE_EXT: + case ERL_NEW_REFERENCE_EXT: + return ei_decode_ref(buf,index,NULL); + + case ERL_PORT_EXT: + return ei_decode_port(buf,index,NULL); + + case ERL_PID_EXT: + return ei_decode_pid(buf,index,NULL); + + case ERL_SMALL_TUPLE_EXT: + case ERL_LARGE_TUPLE_EXT: + if (ei_decode_tuple_header(buf,index,&arity) < 0) + return -1; + + for (i=0; iindex; + ei_encode_term(NULL, &i, t); + if (!x_fix_buff(x, i)) + return -1; + return ei_encode_term(x->buff, &x->index, t); +} + +int ei_encode_term(char *buf, int *index, void *t) +{ + char *s = buf + *index; + char *s0 = s; + + if (!buf) s += erl_term_len(t) -1; /* -1 for version */ + else { + /* this encodes all but the version at the start */ + /* and it will move s forward the right number of bytes */ + if (erl_encode_it(t,(unsigned char **)&s, 5)) return -1; + } + + *index += s - s0; + + return 0; +} + diff --git a/lib/erl_interface/src/legacy/erl_config.h b/lib/erl_interface/src/legacy/erl_config.h new file mode 100644 index 0000000000..166aa7013c --- /dev/null +++ b/lib/erl_interface/src/legacy/erl_config.h @@ -0,0 +1,22 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifndef _ERL_CONFIG_H +#define _ERL_CONFIG_H + +#endif /* _ERL_CONFIG_H */ diff --git a/lib/erl_interface/src/legacy/erl_connect.c b/lib/erl_interface/src/legacy/erl_connect.c new file mode 100644 index 0000000000..3c8c946506 --- /dev/null +++ b/lib/erl_interface/src/legacy/erl_connect.c @@ -0,0 +1,457 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1996-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Purpose: Connect to any node at any host. + */ + +/*************************************************************************** + * + * 'erl_interface' node connection handling is to use 'ei' for all + * operations without access to the internal structure of saved data, + * e.i. it should use the public interface functions. The connection + * handling can be seen as a restricted node interface where only one + * node can be used in one operating system process. + * + ***************************************************************************/ + +#include "eidef.h" + +#include +#include +#include + +#ifdef __WIN32__ +#include +#include +#include + +#elif VXWORKS +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "erl_error.h" + +#else /* some other unix */ +#include +#include +#include + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#include +#include +#include +#include +#include +#include /* for gen_challenge (NEED FIX?) */ +#endif + +/* common includes */ +#include +#include +#include +#include + +/* FIXME include less */ +#include "erl_interface.h" +#include "erl_connect.h" +#include "erl_eterm.h" +#include "erl_malloc.h" +#include "putget.h" +#include "ei.h" +#include "ei_connect_int.h" +#include "ei_locking.h" +#include "ei_epmd.h" +#include "ei_internal.h" + +/* rpc_from() uses a buffer this size */ +#ifndef MAX_RECEIVE_BUF +#define MAX_RECEIVE_BUF 32*1024 +#endif + +/* This is the global state of the old erl_* API */ + +static ei_cnode erl_if_ec; + +/*************************************************************************** + * + * API: erl_connect_init() + * API: erl_connect_xinit() + * + * Returns 1 on success and 0 on failure. + * Not documented to set erl_errno. + * + ***************************************************************************/ + +int erl_connect_init(int this_node_number, char *cookie, short creation) +{ + char nn[MAXATOMLEN+1]; + + sprintf(nn, "c%d", this_node_number); + + return ei_connect_init(&erl_if_ec, nn, cookie, creation) == 0; +} + +/* FIXME documented to use struct in_addr as addr */ + +int erl_connect_xinit(char *thishostname, + char *thisalivename, + char *thisnodename, + struct in_addr *thisipaddr, + char *cookie, + short creation) +{ + return ei_connect_xinit(&erl_if_ec, thishostname, thisalivename, + thisnodename, thisipaddr, cookie, creation) >= 0; +} + +/*************************************************************************** + * + * API: erl_connect() + * API: erl_xconnect() + * + * Set up a connection to a given Node, and interchange hand shake + * messages with it. + * + * Returns valid file descriptor on success and < 0 on failure. + * Set erl_errno to EHOSTUNREACH, ENOMEM, EIO or errno from socket(2) + * or connect(2). + * + ***************************************************************************/ + +int erl_connect(char *nodename) +{ + int res = ei_connect(&erl_if_ec, nodename); + if (res < 0) erl_errno = EIO; + return res; +} + +/* FIXME documented to use struct in_addr as addr */ + +int erl_xconnect(Erl_IpAddr addr, char *alivename) +{ + return ei_xconnect(&erl_if_ec, addr, alivename); +} + + +/*************************************************************************** + * + * API: erl_close_connection() + * + * Close a connection. FIXME call ei_close_connection() later. + * + * Returns valid file descriptor on success and < 0 on failure. + * Set erl_errno to EHOSTUNREACH, ENOMEM, EIO or errno from socket(2) + * or connect(2). + * + ***************************************************************************/ + +int erl_close_connection(int fd) +{ + return closesocket(fd); +} + +/* + * Accept and initiate a connection from an other + * Erlang node. Return a file descriptor at success, + * otherwise -1; + */ +int erl_accept(int lfd, ErlConnect *conp) +{ + return ei_accept(&erl_if_ec, lfd, conp); +} + + +/* Receives a message from an Erlang socket. + * If the message was a TICK it is immediately + * answered. Returns: ERL_ERROR, ERL_TICK or + * the number of bytes read. + */ +int erl_receive(int s, unsigned char *bufp, int bufsize) +{ + return ei_receive(s, bufp, bufsize); +} + +/* + * Send an Erlang message to a registered process + * at the Erlang node, connected with a socket. + */ +int erl_reg_send(int fd, char *server_name, ETERM *msg) +{ + ei_x_buff x; + int r; + + ei_x_new_with_version(&x); + if (ei_x_encode_term(&x, msg) < 0) { + erl_errno = EINVAL; + r = 0; + } else { + r = ei_reg_send(&erl_if_ec, fd, server_name, x.buff, x.index); + } + ei_x_free(&x); + return r == 0; +} + +/* + * Sends an Erlang message to a process at an Erlang node + */ +int erl_send(int fd, ETERM *to ,ETERM *msg) +{ + erlang_pid topid; + ei_x_buff x; + int r; + + ei_x_new_with_version(&x); + ei_x_encode_term(&x, msg); + /* make the to-pid */ + if (!ERL_IS_PID(to)) { + ei_x_free(&x); + erl_errno = EINVAL; + return -1; + } + + strcpy(topid.node, (char *)ERL_PID_NODE(to)); + topid.num = ERL_PID_NUMBER(to); + topid.serial = ERL_PID_SERIAL(to); + topid.creation = ERL_PID_CREATION(to); + r = ei_send(fd, &topid, x.buff, x.index); + ei_x_free(&x); + return r == 0; +} + +static int erl_do_receive_msg(int fd, ei_x_buff* x, ErlMessage* emsg) +{ + erlang_msg msg; + + int r; + msg.from.node[0] = msg.to.node[0] = '\0'; + r = ei_do_receive_msg(fd, 0, &msg, x, 0); + + if (r == ERL_MSG) { + int index = 0; + emsg->type = msg.msgtype; + + /* + We can't call ei_decode_term for cases where there are no + data following the type information. If there are other + types added later where there are data this case has to be + extended. + */ + + switch (msg.msgtype) { + case ERL_SEND: + case ERL_REG_SEND: + case ERL_EXIT: + case ERL_EXIT2: + if (ei_decode_term(x->buff, &index, &emsg->msg) < 0) + r = ERL_ERROR; + break; + default: + emsg->msg = NULL; /* Not needed but may avoid problems for unsafe caller */ + break; + } + } else + emsg->msg = NULL; + if (msg.from.node[0] != '\0') + emsg->from = erl_mk_pid(msg.from.node, msg.from.num, msg.from.serial, msg.from.creation); + if (msg.to.node[0] != '\0') + emsg->to = erl_mk_pid(msg.to.node, msg.to.num, msg.to.serial, msg.to.creation); + return r; +} + +int erl_receive_msg(int fd, unsigned char *buf, int bufsize, ErlMessage *emsg) +{ + ei_x_buff x; + int r; + + ei_x_new(&x); + r = erl_do_receive_msg(fd, &x, emsg); + /* FIXME what is this about? */ + if (bufsize > x.index) + bufsize = x.index; + memcpy(buf, x.buff, bufsize); + ei_x_free(&x); + return r; +} + +int erl_xreceive_msg(int fd, unsigned char **buf, int *bufsize, + ErlMessage *emsg) +{ + ei_x_buff x; + int r; + + ei_x_new(&x); + r = erl_do_receive_msg(fd, &x, emsg); + if (*bufsize < x.index) + *buf = erl_realloc(*buf, x.index); + *bufsize = x.index; + memcpy(*buf, x.buff, *bufsize); + ei_x_free(&x); + return r; +} + +/* + * The RPC consists of two parts, send and receive. + * Here is the send part ! + * { PidFrom, { call, Mod, Fun, Args, user }} + */ +/* + * Now returns non-negative number for success, negative for failure. + */ +int erl_rpc_to(int fd, char *mod, char *fun, ETERM *args) +{ + int r; + ei_x_buff x; + + ei_x_new(&x); + ei_x_encode_term(&x, args); + r = ei_rpc_to(&erl_if_ec, fd, mod, fun, x.buff, x.index); + ei_x_free(&x); + return r; +} /* rpc_to */ + + /* + * And here is the rpc receiving part. A negative + * timeout means 'infinity'. Returns either of: ERL_MSG, + * ERL_TICK, ERL_ERROR or ERL_TIMEOUT. +*/ +int erl_rpc_from(int fd, int timeout, ErlMessage *emsg) +{ + fd_set readmask; + struct timeval tv; + struct timeval *t = NULL; + unsigned char rbuf[MAX_RECEIVE_BUF]; + + if (timeout >= 0) { + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + t = &tv; + } + + FD_ZERO(&readmask); + FD_SET(fd,&readmask); + + switch (select(fd+1, &readmask, NULL, NULL, t)) { + case -1: + erl_errno = EIO; + return ERL_ERROR; + case 0: + erl_errno = ETIMEDOUT; + return ERL_TIMEOUT; + default: + if (FD_ISSET(fd, &readmask)) + return erl_receive_msg(fd, rbuf, MAX_RECEIVE_BUF, emsg); + else { + erl_errno = EIO; + return ERL_ERROR; + } + } +} /* rpc_from */ + +/* + * A true RPC. It return a NULL pointer + * in case of failure, otherwise a valid + * (ETERM *) pointer containing the reply + */ +ETERM *erl_rpc(int fd, char *mod, char *fun, ETERM *args) +{ + int i; + ETERM *ep; + ErlMessage emsg; + + if (erl_rpc_to(fd, mod, fun, args) < 0) { + return NULL; } + while ((i=erl_rpc_from(fd, ERL_NO_TIMEOUT, &emsg)) == ERL_TICK); + + if (i == ERL_ERROR) return NULL; + + ep = erl_element(2,emsg.msg); /* {RPC_Tag, RPC_Reply} */ + erl_free_term(emsg.msg); + erl_free_term(emsg.to); + return ep; +} /* rpc */ + + +/* + ** Handshake + */ + +int erl_publish(int port) +{ + return ei_publish(&erl_if_ec, port); +} + +int erl_unpublish(const char *alive) +{ + return ei_unpublish_tmo(alive,0); +} + +erlang_pid *erl_self(void) +{ + return ei_self(&erl_if_ec); +} + +const char *erl_thisnodename(void) +{ + return ei_thisnodename(&erl_if_ec); +} + +const char *erl_thishostname(void) +{ + return ei_thishostname(&erl_if_ec); +} + +const char *erl_thisalivename(void) +{ + return ei_thisalivename(&erl_if_ec); +} + +const char *erl_thiscookie(void) +{ + return ei_thiscookie(&erl_if_ec); +} + +short erl_thiscreation(void) +{ + return ei_thiscreation(&erl_if_ec); +} diff --git a/lib/erl_interface/src/legacy/erl_connect.h b/lib/erl_interface/src/legacy/erl_connect.h new file mode 100644 index 0000000000..d9d6c4e453 --- /dev/null +++ b/lib/erl_interface/src/legacy/erl_connect.h @@ -0,0 +1,24 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1996-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifndef _ERL_CONNECT_H +#define _ERL_CONNECT_H + +erlang_pid *erl_self(void); + +#endif /* _ERL_CONNECT_H */ diff --git a/lib/erl_interface/src/legacy/erl_error.c b/lib/erl_interface/src/legacy/erl_error.c new file mode 100644 index 0000000000..18dc2423bf --- /dev/null +++ b/lib/erl_interface/src/legacy/erl_error.c @@ -0,0 +1,180 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1996-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Function: Some nice error routines taken from: + * "Advanced Programming in the UNIX Environment", + * by W.Richard Stevens + * + * void erl_err_sys(const char *fmt, ... ) fatal, sys-error + * void erl_err_ret(const char *fmt, ... ) non-fatal, sys-error + * void erl_err_quit(const char *fmt, ...) fatal, non-sys-error + * void erl_err_msg(const char *fmt, ... ) non-fatal, non-sys-error + */ + +#include +#include +#include +#include + +#ifdef VRTX /* What's VRIX? [sverkerw] */ +#define __READY_EXTENSIONS__ +#endif +#include + +#if defined(VXWORKS) +#include +#include +#endif + +#include "eidef.h" +#include "erl_interface.h" +#include "erl_error.h" + +/* Forward */ +static void err_doit(int, const char*, va_list); +/* __attribute__ ((format (printf, 2, 0)))*/ + +/* + * Some thoughts on flushing stdout/stderr: + * + * The defaults are reasonable (linebuffered stdout, unbuffered + * stderr). If they are in effect (the user neither knows nor cares), + * there's no need to flush. + * + * If the user changes these defaults (and knows what he's doing, so + * he knows and cares) we shouldn't surprise him by + * second-guessing. So there's a need to not flush. + * + * If the user doesn't know what he's doing, he's hosed anyway. + */ + +/* Fatal error related to a system call. + * Print a message and terminate. + */ +void erl_err_sys(const char *fmt, ... ) +{ + va_list ap; + + va_start(ap, fmt); + err_doit(1, fmt, ap); + va_end(ap); + exit(1); +} /* erl_err_sys */ + +/* Nonfatal error related to a system call. + * Print a message and return + */ +void erl_err_ret(const char *fmt, ... ) +{ + va_list ap; + + va_start(ap, fmt); + err_doit(1, fmt, ap); + va_end(ap); + return; +} /* erl_err_ret */ + +/* Nonfatal error unrelated to a system call. + * Print a message and return + */ +void erl_err_msg(const char *fmt, ... ) +{ + va_list ap; + + va_start(ap, fmt); + err_doit(0, fmt, ap); + va_end(ap); + return; +} /* erl_err_msg */ + +/* Fatal error unrelated to a system call. + * Print a message and terminate + */ +void erl_err_quit(const char *fmt, ... ) +{ + va_list ap; + + va_start(ap, fmt); + err_doit(0, fmt, ap); + va_end(ap); + exit(1); +} /* erl_err_quit */ + + + +/* + * For example on SunOS we don't have the ANSI C strerror. + * + * maybe move to a convenince lib [sverkerw] + */ +#ifndef HAVE_STRERROR + +/* FIXME: move to configure */ +/* CONFIG: probe for sys_nerr/_sys_nerr */ +extern int sys_nerr; + +/* CONFIG: probe for sys_errlist/_sys_errlist and maybe for const-ness */ +#ifdef FREEBSD +extern const char * const sys_errlist[]; +#else +extern char * sys_errlist[]; +#endif + +/* Should be in string.h */ +/* Is supposed to return 'char *' (no const-ness in ANSI's prototype), + but if you rewrite the returned string in place you deserve to + lose. */ +static const char *strerror(int errnum) +{ + if (errnum >= 0 && errnum < sys_nerr) { + return sys_errlist[errnum]; + } else { + /* Enough buffer for 64 bits of error. It should last a while. */ + /* FIXME problem for threaded ? */ + static char b[] = "(error -9223372036854775808)"; + sprintf(b, "(error %d)", errnum); + buf[sizeof(b)-1] = '\0'; + return b; + } +} +#endif /* !HAVE_STRERROR */ + + +/* Print a message and return to caller. + * Caller specifies "errnoflag". + */ +static void err_doit(int errnoflag, const char *fmt, va_list ap) +{ +#ifndef NO_ERR_MSG + int errno_save; + + errno_save = errno; + + vfprintf(stderr, fmt, ap); + if (errnoflag) + { + fputs(": ", stderr); + fputs(strerror(errno_save), stderr); + } + fputs("\n", stderr); +#endif + + return; +} /* err_doit */ + diff --git a/lib/erl_interface/src/legacy/erl_error.h b/lib/erl_interface/src/legacy/erl_error.h new file mode 100644 index 0000000000..931c639c30 --- /dev/null +++ b/lib/erl_interface/src/legacy/erl_error.h @@ -0,0 +1,25 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1996-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifndef _ERL_ERROR_H +#define _ERL_ERROR_H + +/* Initialize thread/task-safe erl_errno handling */ +void erl_init_errno(void); + +#endif /* _ERL_ERROR_H */ diff --git a/lib/erl_interface/src/legacy/erl_eterm.c b/lib/erl_interface/src/legacy/erl_eterm.c new file mode 100644 index 0000000000..b685709c02 --- /dev/null +++ b/lib/erl_interface/src/legacy/erl_eterm.c @@ -0,0 +1,1308 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1996-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Purpose: Representation of Erlang terms. + */ + +#include "eidef.h" + +#include +#include +#include +#include + +#include "ei_locking.h" +#include "ei_resolve.h" +#include "erl_interface.h" +#include "erl_eterm.h" +#include "erl_malloc.h" +#include "erl_marshal.h" +#include "erl_error.h" +#include "erl_internal.h" +#include "ei_internal.h" + +#define ERL_IS_BYTE(x) (ERL_IS_INTEGER(x) && (ERL_INT_VALUE(x) & ~0xFF) == 0) + +/* FIXME use unsigned char, or uint8 for buffers, cast (int) really needed? */ + +static void iolist_to_buf(const ETERM* term, char** bufp); +static char* strsave(const char *src); + +/*************************************************************************** + * + * API: erl_init() + * + * Not documented to set erl_errno. + * + ***************************************************************************/ + +/* all initialisation of erl_interface modules should be called from here */ +/* order is important: erl_malloc and erl_resolve depend on ei_locking */ +/* NOTE: don't call this directly - please use erl_init() macro defined + in ei_locking.h! */ +void erl_init(void *hp,long heap_size) +{ + erl_init_malloc(hp, heap_size); + erl_init_marshal(); + ei_init_resolve(); +} + +void erl_set_compat_rel(unsigned rel) +{ + ei_set_compat_rel(rel); +} + +/* + * Create an INTEGER. Depending on its value it + * may end up as a BigNum. + */ +ETERM *erl_mk_int (int i) +{ + ETERM *ep; + + ep = erl_alloc_eterm(ERL_INTEGER); + ERL_COUNT(ep) = 1; + ERL_INT_VALUE(ep) = i; + return ep; +} + +ETERM *erl_mk_longlong (long long i) +{ + ETERM *ep; + + ep = erl_alloc_eterm(ERL_LONGLONG); + ERL_COUNT(ep) = 1; + ERL_LL_VALUE(ep) = i; + return ep; +} + +/* + * Create an UNSIGNED INTEGER. Depending on its + * value it may end up as a BigNum. + */ + +ETERM *erl_mk_uint (unsigned int u) +{ + ETERM *ep; + + ep = erl_alloc_eterm(ERL_U_INTEGER); + ERL_COUNT(ep) = 1; + ERL_INT_UVALUE(ep) = u; + return ep; +} + +ETERM *erl_mk_ulonglong (unsigned long long i) +{ + ETERM *ep; + + ep = erl_alloc_eterm(ERL_U_LONGLONG); + ERL_COUNT(ep) = 1; + ERL_LL_UVALUE(ep) = i; + return ep; +} + +/* + * Create a FLOAT. + */ +ETERM *erl_mk_float (double d) +{ + ETERM *ep; + + ep = erl_alloc_eterm(ERL_FLOAT); + ERL_COUNT(ep) = 1; + ERL_FLOAT_VALUE(ep) = d; + return ep; +} + +/* + * Create an ATOM + */ +ETERM *erl_mk_atom (const char *s) +{ + ETERM *ep; + + /* ASSERT(s != NULL); */ + if (!s) return NULL; + + ep = erl_alloc_eterm(ERL_ATOM); + ERL_COUNT(ep) = 1; + ERL_ATOM_SIZE(ep) = strlen(s); + if ((ERL_ATOM_PTR(ep) = strsave(s)) == NULL) + { + erl_free_term(ep); + erl_errno = ENOMEM; + return NULL; + } + return ep; +} + +/* + * Given a string as input, creates a list. + */ +ETERM *erl_mk_string(const char *s) +{ + /* ASSERT(s != NULL); */ + if (!s) return NULL; + + return erl_mk_estring(s, strlen(s)); +} + +ETERM *erl_mk_estring(const char *s, int len) +{ + ETERM *ep; + int i; + + if ((!s) || (len < 0)) return NULL; + + /* + * ASSERT(s != NULL); + * ASSERT(len >= 0); + */ + + ep = erl_mk_empty_list(); + for (i = len-1; i >= 0; i--) { + ETERM* integer; + ETERM* cons; + + integer = erl_alloc_eterm(ERL_INTEGER); + ERL_COUNT(integer) = 1; + ERL_INT_VALUE(integer) = (unsigned char)s[i]; + + cons = erl_alloc_eterm(ERL_LIST); + ERL_COUNT(cons) = 1; + HEAD(cons) = integer; + TAIL(cons) = ep; + ep = cons; + } + return ep; +} + +/* + * Create a PID. + */ +ETERM *erl_mk_pid(const char *node, + unsigned int number, + unsigned int serial, + unsigned char creation) +{ + ETERM *ep; + + if (!node) return NULL; + /* ASSERT(node != NULL); */ + + ep = erl_alloc_eterm(ERL_PID); + ERL_COUNT(ep) = 1; + if ((ERL_PID_NODE(ep) = strsave(node)) == NULL) + { + erl_free_term(ep); + erl_errno = ENOMEM; + return NULL; + } + ERL_PID_NUMBER(ep) = number & 0x7fff; /* 15 bits */ + if (ei_internal_use_r9_pids_ports()) { + ERL_PID_SERIAL(ep) = serial & 0x07; /* 3 bits */ + } + else { + ERL_PID_SERIAL(ep) = serial & 0x1fff; /* 13 bits */ + } + ERL_PID_CREATION(ep) = creation & 0x03; /* 2 bits */ + return ep; +} + +/* + * Create a PORT. + */ +ETERM *erl_mk_port(const char *node, + unsigned int number, + unsigned char creation) +{ + ETERM *ep; + + if (!node) return NULL; + /* ASSERT(node != NULL); */ + + ep = erl_alloc_eterm(ERL_PORT); + ERL_COUNT(ep) = 1; + if ((ERL_PORT_NODE(ep) = strsave(node)) == NULL) + { + erl_free_term(ep); + erl_errno = ENOMEM; + return NULL; + } + if (ei_internal_use_r9_pids_ports()) { + ERL_PORT_NUMBER(ep) = number & 0x3ffff; /* 18 bits */ + } + else { + ERL_PORT_NUMBER(ep) = number & 0x0fffffff; /* 18 bits */ + } + ERL_PORT_CREATION(ep) = creation & 0x03; /* 2 bits */ + return ep; +} + +/* + * Create any kind of reference. + */ +ETERM *__erl_mk_reference (const char *node, + size_t len, + unsigned int n[], + unsigned char creation) +{ + ETERM * t; + + if (node == NULL) return NULL; + + t = erl_alloc_eterm(ERL_REF); + ERL_COUNT(t) = 1; + + if ((ERL_REF_NODE(t) = strsave(node)) == NULL) + { + erl_free_term(t); + erl_errno = ENOMEM; + return NULL; + } + ERL_REF_LEN(t) = len; + ERL_REF_NUMBERS(t)[0] = n[0] & 0x3ffff; /* 18 bits */ + ERL_REF_NUMBERS(t)[1] = n[1]; + ERL_REF_NUMBERS(t)[2] = n[2]; + ERL_REF_CREATION(t) = creation & 0x03; /* 2 bits */ + + return t; +} + +/* + * Create a REFERENCE. + */ +ETERM *erl_mk_ref (const char *node, + unsigned int number, + unsigned char creation) +{ + unsigned int n[3] = {0, 0, 0}; + n[0] = number; + return __erl_mk_reference(node, 1, n, creation); +} + +/* + * Create a long REFERENCE. + */ +ETERM * +erl_mk_long_ref (const char *node, + unsigned int n1, unsigned int n2, unsigned int n3, + unsigned char creation) +{ + unsigned int n[3] = {0, 0, 0}; + n[0] = n3; n[1] = n2; n[2] = n1; + return __erl_mk_reference(node, 3, n, creation); +} + +/* + * Create a BINARY. + */ +ETERM *erl_mk_binary (const char *b, int size) +{ + ETERM *ep; + + if ((!b) || (size < 0)) return NULL; + /* ASSERT(b != NULL); */ + + ep = erl_alloc_eterm(ERL_BINARY); + ERL_COUNT(ep) = 1; + ERL_BIN_SIZE(ep) = size; + ERL_BIN_PTR(ep) = (unsigned char *) erl_malloc(size); + memcpy(ERL_BIN_PTR(ep), b, size); + return ep; +} + +/* + * Create a TUPLE. For each element in the tuple + * bump its reference counter. + */ +ETERM *erl_mk_tuple (ETERM **arr,int size) +{ + ETERM *ep; + int i; + + if ((!arr) || (size < 0)) return NULL; + for (i=0; i erl_setelement: Bad type to setelement or out of range \n"); + return 0; +} +#endif + +/* + * Extract an ELEMENT from a TUPLE. Bump the + * reference counter on the extracted object. + */ +ETERM *erl_element (int ix, const ETERM *ep) +{ + if ((!ep) || (ix < 0)) return NULL; + /* + * ASSERT(ep != NULL); + * ASSERT(ix >= 0); + */ + + if ((ERL_TYPE(ep) == ERL_TUPLE) && (ix <= ERL_TUPLE_SIZE(ep))) { + ERL_COUNT(ERL_TUPLE_ELEMENT(ep, ix-1))++; + return ERL_TUPLE_ELEMENT(ep, ix-1); + } + else + return NULL; +} /* erl_element */ + +ETERM *erl_mk_empty_list(void) +{ + ETERM *ep; + + ep = erl_alloc_eterm(ERL_EMPTY_LIST); + ERL_COUNT(ep) = 1; + return ep; +} + +/* + * Construct a new list by CONS'ing a HEAD on + * to the TAIL. Bump the reference counter on + * the head and tail object. Note that we allow + * non-well formed lists to be created. + */ +ETERM *erl_cons(ETERM *hd, ETERM *tl) +{ + ETERM *ep; + + if ((!hd) || (!tl)) return NULL; + + /* + * ASSERT(hd != NULL); + * ASSERT(tl != NULL); + */ + + ep = erl_alloc_eterm(ERL_LIST); + ERL_COUNT(ep) = 1; + HEAD(ep) = hd; + TAIL(ep) = tl; + ERL_COUNT(hd)++; + ERL_COUNT(tl)++; + return ep; +} + +/* + * Extract the HEAD of a LIST. Bump the reference + * counter on the head object. + */ +ETERM *erl_hd (const ETERM *ep) +{ + if (!ep) return NULL; + /* ASSERT(ep != NULL); */ + + if (ERL_TYPE(ep) != ERL_LIST) { + return (ETERM *) NULL; + } + ERL_COUNT(ERL_CONS_HEAD(ep))++; + return ERL_CONS_HEAD(ep); +} + +/* + * Extract the TAIL of a LIST. Bump the reference + * counter on the tail object. + */ +ETERM *erl_tl (const ETERM *ep) +{ + ETERM *tl; + + if (!ep) return NULL; + /* ASSERT(ep != NULL); */ + + if (ERL_TYPE(ep) != ERL_LIST) { + return (ETERM *) NULL; + } + + tl = TAIL(ep); + ERL_COUNT(tl)++; + return tl; +} + +/* + * Create a LIST from an array of elements. Note that + * we create it from the last element in the array to + * the first. Also, note that we decrement the reference + * counter for each member in the list but the first one. + * This is done because of the use of erl_cons. + */ + +ETERM *erl_mk_list (ETERM **arr, int size) +{ + ETERM *ep; + int i; + + if ((!arr) || (size < 0)) return NULL; + for (i=0; i 0) { + ERL_COUNT(ep)--; + } + + for (i = size-1; i >= 0; i--) { + /* ASSERT(arr[i] != NULL); */ + ep = erl_cons(arr[i], ep); + if (i > 0) + ERL_COUNT(ep)--; /* Internal reference */ + } + return ep; +} + +/* + * Create an empty VARIABLE. + */ +ETERM *erl_mk_var(const char *s) +{ + ETERM *ep; + + if (!s) return NULL; + + /* ASSERT(s != NULL); */ + + ep = erl_alloc_eterm(ERL_VARIABLE); + ERL_COUNT(ep) = 1; + ERL_VAR_LEN(ep) = strlen(s); + if ((ERL_VAR_NAME(ep) = strsave(s)) == NULL) + { + erl_free_term(ep); + erl_errno = ENOMEM; + return NULL; + } + ERL_VAR_VALUE(ep) = (ETERM *) NULL; + return ep; +} + +/* + * Return the CONTENT of a VARIABLE with NAME. + * If the content is non-nil then bump its + * reference counter. + */ +ETERM *erl_var_content (const ETERM *ep, const char *name) +{ + int i; + ETERM *vp; + + if ((!ep) || (!name)) return NULL; + + /* ASSERT(ep != NULL); */ + + switch(ERL_TYPE(ep)) + { + case ERL_VARIABLE: + if (strcmp(ERL_VAR_NAME(ep), name) == 0) { + if ((vp = ERL_VAR_VALUE(ep)) != NULL) { + ERL_COUNT(vp)++; + return vp; + } + } + break; + + case ERL_LIST: + while (ep && (ERL_TYPE(ep) != ERL_EMPTY_LIST)) { + if ((vp = erl_var_content(HEAD(ep), name))) return vp; + ep = TAIL(ep); + } + break; + + case ERL_TUPLE: + for (i=0; i < ERL_TUPLE_SIZE(ep); i++) + if ((vp = erl_var_content(ERL_TUPLE_ELEMENT(ep, i), name))) + { + return vp; + } + break; + + default: + /* variables can't occur in other types */ + break; + } + + /* nothing found ! */ + return NULL; +} + +/* + * Return the SIZE of a TUPLE or a BINARY. + * At failure -1 is returned. + */ +int erl_size (const ETERM *ep) +{ + if (!ep) return -1; + + /* ASSERT(ep != NULL); */ + + switch (ERL_TYPE(ep)) { + case ERL_TUPLE: + return ERL_TUPLE_SIZE(ep); + + case ERL_BINARY: + return ERL_BIN_SIZE(ep); + + default: + return -1; + + } +} + +/* + * Return the LENGTH of a LIST. + * At failure -1 is returned (this include non-proper lists like [a|b]). + */ +int erl_length(const ETERM *ep) +{ + int n = 0; + + if (!ep) return -1; + /* ASSERT(ep != NULL); */ + + while (ERL_TYPE(ep) == ERL_LIST) { + n++; + ep = TAIL(ep); + } + + if (!ERL_IS_EMPTY_LIST(ep)) return -1; + + return n; +} + + +/*********************************************************************** + * I o l i s t f u n c t i o n s + * + * The following functions handles I/O lists. + * + * Informally, an I/O list is a deep list of characters and binaries, + * which can be sent to an Erlang port. + * + * Formally, in BNF, an I/O list is defined as: + * + * iolist ::= [] + * | Binary + * | [iohead | iolist] + * ; + * + * iohead ::= Binary + * | Byte (integer in the range [0..255]) + * | iolist + * ; + * + * Note that versions of Erlang/OTP prior to R2 had a slightly more + * restricted definition of I/O lists, in that the tail of a an I/O list + * was not allowed to be a binary. The erl_interface functions + * for I/O lists follows the more liberal rules described by the BNF + * description above. + ***********************************************************************/ + +/* + * This function converts an I/O list to a '\0' terminated C string. + * The I/O list must not contain any occurrences of the integer 0. + * + * The string will be in memory allocated by erl_malloc(). It is the + * responsibility of the caller to eventually call erl_free() to free + * the memory. + * + * Returns: NULL if the list was not an I/O list or contained + * the integer 0, otherwise a pointer to '\0' terminated string. + */ + +char* erl_iolist_to_string(const ETERM* term) +{ + ETERM* bin; + + if ((bin = erl_iolist_to_binary(term)) == NULL) { + return NULL; + } else { + char* result = NULL; + + if (memchr(ERL_BIN_PTR(bin), '\0', ERL_BIN_SIZE(bin)) == NULL) { + result = (char *) erl_malloc(ERL_BIN_SIZE(bin)+1); + memcpy(result, ERL_BIN_PTR(bin), ERL_BIN_SIZE(bin)); + result[ERL_BIN_SIZE(bin)] = '\0'; + } + erl_free_term(bin); + return result; + } +} + +/* + * This function converts an I/O list to a binary term. + * + * Returns: NULL if the list was not an I/O list, otherwise + * an ETERM pointer pointing to a binary term. + */ + +ETERM *erl_iolist_to_binary (const ETERM* term) +{ + ETERM *dest; + int size; + char* ptr; + + if (!term) return NULL; + /* ASSERT(term != NULL); */ + + /* + * Verify that the term is an I/O list and get its length. + */ + + size = erl_iolist_length(term); + if (size == -1) { + return NULL; + } + + /* + * Allocate the binary and copy the contents of the I/O list into it. + */ + + dest = erl_alloc_eterm(ERL_BINARY); + ERL_COUNT(dest) = 1; + ERL_BIN_SIZE(dest) = size; + ptr = (char *)erl_malloc(size); + ERL_BIN_PTR(dest) = (unsigned char *)ptr; + iolist_to_buf(term, &ptr); + + /* + * If ptr doesn't point exactly one byte beyond the end of the + * binary, something must be seriously wrong. + */ + + if (ERL_BIN_PTR(dest) + size != (unsigned char *) ptr) return NULL; + /* ASSERT(ERL_BIN_PTR(dest) + size == (unsigned char *) ptr); */ + + return dest; +} + +/* + * Returns the length of an I/O list. + * + * Returns: -1 if the term if the given term is not a I/O list, + * or the length otherwise. + */ + +int erl_iolist_length (const ETERM* term) +{ + int len = 0; + + while (ERL_IS_CONS(term)) { + ETERM* obj = HEAD(term); + + if (ERL_IS_BYTE(obj)) { + len++; + } else if (ERL_IS_CONS(obj)) { + int i; + if ((i = erl_iolist_length(obj)) < 0) + return i; + len += i; + } else if (ERL_IS_BINARY(obj)) { + len += ERL_BIN_SIZE(obj); + } else if (!ERL_IS_EMPTY_LIST(obj)) { + return(-1); + } + term = TAIL(term); + } + if (ERL_IS_EMPTY_LIST(term)) + return len; + else if (ERL_IS_BINARY(term)) + return len + ERL_BIN_SIZE(term); + else + return -1; +} + +/* + * Return a brand NEW COPY of an ETERM. + */ +/* + * FIXME: Deep (the whole tree) or shallow (just the top term) copy? + * The documentation never says, but the code as written below will + * make a deep copy. This should be documented. + */ +ETERM *erl_copy_term(const ETERM *ep) +{ + int i; + ETERM *cp; + + if (!ep) return NULL; + /* ASSERT(ep != NULL); */ + + cp = erl_alloc_eterm(ERL_TYPE(ep)); + ERL_COUNT(cp) = 1; + + switch(ERL_TYPE(cp)) { + case ERL_INTEGER: + case ERL_SMALL_BIG: + ERL_INT_VALUE(cp) = ERL_INT_VALUE(ep); + break; + case ERL_U_INTEGER: + case ERL_U_SMALL_BIG: + ERL_INT_UVALUE(cp) = ERL_INT_UVALUE(ep); + break; + case ERL_FLOAT: + ERL_FLOAT_VALUE(cp) = ERL_FLOAT_VALUE(ep); + break; + case ERL_ATOM: + ERL_ATOM_SIZE(cp) = ERL_ATOM_SIZE(ep); + ERL_ATOM_PTR(cp) = strsave(ERL_ATOM_PTR(ep)); + if (ERL_ATOM_PTR(cp) == NULL) + { + erl_free_term(cp); + erl_errno = ENOMEM; + return NULL; + } + break; + case ERL_PID: + /* FIXME: First copy the bit pattern, then duplicate the node + name and plug in. Somewhat ugly (also done with port and + ref below). */ + memcpy(&cp->uval.pidval, &ep->uval.pidval, sizeof(Erl_Pid)); + ERL_PID_NODE(cp) = strsave(ERL_PID_NODE(ep)); + ERL_COUNT(cp) = 1; + break; + case ERL_PORT: + memcpy(&cp->uval.portval, &ep->uval.portval, sizeof(Erl_Port)); + ERL_PORT_NODE(cp) = strsave(ERL_PORT_NODE(ep)); + ERL_COUNT(cp) = 1; + break; + case ERL_REF: + memcpy(&cp->uval.refval, &ep->uval.refval, sizeof(Erl_Ref)); + ERL_REF_NODE(cp) = strsave(ERL_REF_NODE(ep)); + ERL_COUNT(cp) = 1; + break; + case ERL_LIST: + HEAD(cp) = erl_copy_term(HEAD(ep)); + TAIL(cp) = erl_copy_term(TAIL(ep)); + break; + case ERL_EMPTY_LIST: + break; + case ERL_TUPLE: + i = ERL_TUPLE_SIZE(cp) = ERL_TUPLE_SIZE(ep); + ERL_TUPLE_ELEMS(cp) = (ETERM**) erl_malloc(i * sizeof(ETERM*)); + for(i=0; i < ERL_TUPLE_SIZE(ep); i++) + ERL_TUPLE_ELEMENT(cp,i) = erl_copy_term(ERL_TUPLE_ELEMENT(ep, i)); + break; + case ERL_BINARY: + ERL_BIN_SIZE(cp) = ERL_BIN_SIZE(ep); + ERL_BIN_PTR(cp) = (unsigned char *) erl_malloc(ERL_BIN_SIZE(ep)); + memcpy(ERL_BIN_PTR(cp), ERL_BIN_PTR(ep), ERL_BIN_SIZE(ep)); + break; + case ERL_FUNCTION: + i = ERL_CLOSURE_SIZE(cp) = ERL_CLOSURE_SIZE(ep); + ERL_FUN_ARITY(cp) = ERL_FUN_ARITY(ep); + ERL_FUN_NEW_INDEX(cp) = ERL_FUN_NEW_INDEX(ep); + ERL_FUN_INDEX(cp) = erl_copy_term(ERL_FUN_INDEX(ep)); + ERL_FUN_UNIQ(cp) = erl_copy_term(ERL_FUN_UNIQ(ep)); + ERL_FUN_CREATOR(cp) = erl_copy_term(ERL_FUN_CREATOR(ep)); + ERL_FUN_MODULE(cp) = erl_copy_term(ERL_FUN_MODULE(ep)); + memcpy(ERL_FUN_MD5(cp), ERL_FUN_MD5(ep), sizeof(ERL_FUN_MD5(ep))); + ERL_CLOSURE(cp) = (ETERM**) erl_malloc(i * sizeof(ETERM*)); + for(i=0; i < ERL_CLOSURE_SIZE(ep); i++) + ERL_CLOSURE_ELEMENT(cp,i) = + erl_copy_term(ERL_CLOSURE_ELEMENT(ep, i)); + break; + default: + erl_err_msg(" erl_copy_term: wrong type encountered !"); + erl_free_term(cp); + return (ETERM *) NULL; + } + + return cp; +} + +#ifndef SILENT + +static int print_string(FILE* fp, const ETERM* ep); +static int is_printable_list(const ETERM* term); + +/* + * PRINT out an ETERM. + */ + +int erl_print_term(FILE *fp, const ETERM *ep) +{ + int j,i,doquote; + int ch_written = 0; /* counter of written chars */ + + if ((!fp) || (!ep)) return 0; + /* ASSERT(ep != NULL); */ + + j = i = doquote = 0; + switch(ERL_TYPE(ep)) + { + case ERL_ATOM: + /* FIXME: what if some weird locale is in use? */ + if (!islower((int)ERL_ATOM_PTR(ep)[0])) + doquote = 1; + + for (i = 0; !doquote && i < ERL_ATOM_SIZE(ep); i++) + { + doquote = !(isalnum((int)ERL_ATOM_PTR(ep)[i]) + || (ERL_ATOM_PTR(ep)[i] == '_')); + } + + if (doquote) { + putc('\'', fp); + ch_written++; + } + fputs(ERL_ATOM_PTR(ep), fp); + ch_written += ERL_ATOM_SIZE(ep); + if (doquote) { + putc('\'', fp); + ch_written++; + } + break; + + case ERL_VARIABLE: + if (!isupper((int)ERL_VAR_NAME(ep)[0])) { + doquote = 1; + putc('\'', fp); + ch_written++; + } + + fputs(ERL_VAR_NAME(ep), fp); + ch_written += ERL_VAR_LEN(ep); + + if (doquote) { + putc('\'', fp); + ch_written++; + } + break; + + case ERL_PID: + ch_written += fprintf(fp, "<%s.%d.%d>", + ERL_PID_NODE(ep), + ERL_PID_NUMBER(ep), ERL_PID_SERIAL(ep)); + break; + case ERL_PORT: + ch_written += fprintf(fp, "#Port"); + break; + case ERL_REF: + ch_written += fprintf(fp, "#Ref"); + break; + case ERL_EMPTY_LIST: + ch_written += fprintf(fp, "[]"); + break; + case ERL_LIST: + if (is_printable_list(ep)) { + ch_written += print_string(fp, ep); + } else { + putc('[', fp); + ch_written++; + while (ERL_IS_CONS(ep)) { + ch_written += erl_print_term(fp, HEAD(ep)); + ep = TAIL(ep); + if (ERL_IS_CONS(ep)) { + putc(',', fp); + ch_written++; + } + } + if (!ERL_IS_EMPTY_LIST(ep)) { + putc('|', fp); + ch_written++; + ch_written += erl_print_term(fp, ep); + } + putc(']', fp); + ch_written++; + } + break; + case ERL_TUPLE: + putc('{', fp); + ch_written++; + for (i=0; i < ERL_TUPLE_SIZE(ep); i++) { + ch_written += erl_print_term(fp, ERL_TUPLE_ELEMENT(ep, j++) ); + if (i != ERL_TUPLE_SIZE(ep)-1) { + putc(',', fp); + ch_written++; + } + } + putc('}', fp); + ch_written++; + break; + case ERL_BINARY: { + int sz = (ERL_BIN_SIZE(ep) > 20) ? 20 : ERL_BIN_SIZE(ep); + unsigned char *ptr = ERL_BIN_PTR(ep); + ch_written += fprintf(fp, "#Bin<"); + for (i = 0; i < sz; i++) { + putc(ptr[i], fp); ch_written++; + } + if (sz == 20) ch_written += fprintf(fp, "(%d)....>", ERL_BIN_SIZE(ep)-20); + else ch_written += fprintf(fp, ">"); + break; + } + case ERL_INTEGER: + case ERL_SMALL_BIG: + ch_written += fprintf(fp, "%d", ERL_INT_VALUE(ep)); + break; + case ERL_U_INTEGER: + case ERL_U_SMALL_BIG: + ch_written += fprintf(fp, "%d", ERL_INT_UVALUE(ep)); + break; + case ERL_LONGLONG: + case ERL_U_LONGLONG: + ch_written += fprintf(fp, "%lld", ERL_LL_UVALUE(ep)); + break; + case ERL_FLOAT: + ch_written += fprintf(fp, "%f", ERL_FLOAT_VALUE(ep)); + break; + case ERL_FUNCTION: + ch_written += fprintf(fp, "#Fun<"); + ch_written += erl_print_term(fp, ERL_FUN_MODULE(ep)); + putc('.', fp); + ch_written++; + ch_written += erl_print_term(fp, ERL_FUN_INDEX(ep)); + putc('.', fp); + ch_written++; + ch_written += erl_print_term(fp, ERL_FUN_UNIQ(ep)); + putc('>', fp); + ch_written++; + break; + default: + ch_written = -10000; + erl_err_msg(" erl_print_term: Bad type of term !"); + } + return ch_written; +} + +/* + * FIXME not done yet.... + */ + +#if 0 + +int erl_sprint_term(char *buf, const ETERM *ep) +{ + int j,i,doquote; + int ch_written = 0; /* counter of written chars */ + + if ((!buf) || (!ep)) return 0; + /* ASSERT(ep != NULL); */ + + j = i = doquote = 0; + switch(ERL_TYPE(ep)) + { + case ERL_ATOM: + /* FIXME: what if some weird locale is in use? */ + if (!islower((int)ERL_ATOM_PTR(ep)[0])) + doquote = 1; + + for (i = 0; !doquote && i < ERL_ATOM_SIZE(ep); i++) + { + doquote = !(isalnum((int)ERL_ATOM_PTR(ep)[i]) + || (ERL_ATOM_PTR(ep)[i] == '_')); + } + + if (doquote) { + *buf++ = '\''; + ch_written++; + } + { + int len = ERL_ATOM_SIZE(ep); + strncpy(buf, ERL_ATOM_PTR(ep), len); + buf += len; + ch_written += len; + } + if (doquote) { + *buf++ = '\''; + ch_written++; + } + break; + + case ERL_VARIABLE: + if (!isupper((int)ERL_VAR_NAME(ep)[0])) { + doquote = 1; + *buf++ = '\''; + ch_written++; + } + len = ERL_VAR_LEN(ep); + strncpy(buf, ERL_VAR_NAME(ep), len); + buf += len; + ch_written += len; + + if (doquote) { + *buf++ = '\''; + ch_written++; + } + break; + + case ERL_PID: + len = sprintf(buf, "<%s.%d.%d>", + ERL_PID_NODE(ep), + ERL_PID_NUMBER(ep), ERL_PID_SERIAL(ep)); + buf += len; + ch_written += len; + break; + case ERL_PORT: + len = sprintf(buf , "#Port"); + buf += len; + ch_written += len; + break; + case ERL_REF: + len = sprintf(buf , "#Ref"); + buf += len; + ch_written += len; + break; + case ERL_EMPTY_LIST: + len = sprintf(buf , "[]"); + buf += len; + ch_written += len; + break; + case ERL_LIST: + if (is_printable_list(ep)) { + ch_written += print_string(fp, ep); + } else { + putc('[', fp); + ch_written++; + while (ERL_IS_CONS(ep)) { + ch_written += erl_sprint_term(fp, HEAD(ep)); + ep = TAIL(ep); + if (ERL_IS_CONS(ep)) { + putc(',', fp); + ch_written++; + } + } + if (!ERL_IS_EMPTY_LIST(ep)) { + putc('|', fp); + ch_written++; + ch_written += erl_sprint_term(fp, ep); + } + putc(']', fp); + ch_written++; + } + break; + case ERL_TUPLE: + putc('{', fp); + ch_written++; + for (i=0; i < ERL_TUPLE_SIZE(ep); i++) { + ch_written += erl_sprint_term(fp, ERL_TUPLE_ELEMENT(ep, j++) ); + if (i != ERL_TUPLE_SIZE(ep)-1) { + putc(',', fp); + ch_written++; + } + } + putc('}', fp); + ch_written++; + break; + case ERL_BINARY: + len = sprintf(buf , "#Bin"); + buf += len; + ch_written += len; + break; + case ERL_INTEGER: + case ERL_SMALL_BIG: + len = sprintf(buf , "%d", ERL_INT_VALUE(ep)); + buf += len; + ch_written += len; + break; + case ERL_U_INTEGER: + case ERL_U_SMALL_BIG: + len = sprintf(buf , "%d", ERL_INT_UVALUE(ep)); + buf += len; + ch_written += len; + break; + case ERL_FLOAT: + len = sprintf(buf , "%f", ERL_FLOAT_VALUE(ep)); + buf += len; + ch_written += len; + break; + case ERL_FUNCTION: + len = sprintf(buf , "#Fun<"); + buf += len; + ch_written += len; + ch_written += erl_sprint_term(fp, ERL_FUN_MODULE(ep)); + putc('.', fp); + ch_written++; + ch_written += erl_sprint_term(fp, ERL_FUN_INDEX(ep)); + putc('.', fp); + ch_written++; + ch_written += erl_sprint_term(fp, ERL_FUN_UNIQ(ep)); + putc('>', fp); + ch_written++; + break; + default: + ch_written = -10000; + erl_err_msg(" erl_sprint_term: Bad type of term !"); + } + return ch_written; +} +#endif + +static int print_string(FILE* fp, const ETERM* ep) +{ + int ch_written = 0; /* counter of written chars */ + + putc('"', fp); + ch_written++; + while (ERL_IS_CONS(ep)) { + int c = ERL_INT_VALUE(HEAD(ep)); + + if (c >= ' ') { + putc(c, fp); + ch_written++; + } + else { + switch (c) { + case '\n': fputs("\\n", fp); ch_written += 2; break; + case '\r': fputs("\\r", fp); ch_written += 2; break; + case '\t': fputs("\\t", fp); ch_written += 2; break; + case '\v': fputs("\\v", fp); ch_written += 2; break; + case '\b': fputs("\\b", fp); ch_written += 2; break; + case '\f': fputs("\\f", fp); ch_written += 2; break; + break; + default: + ch_written += fprintf(fp, "\\%o", c); + break; + } + } + ep = TAIL(ep); + } + putc('"', fp); + ch_written++; + return ch_written; +} + +/* + * Returns 1 if term is a list of printable character, otherwise 0. + */ + +static int is_printable_list(const ETERM* term) +{ + while (ERL_TYPE(term) == ERL_LIST) { + ETERM* head = HEAD(term); + + if (!ERL_IS_BYTE(head)) { + return 0; + } + if (ERL_INT_VALUE(head) < ' ') { + switch (ERL_INT_VALUE(head)) { + case '\n': + case '\r': + case '\t': + case '\v': + case '\b': + case '\f': + break; + default: + return 0; + } + } + term = TAIL(term); + } + + return ERL_IS_EMPTY_LIST(term); +} + +#endif + +/* + * Retrieves the bytes from an I/O list and copy into a buffer. + * + * NOTE! It is the responsibility of the caller to ensure that + * that the buffer is big enough (typically by calling + * erl_iolist_length()), and that the term is an I/O list. + * + * ETERM* term; Term to convert to bytes. + * char** bufp; Pointer to pointer to buffer + * where the bytes should be stored. + * On return, the pointer will point beyond + * the last byte stored. + */ + +static void iolist_to_buf(const ETERM* term, char** bufp) +{ + char* dest = *bufp; + + while (ERL_IS_CONS(term)) { + ETERM* obj = HEAD(term); + + if (ERL_IS_BYTE(obj)) { + *dest++ = ERL_INT_VALUE(obj); + } else if (ERL_IS_CONS(obj)) { + iolist_to_buf(obj, &dest); + } else if (ERL_IS_BINARY(obj)) { + memcpy(dest, ERL_BIN_PTR(obj), ERL_BIN_SIZE(obj)); + dest += ERL_BIN_SIZE(obj); + } else { + /* + * Types have been checked by caller. + */ + if (!ERL_IS_EMPTY_LIST(obj)) return; + /* ASSERT(ERL_IS_EMPTY_LIST(obj)); */ + } + term = TAIL(term); + } + if (ERL_IS_BINARY(term)) { + memcpy(dest, ERL_BIN_PTR(term), ERL_BIN_SIZE(term)); + dest += ERL_BIN_SIZE(term); + } else { + /* + * Types have been checked by caller. + */ + if (!ERL_IS_EMPTY_LIST(term)) return; + /* ASSERT(ERL_IS_EMPTY_LIST(term));*/ + } + *bufp = dest; +} + +static char* strsave(const char *src) +{ + char * dest = malloc(strlen(src)+1); + + if (dest != NULL) + strcpy(dest, src); + return dest; +} + + +/* + * Local Variables: + * compile-command: "cd ..; ERL_TOP=/clearcase/otp/erts make -k" + * End: + */ diff --git a/lib/erl_interface/src/legacy/erl_eterm.h b/lib/erl_interface/src/legacy/erl_eterm.h new file mode 100644 index 0000000000..41b008f04f --- /dev/null +++ b/lib/erl_interface/src/legacy/erl_eterm.h @@ -0,0 +1,61 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1996-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifndef _ERL_ETERM_H +#define _ERL_ETERM_H + +#ifndef SILENT +#include +#endif + +#include "portability.h" + +#define ERL_MAX_COUNT 0xffffff +#define ERL_MAX ((1 << 27)-1) +#define ERL_MIN -(1 << 27) + +/* FIXME should this be documented and in erl_interface.h ??? */ +#define ERL_BIG_ARITY(x) ((x)->uval.bigval.arity) +#define ERL_BIG_IS_NEG(x) ((x)->uval.bigval.is_neg) +#define ERL_BIG_DIGITS(x) ((x)->uval.bigval.digits) +#define ERL_BIG_DIGIT(x,i) (ERL_BIG_DIGITS(x)[(i)]) + +/* + * Typing checking macros. + */ + +/* FIXME should this be documented and in erl_interface.h ??? */ +#define ERL_IS_DEFINED(x) (ERL_TYPE(x) != 0) +#define ERL_IS_COMPOUND(x) (ERL_TYPE(x) & ERL_COMPOUND) +#define ERL_IS_FUNCTION(x) (ERL_TYPE(x) == ERL_FUNCTION) +#define ERL_IS_BIG(x) (ERL_TYPE(x) == ERL_BIG) + + +typedef struct _heapmark { + unsigned long mark; /* id */ + int size; /* size of buffer */ + Erl_Heap *base; /* points to start of buffer */ + Erl_Heap *cur; /* points into buffer */ + struct _heapmark *prev; /* previous heapmark */ +} Erl_HeapMark; + + +ETERM * __erl_mk_reference(const char *, size_t, unsigned int n[], unsigned char); +int erl_current_fix_desc(void); + +#endif /* _ERL_ETERM_H */ diff --git a/lib/erl_interface/src/legacy/erl_fix_alloc.c b/lib/erl_interface/src/legacy/erl_fix_alloc.c new file mode 100644 index 0000000000..20f3024e41 --- /dev/null +++ b/lib/erl_interface/src/legacy/erl_fix_alloc.c @@ -0,0 +1,193 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1996-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Function: General purpose Memory allocator for fixed block + * size objects. This allocater is at least an order of + * magnitude faster than malloc(). + */ +#include "eidef.h" + +#include +#include +#include +#include "ei_locking.h" +#include "erl_interface.h" +#include "erl_error.h" +#include "erl_malloc.h" +#include "erl_fix_alloc.h" +#include "erl_eterm.h" + +#define WIPE_CHAR ((char)0xaa) /* 10101010 */ + +/* the freelist is a singly linked list of these */ +/* i.e. the user structure and a link pointer */ +struct fix_block { + ETERM term; + struct fix_block *next; + int free; +}; + +/* this is a struct just to keep namespace pollution low on VxWorks */ +struct eterm_stateinfo { + struct fix_block *freelist; + unsigned long freed; + unsigned long allocated; +#ifdef _REENTRANT + ei_mutex_t *lock; +#endif /* _REENTRANT */ +}; +/* FIXME problem for threaded ? */ +static struct eterm_stateinfo *erl_eterm_state=NULL; + + +int erl_init_eterm_alloc (void) +{ +#if defined(PURIFY) && defined (DEBUG) + fprintf(stderr,"erl_fix_alloc() compiled for Purify - using \"real\" malloc()"); +#endif + + erl_eterm_state = malloc(sizeof(*erl_eterm_state)); + if (erl_eterm_state == NULL) goto err1; + + erl_eterm_state->freelist = NULL; + erl_eterm_state->freed = 0; + erl_eterm_state->allocated = 0; +#ifdef _REENTRANT + erl_eterm_state->lock = ei_mutex_create(); + if (erl_eterm_state->lock == NULL) goto err2; +#endif /* _REENTRANT */ + + return 1; + + /* Error cleanup */ +#ifdef _REENTRANT + err2: + /* FIXME ENOMEM is not what went wrong... */ + free(erl_eterm_state); +#endif /* _REENTRANT */ + err1: + erl_errno = ENOMEM; + return 0; +} + +/* get an eterm, from the freelist if possible or from malloc() */ +void *erl_eterm_alloc (void) +{ +#ifdef PURIFY + ETERM *p; + + if ((p = malloc(sizeof(*p)))) { + memset(p, WIPE_CHAR, sizeof(*p)); + } + return p; +#else + struct fix_block *b; + +#ifdef _REENTRANT + ei_mutex_lock(erl_eterm_state->lock, 0); +#endif /* _REENTRANT */ + + /* try to pop block from head of freelist */ + if ((b = erl_eterm_state->freelist) != NULL) { + erl_eterm_state->freelist = b->next; + erl_eterm_state->freed--; + } else if ((b = malloc(sizeof(*b))) == NULL) { + erl_errno = ENOMEM; + } + erl_eterm_state->allocated++; + b->free = 0; + b->next = NULL; +#ifdef _REENTRANT + ei_mutex_unlock(erl_eterm_state->lock); +#endif /* _REENTRANT */ + return (void *) &b->term; +#endif /* !PURIFY */ +} + +/* free an eterm back to the freelist */ +void erl_eterm_free(void *p) +{ +#ifdef PURIFY + if (p) { + memset(p, WIPE_CHAR, sizeof(ETERM)); + } + free(p); +#else + struct fix_block *b = p; + + if (b) { + if (b->free) { +#ifdef DEBUG + fprintf(stderr,"erl_eterm_free: attempt to free already freed block %p\n",b); +#endif + return; + } + +#ifdef _REENTRANT + ei_mutex_lock(erl_eterm_state->lock,0); +#endif /* _REENTRANT */ + b->free = 1; + b->next = erl_eterm_state->freelist; + erl_eterm_state->freelist = b; + erl_eterm_state->freed++; + erl_eterm_state->allocated--; +#ifdef _REENTRANT + ei_mutex_unlock(erl_eterm_state->lock); +#endif /* _REENTRANT */ + } +#endif /* !PURIFY */ +} + +/* really free the freelist */ +void erl_eterm_release (void) +{ +#if !defined(PURIFY) + struct fix_block *b; + +#ifdef _REENTRANT + ei_mutex_lock(erl_eterm_state->lock,0); +#endif /* _REENTRANT */ + { + while (erl_eterm_state->freelist != NULL) { + b = erl_eterm_state->freelist; + erl_eterm_state->freelist = b->next; + free(b); + erl_eterm_state->freed--; + } + } +#ifdef _REENTRANT + ei_mutex_unlock(erl_eterm_state->lock); +#endif /* _REENTRANT */ +#endif /* !PURIFY */ +} + +void erl_eterm_statistics (unsigned long *allocd, unsigned long *freed) +{ + if (allocd) *allocd = erl_eterm_state->allocated; + if (freed) *freed = erl_eterm_state->freed; + + return; +} + + +/* + * Local Variables: + * compile-command: "cd ..; ERL_TOP=/clearcase/otp/erts make -k" + * End: + */ diff --git a/lib/erl_interface/src/legacy/erl_fix_alloc.h b/lib/erl_interface/src/legacy/erl_fix_alloc.h new file mode 100644 index 0000000000..16d2f4217a --- /dev/null +++ b/lib/erl_interface/src/legacy/erl_fix_alloc.h @@ -0,0 +1,26 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1996-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifndef _ERL_FIX_ALLOC_H +#define _ERL_FIX_ALLOC_H + +int erl_init_eterm_alloc(void); +void erl_eterm_free(void*); +void *erl_eterm_alloc(void); + +#endif /* _ERL_FIX_ALLOC_H */ diff --git a/lib/erl_interface/src/legacy/erl_format.c b/lib/erl_interface/src/legacy/erl_format.c new file mode 100644 index 0000000000..9848e9296a --- /dev/null +++ b/lib/erl_interface/src/legacy/erl_format.c @@ -0,0 +1,729 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1996-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Function: Provides two primitives: erl_format to build + * Erlang terms in an easy way, and erl_match to perform + * pattern match similar to what is done in Erlang. + * + */ + +#include "eidef.h" + +#include +#include +#include +#include +#include + +#ifdef VRTX +#define __READY_EXTENSIONS__ +#include +#endif +#include "erl_interface.h" +#include "erl_eterm.h" +#include "erl_malloc.h" +#include "erl_error.h" +#include "erl_internal.h" + +#define ERL_TRUE 1 +#define ERL_FALSE 0 +#define ERL_OK 0 +#define ERL_FORMAT_ERROR -1 + +#define ERL_MAX_ENTRIES 255 /* Max entries in a tuple/list term */ +#define ERL_MAX_NAME_LENGTH 255 /* Max length of variable names */ + +#define PRINT(t) \ +{ \ + print_term(stderr,t); \ + fprintf(stderr,"\n"); \ + } + + +typedef struct lvar { + ETERM *var; + struct lvar *next; +} lvar; + + +/* Forward */ +static ETERM *eformat(char**, va_list*); +static int ematch(ETERM*, ETERM*); + +/* FIXME not thread safe */ +struct _ef { + lvar *chain; /* Chain of local variables */ + lvar *idle; /* Idle list of lvar's */ +} ef; + +/* Find local variable in term. + */ +static ETERM *find_lvar(char *name) +{ + lvar *tmp=ef.chain; + + while (tmp != NULL) { + if (strcmp(tmp->var->uval.vval.name,name) == 0) + return tmp->var->uval.vval.v; + tmp = tmp->next; + } + return (ETERM *) NULL; + +} /* find_lvar */ + +static void lvar_free(lvar *lv) +{ + lvar *tmp=ef.chain; + + /* Link in the chain into the idle list */ + if (ef.idle == NULL) + ef.idle = lv; + else { + tmp = ef.idle; + while (tmp->next != NULL) + tmp = tmp->next; + tmp->next = lv; + } + + + /* Clear out the variable information */ + tmp = lv; + while (tmp != NULL) { + tmp->var = (ETERM *) NULL; + tmp = tmp->next; + } + +} /* lvar_free */ + +static lvar *lvar_alloc(void) +{ + lvar *tmp; + + if ((tmp = ef.idle) == NULL) { + tmp = (lvar *) malloc(sizeof(lvar)); /* FIXME check result */ + } + else { + tmp = ef.idle; + ef.idle = tmp->next; + } + return tmp; + +} /* lvar_alloc */ + +static void undo_bindings(void) +{ + lvar *tmp=ef.chain; + + while (tmp != NULL) { + erl_free_term(tmp->var->uval.vval.v); + tmp->var->uval.vval.v = (ETERM *) NULL; + tmp = tmp->next; + } + +} /* undo_bindings */ + +static void release_chain(void) +{ + + lvar_free(ef.chain); + ef.chain = (lvar *) NULL; + +} /* release_chain */ + +static void add_lvar(ETERM *t) +{ + lvar *lv; + + lv = lvar_alloc(); + lv->var = t; + lv->next = ef.chain; + ef.chain = lv; + +} /* add_lvar */ + +static char *pvariable(char **fmt, char *buf) +{ + char *start=*fmt; + char c; + int len; + + while (1) { + c = *(*fmt)++; + if (isalnum((int) c) || (c == '_')) + continue; + else + break; + } + (*fmt)--; + len = *fmt - start; + memcpy(buf, start, len); + buf[len] = 0; + + return buf; + +} /* pvariable */ + +static char *patom(char **fmt, char *buf) +{ + char *start=*fmt; + char c; + int len; + + while (1) { + c = *(*fmt)++; + if (isalnum((int) c) || (c == '_') || (c == '@')) + continue; + else + break; + } + (*fmt)--; + len = *fmt - start; + memcpy(buf, start, len); + buf[len] = 0; + + return buf; + +} /* patom */ + +/* Check if integer or float + */ +static char *pdigit(char **fmt, char *buf) +{ + char *start=*fmt; + char c; + int len,dotp=0; + + while (1) { + c = *(*fmt)++; + if (isdigit((int) c)) + continue; + else if (!dotp && (c == '.')) { + dotp = 1; + continue; + } + else + break; + } + (*fmt)--; + len = *fmt - start; + memcpy(buf, start, len); + buf[len] = 0; + + return buf; + +} /* pdigit */ + +static char *pstring(char **fmt, char *buf) +{ + char *start=++(*fmt); /* skip first quote */ + char c; + int len; + + while (1) { + c = *(*fmt)++; + if (c == '"') { + if (*((*fmt)-1) == '\\') + continue; + else + break; + } else + continue; + } + len = *fmt - 1 - start; /* skip last quote */ + memcpy(buf, start, len); + buf[len] = 0; + + return buf; + +} /* pstring */ + +static char *pquotedatom(char **fmt, char *buf) +{ + char *start=++(*fmt); /* skip first quote */ + char c; + int len; + + while (1) { + c = *(*fmt)++; + if (c == '\'') { + if (*((*fmt)-1) == '\\') + continue; + else + break; + } else + continue; + } + len = *fmt - 1 - start; /* skip last quote */ + memcpy(buf, start, len); + buf[len] = 0; + + return buf; + +} /* pquotedatom */ + + +/* + * The format letters are: + * w - Any Erlang term + * a - An Atom + * b - A Binary + * s - A String + * i - An Integer + * f - A Float (double) + */ +static int pformat(char **fmt, va_list *pap, ETERM *v[], int size) +{ + int rc=ERL_OK; + + /* this next section hacked to remove the va_arg calls */ + switch (*(*fmt)++) { + + case 'w': + v[size] = va_arg(*pap, ETERM*); + ERL_COUNT(v[size])++; + break; + + case 'a': + v[size] = erl_mk_atom(va_arg(*pap, char *)); + break; + + case 's': + v[size] = erl_mk_string(va_arg(*pap, char *)); + break; + + case 'i': + v[size] = erl_mk_int(va_arg(*pap, int)); + break; + + case 'f': + v[size] = erl_mk_float(va_arg(*pap, double)); + break; + + case 'b': { + char *sarg = va_arg(*pap, char *); + v[size] = erl_mk_binary(sarg, strlen(sarg)); + break; + } + + default: + rc = ERL_FORMAT_ERROR; + break; + } + + return rc; + +} /* pformat */ + +static int ptuple(char **fmt, va_list *pap, ETERM *v[], int size) +{ + int res=ERL_FORMAT_ERROR; + + switch (*(*fmt)++) { + + case '}': + res = size; + break; + + case ',': + res = ptuple(fmt, pap, v, size); + break; + + case '~': + + if (pformat(fmt, pap, v, size) == ERL_OK) + res = ptuple(fmt, pap, v, ++size); + else + erl_err_msg("ptuple(1): Wrong format sequence !"); + break; + + case ' ': + return ptuple(fmt, pap, v, size); + break; + + default: { + (*fmt)--; + if ((v[size++] = eformat(fmt, pap)) != (ETERM *) NULL) + res = ptuple(fmt, pap, v, size); + break; + + /* + if (isupper(**fmt)) { + v[size++] = erl_mk_var(pvariable(fmt, wbuf)); + res = ptuple(fmt, pap, v, size); + } + else if ((v[size++] = eformat(fmt, pap)) != (ETERM *) NULL) + res = ptuple(fmt, pap, v, size); + break; + */ + } + + } /* switch */ + + return res; + +} /* ptuple */ + + +static int plist(char **fmt, va_list *pap, ETERM *v[], int size) +{ + int res=ERL_FORMAT_ERROR; + + switch (*(*fmt)++) { + + case ']': + res = size; + break; + + case ',': + res = plist(fmt, pap, v, size); + break; + + case '~': + + if (pformat(fmt, pap, v, size) == ERL_OK) + res = plist(fmt, pap, v, ++size); + else + erl_err_msg("plist(1): Wrong format sequence !"); + break; + + case ' ': + return plist(fmt, pap, v, size); + break; + + default: { + (*fmt)--; + if ((v[size++] = eformat(fmt, pap)) != (ETERM *) NULL) + res = plist(fmt, pap, v, size); + break; + + /* + if (isupper(**fmt)) { + v[size++] = erl_mk_var(pvariable(fmt, wbuf)); + res = plist(fmt, pap, v, size); + } + else if ((v[size++] = eformat(fmt, pap)) != (ETERM *) NULL) + res = plist(fmt, pap, v, size); + break; + */ + } + + } /* switch */ + + return res; + +} /* plist */ + + +static ETERM *eformat(char **fmt, va_list *pap) +{ + int size; + ETERM *v[ERL_MAX_ENTRIES],*ep; + + switch (*(*fmt)++) { + case '{': + if ((size = ptuple(fmt, pap , v, 0)) != ERL_FORMAT_ERROR) { + ep = erl_mk_tuple(v, size); + erl_free_array(v, size); + return ep; + } + else + return (ETERM *) NULL; + break; + + case '[': + if (**fmt == ']') { + (*fmt)++; + return erl_mk_empty_list(); + } else if ((size = plist(fmt, pap , v, 0)) != ERL_FORMAT_ERROR) { + ep = erl_mk_list(v, size); + erl_free_array(v, size); + return ep; + } else + return (ETERM *) NULL; + break; + + case '$': /* char-value? */ + return erl_mk_int((int)(*(*fmt)++)); + break; + + case '~': + if (pformat(fmt, pap, v, 0) == ERL_OK) { + ep = erl_copy_term(v[0]); + erl_free_term(v[0]); + return ep; + } + break; + + case ' ': + return eformat(fmt, pap); + break; + + /* handle negative numbers too... + * case '-': + * { + * ETERM *tmp; + * + * tmp = eformat(fmt,pap); + * if (ERL_IS_INTEGER(tmp)) ERL_INT_VALUE(tmp) = -(ERL_INT_VALUE(tmp)); + * return tmp; + * } + * + * + * break; + */ + + default: + { + char wbuf[BUFSIZ]; /* now local to this function for reentrancy */ + + (*fmt)--; + if (islower((int)**fmt)) { /* atom ? */ + char *atom=patom(fmt, wbuf); + return erl_mk_atom(atom); + } + else if (isupper((int)**fmt) || (**fmt == '_')) { + char *var=pvariable(fmt, wbuf); + return erl_mk_var(var); + } + else if (isdigit((int)**fmt)) { /* integer/float ? */ + char *digit=pdigit(fmt, wbuf); + if (strchr(digit,(int) '.') == NULL) + return erl_mk_int(atoi((const char *) digit)); + else + return erl_mk_float(atof((const char *) digit)); + } + else if (**fmt == '"') { /* string ? */ + char *string=pstring(fmt, wbuf); + return erl_mk_string(string); + } + else if (**fmt == '\'') { /* quoted atom ? */ + char *qatom=pquotedatom(fmt, wbuf); + return erl_mk_atom(qatom); + } + } + break; + + } + + erl_err_msg(" Syntax error in eformat, char was: %c !", **fmt); + return (ETERM *) NULL; + +} /* eformat */ + + +ETERM *erl_format(char *fmt, ... ) +{ + ETERM *res=NULL; + va_list ap; + + va_start(ap, fmt); + res = eformat(&fmt, &ap); + va_end(ap); + + return res; +} /* erl_format */ + + +/* + * Perform a pattern match between a pattern p and a term t. + * As a side effect bind any unbound variables in p. + * Return true or false. + */ +static int ematch(ETERM *p, ETERM *t) +{ + unsigned int type_p; + unsigned int type_t; + ETERM *tmp; + + /* two NULLs are equal, one is not... */ + if (!p && !t) return ERL_TRUE; + if (!p || !t) return ERL_FALSE; + /* + * ASSERT(p != NULL); + * ASSERT(t != NULL); + */ + + type_p = ERL_TYPE(p); + type_t = ERL_TYPE(t); + + if (type_t == ERL_VARIABLE) { + if (t->uval.vval.v == NULL) + return ERL_FALSE; /* Can't have an unbound variable here ! */ + else + t = t->uval.vval.v; + } + + if (type_p != ERL_VARIABLE && type_p != type_t) + return ERL_FALSE; + + switch (type_p) { + + case ERL_ATOM: + return p->uval.aval.len == t->uval.aval.len && + memcmp(p->uval.aval.a, t->uval.aval.a, p->uval.aval.len) == 0; + + case ERL_VARIABLE: + if (strcmp(p->uval.vval.name, "_") == 0) /* anon. variable */ + return ERL_TRUE; + else if ((tmp = find_lvar(p->uval.vval.name)) != (ETERM *) NULL) { + /* v points to NULL in cases like erl_format("{X,X}") for the + second variable */ + if (p->uval.vval.v == NULL) + p->uval.vval.v = erl_copy_term(tmp); + return ematch(p->uval.vval.v, t); + } + else { + /* check if the variable is bound already */ + if (p->uval.vval.v != NULL) { + if (ematch(p->uval.vval.v, t) == ERL_TRUE ){ + add_lvar(p); + return ERL_TRUE; + } + else + return ERL_FALSE; + } + else { + p->uval.vval.v = erl_copy_term(t); + add_lvar(p); + return ERL_TRUE; + } + } + break; + + case ERL_PID: + if ((strcmp(ERL_PID_NODE(p), ERL_PID_NODE(t)) == 0) && + (ERL_PID_NUMBER(p) == ERL_PID_NUMBER(t)) && + (ERL_PID_SERIAL(p) == ERL_PID_SERIAL(t)) && + (ERL_PID_CREATION(p) == ERL_PID_CREATION(t))) + return ERL_TRUE; + else + return ERL_FALSE; + break; + + case ERL_PORT: + if ((strcmp(ERL_PORT_NODE(p), ERL_PORT_NODE(t)) == 0) && + (ERL_PORT_NUMBER(p) == ERL_PORT_NUMBER(t)) && + (ERL_PORT_CREATION(p) == ERL_PORT_CREATION(t))) + return ERL_TRUE; + else + return ERL_FALSE; + break; + + case ERL_REF: { + int i, len; + + if (strcmp(ERL_REF_NODE(p), ERL_REF_NODE(t)) != 0 || + ERL_REF_CREATION(p) != ERL_REF_CREATION(t)) + return ERL_FALSE; + + /* FIXME: {len=1, n={42}} and {len=3, n={42, 17, 13}} tests equal. */ + len = ERL_REF_LEN(p); + if (len > ERL_REF_LEN(t)) + len = ERL_REF_LEN(t); + + for (i = 0; i < len; i++) + if (ERL_REF_NUMBERS(p)[i] != ERL_REF_NUMBERS(t)[i]) + return ERL_FALSE; + + return ERL_TRUE; + break; + } + + case ERL_EMPTY_LIST: + return ERL_TRUE; + + case ERL_LIST: + while (ERL_IS_CONS(p) && ERL_IS_CONS(t)) { + if (ematch(p->uval.lval.head, t->uval.lval.head) == ERL_FALSE) + return ERL_FALSE; + p = p->uval.lval.tail; + t = t ->uval.lval.tail; + } + return ematch(p, t); + + case ERL_TUPLE: + { + int i; + if (erl_size(p) != erl_size(t)) + return ERL_FALSE; + else { + for(i=0; iuval.tval.elems[i],t->uval.tval.elems[i]) == ERL_FALSE) + return ERL_FALSE; + return ERL_TRUE; + } + } + break; + + case ERL_BINARY: + { + int i; + if ((i = p->uval.bval.size) != t->uval.bval.size) + return ERL_FALSE; + else + return (memcmp(p->uval.bval.b,t->uval.bval.b,i)==0) ? ERL_TRUE : ERL_FALSE; + } + break; + + case ERL_INTEGER: + return (p->uval.ival.i == t->uval.ival.i) ? ERL_TRUE : ERL_FALSE; + break; + + case ERL_SMALL_BIG: + case ERL_U_SMALL_BIG: + /* This case can't happend since it is impossible + * to create a bignum from the C code. + */ + return ERL_FALSE; + break; + + case ERL_FLOAT: +#if defined(VXWORKS) && CPU == PPC860 + { + return (erl_fp_compare((unsigned *)&(p->uval.fval.f), + (unsigned *)&(t->uval.fval.f)) == 0) + ? ERL_TRUE : ERL_FALSE; + } +#else + return (p->uval.fval.f == t->uval.fval.f) ? ERL_TRUE : ERL_FALSE; +#endif + break; + default: + return ERL_FALSE; + break; + } + + /* erl_err_msg("ematch: Unknown type == %c\n", type_p); */ + return ERL_FALSE; + +} /* ematch */ + + +int erl_match(ETERM *p, ETERM *t) +{ + int i; + + if ((i = ematch(p, t)) == ERL_FALSE) + undo_bindings(); + release_chain(); + return i; + +} /* erl_match */ + + diff --git a/lib/erl_interface/src/legacy/erl_format.h b/lib/erl_interface/src/legacy/erl_format.h new file mode 100644 index 0000000000..90801e4892 --- /dev/null +++ b/lib/erl_interface/src/legacy/erl_format.h @@ -0,0 +1,22 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1996-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifndef _ERL_FORMAT_H +#define _ERL_FORMAT_H + +#endif /* _ERL_FORMAT_H */ diff --git a/lib/erl_interface/src/legacy/erl_global.h b/lib/erl_interface/src/legacy/erl_global.h new file mode 100644 index 0000000000..ef09eab0b0 --- /dev/null +++ b/lib/erl_interface/src/legacy/erl_global.h @@ -0,0 +1,27 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifndef _ERL_GLOBAL_H +#define _ERL_GLOBAL_H + +char **erl_global_names(int fd, int *count); +ETERM *erl_global_whereis(int fd, const char *name, char *node); +int erl_global_register(int fd, const char *name, ETERM *pid); +int erl_global_unregister(int fd, const char *name); + +#endif /* _ERL_GLOBAL_H */ diff --git a/lib/erl_interface/src/legacy/erl_internal.h b/lib/erl_interface/src/legacy/erl_internal.h new file mode 100644 index 0000000000..e79c815946 --- /dev/null +++ b/lib/erl_interface/src/legacy/erl_internal.h @@ -0,0 +1,47 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1996-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifndef _ERL_INTERNAL_H +#define _ERL_INTERNAL_H + +/* + * Function: Some useful stuff not to be exported to users. + */ + +#define HEAD(ep) ep->uval.lval.head +#define TAIL(ep) ep->uval.lval.tail +#define ERL_NO_REF(x) (ERL_COUNT(x) == 0) + +#ifdef DEBUG +#define ASSERT(e) \ + if (e) { \ + ; \ + } else { \ + erl_assert_error(#e, __FILE__, __LINE__); \ + } + +extern void erl_assert_error(char* expr, char* file, int line) + __attribute__ ((__noreturn__)); + +#else + +#define ASSERT(e) + +#endif + +#endif /* _ERL_INTERNAL_H */ diff --git a/lib/erl_interface/src/legacy/erl_malloc.c b/lib/erl_interface/src/legacy/erl_malloc.c new file mode 100644 index 0000000000..f51a6c69b3 --- /dev/null +++ b/lib/erl_interface/src/legacy/erl_malloc.c @@ -0,0 +1,239 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1996-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +#include "eidef.h" + +#include +#include + +#include "erl_interface.h" +#include "erl_fix_alloc.h" +#include "erl_malloc.h" +#include "erl_internal.h" +#include "erl_eterm.h" +#include "ei_malloc.h" + +void erl_init_malloc(Erl_Heap *hp, long heap_size) +{ + erl_init_eterm_alloc(); +} /* erl_init_malloc */ + +ETERM *erl_alloc_eterm(unsigned char type) +{ + ETERM *e; + + /* Use fix size allocator */ + if (!(e = (ETERM *) erl_eterm_alloc())) + erl_err_sys(" erl_alloc_eterm: Failed to allocate more memory\n"); + + ERL_HEADER(e)->count = 0; + ERL_HEADER(e)->type = type; + return e; + +} /* erl_alloc_eterm */ + +#define EXTERNAL 1 +#define INTERNAL 0 +#define COMPOUND 1 +#define NOT_COMPOUND 0 + +static void _erl_free_term (ETERM *ep, int external, int compound); + +/* + * Free a term, but don't deallocate it until + * the reference counter triggers. + */ +void erl_free_term(ETERM *ep) +{ + _erl_free_term(ep, EXTERNAL, NOT_COMPOUND); +} /* erl_free_term */ + +/* + * Free a term regardless of its reference + * counter value. Use this when you have + * built compound terms such as lists or tuples. + */ + +/* + * FIXME is this true?! + * Tearing down term structures no-matter-what is a horrible idea if + * any term happens to be shared (with some other structure or even + * with yourself). + */ + +void erl_free_compound (ETERM *ep) +{ + _erl_free_term(ep, EXTERNAL, COMPOUND); +} /* erl_free_compound */ + + +/* +** The actual free'ing is done here in _erl_free_term. +** It is by nature recursive, but does not recurse +** on the CDR of a list, which makes it usable for large lists. +*/ + +/* +** Convenience macro, called for variables and lists, +** avoids deep recursions. +*/ +#define RESTART(Eterm, External, Compound) \ +do { \ + ETERM *sep; \ + sep = (Eterm); \ + external = (External); \ + compound = (Compound); \ + /* Clear header info */ \ + ERL_TYPE(ep) = ERL_UNDEF; \ + erl_eterm_free((unsigned int *) ep); \ + ep = sep; \ + goto restart; \ +} while(0) + +#define FREE_AND_CLEAR(ptr) \ +do { \ + erl_free(ptr); \ + (ptr) = NULL; \ +} while (0) + +static void _erl_free_term (ETERM *ep, int external, int compound) +{ +restart: + if (ep == NULL) + return; + if (compound || ERL_NO_REF(ep)) { + /* Yes, it's time to *really* free this one ! */ + switch(ERL_TYPE(ep)) + { + case ERL_ATOM: + FREE_AND_CLEAR(ERL_ATOM_PTR(ep)); + break; + case ERL_VARIABLE: + FREE_AND_CLEAR(ERL_VAR_NAME(ep)); + /* Note: It may be unbound ! */ + if (ERL_VAR_VALUE(ep) != NULL) { + ERL_COUNT(ERL_VAR_VALUE(ep))--; + /* Cleanup and Restart with the actual value */ + RESTART(ERL_VAR_VALUE(ep), INTERNAL, compound); + } + break; + case ERL_LIST: + if (HEAD(ep)) { + ERL_COUNT(HEAD(ep))--; + /* FIXME added cast, is this correct? */ + _erl_free_term((ETERM *)HEAD(ep), INTERNAL, compound); + } + if (TAIL(ep)) { + ERL_COUNT(TAIL(ep))--; + /* Clean up and walk on to CDR in list */ + RESTART(TAIL(ep), INTERNAL, compound); + } + break; + case ERL_TUPLE: + { + int i; + for (i=0; i < ERL_TUPLE_SIZE(ep); i++) + if (ERL_TUPLE_ELEMENT(ep, i)) { + ERL_COUNT(ERL_TUPLE_ELEMENT(ep, i))--; + _erl_free_term(ERL_TUPLE_ELEMENT(ep, i), + INTERNAL, compound); + } + FREE_AND_CLEAR(ERL_TUPLE_ELEMS(ep)); + } + break; + case ERL_BINARY: + FREE_AND_CLEAR(ERL_BIN_PTR(ep)); + break; + case ERL_PID: + FREE_AND_CLEAR(ERL_PID_NODE(ep)); + break; + case ERL_PORT: + FREE_AND_CLEAR(ERL_PORT_NODE(ep)); + break; + case ERL_REF: + FREE_AND_CLEAR(ERL_REF_NODE(ep)); + break; + case ERL_EMPTY_LIST: + case ERL_INTEGER: + case ERL_SMALL_BIG: + case ERL_U_SMALL_BIG: + case ERL_FLOAT: + break; + case ERL_FUNCTION: + { + int i; + + _erl_free_term(ERL_FUN_INDEX(ep), INTERNAL, compound); + _erl_free_term(ERL_FUN_UNIQ(ep), INTERNAL, compound); + _erl_free_term(ERL_FUN_CREATOR(ep), INTERNAL, compound); + _erl_free_term(ERL_FUN_MODULE(ep), INTERNAL, compound); + if (ERL_CLOSURE(ep) != NULL) { + for (i = 0; i < ERL_CLOSURE_SIZE(ep); i++) + _erl_free_term(ERL_CLOSURE_ELEMENT(ep,i), + INTERNAL, compound); + } + } + break; + } /* switch */ + + /* Clear header info for those cases where we are done */ + ERL_TYPE(ep) = ERL_UNDEF; + erl_eterm_free(ep); + } else if (external) { + ERL_COUNT(ep)--; + external = INTERNAL; + goto restart; + } +} /* _erl_free_term */ +#undef RESTART +#undef FREE_AND_CLEAR + +void erl_free_array(ETERM **arr, int size) +{ + int i; + + for (i=0; i erl_malloc: Failed to allocate more memory"); + + return res; +} + +void* erl_realloc(void* orig, long size) +{ + void *res; + + if ((res = ei_realloc(orig, size)) == NULL) + erl_err_sys(" erl_realloc: Failed to allocate more memory"); + return res; +} + +void erl_free (void *ptr) +{ + ei_free(ptr); +} diff --git a/lib/erl_interface/src/legacy/erl_malloc.h b/lib/erl_interface/src/legacy/erl_malloc.h new file mode 100644 index 0000000000..787d3bb98f --- /dev/null +++ b/lib/erl_interface/src/legacy/erl_malloc.h @@ -0,0 +1,26 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1996-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifndef _ERL_MALLOC_H +#define _ERL_MALLOC_H + +/* FIXME: not documented */ +void *erl_realloc(void*, long); +int erl_current_fix_desc(void); + +#endif /* _ERL_MALLOC_H */ diff --git a/lib/erl_interface/src/legacy/erl_marshal.c b/lib/erl_interface/src/legacy/erl_marshal.c new file mode 100644 index 0000000000..4b5f28178f --- /dev/null +++ b/lib/erl_interface/src/legacy/erl_marshal.c @@ -0,0 +1,2117 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1996-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Purpose: Decoding and encoding Erlang terms. + */ +#include "eidef.h" + +#include +#include +#include +#include +#include + +#include "erl_interface.h" +#include "erl_marshal.h" +#include "erl_eterm.h" +#include "erl_malloc.h" +#include "erl_error.h" +#include "erl_internal.h" + +#include "eiext.h" /* replaces external.h */ +#include "putget.h" + +static int is_string(ETERM* term); +#if defined(VXWORKS) && CPU == PPC860 +int erl_fp_compare(unsigned *a, unsigned *b); +static void erl_long_to_fp(long l, unsigned *d); +#endif + +/* Used when comparing two encoded byte arrays */ +/* this global data is ok (from threading point of view) since it is + * initialized once and never changed + */ + +#define CMP_ARRAY_SIZE 256 +/* FIXME problem for threaded ? */ +static char cmp_array[CMP_ARRAY_SIZE]; +static int init_cmp_array_p=1; /* initialize array, the first time */ + +#if defined(VXWORKS) && CPU == PPC860 +#include +#endif + +#if defined(__GNUC__) +# define INLINE __inline__ +#elif defined(__WIN32__) +# define INLINE __inline +#else +# define INLINE +#endif + +static int cmp_floats(double f1, double f2); +static INLINE double to_float(long l); + +#define ERL_NUM_CMP 1 +#define ERL_REF_CMP 3 + +#define IS_ERL_NUM(t) (cmp_array[t]==ERL_NUM_CMP) + +#define CMP_NUM_CLASS_SIZE 256 +static unsigned char cmp_num_class[CMP_NUM_CLASS_SIZE]; +static int init_cmp_num_class_p=1; /* initialize array, the first time */ + +#define MK_CMP_NUM_CODE(x,y) (((x)<<2)|(y)) +#define CMP_NUM_CLASS(x) (cmp_num_class[x] & 0x03) +#define CMP_NUM_CODE(x,y) (MK_CMP_NUM_CODE(CMP_NUM_CLASS(x),CMP_NUM_CLASS(y))) + +#define SMALL 1 +#define FLOAT 2 +#define BIG 3 + +#define SMALL_SMALL MK_CMP_NUM_CODE(SMALL,SMALL) +#define SMALL_FLOAT MK_CMP_NUM_CODE(SMALL,FLOAT) +#define SMALL_BIG MK_CMP_NUM_CODE(SMALL,BIG) +#define FLOAT_SMALL MK_CMP_NUM_CODE(FLOAT,SMALL) +#define FLOAT_FLOAT MK_CMP_NUM_CODE(FLOAT,FLOAT) +#define FLOAT_BIG MK_CMP_NUM_CODE(FLOAT,BIG) +#define BIG_SMALL MK_CMP_NUM_CODE(BIG,SMALL) +#define BIG_FLOAT MK_CMP_NUM_CODE(BIG,FLOAT) +#define BIG_BIG MK_CMP_NUM_CODE(BIG,BIG) + +void erl_init_marshal(void) +{ + if (init_cmp_array_p) { + memset(cmp_array, 0, CMP_ARRAY_SIZE); + cmp_array[ERL_SMALL_INTEGER_EXT] = 1; + cmp_array[ERL_INTEGER_EXT] = 1; + cmp_array[ERL_FLOAT_EXT] = 1; + cmp_array[ERL_SMALL_BIG_EXT] = 1; + cmp_array[ERL_LARGE_BIG_EXT] = 1; + cmp_array[ERL_ATOM_EXT] = 2; + cmp_array[ERL_REFERENCE_EXT] = 3; + cmp_array[ERL_NEW_REFERENCE_EXT] = 3; + cmp_array[ERL_FUN_EXT] = 4; + cmp_array[ERL_NEW_FUN_EXT] = 4; + cmp_array[ERL_PORT_EXT] = 5; + cmp_array[ERL_PID_EXT] = 6; + cmp_array[ERL_SMALL_TUPLE_EXT] = 7; + cmp_array[ERL_LARGE_TUPLE_EXT] = 7; + cmp_array[ERL_NIL_EXT] = 8; + cmp_array[ERL_STRING_EXT] = 9; + cmp_array[ERL_LIST_EXT] = 9; + cmp_array[ERL_BINARY_EXT] = 10; + init_cmp_array_p = 0; + } + if (init_cmp_num_class_p) { + memset(cmp_num_class, 0, CMP_NUM_CLASS_SIZE); + cmp_num_class[ERL_SMALL_INTEGER_EXT] = SMALL; + cmp_num_class[ERL_INTEGER_EXT] = SMALL; + cmp_num_class[ERL_FLOAT_EXT] = FLOAT; + cmp_num_class[ERL_SMALL_BIG_EXT] = BIG; + cmp_num_class[ERL_LARGE_BIG_EXT] = BIG; + init_cmp_num_class_p = 0; + } +} + +/* The encoder calls length, if erl_length() should return */ +/* -1 for dotted pairs (why !!!!) we can't use erl_length() */ +/* from the encoder in erl_marshal.c */ + +static int erl_length_x(const ETERM *ep) { + int n = 0; + + if (!ep) return -1; + + while (ERL_TYPE(ep) == ERL_LIST) { + n++; + ep = TAIL(ep); + } + + return n; +} + + +/*============================================================== + * Marshalling routines. + *============================================================== + */ + +/* + * The actual ENCODE engine. + * Returns 0 on success, otherwise 1. + */ +int erl_encode_it(ETERM *ep, unsigned char **ext, int dist) +{ + int i; + unsigned int u; + long long l; + unsigned long long ul; + + switch(ERL_TYPE(ep)) + { + case ERL_ATOM: + i = ep->uval.aval.len; + *(*ext)++ = ERL_ATOM_EXT; + *(*ext)++ = (i >>8) &0xff; + *(*ext)++ = i &0xff; + memcpy((void *) *ext, (const void *) ep->uval.aval.a, i); + *ext += i; + return 0; + + case ERL_INTEGER: + i = ep->uval.ival.i; + /* ERL_SMALL_BIG */ + if ((i > ERL_MAX) || (i < ERL_MIN)) { + *(*ext)++ = ERL_SMALL_BIG_EXT; + *(*ext)++ = 4; /* four bytes */ + if ((*(*ext)++ = ((i>>31) & 0x01))) /* sign byte */ + i = -i; + *(*ext)++ = i & 0xff; /* LSB first */ + *(*ext)++ = (i >> 8) & 0xff; + *(*ext)++ = (i >> 16) & 0xff; + *(*ext)++ = (i >> 24) & 0x7f; /* Don't include the sign bit */ + return 0; + } + /* SMALL_INTEGER */ + if ((i < 256) && (i >= 0)) { + *(*ext)++ = ERL_SMALL_INTEGER_EXT; + *(*ext)++ = i & 0xff; + return 0; + } + /* INTEGER */ + *(*ext)++ = ERL_INTEGER_EXT; + *(*ext)++ = (i >> 24) & 0xff; + *(*ext)++ = (i >> 16) & 0xff; + *(*ext)++ = (i >> 8) & 0xff; + *(*ext)++ = i & 0xff; + return 0; + + case ERL_U_INTEGER: + u = ep->uval.uival.u; + /* ERL_U_SMALL_BIG */ + if (u > ERL_MAX) { + *(*ext)++ = ERL_SMALL_BIG_EXT; + *(*ext)++ = 4; /* four bytes */ + *(*ext)++ = 0; /* sign byte */ + *(*ext)++ = u & 0xff; /* LSB first */ + *(*ext)++ = (u >> 8) & 0xff; + *(*ext)++ = (u >> 16) & 0xff; + *(*ext)++ = (u >> 24) & 0xff; + return 0; + } + /* SMALL_INTEGER */ + if ((u < 256) && (u >= 0)) { + *(*ext)++ = ERL_SMALL_INTEGER_EXT; + *(*ext)++ = u & 0xff; + return 0; + } + /* INTEGER */ + *(*ext)++ = ERL_INTEGER_EXT; + *(*ext)++ = (u >> 24) & 0xff; + *(*ext)++ = (u >> 16) & 0xff; + *(*ext)++ = (u >> 8) & 0xff; + *(*ext)++ = u & 0xff; + return 0; + case ERL_LONGLONG: + l = ep->uval.llval.i; + /* ERL_SMALL_BIG */ + if ((l > ((long long) ERL_MAX)) || + (l < ((long long) ERL_MIN))) { + *(*ext)++ = ERL_SMALL_BIG_EXT; + *(*ext)++ = 8; /* eight bytes */ + if ((*(*ext)++ = ((l>>63) & 0x01))) /* sign byte */ + l = -l; + *(*ext)++ = l & 0xff; /* LSB first */ + *(*ext)++ = (l >> 8) & 0xff; + *(*ext)++ = (l >> 16) & 0xff; + *(*ext)++ = (l >> 24) & 0xff; + *(*ext)++ = (l >> 32) & 0xff; + *(*ext)++ = (l >> 40) & 0xff; + *(*ext)++ = (l >> 48) & 0xff; + *(*ext)++ = (l >> 56) & 0x7f; /* Don't include the sign bit */ + return 0; + } + /* SMALL_INTEGER */ + if ((l < 256) && (l >= 0)) { + *(*ext)++ = ERL_SMALL_INTEGER_EXT; + *(*ext)++ = l & 0xff; + return 0; + } + /* INTEGER */ + *(*ext)++ = ERL_INTEGER_EXT; + *(*ext)++ = (l >> 24) & 0xff; + *(*ext)++ = (l >> 16) & 0xff; + *(*ext)++ = (l >> 8) & 0xff; + *(*ext)++ = l & 0xff; + return 0; + + case ERL_U_LONGLONG: + ul = ep->uval.ullval.u; + /* ERL_U_SMALL_BIG */ + if (ul > ((unsigned long long) ERL_MAX)) { + *(*ext)++ = ERL_SMALL_BIG_EXT; + *(*ext)++ = 8; /* eight bytes */ + *(*ext)++ = 0; /* sign byte */ + *(*ext)++ = ul & 0xff; /* LSB first */ + *(*ext)++ = (ul >> 8) & 0xff; + *(*ext)++ = (ul >> 16) & 0xff; + *(*ext)++ = (ul >> 24) & 0xff; + *(*ext)++ = (ul >> 32) & 0xff; + *(*ext)++ = (ul >> 40) & 0xff; + *(*ext)++ = (ul >> 48) & 0xff; + *(*ext)++ = (ul >> 56) & 0xff; + return 0; + } + /* SMALL_INTEGER */ + if ((ul < 256) && (ul >= 0)) { + *(*ext)++ = ERL_SMALL_INTEGER_EXT; + *(*ext)++ = ul & 0xff; + return 0; + } + /* INTEGER */ + *(*ext)++ = ERL_INTEGER_EXT; + *(*ext)++ = (ul >> 24) & 0xff; + *(*ext)++ = (ul >> 16) & 0xff; + *(*ext)++ = (ul >> 8) & 0xff; + *(*ext)++ = ul & 0xff; + return 0; + + case ERL_PID: + *(*ext)++ = ERL_PID_EXT; + /* First poke in node as an atom */ + i = strlen((char *)ERL_PID_NODE(ep)); + *(*ext)++ = ERL_ATOM_EXT; + *(*ext)++ = (i >>8) &0xff; + *(*ext)++ = i &0xff; + memcpy(*ext, ERL_PID_NODE(ep), i); + *ext += i; + /* And then fill in the integer fields */ + i = ERL_PID_NUMBER(ep); + *(*ext)++ = (i >> 24) &0xff; + *(*ext)++ = (i >> 16) &0xff; + *(*ext)++ = (i >> 8) &0xff; + *(*ext)++ = i &0xff; + i = ERL_PID_SERIAL(ep); + *(*ext)++ = (i >> 24) &0xff; + *(*ext)++ = (i >> 16) &0xff; + *(*ext)++ = (i >> 8) &0xff; + *(*ext)++ = i &0xff; + *(*ext)++ = ERL_PID_CREATION(ep); + return 0; + case ERL_REF: { + int len, j; + + /* Always encode as an extended reference; all + participating parties are now expected to be + able to decode extended references. */ + + *(*ext)++ = ERL_NEW_REFERENCE_EXT; + + i = strlen((char *)ERL_REF_NODE(ep)); + len = ERL_REF_LEN(ep); + *(*ext)++ = (len >> 8) &0xff; + *(*ext)++ = len &0xff; + + *(*ext)++ = ERL_ATOM_EXT; + *(*ext)++ = (i >> 8) &0xff; + *(*ext)++ = i &0xff; + memcpy(*ext, ERL_REF_NODE(ep), i); + *ext += i; + *(*ext)++ = ERL_REF_CREATION(ep); + /* Then the integer fields */ + for (j = 0; j < ERL_REF_LEN(ep); j++) { + i = ERL_REF_NUMBERS(ep)[j]; + *(*ext)++ = (i >> 24) &0xff; + *(*ext)++ = (i >> 16) &0xff; + *(*ext)++ = (i >> 8) &0xff; + *(*ext)++ = i &0xff; + } + } + return 0; + case ERL_PORT: + *(*ext)++ = ERL_PORT_EXT; + /* First poke in node as an atom */ + i = strlen((char *)ERL_PORT_NODE(ep)); + *(*ext)++ = ERL_ATOM_EXT; + *(*ext)++ = (i >>8) &0xff; + *(*ext)++ = i &0xff; + memcpy(*ext, ERL_PORT_NODE(ep), i); + *ext += i; + /* Then the integer fields */ + i = ERL_PORT_NUMBER(ep); + *(*ext)++ = (i >> 24) &0xff; + *(*ext)++ = (i >> 16) &0xff; + *(*ext)++ = (i >> 8) &0xff; + *(*ext)++ = i &0xff; + *(*ext)++ = ERL_PORT_CREATION(ep); + return 0; + case ERL_EMPTY_LIST: + *(*ext)++ = ERL_NIL_EXT; + break; + case ERL_LIST: + i = is_string(ep); + if (0 < i && i < 0x10000) { /* String. */ + *(*ext)++ = ERL_STRING_EXT; + *(*ext)++ = (i >>8) &0xff; + *(*ext)++ = i &0xff; + while (ERL_TYPE(ep) == ERL_LIST) { + *(*ext)++ = HEAD(ep)->uval.ival.i; + ep = TAIL(ep); + } + break; + } else { /* List. */ + i = erl_length_x(ep); + *(*ext)++ = ERL_LIST_EXT; + *(*ext)++ = (i >> 24) &0xff; + *(*ext)++ = (i >> 16) &0xff; + *(*ext)++ = (i >> 8) &0xff; + *(*ext)++ = i &0xff; + while (ERL_TYPE(ep) == ERL_LIST) { + if (erl_encode_it(HEAD(ep), ext, dist)) + return 1; + ep = TAIL(ep); + } + i = erl_encode_it(ep, ext, dist); + return i; + } + case ERL_TUPLE: + i = ep->uval.tval.size; + if (i <= 0xff) { + *(*ext)++ = ERL_SMALL_TUPLE_EXT; + *(*ext)++ = i & 0xff; + } + else { + *(*ext)++ = ERL_LARGE_TUPLE_EXT; + *(*ext)++ = (i >> 24) & 0xff; + *(*ext)++ = (i >> 16) & 0xff; + *(*ext)++ = (i >> 8) & 0xff; + *(*ext)++ = i & 0xff; + } + for (i=0; iuval.tval.size; i++) + if (erl_encode_it(ep->uval.tval.elems[i], ext, dist)) + return 1; + break; + case ERL_FLOAT: + *(*ext)++ = ERL_FLOAT_EXT; + memset(*ext, 0, 31); + sprintf((char *) *ext, "%.20e", ep->uval.fval.f); + *ext += 31; + break; + case ERL_BINARY: + *(*ext)++ = ERL_BINARY_EXT; + i = ep->uval.bval.size; + *(*ext)++ = (i >> 24) & 0xff; + *(*ext)++ = (i >> 16) & 0xff; + *(*ext)++ = (i >> 8) & 0xff; + *(*ext)++ = i & 0xff; + memcpy((char *) *ext, (char*) ep->uval.bval.b, i); + *ext += i; + break; + case ERL_FUNCTION: + if (ERL_FUN_ARITY(ep) != -1) { + unsigned char *size_p = *ext + 1; + *(*ext)++ = ERL_NEW_FUN_EXT; + *ext += 4; + i = ERL_FUN_ARITY(ep); + put8(*ext, i); + memcpy(*ext, ERL_FUN_MD5(ep), 16); + *ext += 16; + i = ERL_FUN_NEW_INDEX(ep); + put32be(*ext, i); + i = ERL_CLOSURE_SIZE(ep); + put32be(*ext, i); + erl_encode_it(ERL_FUN_MODULE(ep), ext, dist); + erl_encode_it(ERL_FUN_INDEX(ep), ext, dist); + erl_encode_it(ERL_FUN_UNIQ(ep), ext, dist); + erl_encode_it(ERL_FUN_CREATOR(ep), ext, dist); + for (i = 0; i < ERL_CLOSURE_SIZE(ep); i++) + erl_encode_it(ep->uval.funcval.closure[i], ext, dist); + if (size_p != NULL) { + i = *ext - size_p; + put32be(size_p, i); + } + } else { + *(*ext)++ = ERL_FUN_EXT; + i = ERL_CLOSURE_SIZE(ep); + *(*ext)++ = (i >> 24) & 0xff; + *(*ext)++ = (i >> 16) & 0xff; + *(*ext)++ = (i >> 8) & 0xff; + *(*ext)++ = i & 0xff; + erl_encode_it(ERL_FUN_CREATOR(ep), ext, dist); + erl_encode_it(ERL_FUN_MODULE(ep), ext, dist); + erl_encode_it(ERL_FUN_INDEX(ep), ext, dist); + erl_encode_it(ERL_FUN_UNIQ(ep), ext, dist); + for (i = 0; i < ERL_CLOSURE_SIZE(ep); i++) + erl_encode_it(ep->uval.funcval.closure[i], ext, dist); + } + break; + default: + return 1; + } + return 0; +} + +/* + * ENCODE an ETERM into a BUFFER, assuming BUFFER is of + * enough size. At success return number of bytes written + * into it, otherwise return 0. + */ +static int erl_encode3(ETERM *ep, unsigned char *t, int dist) +{ + unsigned char *x = t; + + *x++ = ERL_VERSION_MAGIC; + if (erl_encode_it(ep, &x, dist)) { +#ifdef DEBUG + erl_err_msg(" erl_encode: Error while encoding"); +#endif + return 0; + } + return (x - t); + +} + +/* API */ + +int erl_encode(ETERM *ep, unsigned char *t) +{ + return erl_encode3(ep, t, 4); +} + +/* determine the buffer size that will be required for the eterm */ +static int erl_term_len_helper(ETERM *ep, int dist); + +/* FIXME hard coded dist version */ +int erl_term_len(ETERM *ep) +{ + return 1+erl_term_len_helper(ep, 4); +} + +static int erl_term_len_helper(ETERM *ep, int dist) +{ + int len = 0; + int i; + unsigned int u; + long long l; + unsigned long long ul; + + if (ep) { + switch (ERL_TYPE(ep)) { + case ERL_ATOM: + i = ep->uval.aval.len; + len = i + 3; + break; + + case ERL_INTEGER: + i = ep->uval.ival.i; + if ((i > ERL_MAX) || (i < ERL_MIN)) len = 7; + else if ((i < 256) && (i >= 0)) len = 2; + else len = 5; + break; + + case ERL_U_INTEGER: + u = ep->uval.uival.u; + if (u > ERL_MAX) len = 7; + else if (u < 256) len = 2; + else len = 5; + break; + + case ERL_LONGLONG: + l = ep->uval.llval.i; + if ((l > ((long long) ERL_MAX)) || + (l < ((long long) ERL_MIN))) len = 11; + else if ((l < 256) && (l >= 0)) len = 2; + else len = 5; + break; + + case ERL_U_LONGLONG: + ul = ep->uval.ullval.u; + if (ul > ((unsigned long long) ERL_MAX)) len = 11; + else if (ul < 256) len = 2; + else len = 5; + break; + + case ERL_PID: + /* 1 + N + 4 + 4 + 1 where N = 3 + strlen */ + i = strlen((char *)ERL_PID_NODE(ep)); + len = 13 + i; + break; + + case ERL_REF: + i = strlen((char *)ERL_REF_NODE(ep)); + if (dist >= 4 && ERL_REF_LEN(ep) > 1) { + len = 1 + 2 + (i+3) + 1 + ERL_REF_LEN(ep) * 4; + } else { + /* 1 + N + 4 + 1 where N = 3 + strlen */ + len = 9 + i; + } + break; + + case ERL_PORT: + /* 1 + N + 4 + 1 where N = 3 + strlen */ + i = strlen((char *)ERL_PORT_NODE(ep)); + len = 9 + i; + break; + + case ERL_EMPTY_LIST: + len = 1; + break; + + case ERL_LIST: + i = is_string(ep); + if ((i > 0) && (i < 0x10000)) { /* string: 3 + strlen */ + for (len = 3; ERL_TYPE(ep) == ERL_LIST; ep = TAIL(ep)) { + len++; + } + } + else { /* list: 5 + len(elem1) + len(elem2) ... */ + for (len = 5; ERL_TYPE(ep) == ERL_LIST; ep = TAIL(ep)) { + len += erl_term_len_helper(HEAD(ep), dist); + } + len += erl_term_len_helper(ep, dist); /* last element */ + } + break; + + case ERL_TUPLE: + /* (2 or 5) + len(elem1) + len(elem2) ... */ + i = ep->uval.tval.size; + if (i <= 0xff) len = 2; + else len = 5; + + for (i=0; iuval.tval.size; i++) { + len += erl_term_len_helper(ep->uval.tval.elems[i], dist); + } + break; + + case ERL_FLOAT: + len = 32; + break; + + case ERL_BINARY: + i = ep->uval.bval.size; + len = 5 + i; + break; + + case ERL_FUNCTION: + if (ERL_FUN_ARITY(ep) == -1) { + len = 1 + 4; + len += erl_term_len_helper(ERL_FUN_CREATOR(ep),dist); + len += erl_term_len_helper(ERL_FUN_MODULE(ep),dist); + len += erl_term_len_helper(ERL_FUN_INDEX(ep),dist); + len += erl_term_len_helper(ERL_FUN_UNIQ(ep),dist); + for (i = 0; i < ERL_CLOSURE_SIZE(ep); i++) + len += erl_term_len_helper(ERL_CLOSURE_ELEMENT(ep,i), dist); + } else { + len = 1 + 4 + 16 + 4 + 4; + len += erl_term_len_helper(ERL_FUN_MODULE(ep),dist); + len += erl_term_len_helper(ERL_FUN_INDEX(ep),dist); + len += erl_term_len_helper(ERL_FUN_UNIQ(ep),dist); + len += erl_term_len_helper(ERL_FUN_CREATOR(ep),dist); + for (i = 0; i < ERL_CLOSURE_SIZE(ep); i++) + len += erl_term_len_helper(ERL_CLOSURE_ELEMENT(ep,i), dist); + } + break; + + default: +#ifdef DEBUG + fprintf(stderr, "Shouldn't happen: erl_term_len, unknown term type: '%c'\n",ERL_TYPE(ep)); +#endif + erl_errno = EINVAL; + exit(1); + } + } + + return len; +} + +/* + * This one makes it easy to ENCODE several CONSECUTIVE + * ETERM's into the same buffer. + */ +int erl_encode_buf(ETERM *ep, unsigned char **ext) +{ + unsigned char *start=*ext; + + *(*ext)++ = ERL_VERSION_MAGIC; + if (erl_encode_it(ep, ext, 0)) { +#ifdef DEBUG + erl_err_msg(" erl_encode_buf: Error while encoding\n"); +#endif + return 0; + } + return (*ext - start); + +} /* erl_encode_buf */ + +/* + * A nice macro to make it look cleaner in the + * cases of PID's,PORT's and REF's below. + * It reads the NODE name from a buffer. + */ +#define READ_THE_NODE(ext,cp,len,i) \ +/* eat first atom, repr. the node */ \ +if (**ext != ERL_ATOM_EXT) \ + return (ETERM *) NULL; \ +*ext += 1; \ +i = (**ext << 8) | (*ext)[1]; \ +cp = (char *) *(ext) + 2; \ +*ext += (i + 2); \ +len = i + +#define STATIC_NODE_BUF_SZ 30 + +#define SET_NODE(node,node_buf,cp,len) \ +if (len >= STATIC_NODE_BUF_SZ) node = malloc(len+1); \ +else node = node_buf; \ +memcpy(node, cp, len); \ +node[len] = '\0' + +#define RESET_NODE(node,len) \ +if (len >= STATIC_NODE_BUF_SZ) free(node) + +/* + * The actual DECODE engine. + * Returns NULL in case of failure. + */ +static ETERM *erl_decode_it(unsigned char **ext) +{ + char *cp; + ETERM *ep,*tp,*np; + unsigned int u,sign; + int i,j,len,arity; + double ff; + + /* Assume we are going to decode an integer */ + ep = erl_alloc_eterm(ERL_INTEGER); + ERL_COUNT(ep) = 1; + + switch (*(*ext)++) + { + case ERL_INTEGER_EXT: + i = (int) (**ext << 24) | ((*ext)[1] << 16) | + ((*ext)[2] << 8) | (*ext)[3]; + *ext += 4; + ep->uval.ival.i = i; + return ep; + + case ERL_SMALL_INTEGER_EXT: + i = *(*ext)++; + ep->uval.ival.i = i; + return ep; + + /* NOTE: The arity below for bigs is not really the arity (= number of digits) */ + /* It is the byte count and this might cause problems in other parts... */ + case ERL_SMALL_BIG_EXT: + arity = *(*ext)++; + goto big_cont; + case ERL_LARGE_BIG_EXT: + arity = (**ext << 24) | ((*ext)[1])<< 16 | + ((*ext)[2]) << 8 |((*ext)[3]); + *ext += 4; + big_cont: + sign = *(*ext)++; + if (arity > 8) + goto big_truncate; + + if (arity == 8 && ((*ext)[7] & 0x80) && sign) { + /* MSB already occupied ! */ + goto big_truncate; + } + + if (arity == 4 && ((*ext)[3] & 0x80) && !sign) { + /* It will fit into an unsigned int !! */ + u = (((*ext)[3] << 24)|((*ext)[2])<< 16|((*ext)[1]) << 8 |(**ext)); + ERL_TYPE(ep) = ERL_U_INTEGER; + ep->uval.uival.u = u; + /* *ext += i; */ + *ext += arity; + return ep; + } else if (arity == 4 && !((*ext)[3] & 0x80)) { + /* It will fit into an int !! + * Note: It comes in "one's-complement notation" + */ + if (sign) + i = (int) (~(((*ext)[3] << 24) | ((*ext)[2])<< 16 | + ((*ext)[1]) << 8 | (**ext)) | (unsigned int) sign); + else + i = (int) (((*ext)[3] << 24) | ((*ext)[2])<< 16 | + ((*ext)[1]) << 8 | (**ext)); + ERL_TYPE(ep) = ERL_INTEGER; + ep->uval.ival.i = i; + *ext += arity; + return ep; + } else if (arity == 8 && ((*ext)[7] & 0x80) && !sign) { + /* Fits in an unsigned long long */ + int x; + unsigned long long ul = 0LL; + + for(x = 0 ; x < arity ; x++) { + ul |= ((unsigned long long)(*ext)[x]) << ((unsigned long long)(8*x)); + } + + ERL_TYPE(ep) = ERL_U_LONGLONG; + ep->uval.ullval.u = ul; + *ext += arity; + return ep; + } else { + /* Fits in a long long */ + int x; + long long l = 0LL; + + for(x = 0 ; x < arity ; x++) { + l |= ((long long)(*ext)[x]) << ((long long)(8*x)); + } + + if (sign) l = (long long) (~l | (unsigned long long) sign); + + ERL_TYPE(ep) = ERL_LONGLONG; + ep->uval.llval.i = l; + *ext += arity; + return ep; + } + big_truncate: + /* truncate to: (+/-) 1 */ +#ifdef DEBUG + erl_err_msg(" erl_decode_it: Integer truncated..."); +#endif + ERL_TYPE(ep) = ERL_INTEGER; + ep->uval.ival.i = sign?-1:1; + *ext += arity; + return ep; + + case ERL_ATOM_EXT: + ERL_TYPE(ep) = ERL_ATOM; + i = (**ext << 8) | (*ext)[1]; + cp = (char *) *(ext) + 2; + *ext += (i + 2); + ep->uval.aval.len = i; + ep->uval.aval.a = (char *) erl_malloc(i+1); + memcpy(ep->uval.aval.a, cp, i); + ep->uval.aval.a[i]='\0'; + return ep; + + case ERL_PID_EXT: + erl_free_term(ep); + { /* Why not use the constructors? */ + char *node; + char node_buf[STATIC_NODE_BUF_SZ]; + unsigned int number, serial; + unsigned char creation; + ETERM *eterm_p; + + READ_THE_NODE(ext,cp,len,i); + SET_NODE(node,node_buf,cp,len); + + /* get the integers */ +#if 0 + /* FIXME: Remove code or whatever.... + Ints on the wire are big-endian (== network byte order) + so use ntoh[sl]. (But some are little-endian! Arrrgh!) + Also, the libc authors can be expected to optimize them + heavily. However, the marshalling makes no guarantees + about alignments -- so it won't work at all. */ + number = ntohl(*((unsigned int *)*ext)++); + serial = ntohl(*((unsigned int *)*ext)++); +#else + number = ((*ext)[0] << 24) | ((*ext)[1]) << 16 | + ((*ext)[2]) << 8 | ((*ext)[3]); + *ext += 4; + serial = ((*ext)[0] << 24) | ((*ext)[1]) << 16 | + ((*ext)[2]) << 8 | ((*ext)[3]); + *ext += 4; +#endif + creation = *(*ext)++; + eterm_p = erl_mk_pid(node, number, serial, creation); + RESET_NODE(node,len); + return eterm_p; + } + case ERL_REFERENCE_EXT: + erl_free_term(ep); + { + char *node; + char node_buf[STATIC_NODE_BUF_SZ]; + unsigned int number; + unsigned char creation; + ETERM *eterm_p; + + READ_THE_NODE(ext,cp,len,i); + SET_NODE(node,node_buf,cp,len); + + /* get the integers */ +#if 0 + number = ntohl(*((unsigned int *)*ext)++); +#else + number = ((*ext)[0] << 24) | ((*ext)[1]) << 16 | + ((*ext)[2]) << 8 | ((*ext)[3]); + *ext += 4; +#endif + creation = *(*ext)++; + eterm_p = erl_mk_ref(node, number, creation); + RESET_NODE(node,len); + return eterm_p; + } + + case ERL_NEW_REFERENCE_EXT: + erl_free_term(ep); + { + char *node; + char node_buf[STATIC_NODE_BUF_SZ]; + size_t cnt, i; + unsigned int n[3]; + unsigned char creation; + ETERM *eterm_p; + +#if 0 + cnt = ntohs(*((unsigned short *)*ext)++); +#else + cnt = ((*ext)[0] << 8) | (*ext)[1]; + *ext += 2; +#endif + + READ_THE_NODE(ext,cp,len,i); + SET_NODE(node,node_buf,cp,len); + + /* get the integers */ + creation = *(*ext)++; + for(i = 0; i < cnt; i++) + { +#if 0 + n[i] = ntohl(*((unsigned int *)*ext)++); +#else + n[i] = ((*ext)[0] << 24) | ((*ext)[1]) << 16 | + ((*ext)[2]) << 8 | ((*ext)[3]); + *ext += 4; +#endif + } + eterm_p = __erl_mk_reference(node, cnt, n, creation); + RESET_NODE(node,len); + return eterm_p; + } + + case ERL_PORT_EXT: + erl_free_term(ep); + { + char *node; + char node_buf[STATIC_NODE_BUF_SZ]; + unsigned int number; + unsigned char creation; + ETERM *eterm_p; + + READ_THE_NODE(ext,cp,len,i); + SET_NODE(node,node_buf,cp,len); + + /* get the integers */ +#if 0 + number = ntohl(*((unsigned int *)*ext)++); +#else + number = ((*ext)[0] << 24) | ((*ext)[1]) << 16 | + ((*ext)[2]) << 8 | ((*ext)[3]); + *ext += 4; +#endif + creation = *(*ext)++; + eterm_p = erl_mk_port(node, number, creation); + RESET_NODE(node,len); + return eterm_p; + } + + case ERL_NIL_EXT: + ERL_TYPE(ep) = ERL_EMPTY_LIST; + return ep; + + case ERL_LIST_EXT: + ERL_TYPE(ep) = ERL_LIST; + i = (**ext << 24) | ((*ext)[1] << 16) |((*ext)[2] << 8) | (*ext)[3]; + *ext += 4; + /* ASSERT(i != 0); */ /* Should be represented by ERL_NIL_EXT. */ + tp = ep; + for (j = 0; j < i; j++) + if ((HEAD(tp) = erl_decode_it(ext)) == NULL) + goto failure; + else if (j + 1 < i) { + /* We have to watch out for how we allocates the + * last tail element since we may encounter non- + * well formed lists. + */ + np = erl_alloc_eterm(ERL_LIST); + ERL_COUNT(np) = 1; + TAIL(np) = NULL; /* in case of failure */ + TAIL(tp) = np; + tp = np; + } + if ((TAIL(tp) = erl_decode_it(ext)) == NULL) + goto failure; + return ep; + + case ERL_STRING_EXT: + { + unsigned char* s; + + ERL_TYPE(ep) = ERL_EMPTY_LIST; + i = (**ext << 8) | ((*ext)[1]); + *ext += 2; + s = *ext+i; + + while (*ext < s) { + ETERM* integer; + ETERM* cons; + + integer = erl_alloc_eterm(ERL_INTEGER); + ERL_COUNT(integer) = 1; + integer->uval.ival.i = *--s; + + cons = erl_alloc_eterm(ERL_LIST); + ERL_COUNT(cons) = 1; + HEAD(cons) = integer; + TAIL(cons) = ep; + ep = cons; + } + *ext += i; + return ep; + } + + case ERL_SMALL_TUPLE_EXT: + ERL_TYPE(ep) = ERL_TUPLE; + i = *(*ext)++; + goto decode_tuple; + + case ERL_LARGE_TUPLE_EXT: + i = (**ext << 24) | ((*ext)[1]) << 16 | + ((*ext)[2]) << 8 | ((*ext)[3]) ; + *ext += 4; + decode_tuple: + ep->uval.tval.size = i; + j = (i + 1) * sizeof(ETERM*); + ep->uval.tval.elems = (ETERM**) erl_malloc(j); + memset(ep->uval.tval.elems, 0, j); /* in case of failure below... */ + for (i=0; iuval.tval.size; i++) + if ((tp = erl_decode_it(ext)) == NULL) + goto failure; + else + ep->uval.tval.elems[i] = tp; + return ep; + + case ERL_FLOAT_EXT: + ERL_TYPE(ep) = ERL_FLOAT; + if (sscanf((char *) *ext, "%lf", &ff) != 1) + goto failure; + *ext += 31; + ep->uval.fval.f = ff; + return ep; + + case ERL_BINARY_EXT: + ERL_TYPE(ep) = ERL_BINARY; + i = (**ext << 24) | ((*ext)[1] << 16) | + ((*ext)[2] << 8) | (*ext)[3]; + *ext += 4; + ep->uval.bval.size = i; + ep->uval.bval.b = (unsigned char *) erl_malloc(i); + memcpy(ep->uval.bval.b, *ext, i); + *ext += i; + return ep; + + case ERL_FUN_EXT: /* FIXME: error checking */ + ERL_TYPE(ep) = ERL_FUNCTION; + i = get32be(*ext); + /*i = *(**ext << 24) | ((*ext)[1] << 16) | ((*ext)[2] << 8) | (*ext)[3]; + *ext += 4; */ + ERL_FUN_ARITY(ep) = -1; + ERL_CLOSURE_SIZE(ep) = i; + ERL_FUN_CREATOR(ep) = erl_decode_it(ext); + ERL_FUN_MODULE(ep) = erl_decode_it(ext); + ERL_FUN_INDEX(ep) = erl_decode_it(ext); + ERL_FUN_UNIQ(ep) = erl_decode_it(ext); + j = i * sizeof(ETERM*); + ERL_CLOSURE(ep) = (ETERM**) erl_malloc(j); + memset(ERL_CLOSURE(ep), 0, j); + for (i = 0; i < ERL_CLOSURE_SIZE(ep); i++) + ERL_CLOSURE_ELEMENT(ep,i) = erl_decode_it(ext); + return ep; + + case ERL_NEW_FUN_EXT: /* FIXME: error checking */ + ERL_TYPE(ep) = ERL_FUNCTION; + i = get32be(*ext); /* size, we don't use it here */ + ERL_FUN_ARITY(ep) = get8(*ext); + memcpy(ERL_FUN_MD5(ep), *ext, 16); + *ext += 16; + ERL_FUN_NEW_INDEX(ep) = get32be(*ext); + i = get32be(*ext); + ERL_CLOSURE_SIZE(ep) = i; + ERL_FUN_MODULE(ep) = erl_decode_it(ext); + ERL_FUN_INDEX(ep) = erl_decode_it(ext); + ERL_FUN_UNIQ(ep) = erl_decode_it(ext); + ERL_FUN_CREATOR(ep) = erl_decode_it(ext); + j = i * sizeof(ETERM*); + ERL_CLOSURE(ep) = (ETERM**) erl_malloc(j); + memset(ERL_CLOSURE(ep), 0, j); + for (i = 0; i < ERL_CLOSURE_SIZE(ep); i++) + ERL_CLOSURE_ELEMENT(ep,i) = erl_decode_it(ext); + return ep; + + } /* switch */ + + failure: + erl_free_term(ep); + return (ETERM *) NULL; + +} /* erl_decode_it */ + +/* + * DECODE a buffer of BYTES into an ETERM. + * Returns NULL in case of failure. + */ +ETERM *erl_decode(unsigned char *t) +{ + ETERM *ep; + unsigned char *ext; + + ext = t; + + /* We ignore the version magic since it might be + * possible that the buffer has been manipulated + * with erl_peek_ext. + */ + if (*ext == ERL_VERSION_MAGIC) + ext++; + + ep = NULL; + ep = erl_decode_it(&ext); +#ifdef DEBUG + if (!ep) erl_err_msg(" erl_decode: Error while decoding"); +#endif + return ep; + +} /* erl_decode */ + +/* + * This one makes it possible to DECODE two CONSECUTIVE + * ETERM's in the same buffer. + */ +ETERM *erl_decode_buf(unsigned char **ext) +{ + ETERM *ep; + + /* We ignore the version magic since it might be + * possible that the buffer has been manipulated + * with erl_peek_ext. + */ + if (**ext == ERL_VERSION_MAGIC) + (*ext)++; + + ep = NULL; + ep = erl_decode_it(ext); +#ifdef DEBUG + if (!ep) erl_err_msg(" erl_decode_buf: Error while decoding"); +#endif + return ep; + +} /* erl_decode_buf */ + + +/*============================================================== + * Ok, here comes routines for inspecting/manipulating + * an encoded buffer of bytes. + *============================================================== + */ + +/* + * Return 1 if the VERSION MAGIC in the BUFFER is the + * same as the this library version. + */ +int erl_verify_magic(unsigned char *ext) +{ + + if (*ext == ERL_VERSION_MAGIC) + return 1; + else + return 0; + +} /* erl_verify_magic */ + +/* + * Return the TYPE of an ENCODED ETERM. + * At failure, return 0. + */ +unsigned char erl_ext_type(unsigned char *ext) +{ + /* FIXME old code could skip multiple magic */ + + /* Move over magic number if any */ + if (*ext == ERL_VERSION_MAGIC) ext++; + + switch (*ext) { + case ERL_SMALL_INTEGER_EXT: + case ERL_INTEGER_EXT: + return ERL_INTEGER; + case ERL_ATOM_EXT: + return ERL_ATOM; + case ERL_PID_EXT: + return ERL_PID; + case ERL_PORT_EXT: + return ERL_PORT; + case ERL_REFERENCE_EXT: + case ERL_NEW_REFERENCE_EXT: + return ERL_REF; + case ERL_NIL_EXT: + return ERL_EMPTY_LIST; + case ERL_LIST_EXT: + return ERL_LIST; + case ERL_SMALL_TUPLE_EXT: + case ERL_LARGE_TUPLE_EXT: + return ERL_TUPLE; + case ERL_FLOAT_EXT: + return ERL_FLOAT; + case ERL_BINARY_EXT: + return ERL_BINARY; + case ERL_FUN_EXT: + case ERL_NEW_FUN_EXT: + return ERL_FUNCTION; + case ERL_SMALL_BIG_EXT: + case ERL_LARGE_BIG_EXT: + return ERL_BIG; + default: + return 0; + + } /* switch */ + +} /* erl_ext_type */ + +/* + * Returns the number of elements in compund + * terms. For other kind of terms zero is returned. + * At failure -1 is returned. + */ +int erl_ext_size(unsigned char *t) +{ + int i; + unsigned char *v; + + if (*t == ERL_VERSION_MAGIC) + return erl_ext_size(t+1); + + v = t+1; + switch(*t) { + case ERL_SMALL_INTEGER_EXT: + case ERL_INTEGER_EXT: + case ERL_ATOM_EXT: + case ERL_PID_EXT: + case ERL_PORT_EXT: + case ERL_REFERENCE_EXT: + case ERL_NEW_REFERENCE_EXT: + case ERL_NIL_EXT: + case ERL_BINARY_EXT: + case ERL_STRING_EXT: + case ERL_FLOAT_EXT: + case ERL_SMALL_BIG_EXT: + case ERL_LARGE_BIG_EXT: + return 0; + break; + case ERL_SMALL_TUPLE_EXT: + i = v[0]; + return i; + break; + case ERL_LIST_EXT: + case ERL_LARGE_TUPLE_EXT: + i = (v[0] << 24) | (v[1] << 16) | (v[2] << 8) | v[3]; + return i; + break; + case ERL_FUN_EXT: + i = (v[0] << 24) | (v[1] << 16) | (v[2] << 8) | v[3]; + return i+4; + break; + case ERL_NEW_FUN_EXT: + v += 4 + 1 + 16 + 4; + i = get32be(v); + return i + 4; + break; + default: + return -1; + break; + } /* switch */ + +} /* ext_size */ + +/* + * A nice macro that eats up the atom pointed to. + */ +#define JUMP_ATOM(ext,i) \ +if (**ext != ERL_ATOM_EXT) \ + return 0; \ +*ext += 1; \ +i = (**ext << 8) | (*ext)[1]; \ +*ext += (i + 2) + +/* + * MOVE the POINTER PAST the ENCODED ETERM we + * are currently pointing at. Returns 1 at + * success, otherwise 0. + */ +static int jump(unsigned char **ext) +{ + int j,k,i=0; + int n; + + switch (*(*ext)++) { + case ERL_VERSION_MAGIC: + return jump(ext); + case ERL_INTEGER_EXT: + *ext += 4; + break; + case ERL_SMALL_INTEGER_EXT: + *ext += 1; + break; + case ERL_ATOM_EXT: + i = (**ext << 8) | (*ext)[1]; + *ext += (i + 2); + break; + case ERL_PID_EXT: + /* eat first atom */ + JUMP_ATOM(ext,i); + *ext += 9; /* Two int's and the creation field */ + break; + case ERL_REFERENCE_EXT: + case ERL_PORT_EXT: + /* first field is an atom */ + JUMP_ATOM(ext,i); + *ext += 5; /* One int and the creation field */ + break; + case ERL_NEW_REFERENCE_EXT: + n = (**ext << 8) | (*ext)[1]; + *ext += 2; + /* first field is an atom */ + JUMP_ATOM(ext,i); + *ext += 4*n+1; + break; + case ERL_NIL_EXT: + /* We just passed it... */ + break; + case ERL_LIST_EXT: + i = j = 0; + j = (**ext << 24) | ((*ext)[1] << 16) |((*ext)[2] << 8) | (*ext)[3]; + *ext += 4; + for(k=0; k peek_ext: Out of range"); +#endif + return NULL; + } + for(i=0; i peek_ext: Bad data"); +#endif + return NULL; + } + return *ext; + default: +#ifdef DEBUG + erl_err_msg(" peek_ext: Can't peek in non list/tuple type"); +#endif + return NULL; + } /* switch */ + +} /* peek_ext */ + +/* + * Return a POINTER TO the N:TH ELEMENT in a + * COMPUND ENCODED ETERM. + */ +unsigned char *erl_peek_ext(unsigned char *ext, int jumps) +{ + unsigned char *x=ext; + + return peek_ext(&x, jumps); + +} /* erl_peek_ext */ + +/* + * Lexically compare two strings of bytes, + * (string s1 length l1 and s2 l2). + * Return: -1 if s1 < s2 + * 0 if s1 = s2 + * 1 if s1 > s2 + */ +static int cmpbytes(unsigned char* s1,int l1,unsigned char* s2,int l2) +{ + int i; + i = 0; + while((i < l1) && (i < l2)) { + if (s1[i] < s2[i]) return(-1); + if (s1[i] > s2[i]) return(1); + i++; + } + if (l1 < l2) return(-1); + if (l1 > l2) return(1); + return(0); + +} /* cmpbytes */ + +#define CMP_EXT_ERROR_CODE 4711 + +#define CMP_EXT_INT32_BE(AP, BP) \ +do { \ + if ((AP)[0] != (BP)[0]) return (AP)[0] < (BP)[0] ? -1 : 1; \ + if ((AP)[1] != (BP)[1]) return (AP)[1] < (BP)[1] ? -1 : 1; \ + if ((AP)[2] != (BP)[2]) return (AP)[2] < (BP)[2] ? -1 : 1; \ + if ((AP)[3] != (BP)[3]) return (AP)[3] < (BP)[3] ? -1 : 1; \ +} while (0) + +#define CMP_EXT_SKIP_ATOM(EP) \ +do { \ + if ((EP)[0] != ERL_ATOM_EXT) \ + return CMP_EXT_ERROR_CODE; \ + (EP) += 3 + ((EP)[1] << 8 | (EP)[2]); \ +} while (0) + +/* + * We now know that both byte arrays are of the same type. + */ +static int compare_top_ext(unsigned char**, unsigned char **); /* forward */ +static int cmp_exe2(unsigned char **e1, unsigned char **e2); + +static int cmp_refs(unsigned char **e1, unsigned char **e2) +{ + int tmp, n1, n2; + unsigned char *node1, *node2, *id1, *id2, cre1, cre2; + + if (*((*e1)++) == ERL_REFERENCE_EXT) { + node1 = *e1; + CMP_EXT_SKIP_ATOM(*e1); + n1 = 1; + id1 = *e1; + cre1 = (*e1)[4]; + *e1 += 5; + } else { + n1 = get16be(*e1); + node1 = *e1; + CMP_EXT_SKIP_ATOM(*e1); + cre1 = **e1; + id1 = (*e1) + 1 + (n1 - 1)*4; + *e1 = id1 + 4; + } + + if (*((*e2)++) == ERL_REFERENCE_EXT) { + node2 = *e2; + CMP_EXT_SKIP_ATOM(*e2); + n2 = 1; + id2 = *e2; + cre2 = (*e2)[4]; + *e2 += 5; + } else { + n2 = get16be(*e2); + node2 = *e2; + CMP_EXT_SKIP_ATOM(*e2); + cre2 = **e2; + id2 = (*e2) + 1 + (n2 - 1)*4; + *e2 = id2 + 4; + } + + /* First compare node names... */ + tmp = cmp_exe2(&node1, &node2); + if (tmp != 0) + return tmp; + + /* ... then creations ... */ + if (cre1 != cre2) + return cre1 < cre2 ? -1 : 1; + + /* ... and then finaly ids. */ + if (n1 != n2) { + unsigned char zero[] = {0, 0, 0, 0}; + if (n1 > n2) + do { + CMP_EXT_INT32_BE(id1, zero); + id1 -= 4; + n1--; + } while (n1 > n2); + else + do { + CMP_EXT_INT32_BE(zero, id2); + id2 -= 4; + n2--; + } while (n2 > n1); + } + + for (; n1 > 0; n1--, id1 -= 4, id2 -= 4) + CMP_EXT_INT32_BE(id1, id2); + + return 0; +} + +static int cmp_string_list(unsigned char **e1, unsigned char **e2) { + + /* we need to compare a string in **e1 and a list in **e2 */ + /* convert the string to list representation and convert that with e2 */ + /* we need a temporary buffer of: */ + /* 5 (list tag + length) + 2*string length + 1 (end of list tag) */ + /* for short lists we use a stack allocated buffer, otherwise we malloc */ + + unsigned char *bp; + unsigned char buf[5+2*255+1]; /* used for short lists */ + int i,e1_len; + int res; + + e1_len = ((*e1)[1] << 8) | ((*e1)[2]); + if ( e1_len < 256 ) { + bp = buf; + } else { + bp = malloc(5+(2*e1_len)+1); + } + + bp[0] = ERL_LIST_EXT; + bp[1] = bp[2] = 0; + bp[3] = (*e1)[1]; + bp[4] = (*e1)[2]; + + for(i=0;i= 256 ) free(bp); + + return res; +} + +static int cmp_exe2(unsigned char **e1, unsigned char **e2) +{ + int min, ret,i,j,k; + double ff1, ff2; + unsigned char *tmp1, *tmp2; + + if ( ((*e1)[0] == ERL_STRING_EXT) && ((*e2)[0] == ERL_LIST_EXT) ) { + return cmp_string_list(e1, e2); + } else if ( ((*e1)[0] == ERL_LIST_EXT) && ((*e2)[0] == ERL_STRING_EXT) ) { + return -cmp_string_list(e2, e1); + } + + *e2 += 1; + switch (*(*e1)++) + { + case ERL_SMALL_INTEGER_EXT: + if (**e1 < **e2) ret = -1; + else if (**e1 > **e2) ret = 1; + else ret = 0; + *e1 += 1; *e2 += 1; + return ret; + case ERL_INTEGER_EXT: + i = (int) (**e1 << 24) | ((*e1)[1] << 16) |((*e1)[2] << 8) | (*e1)[3]; + j = (int) (**e2 << 24) | ((*e2)[1] << 16) |((*e2)[2] << 8) | (*e2)[3]; + if ( i < j) + ret = -1; + else if ( i > j) + ret = 1; + else + ret = 0; + *e1 += 4; *e2 += 4; + return ret; + case ERL_ATOM_EXT: + i = (**e1 << 8) | (*e1)[1]; + j = (**e2 << 8) | (*e2)[1]; + ret = cmpbytes(*e1 +2, i, *e2 +2, j); + *e1 += (i + 2); + *e2 += (j + 2); + return ret; + case ERL_PID_EXT: { + unsigned char *n1 = *e1; + unsigned char *n2 = *e2; + CMP_EXT_SKIP_ATOM(*e1); CMP_EXT_SKIP_ATOM(*e2); + *e1 += 9; *e2 += 9; + + /* First compare serials ... */ + tmp1 = *e1 - 5; tmp2 = *e2 - 5; + CMP_EXT_INT32_BE(tmp1, tmp2); + + /* ... then ids ... */ + tmp1 -= 4; tmp2 -= 4; + CMP_EXT_INT32_BE(tmp1, tmp2); + + /* ... then node names ... */ + ret = cmp_exe2(&n1, &n2); + if (ret != 0) + return ret; + + /* ... and then finaly creations. */ + tmp1 += 8; tmp2 += 8; + if (*tmp1 != *tmp2) + return *tmp1 < *tmp2 ? -1 : 1; + return 0; + } + case ERL_PORT_EXT: + /* First compare node names ... */ + if (**e1 != ERL_ATOM_EXT || **e2 != ERL_ATOM_EXT) + return CMP_EXT_ERROR_CODE; + ret = cmp_exe2(e1, e2); + *e1 += 5; *e2 += 5; + if (ret != 0) + return ret; + /* ... then creations ... */ + tmp1 = *e1 - 1; tmp2 = *e2 - 1; + if (*tmp1 != *tmp2) + return *tmp1 < *tmp2 ? -1 : 1; + /* ... and then finaly ids. */ + tmp1 -= 4; tmp2 -= 4; + CMP_EXT_INT32_BE(tmp1, tmp2); + return 0; + case ERL_NIL_EXT: return 0; + case ERL_LIST_EXT: + i = (**e1 << 24) | ((*e1)[1] << 16) |((*e1)[2] << 8) | (*e1)[3]; + *e1 += 4; + j = (**e2 << 24) | ((*e2)[1] << 16) |((*e2)[2] << 8) | (*e2)[3]; + *e2 += 4; + if ( i == j && j == 0 ) return 0; + min = (i < j) ? i : j; + k = 0; + while (1) { + if (k++ == min) + return compare_top_ext(e1 , e2); + if ((ret = compare_top_ext(e1 , e2)) == 0) + continue; + return ret; + } + case ERL_STRING_EXT: + i = (**e1 << 8) | ((*e1)[1]); + *e1 += 2; + j = (**e2 << 8) | ((*e2)[1]); + *e2 += 2; + ret = cmpbytes(*e1, i, *e2, j); + *e1 += i; + *e2 += j; + return ret; + case ERL_SMALL_TUPLE_EXT: + i = *(*e1)++; j = *(*e2)++; + if (i < j) return -1; + if (i > j ) return 1; + while (i--) { + if ((j = compare_top_ext(e1, e2))) return j; + } + return 0; + case ERL_LARGE_TUPLE_EXT: + i = (**e1 << 24) | ((*e1)[1]) << 16| ((*e1)[2]) << 8| ((*e1)[3]) ; + *e1 += 4; + j = (**e2 << 24) | ((*e2)[1]) << 16| ((*e2)[2]) << 8| ((*e2)[3]) ; + *e2 += 4; + if (i < j) return -1; + if (i > j ) return 1; + while (i--) { + if ((j = compare_top_ext(e1, e2))) return j; + } + return 0; + case ERL_FLOAT_EXT: + if (sscanf((char *) *e1, "%lf", &ff1) != 1) + return -1; + *e1 += 31; + if (sscanf((char *) *e2, "%lf", &ff2) != 1) + return -1; + *e2 += 31; + return cmp_floats(ff1,ff2); + + case ERL_BINARY_EXT: + i = (**e1 << 24) | ((*e1)[1] << 16) |((*e1)[2] << 8) | (*e1)[3]; + *e1 += 4; + j = (**e2 << 24) | ((*e2)[1] << 16) |((*e2)[2] << 8) | (*e2)[3]; + *e2 += 4; + ret = cmpbytes(*e1, i , *e2 , j); + *e1 += i; *e2 += j; + return ret; + + case ERL_FUN_EXT: /* FIXME: */ + case ERL_NEW_FUN_EXT: /* FIXME: */ + return -1; + + default: + return cmpbytes(*e1, 1, *e2, 1); + + } /* switch */ + +} /* cmp_exe2 */ + +/* Number compare */ + +static int cmp_floats(double f1, double f2) +{ +#if defined(VXWORKS) && CPU == PPC860 + return erl_fp_compare((unsigned *) &f1, (unsigned *) &f2); +#else + if (f1f2) return 1; + else return 0; +#endif +} + +static INLINE double to_float(long l) +{ + double f; +#if defined(VXWORKS) && CPU == PPC860 + erl_long_to_fp(l, (unsigned *) &f); +#else + f = l; +#endif + return f; +} + + +static int cmp_small_big(unsigned char**e1, unsigned char **e2) +{ + int i1,i2; + int t2; + int n2; + long l1; + int res; + + erlang_big *b1,*b2; + + i1 = i2 = 0; + if ( ei_decode_long((char *)*e1,&i1,&l1) < 0 ) return -1; + + ei_get_type((char *)*e2,&i2,&t2,&n2); + + /* any small will fit in two digits */ + if ( (b1 = ei_alloc_big(2)) == NULL ) return -1; + if ( ei_small_to_big(l1,b1) < 0 ) { + ei_free_big(b1); + return -1; + } + + if ( (b2 = ei_alloc_big(n2)) == NULL ) { + ei_free_big(b1); + return 1; + } + + if ( ei_decode_big((char *)*e2,&i2,b2) < 0 ) { + ei_free_big(b1); + ei_free_big(b2); + return 1; + } + + res = ei_big_comp(b1,b2); + + ei_free_big(b1); + ei_free_big(b2); + + *e1 += i1; + *e2 += i2; + + return res; +} + +static int cmp_small_float(unsigned char**e1, unsigned char **e2) +{ + int i1,i2; + long l1; + double f1,f2; + + /* small -> float -> float_comp */ + + i1 = i2 = 0; + if ( ei_decode_long((char *)*e1,&i1,&l1) < 0 ) return -1; + if ( ei_decode_double((char *)*e2,&i2,&f2) < 0 ) return 1; + + f1 = to_float(l1); + + *e1 += i1; + *e2 += i2; + + return cmp_floats(f1,f2); +} + +static int cmp_float_big(unsigned char**e1, unsigned char **e2) +{ + int res; + int i1,i2; + int t2,n2; + double f1,f2; + erlang_big *b2; + + /* big -> float if overflow return big sign else float_comp */ + + i1 = i2 = 0; + if ( ei_decode_double((char *)*e1,&i1,&f1) < 0 ) return -1; + + if (ei_get_type((char *)*e2,&i2,&t2,&n2) < 0) return 1; + if ((b2 = ei_alloc_big(n2)) == NULL) return 1; + if (ei_decode_big((char *)*e2,&i2,b2) < 0) return 1; + + /* convert the big to float */ + if ( ei_big_to_double(b2,&f2) < 0 ) { + /* exception look at the sign */ + res = b2->is_neg ? 1 : -1; + ei_free_big(b2); + return res; + } + + ei_free_big(b2); + + *e1 += i1; + *e2 += i2; + + return cmp_floats(f1,f2); +} + +static int cmp_small_small(unsigned char**e1, unsigned char **e2) +{ + int i1,i2; + long l1,l2; + + i1 = i2 = 0; + if ( ei_decode_long((char *)*e1,&i1,&l1) < 0 ) { + fprintf(stderr,"Failed to decode 1\r\n"); + return -1; + } + if ( ei_decode_long((char *)*e2,&i2,&l2) < 0 ) { + fprintf(stderr,"Failed to decode 2\r\n"); + return 1; + } + + *e1 += i1; + *e2 += i2; + + if ( l1 < l2 ) return -1; + else if ( l1 > l2 ) return 1; + else return 0; +} + +static int cmp_float_float(unsigned char**e1, unsigned char **e2) +{ + int i1,i2; + double f1,f2; + + i1 = i2 = 0; + if ( ei_decode_double((char *)*e1,&i1,&f1) < 0 ) return -1; + if ( ei_decode_double((char *)*e2,&i2,&f2) < 0 ) return 1; + + *e1 += i1; + *e2 += i2; + + return cmp_floats(f1,f2); +} + +static int cmp_big_big(unsigned char**e1, unsigned char **e2) +{ + int res; + int i1,i2; + int t1,t2; + int n1,n2; + erlang_big *b1,*b2; + + i1 = i2 = 0; + ei_get_type((char *)*e1,&i1,&t1,&n1); + ei_get_type((char *)*e2,&i2,&t2,&n2); + + b1 = ei_alloc_big(n1); + b2 = ei_alloc_big(n2); + + ei_decode_big((char *)*e1,&i1,b1); + ei_decode_big((char *)*e2,&i2,b2); + + res = ei_big_comp(b1,b2); + + ei_free_big(b1); + ei_free_big(b2); + + *e1 += i1; + *e2 += i2; + + return res; +} + +static int cmp_number(unsigned char**e1, unsigned char **e2) +{ + switch (CMP_NUM_CODE(**e1,**e2)) { + + case SMALL_BIG: + /* fprintf(stderr,"compare small_big\r\n"); */ + return cmp_small_big(e1,e2); + + case BIG_SMALL: + /* fprintf(stderr,"compare sbig_small\r\n"); */ + return -cmp_small_big(e2,e1); + + case SMALL_FLOAT: + /* fprintf(stderr,"compare small_float\r\n"); */ + return cmp_small_float(e1,e2); + + case FLOAT_SMALL: + /* fprintf(stderr,"compare float_small\r\n"); */ + return -cmp_small_float(e2,e1); + + case FLOAT_BIG: + /* fprintf(stderr,"compare float_big\r\n"); */ + return cmp_float_big(e1,e2); + + case BIG_FLOAT: + /* fprintf(stderr,"compare big_float\r\n"); */ + return -cmp_float_big(e2,e1); + + case SMALL_SMALL: + /* fprintf(stderr,"compare small_small\r\n"); */ + return cmp_small_small(e1,e2); + + case FLOAT_FLOAT: + /* fprintf(stderr,"compare float_float\r\n"); */ + return cmp_float_float(e1,e2); + + case BIG_BIG: + /* fprintf(stderr,"compare big_big\r\n"); */ + return cmp_big_big(e1,e2); + + default: + /* should never get here ... */ + /* fprintf(stderr,"compare standard\r\n"); */ + return cmp_exe2(e1,e2); + } + +} + +/* + * If the arrays are of the same type, then we + * have to do a real compare. + */ +/* + * COMPARE TWO encoded BYTE ARRAYS e1 and e2. + * Return: -1 if e1 < e2 + * 0 if e1 == e2 + * 1 if e2 > e1 + */ +static int compare_top_ext(unsigned char**e1, unsigned char **e2) +{ + if (**e1 == ERL_VERSION_MAGIC) (*e1)++; + if (**e2 == ERL_VERSION_MAGIC) (*e2)++; + + if (cmp_array[**e1] < cmp_array[**e2]) return -1; + if (cmp_array[**e1] > cmp_array[**e2]) return 1; + + if (IS_ERL_NUM(**e1)) + return cmp_number(e1,e2); + + if (cmp_array[**e1] == ERL_REF_CMP) + return cmp_refs(e1, e2); + + return cmp_exe2(e1, e2); +} + +int erl_compare_ext(unsigned char *e1, unsigned char *e2) +{ + return compare_top_ext(&e1, &e2); +} /* erl_compare_ext */ + +#if defined(VXWORKS) && CPU == PPC860 +/* FIXME we have no floating point but don't we have emulation?! */ +int erl_fp_compare(unsigned *a, unsigned *b) +{ + /* Big endian mode of powerPC, IEEE floating point. */ + unsigned a_split[4] = {a[0] >> 31, /* Sign bit */ + (a[0] >> 20) & 0x7FFU, /* Exponent */ + a[0] & 0xFFFFFU, /* Mantissa MS bits */ + a[1]}; /* Mantissa LS bits */ + unsigned b_split[4] = {b[0] >> 31, + (b[0] >> 20) & 0x7FFU, + b[0] & 0xFFFFFU, + b[1]}; + int a_is_infinite, b_is_infinite; + int res; + + + /* Make -0 be +0 */ + if (a_split[1] == 0 && a_split[2] == 0 && a_split[3] == 0) + a_split[0] = 0; + if (b_split[1] == 0 && b_split[2] == 0 && b_split[3] == 0) + b_split[0] = 0; + /* Check for infinity */ + a_is_infinite = (a_split[1] == 0x7FFU && a_split[2] == 0 && + a_split[3] == 0); + b_is_infinite = (b_split[1] == 0x7FFU && b_split[2] == 0 && + b_split[3] == 0); + + if (a_is_infinite && !b_is_infinite) + return (a_split[0]) ? -1 : 1; + if (b_is_infinite && !a_is_infinite) + return (b_split[0]) ? 1 : -1; + if (a_is_infinite && b_is_infinite) + return b[0] - a[0]; + /* Check for indeterminate or nan, infinite is already handled, + so we only check the exponent. */ + if((a_split[1] == 0x7FFU) || (b_split[1] == 0x7FFU)) + return INT_MAX; /* Well, they are not equal anyway, + abort() could be an alternative... */ + + if (a_split[0] && !b_split[0]) + return -1; + if (b_split[0] && !a_split[0]) + return 1; + /* Compare */ + res = memcmp(a_split + 1, b_split + 1, 3 * sizeof(unsigned)); + /* Make -1, 0 or 1 */ + res = (!!res) * ((res < 0) ? -1 : 1); + /* Turn sign if negative values */ + if (a_split[0]) /* Both are negative */ + res = -1 * res; + return res; +} + +static void join(unsigned d_split[4], unsigned *d) +{ + d[0] = (d_split[0] << 31) | /* Sign bit */ + ((d_split[1] & 0x7FFU) << 20) | /* Exponent */ + (d_split[2] & 0xFFFFFU); /* Mantissa MS bits */ + d[1] = d_split[3]; /* Mantissa LS bits */ +} + +static int blength(unsigned long l) +{ + int i; + for(i = 0; l; ++i) + l >>= 1; + return i; +} + +static void erl_long_to_fp(long l, unsigned *d) +{ + unsigned d_split[4]; + unsigned x; + if (l < 0) { + d_split[0] = 1; + x = -l; + } else { + d_split[0] = 0; + x = l; + } + + if (!l) { + memset(d_split,0,sizeof(d_split)); + } else { + int len = blength(x); + x <<= (33 - len); + d_split[2] = (x >> 12); + d_split[3] = (x << 20); + d_split[1] = 1023 + len - 1; + } + join(d_split,d); +} + +#endif + + +/* + * Checks if a term is a "string": a flat list of byte-sized integers. + * + * Returns: 0 if the term is not a string, otherwise the length is returned. + */ + +static int is_string(ETERM* term) +{ + int len = 0; + + while (ERL_TYPE(term) == ERL_LIST) { + ETERM* head = HEAD(term); + + if (!ERL_IS_INTEGER(head) || ((unsigned)head->uval.ival.i) > 255) { + return 0; + } + len++; + term = TAIL(term); + } + + if (ERL_IS_EMPTY_LIST(term)) { + return len; + } + return 0; +} diff --git a/lib/erl_interface/src/legacy/erl_marshal.h b/lib/erl_interface/src/legacy/erl_marshal.h new file mode 100644 index 0000000000..8b3c3b6fa1 --- /dev/null +++ b/lib/erl_interface/src/legacy/erl_marshal.h @@ -0,0 +1,29 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1996-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifndef _ERL_MARSHALL_H +#define _ERL_MARSHALL_H + +#include "erl_eterm.h" /* FIXME don't want to include this here */ + +/* FIXME: not documented, may be internal */ +int erl_verify_magic(unsigned char*); +void erl_init_marshal(void); +int erl_encode_it(ETERM *ep, unsigned char **ext, int dist); + +#endif /* _ERL_MARSHALL_H */ diff --git a/lib/erl_interface/src/legacy/erl_resolve.c b/lib/erl_interface/src/legacy/erl_resolve.c new file mode 100644 index 0000000000..7dfebb78ed --- /dev/null +++ b/lib/erl_interface/src/legacy/erl_resolve.c @@ -0,0 +1,106 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2003-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +/*************************************************************************** + * + * Compatibility with the old erl_interface library that had some + * undocumented functions. + * + ***************************************************************************/ + +#include "eidef.h" + +#include "erl_interface.h" +#include "ei_resolve.h" +#include "ei_connect_int.h" +#include "ei_epmd.h" + +struct hostent *erl_gethostbyname(const char *name) +{ + return ei_gethostbyname(name); +} + + +void erl_init_resolve(void) +{ + ei_init_resolve(); +} + + +struct hostent *erl_gethostbyaddr(const char *addr, int len, int type) +{ + return ei_gethostbyaddr(addr, len, type); +} + + +struct hostent *erl_gethostbyname_r(const char *name, + struct hostent *hostp, + char *buffer, + int buflen, + int *h_errnop) +{ + return ei_gethostbyname_r(name,hostp,buffer,buflen,h_errnop); +} + + +struct hostent *erl_gethostbyaddr_r(const char *addr, + int length, + int type, + struct hostent *hostp, + char *buffer, + int buflen, + int *h_errnop) +{ + return ei_gethostbyaddr_r(addr,length,type,hostp,buffer,buflen,h_errnop); +} + + +int erl_distversion(int fd) +{ + return ei_distversion(fd); +} + +int erl_epmd_connect(struct in_addr *inaddr) +{ + return ei_epmd_connect_tmo(inaddr,0); +} + +int erl_epmd_port(struct in_addr *inaddr, const char *alive, int *dist) +{ + return ei_epmd_port(inaddr, alive, dist); +} + + + +/* FIXME !!!!! +erl_epmd_port ei_epmd_port +erl_mutex_lock ei_mutex_lock +erl_malloc erl_free ???? +erl_publish erl_unpublish +< extern int erl_epmd_connect(struct in_addr *inaddr); +< extern int erl_epmd_publish(int port, const char *alive); +< extern int erl_epmd_port(struct in_addr *inaddr, const char *alive, int *dist); + +< int erl_unpublish(const char *alive) +--- +> int ei_unpublish_alive(const char *alive) + +erl_self +erl_getfdcookie +*/ diff --git a/lib/erl_interface/src/legacy/erl_timeout.c b/lib/erl_interface/src/legacy/erl_timeout.c new file mode 100644 index 0000000000..af1a4a1f3a --- /dev/null +++ b/lib/erl_interface/src/legacy/erl_timeout.c @@ -0,0 +1,161 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1997-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* timeout.c + * + * todo: use posix timers (timer_create etc) instead of setitimer. + * + */ +#if !defined(__WIN32__) && !defined(VXWORKS) + +/* FIXME: well, at least I can compile now... */ + +#include "eidef.h" + +#include +#include +#include +#include + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#include "erl_timeout.h" + +typedef struct jmp_s { + jmp_buf jmpbuf; + struct itimerval timerinfo; + void *siginfo; + struct jmp_s *next; +} *jmp_t; + +static jmp_t push(jmp_t j); +static jmp_t pop(void); +static void timeout_handler(int dummy); + +jmp_buf *timeout_setup(int ms) +{ + struct itimerval t; + jmp_t j; + void *s; + +#ifdef DEBUG + fprintf(stderr,"timeout setup\n"); +#endif + s=signal(SIGALRM,timeout_handler); + + /* set the timer */ + t.it_interval.tv_sec = 0; + t.it_interval.tv_usec = 0; + t.it_value.tv_sec = ms / 1000; + t.it_value.tv_usec = (ms % 1000) * 1000; + + /* get a jump buffer and save it */ + j = malloc(sizeof(*j)); /* FIXME check result */ + j->siginfo = s; + push(j); + + setitimer(ITIMER_REAL,&t,&(j->timerinfo)); + + return &(j->jmpbuf); +} + + +int timeout_cancel(void) +{ + jmp_t j; + +#ifdef DEBUG + fprintf(stderr,"timeout cancel\n"); +#endif + /* retrieve the jump buffer */ + j=pop(); + /* restore the timer and signal disposition */ + setitimer(ITIMER_REAL,&(j->timerinfo),NULL); + signal(SIGALRM,j->siginfo); + + free(j); + + return 0; +} + +void timeout_handler(int dummy) +{ + jmp_t j; + +#ifdef DEBUG + fprintf(stderr,"timeout handler\n"); +#endif + + /* retrieve the jump buffer */ + j=pop(); + + /* restore the timer and signal disposition */ + setitimer(ITIMER_REAL,&(j->timerinfo),NULL); + signal(SIGALRM,j->siginfo); + + free(j); + longjmp(j->jmpbuf,JMPVAL); + return; /* not reached */ +} + + +/* a simple stack for saving the jump buffer allows us to pass a + * variable between functions that don't call each other, in a way + * that will survive the longjmp(). + */ + +/* FIXME problem for threaded ? */ +static jmp_t jmp_head=NULL; +#ifdef DEBUG +static int depth = 0; +static int maxdepth = 0; +#endif + +static jmp_t push(jmp_t j) +{ + j->next = jmp_head; + jmp_head = j; + +#ifdef DEBUG + depth++; + if (depth > maxdepth) maxdepth = depth; +#endif + + return j; +} + +static jmp_t pop(void) +{ + jmp_t j = jmp_head; + if (j) jmp_head = j->next; +#ifdef DEBUG + depth--; +#endif + return j; +} + +#endif /* platform */ diff --git a/lib/erl_interface/src/legacy/erl_timeout.h b/lib/erl_interface/src/legacy/erl_timeout.h new file mode 100644 index 0000000000..4ef6d21a72 --- /dev/null +++ b/lib/erl_interface/src/legacy/erl_timeout.h @@ -0,0 +1,74 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1997-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifndef _ERL_TIMEOUT_H +#define _ERL_TIMEOUT_H + +#if !defined (__WIN32__) && !defined (VXWORKS) + +#include + +/* + use timeout like this (delay in ms): + + if (timeout(delay,fun(a,b,c))) { + printf("timeout occurred\n"); + } + else { + ... + } + +If the call to fun() has not returned before 'delay' ms, it will be +interrupted and and timeout() will return a non-zero value. + +If fun() finishes before 'delay' ms, then timeout will return 0. + +If you need the return value from fun then assign it like this: + + if (timeout(delay,(x = fun(...)))) { + } + +These functions work by setting and catching SIGALRM, and although it +saves and restores the signal handler, it may not work in situations +where you are already using SIGALRM (this includes calls to sleep(3)). + +Note that although recursive calls to timeout will not fail, they may +not give the expected results. All invocations of timeout use the same +timer, which is set on entrance to timeout and restored on exit from +timeout. So although an inner call to timeout will restart the timer +for any pending outer call when it exits, any time that has already +elapsed against the outer timeout is forgotten. In addition, the alarm +signal will always go to the innermost (last called) timeout, which +may or may not be the intention in recursive cases. + +*/ + +#define JMPVAL 997 /* magic */ + +#define timeout(ms,funcall) \ + (setjmp(*timeout_setup(ms)) == JMPVAL ? -1: \ + ((void)(funcall), timeout_cancel())) + + +/* don't call any of these directly - use the macro! see above! */ +jmp_buf *timeout_setup(int ms); +int timeout_cancel(void); + +#endif /* WIN32 && VXWORKS */ + +#endif /* _ERL_TIMEOUT_H */ diff --git a/lib/erl_interface/src/legacy/global_names.c b/lib/erl_interface/src/legacy/global_names.c new file mode 100644 index 0000000000..7333d94931 --- /dev/null +++ b/lib/erl_interface/src/legacy/global_names.c @@ -0,0 +1,109 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include +#include +#include "eidef.h" +#include "eiext.h" +#include "eisend.h" +#include "eirecv.h" +#include "ei_connect_int.h" +#include "erl_interface.h" +#include "erl_connect.h" + +#define GLOBALNAMEBUF (16*1024) /* not very small actually */ + +/* return a list of all registered names. Function allocates and + * returns a NULL-terminated array of pointers to strings. The caller + * is responsible for freeing the array. Space for the array and + * all strings is allocated with a single call to malloc, so the + * caller can make one call to free(). + */ +/* global:registered_names() -> [name1,name2,...] */ +char **erl_global_names(int fd, int *count) +{ + char buf[GLOBALNAMEBUF]; + char *bufp=buf; + char tmpbuf[64]; + int size = 0; + int index = 0; + erlang_pid *self = erl_self(); + erlang_msg msg; + int i; + int version; + int arity; + int msglen; + char **names; + char *s; + + self->num = fd; + ei_encode_version(buf,&index); + ei_encode_tuple_header(buf,&index,2); + ei_encode_pid(buf,&index,self); /* PidFrom */ + ei_encode_tuple_header(buf,&index,5); + ei_encode_atom(buf,&index,"call"); /* call */ + ei_encode_atom(buf,&index,"global"); /* Mod */ + ei_encode_atom(buf,&index,"registered_names"); /* Fun */ + ei_encode_list_header(buf,&index,0); /* Args: [ ] */ + ei_encode_atom(buf,&index,"user"); /* user */ + + /* make the rpc call */ + if (ei_send_reg_encoded(fd,self,"rex",buf,index)) return NULL; + + while (1) { + index = GLOBALNAMEBUF; + if (!(i = ei_recv_internal(fd,&bufp,&index,&msg,&msglen,1,0))) continue; + else break; + } + + if (i != ERL_SEND) return NULL; + + /* expecting { rex, [name1, name2, ...] } */ + size = msglen; + index = 0; + + if (ei_decode_version(buf,&index,&version) + || ei_decode_tuple_header(buf,&index,&arity) + || (arity != 2) + || ei_decode_atom(buf,&index,tmpbuf) + || strcmp(tmpbuf,"rex") + || ei_decode_list_header(buf,&index,&arity)) return NULL; + + + /* we use the size of the rest of the received message to estimate + * the buffer space required for all the strings. we know how many + * they are (arity) so we need space for that many pointers, plus + * a little less than the atoms themselves needed in the reply. + */ + arity++; /* we will need a terminating NULL as well */ + if (!(names = malloc((arity * sizeof(char**)) + (size-index)))) return NULL; + + /* arity pointers first, followed by s */ + s = (char *)(names+arity+1); + + if (count) *count = 0; + for (i=0; i +#include "eidef.h" +#include "eiext.h" +#include "eisend.h" +#include "eirecv.h" +#include "erl_interface.h" + +int erl_global_register(int fd, const char *name, ETERM *pid) +{ + char buf[EISMALLBUF]; + char *bufp=buf; + char tmpbuf[64]; + int index = 0; + erlang_pid self; + erlang_msg msg; + int needlink, needatom; + int arity; + int version; + int msglen; + int i; + + /* get that pid into a better format */ + if (!erl_encode(pid,(unsigned char*)buf)) return -1; + if (ei_decode_version(buf,&index,&version) + || ei_decode_pid(buf,&index,&self)) return -1; + + /* set up rpc arguments */ + /* { PidFrom, { call, Mod, Fun, Args, user }} */ + index = 0; + ei_encode_version(buf,&index); + ei_encode_tuple_header(buf,&index,2); + ei_encode_pid(buf,&index,&self); /* PidFrom */ + ei_encode_tuple_header(buf,&index,5); + ei_encode_atom(buf,&index,"call"); /* call */ + ei_encode_atom(buf,&index,"global"); /* Mod */ + ei_encode_atom(buf,&index,"register_name_external"); /* Fun */ + ei_encode_list_header(buf,&index,3); /* Args: [ name, self(), cnode ] */ + ei_encode_atom(buf,&index,name); + ei_encode_pid(buf,&index,&self); + ei_encode_tuple_header(buf,&index,2); + ei_encode_atom(buf,&index,"global"); /* special "resolve" treatment */ + ei_encode_atom(buf,&index,"cnode"); /* i.e. we get a SEND when conflict */ + ei_encode_empty_list(buf,&index); + ei_encode_atom(buf,&index,"user"); /* user */ + + /* make the rpc call */ + if (ei_send_reg_encoded(fd,&self,"rex",buf,index)) return -1; + + /* get the reply: expect link and an atom, or just an atom */ + needlink = needatom = 1; + while (1) { + /* get message */ + while (1) { + index = EISMALLBUF; + if (!(i = ei_recv_internal(fd,&bufp,&index,&msg,&msglen,1,0))) continue; + else break; + } + + switch (i) { + case ERL_LINK: + /* got link */ + if (!needlink) return -1; + needlink = 0; + break; + + case ERL_SEND: + /* got message - does it contain our atom? */ + if (!needatom) return -1; + else { + /* expecting { rex, yes } */ + index = 0; + if (ei_decode_version(buf,&index,&version) + || ei_decode_tuple_header(buf,&index,&arity) + || (arity != 2) + || ei_decode_atom(buf,&index,tmpbuf) + || strcmp(tmpbuf,"rex") + || ei_decode_atom(buf,&index,tmpbuf) + || strcmp(tmpbuf,"yes")) + return -1; /* bad response from other side */ + + /* we're done */ + return 0; + } + break; + + default: + return -1; /* something else */ + } + } + return 0; +} + diff --git a/lib/erl_interface/src/legacy/global_unregister.c b/lib/erl_interface/src/legacy/global_unregister.c new file mode 100644 index 0000000000..514dbc3c68 --- /dev/null +++ b/lib/erl_interface/src/legacy/global_unregister.c @@ -0,0 +1,102 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include +#include "eidef.h" /* Has to be first */ +#include "eiext.h" +#include "eisend.h" +#include "eirecv.h" +#include "ei_connect_int.h" +#include "erl_interface.h" +#include "erl_connect.h" + +/* remove the association between name and its pid */ +/* global:unregister_name(name) -> ok */ +int erl_global_unregister(int fd, const char *name) +{ + char buf[EISMALLBUF]; + char *bufp=buf; + char tmpbuf[64]; + int index = 0; + erlang_pid *self = erl_self(); + erlang_msg msg; + int i; + int version,arity,msglen; + int needunlink, needatom; + + /* make a self pid */ + self->num = fd; + ei_encode_version(buf,&index); + ei_encode_tuple_header(buf,&index,2); + ei_encode_pid(buf,&index,self); /* PidFrom */ + ei_encode_tuple_header(buf,&index,5); + ei_encode_atom(buf,&index,"call"); /* call */ + ei_encode_atom(buf,&index,"global"); /* Mod */ + ei_encode_atom(buf,&index,"unregister_name_external"); /* Fun */ + ei_encode_list_header(buf,&index,1); /* Args: [ name ] */ + ei_encode_atom(buf,&index,name); + ei_encode_empty_list(buf,&index); + ei_encode_atom(buf,&index,"user"); /* user */ + + /* make the rpc call */ + if (ei_send_reg_encoded(fd,self,"rex",buf,index)) return -1; + + /* get the reply: expect unlink and an atom, or just an atom */ + needunlink = needatom = 1; + while (1) { + /* get message */ + while (1) { + index = EISMALLBUF; + if (!(i = ei_recv_internal(fd,&bufp,&index,&msg,&msglen,1,0))) continue; + else break; + } + + switch (i) { + case ERL_UNLINK: + /* got link */ + if (!needunlink) return -1; + needunlink = 0; + break; + + case ERL_SEND: + /* got message - does it contain our atom? */ + if (!needatom) return -1; + else { + /* expecting { rex, ok } */ + index = 0; + if (ei_decode_version(buf,&index,&version) + || ei_decode_tuple_header(buf,&index,&arity) + || (arity != 2) + || ei_decode_atom(buf,&index,tmpbuf) + || strcmp(tmpbuf,"rex") + || ei_decode_atom(buf,&index,tmpbuf) + || strcmp(tmpbuf,"ok")) + return -1; /* bad response from other side */ + + /* we're done here */ + return 0; + } + break; + + default: + return -1; + } + } + + return 0; +} diff --git a/lib/erl_interface/src/legacy/global_whereis.c b/lib/erl_interface/src/legacy/global_whereis.c new file mode 100644 index 0000000000..2afb193504 --- /dev/null +++ b/lib/erl_interface/src/legacy/global_whereis.c @@ -0,0 +1,91 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#include +#include +#include "eidef.h" +#include "eiext.h" +#include "eisend.h" +#include "eirecv.h" +#include "ei_connect_int.h" +#include "erl_interface.h" +#include "erl_connect.h" + +/* return the ETERM pid corresponding to name. If caller + * provides non-NULL node, nodename will be returned there + */ +/* global:whereis_name(name) -> pid */ + +ETERM *erl_global_whereis(int fd, const char *name, char *node) +{ + char buf[EISMALLBUF]; + char *bufp=buf; + char tmpbuf[64]; + int index = 0; + erlang_pid *self = erl_self(); + erlang_pid epid; + ETERM *opid; + erlang_msg msg; + int i; + int version,arity,msglen; + + self->num = fd; /* FIXME looks strange to change something?! */ + + ei_encode_version(buf,&index); + ei_encode_tuple_header(buf,&index,2); + ei_encode_pid(buf,&index,self); /* PidFrom */ + ei_encode_tuple_header(buf,&index,5); + ei_encode_atom(buf,&index,"call"); /* call */ + ei_encode_atom(buf,&index,"global"); /* Mod */ + ei_encode_atom(buf,&index,"whereis_name"); /* Fun */ + ei_encode_list_header(buf,&index,1); /* Args: [ name ] */ + ei_encode_atom(buf,&index,name); + ei_encode_empty_list(buf,&index); + ei_encode_atom(buf,&index,"user"); /* user */ + + /* make the rpc call */ + if (ei_send_reg_encoded(fd,self,"rex",buf,index)) return NULL; + + while (1) { + index = EISMALLBUF; + if (!(i = ei_recv_internal(fd,&bufp,&index,&msg,&msglen,1,0))) continue; + else break; + } + + if (i != ERL_SEND) return NULL; + + /* expecting { rex, pid } */ + index = 0; + if (ei_decode_version(buf,&index,&version) + || ei_decode_tuple_header(buf,&index,&arity) + || (arity != 2) + || ei_decode_atom(buf,&index,tmpbuf) + || strcmp(tmpbuf,"rex") + || ei_decode_pid(buf,&index,&epid)) + return NULL; /* bad response from other side */ + + /* put the pid into a format for the caller */ + index = 0; + ei_encode_pid(buf,&index,&epid); + opid = erl_decode((unsigned char*)buf); + + /* extract the nodename for the caller */ + if (node) strcpy(node,epid.node); + + return opid; +} diff --git a/lib/erl_interface/src/legacy/portability.h b/lib/erl_interface/src/legacy/portability.h new file mode 100644 index 0000000000..5f984b08e1 --- /dev/null +++ b/lib/erl_interface/src/legacy/portability.h @@ -0,0 +1,33 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2000-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +#ifndef _PORTABILITY_H +#define _PORTABILITY_H + +#if !defined(__GNUC__) || __GNUC__ < 2 + +/* + * GCC's attributes are too useful to not use. Other compilers + * just lose opportunities to optimize and warn. + */ +# define __attribute__(foo) /* nothing */ + +#endif + +#endif /* _PORTABILITY_H */ diff --git a/lib/erl_interface/src/misc/ei_compat.c b/lib/erl_interface/src/misc/ei_compat.c new file mode 100644 index 0000000000..45ea6e3a72 --- /dev/null +++ b/lib/erl_interface/src/misc/ei_compat.c @@ -0,0 +1,39 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2004-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include "ei.h" +#include "ei_internal.h" + +#define EI_COMPAT_NO_REL (~((unsigned) 0)) + +static unsigned compat_rel = EI_COMPAT_NO_REL; + +void +ei_set_compat_rel(unsigned rel) +{ + if (compat_rel == EI_COMPAT_NO_REL) + compat_rel = rel; +} + +int +ei_internal_use_r9_pids_ports(void) +{ + return compat_rel < 10; +} diff --git a/lib/erl_interface/src/misc/ei_decode_term.c b/lib/erl_interface/src/misc/ei_decode_term.c new file mode 100644 index 0000000000..7b95ff232f --- /dev/null +++ b/lib/erl_interface/src/misc/ei_decode_term.c @@ -0,0 +1,156 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include + +#include "eidef.h" +#include "eiext.h" +#include "ei_decode_term.h" +#include "putget.h" + +/* Returns 1 if term is decoded, 0 if term is OK, but not decoded here + and -1 if something is wrong. + ONLY changes index if term is decoded (return value 1)! */ + +int ei_decode_ei_term(const char* buf, int* index, ei_term* term) +{ + const char* s = buf + *index, * s0 = s; + int len, i, n, sign; + char c; + double f; + + if (term == NULL) return -1; + c = term->ei_type = get8(s); + switch (c) { + case ERL_SMALL_INTEGER_EXT: + term->value.i_val = get8(s); + break; + case ERL_INTEGER_EXT: + term->value.i_val = get32be(s); + break; + case ERL_FLOAT_EXT: + if (s[30]) return -1; + if (sscanf(s, "%lf", &f) != 1) return -1; + s += 31; + term->value.d_val = f; + break; + case ERL_ATOM_EXT: + len = get16be(s); + memcpy(term->value.atom_name, s, len); + term->value.atom_name[len] = '\0'; + s += len; + break; + case ERL_REFERENCE_EXT: + /* first the nodename */ + if (get8(s) != ERL_ATOM_EXT) return -1; + len = get16be(s); + memcpy(term->value.ref.node, s, len); + term->value.ref.node[len] = '\0'; + s += len; + /* now the numbers: num (4), creation (1) */ + term->value.ref.n[0] = get32be(s); + term->value.ref.len = 1; + term->value.ref.creation = get8(s) & 0x03; + break; + case ERL_NEW_REFERENCE_EXT: + /* first the integer count */ + term->value.ref.len = get16be(s); + /* then the nodename */ + if (get8(s) != ERL_ATOM_EXT) return -1; + len = get16be(s); + memcpy(term->value.ref.node, s, len); + term->value.ref.node[len] = '\0'; + s += len; + /* creation */ + term->value.ref.creation = get8(s) & 0x03; + /* finally the id integers */ + for (i = 0; (ivalue.ref.len) && (i<3); i++) { + term->value.ref.n[i] = get32be(s); + } + if (term->value.ref.len > 3) { + s += 4 * (term->value.ref.len - 3); + } + break; + case ERL_PORT_EXT: + if (get8(s) != ERL_ATOM_EXT) return -1; + len = get16be(s); + memcpy(term->value.port.node, s, len); + term->value.port.node[len] = '\0'; + term->value.port.id = get32be(s) & 0x0fffffff; /* 28 bits */; + term->value.port.creation = get8(s) & 0x03; + break; + case ERL_PID_EXT: + if (get8(s) != ERL_ATOM_EXT) return -1; + /* name first */ + len = get16be(s); + memcpy(term->value.pid.node, s, len); + term->value.pid.node[len] = '\0'; + s += len; + /* now the numbers: num (4), serial (4), creation (1) */ + term->value.pid.num = get32be(s) & 0x7fff; /* 15 bits */ + term->value.pid.serial = get32be(s) & 0x1fff; /* 13 bits */ + term->value.pid.creation = get8(s) & 0x03; /* 2 bits */ + break; + case ERL_SMALL_TUPLE_EXT: + term->arity = get8(s); + break; /*return 0;*/ + case ERL_LARGE_TUPLE_EXT: + term->arity = get32be(s); + break; /*return 0;*/ + case ERL_NIL_EXT: + term->arity = 0; + break; + case ERL_STRING_EXT: + term->size = get16be(s); + return 0; + case ERL_LIST_EXT: + term->arity = get32be(s); + break; /*return 0;*/ + case ERL_BINARY_EXT: + term->size = get32be(s); + return 0; + case ERL_SMALL_BIG_EXT: + if ((term->arity = get8(s)) != 4) return -1; + sign = get8(s); + /* Little Endian, and n always positive, except for LONG_MIN */ + n = get32le(s); + if (sign) { + /* check for overflow */ + if ((n - 1) < 0) return -1; + n = -n; + } else { + /* check for overflow */ + if (n < 0) return -1; + } + break; + case ERL_LARGE_BIG_EXT: + return 0; + case ERL_PASS_THROUGH: + return 0; + case ERL_NEW_CACHE: + return -1; + case ERL_CACHED_ATOM: + return -1; + default: + return -1; + } + *index += s-s0; + return 1; +} diff --git a/lib/erl_interface/src/misc/ei_decode_term.h b/lib/erl_interface/src/misc/ei_decode_term.h new file mode 100644 index 0000000000..76a71ae0a6 --- /dev/null +++ b/lib/erl_interface/src/misc/ei_decode_term.h @@ -0,0 +1,31 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ + +#ifndef _EI_DECODE_TERM_H +#define _EI_DECODE_TERM_H + +/* Returns 1 if term is decoded, 0 if term is OK, but not decoded here + and -1 if something is wrong. + ONLY changes index if term is decoded (return value 1)! */ + +int ei_decode_ei_term(const char* buf, int* index, ei_term* term); + +#endif /* _EI_DECODE_TERM_H */ diff --git a/lib/erl_interface/src/misc/ei_format.c b/lib/erl_interface/src/misc/ei_format.c new file mode 100644 index 0000000000..08235d0ebe --- /dev/null +++ b/lib/erl_interface/src/misc/ei_format.c @@ -0,0 +1,466 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +/* + * Function: + * ei_format to build binary format terms a bit like printf + */ + +#ifdef VXWORKS +#include +#endif + +#include +#include +#include +#include +#include + +#ifdef VRTX +#define __READY_EXTENSIONS__ +#include +#endif + +#include "eidef.h" +#include "ei_malloc.h" +#include "ei_format.h" + +/* + * To avoid problems we read the variable number of arguments to an + * array of unions. + */ +union arg { + char* s; + long l; + unsigned long u; + double d; +}; + +static int eiformat(const char** s, union arg** args, ei_x_buff* x); + +/* forwards of parse functions */ +static int pformat(const char** fmt, union arg**, ei_x_buff* x); +static int plist(const char** fmt, union arg**, ei_x_buff* x, int size); +static int ptuple(const char** fmt, union arg**, ei_x_buff* x, int size); +static int pquotedatom(const char** fmt, ei_x_buff* x); +static int pdigit(const char** fmt, ei_x_buff* x); +static int patom(const char** fmt, ei_x_buff* x); +static int pstring(const char** fmt, ei_x_buff* x); + +/* format a string into an ei_x_buff, except the version token */ +static int eiformat(const char** fmt, union arg** args, ei_x_buff* x) +{ + const char* p = *fmt; + int res; + ei_x_buff x2; + + while (isspace((int)*p)) + ++p; + switch (*p) { + case '~': + res = pformat(&p, args, x); + break; + case '[': + res = ei_x_new(&x2); + if (res >= 0) + res = plist(&p, args, &x2, 0); + if (res > 0) + res = ei_x_encode_list_header(x, res); + if (res >= 0) + res = ei_x_append(x, &x2); + ei_x_free(&x2); + break; + case '{': + res = ei_x_new(&x2); + if (res >= 0) + res = ptuple(&p, args, &x2, 0); + if (res >= 0) + res = ei_x_encode_tuple_header(x, res); + if (res >= 0) + res = ei_x_append(x, &x2); + ei_x_free(&x2); + break; + case '"': + res = pstring(&p, x); + break; + case '\'': + res = pquotedatom(&p, x); + break; + default: + if (isdigit((int)*p)) + res = pdigit(&p, x); + else if (islower((int)*p)) + res = patom(&p, x); + else + res = -1; + break; + /* + Variables + */ + } + *fmt = p; + return res; +} + +static int patom(const char** fmt, ei_x_buff* x) +{ + const char* start = *fmt; + char c; + int len; + + for (;;) { + c = *(*fmt)++; + if (isalnum((int) c) || (c == '_') || (c == '@')) + continue; + else + break; + } + --(*fmt); + len = *fmt - start; + /* FIXME why truncate atom name and not fail?! */ + if (len > MAXATOMLEN) + len = MAXATOMLEN; + return ei_x_encode_atom_len(x, start, len); +} + +/* Check if integer or float */ +static int pdigit(const char** fmt, ei_x_buff* x) +{ + const char* start = *fmt; + char c; + int len, dotp=0; + double d; + long l; + + for (;;) { + c = *(*fmt)++; + if (isdigit((int)c)) + continue; + else if (!dotp && (c == '.')) { + dotp = 1; + continue; + } else + break; + } + --(*fmt); + len = *fmt - start; + if (dotp) { + sscanf(start, "%lf", &d); + return ei_x_encode_double(x, d); + } else { + sscanf(start, "%ld", &l); + return ei_x_encode_long(x, l); + } +} + +/* "string" */ +static int pstring(const char** fmt, ei_x_buff* x) +{ + const char* start = ++(*fmt); /* skip first quote */ + char c; + int res; + + for (;;) { + c = *(*fmt)++; + if (c == '\0') + return -1; + if (c == '"') { + if (*((*fmt)-1) == '\\') + continue; + else + break; + } else + continue; + } + res = ei_x_encode_string_len(x, start, *fmt - start - 1); + return res; +} + +/* 'atom' */ +static int pquotedatom(const char** fmt, ei_x_buff* x) +{ + const char* start = ++(*fmt); /* skip first quote */ + char c; + int res; + + for (;;) { + c = *(*fmt)++; + if (c == 0) + return -1; + if (c == '\'') { + if (*((*fmt)-1) == '\\') + continue; + else + break; + } else + continue; + } + res = ei_x_encode_atom_len(x, start, *fmt - start - 1); + return res; +} + + + /* + * The format letters are: + * a - An atom + * s - A string + * i - An integer + * l - A long integer + * u - An unsigned long integer + * f - A float + * d - A double float + */ +static int pformat(const char** fmt, union arg** args, ei_x_buff* x) +{ + int res = 0; + ++(*fmt); /* skip tilde */ + switch (*(*fmt)++) { + case 'a': + res = ei_x_encode_atom(x, (*args)->s); + (*args)++; + break; + case 's': + res = ei_x_encode_string(x, (*args)->s); + (*args)++; + break; + case 'i': + res = ei_x_encode_long(x, (*args)->l); + (*args)++; + break; + case 'l': + res = ei_x_encode_long(x, (*args)->l); + (*args)++; + break; + case 'u': + res = ei_x_encode_ulong(x, (*args)->u); + (*args)++; + break; + case 'f': /* float is expanded to double (C calling conventions) */ + case 'd': + res = ei_x_encode_double(x, (*args)->d); + (*args)++; + break; + default: + res = -1; + break; + } + return res; +} + +/* encode a tuple */ +static int ptuple(const char** fmt, union arg** args, ei_x_buff* x, int size) +{ + int res = 0; + const char* p = *fmt; + char after = *p++; + + if (after == '}') { + *fmt = p; + return size; + } + while (isspace((int)*p)) + ++p; + switch (*p++) { + case '}': + if (after == ',') + res = -1; + else + res = size; + break; + case ',': + if (after == ',' || after == '{') + res = -1; + else + res = ptuple(&p, args, x, size); + break; + default: + --p; + res = eiformat(&p, args, x); + if (res >= 0) + res = ptuple(&p, args, x, size + 1); + break; + /* + Variables + */ + } + *fmt = p; + return res; +} + +/* encode a list */ +static int plist(const char** fmt, union arg** args, ei_x_buff* x, int size) +{ + int res = 0; + const char* p = *fmt; + char after = *p++; + + if (after == ']') + --p; + while (isspace((int)*p)) + ++p; + switch (*p++) { + case ']': + if (after == ',') + res = -1; + else { + if (after != '|') + ei_x_encode_empty_list(x); + res = size; + } + break; + case '|': + if (after == '|' || after == ',') + res = -1; + else + res = plist(&p, args, x, size); + break; + case ',': + if (after == '|' || after == ',') + res = -1; + else + res = plist(&p, args, x, size); + break; + default: + --p; + res = eiformat(&p, args, x); + ++size; + if (res >= 0) { + if (after == '|') { + while (isspace((int)*p)) + ++p; + if (*p != ']') + res = -1; + } else + res = plist(&p, args, x, size); + } + break; + /* + Variables + */ + } + *fmt = p; + return res; +} + +static int read_args(const char* fmt, va_list ap, union arg **argp) +{ + const char* p = fmt; + int arg_count = 0; + union arg* args; + int i = 0; + + /* Count the number of format strings. Assume null terminated string. */ + + *argp = NULL; + + while (*p) if (*p++ == '~') arg_count++; + + + if (!arg_count) { + return 0; + } + /* Allocate space for the arguments */ + + args = (union arg*)ei_malloc(arg_count * sizeof(union arg)); + + if (!args) + return -1; + + p = fmt; /* Start again and fill array */ + + while (*p) { + if (*p++ == '~') { + if (!*p) { + ei_free(args); + return -1; /* Error, string not complete */ + } + switch (*p++) { + case 'a': + case 's': + args[i++].s = va_arg(ap, char*); + break; + case 'i': +#ifdef EI_64BIT + args[i++].l = (long) va_arg(ap, int); + break; +#endif + case 'l': + args[i++].l = va_arg(ap, long); + break; + case 'u': + args[i++].u = va_arg(ap, unsigned long); + break; + case 'f': /* float is expanded to double (C calling conventions) */ + case 'd': + args[i++].d = va_arg(ap, double); + break; + default: + ei_free(args); /* Invalid specifier */ + return -1; + } + } + } + *argp = args; + return 0; +} + +int ei_x_format(ei_x_buff* x, const char* fmt, ... ) +{ + va_list ap; + union arg* args; + union arg* saved_args; + int res; + + res = ei_x_encode_version(x); + if (res < 0) return res; + + va_start(ap, fmt); + res = read_args(fmt,ap,&args); + saved_args = args; + va_end(ap); + if (res < 0) { + return -1; + } + + res = eiformat(&fmt, &args, x); + ei_free(saved_args); + + return res; +} + +int ei_x_format_wo_ver(ei_x_buff* x, const char* fmt, ... ) +{ + va_list ap; + union arg* args; + union arg* saved_args; + int res; + + va_start(ap, fmt); + res = read_args(fmt,ap,&args); + saved_args = args; + va_end(ap); + if (res < 0) { + return -1; + } + res = eiformat(&fmt, &args, x); + ei_free(saved_args); + + return res; +} diff --git a/lib/erl_interface/src/misc/ei_format.h b/lib/erl_interface/src/misc/ei_format.h new file mode 100644 index 0000000000..e94d0531f5 --- /dev/null +++ b/lib/erl_interface/src/misc/ei_format.h @@ -0,0 +1,26 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ + +#ifndef _EI_FORMAT_H +#define _EI_FORMAT_H + +#endif /* _EI_FORMAT_H */ + diff --git a/lib/erl_interface/src/misc/ei_internal.h b/lib/erl_interface/src/misc/ei_internal.h new file mode 100644 index 0000000000..9f51d1f61b --- /dev/null +++ b/lib/erl_interface/src/misc/ei_internal.h @@ -0,0 +1,157 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2002-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#ifndef _EI_INTERNAL_H +#define _EI_INTERNAL_H + +/* + * Some useful stuff not to be exported to users. + */ + +#ifdef __WIN32__ +#define MAXPATHLEN 256 +#define writesocket(sock,buf,nbyte) send(sock,buf,nbyte,0) +#define readsocket(sock,buf,nbyte) recv(sock,buf,nbyte,0) +#else /* not __WIN32__ */ +#define writesocket write +#define readsocket read +#define closesocket close +#define ioctlsocket ioctl +#endif + +/* + * Trace functions + * + * The variable ei_tracelevel means + * 0 No tracing + * 1 Write verbose error messages + * 2 Write verbose warning messages + 1 + * 3 Write progress reports for connect handlin + 1 + 2 + * 4 Write progress reports for communication + 1 + 2 + 3 + * 5 Write progress reports for data conversion + 1 + 2 + 3 + 4 + * + */ + +#define EI_TRACE_ERR0(NAME,FORMAT) \ + {if (ei_tracelevel >= 1) ei_trace_printf(NAME,1,FORMAT);} +#define EI_TRACE_ERR1(NAME,FORMAT,ARG1) \ + {if (ei_tracelevel >= 1) ei_trace_printf(NAME,1,FORMAT,ARG1);} +#define EI_TRACE_ERR2(NAME,FORMAT,ARG1,ARG2) \ + {if (ei_tracelevel >= 1) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2);} +#define EI_TRACE_ERR3(NAME,FORMAT,ARG1,ARG2,ARG3) \ + {if (ei_tracelevel >= 1) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3);} +#define EI_TRACE_ERR4(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4) \ + {if (ei_tracelevel >= 1) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4);} +#define EI_TRACE_ERR5(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5) \ + {if (ei_tracelevel >= 1) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \ + ARG5);} +#define EI_TRACE_ERR6(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6) \ + {if (ei_tracelevel >= 1) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \ + ARG5,ARG6);} +#define EI_TRACE_ERR7(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6,ARG7) \ + {if (ei_tracelevel >= 1) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \ + ARG5,ARG6,ARG7);} + +#define EI_TRACE_WARN0(NAME,FORMAT) \ + {if (ei_tracelevel >= 2) ei_trace_printf(NAME,1,FORMAT);} +#define EI_TRACE_WARN1(NAME,FORMAT,ARG1) \ + {if (ei_tracelevel >= 2) ei_trace_printf(NAME,1,FORMAT,ARG1);} +#define EI_TRACE_WARN2(NAME,FORMAT,ARG1,ARG2) \ + {if (ei_tracelevel >= 2) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2);} +#define EI_TRACE_WARN3(NAME,FORMAT,ARG1,ARG2,ARG3) \ + {if (ei_tracelevel >= 2) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3);} +#define EI_TRACE_WARN4(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4) \ + {if (ei_tracelevel >= 2) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4);} +#define EI_TRACE_WARN5(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5) \ + {if (ei_tracelevel >= 2) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \ + ARG5);} +#define EI_TRACE_WARN6(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6) \ + {if (ei_tracelevel >= 2) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \ + ARG5,ARG6);} +#define EI_TRACE_WARN7(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6,ARG7) \ + {if (ei_tracelevel >= 2) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \ + ARG5,ARG6,ARG7);} + +#define EI_TRACE_CONN0(NAME,FORMAT) \ + {if (ei_tracelevel >= 3) ei_trace_printf(NAME,1,FORMAT);} +#define EI_TRACE_CONN1(NAME,FORMAT,ARG1) \ + {if (ei_tracelevel >= 3) ei_trace_printf(NAME,1,FORMAT,ARG1);} +#define EI_TRACE_CONN2(NAME,FORMAT,ARG1,ARG2) \ + {if (ei_tracelevel >= 3) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2);} +#define EI_TRACE_CONN3(NAME,FORMAT,ARG1,ARG2,ARG3) \ + {if (ei_tracelevel >= 3) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3);} +#define EI_TRACE_CONN4(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4) \ + {if (ei_tracelevel >= 3) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4);} +#define EI_TRACE_CONN5(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5) \ + {if (ei_tracelevel >= 3) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \ + ARG5);} +#define EI_TRACE_CONN6(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6) \ + {if (ei_tracelevel >= 3) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \ + ARG5,ARG6);} +#define EI_TRACE_CONN7(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6,ARG7) \ + {if (ei_tracelevel >= 3) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \ + ARG5,ARG6,ARG7);} + +#define EI_TRACE_COMM0(NAME,FORMAT) \ + {if (ei_tracelevel >= 4) ei_trace_printf(NAME,1,FORMAT);} +#define EI_TRACE_COMM1(NAME,FORMAT,ARG1) \ + {if (ei_tracelevel >= 4) ei_trace_printf(NAME,1,FORMAT,ARG1);} +#define EI_TRACE_COMM2(NAME,FORMAT,ARG1,ARG2) \ + {if (ei_tracelevel >= 4) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2);} +#define EI_TRACE_COMM3(NAME,FORMAT,ARG1,ARG2,ARG3) \ + {if (ei_tracelevel >= 4) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3);} +#define EI_TRACE_COMM4(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4) \ + {if (ei_tracelevel >= 4) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4);} +#define EI_TRACE_COMM5(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5) \ + {if (ei_tracelevel >= 4) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \ + ARG5);} +#define EI_TRACE_COMM6(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6) \ + {if (ei_tracelevel >= 4) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \ + ARG5,ARG6);} +#define EI_TRACE_COMM7(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6,ARG7) \ + {if (ei_tracelevel >= 4) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \ + ARG5,ARG6,ARG7);} + +#define EI_TRACE0(NAME,FORMAT) \ + {if (ei_tracelevel >= 5) ei_trace_printf(NAME,1,FORMAT);} +#define EI_TRACE1(NAME,FORMAT,ARG1) \ + {if (ei_tracelevel >= 5) ei_trace_printf(NAME,1,FORMAT,ARG1);} +#define EI_TRACE2(NAME,FORMAT,ARG1,ARG2) \ + {if (ei_tracelevel >= 5) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2);} +#define EI_TRACE3(NAME,FORMAT,ARG1,ARG2,ARG3) \ + {if (ei_tracelevel >= 5) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3);} +#define EI_TRACE4(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4) \ + {if (ei_tracelevel >= 5) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4);} +#define EI_TRACE5(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5) \ + {if (ei_tracelevel >= 5) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \ + ARG5);} +#define EI_TRACE6(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6) \ + {if (ei_tracelevel >= 5) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \ + ARG5,ARG6);} +#define EI_TRACE7(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6,ARG7) \ + {if (ei_tracelevel >= 5) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \ + ARG5,ARG6,ARG7);} + +int ei_tracelevel; + +void ei_trace_printf(const char *name, int level, const char *format, ...); + +int ei_internal_use_r9_pids_ports(void); +#endif /* _EI_INTERNAL_H */ diff --git a/lib/erl_interface/src/misc/ei_locking.c b/lib/erl_interface/src/misc/ei_locking.c new file mode 100644 index 0000000000..e3f57d5ba2 --- /dev/null +++ b/lib/erl_interface/src/misc/ei_locking.c @@ -0,0 +1,164 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1997-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +/* + * common interface to some simple synchronisation primitives for + * internal use by ei. + */ + +/* Note that these locks are NOT recursive on Win32 or Solaris, + * i.e. self-deadlock will occur if a thread tries to obtain a lock it + * is already holding. The primitives used on VxWorks are recursive however. + */ + +#include "eidef.h" + +#ifdef __WIN32__ +#include +#include +#include + +#elif VXWORKS +#include +#include + +#else /* unix */ +#include +#include +#include +#endif /* platforms */ + +#include "ei_malloc.h" +#include "ei_locking.h" + +#ifdef _REENTRANT + +/* + * Create a new mutex object. + * Returns a pointer to the mutex if successful, NULL otherwise. + */ +ei_mutex_t *ei_mutex_create(void) +{ + ei_mutex_t *l; + + if ((l = ei_malloc(sizeof(*l))) == NULL) return NULL; + +#ifdef __WIN32__ + l->lock = CreateMutex(NULL,FALSE,NULL); + +#elif VXWORKS + if (!(l->lock = semMCreate(SEM_DELETE_SAFE))) { + ei_free(l); + return NULL; + } +#else /* unix */ + l->lock = ei_m_create(); +#endif + + return l; +} + +/* + * Free a mutex and the structure asociated with it. + * + * This function attempts to obtain the mutex before releasing it; + * If nblock == 1 and the mutex was unavailable, the function will + * return failure and the mutex will not have been removed. + * + * If nblock == 0 the function will block until the mutex becomes + * available, at which time it will be removed and the function will + * succeed. + * + * returns 0 if the mutex is removed, -1 on failure (busy) + */ +int ei_mutex_free(ei_mutex_t *l, int nblock) +{ + /* attempt to lock it first, to make sure it's really free */ + if (ei_mutex_lock(l,nblock)) return -1; /* attempt failed */ + + /* we are now holding the lock */ +#ifdef __WIN32__ + CloseHandle(l->lock); + +#elif VXWORKS + if (semDelete(l->lock) == ERROR) return -1; + +#else /* unix */ + ei_m_destroy(l->lock); +#endif + + ei_free(l); + + return 0; +} + +/* Grab a mutex. If the mutex is not held by any other process the + * function returns so that the caller may enter a critical section. + * Processes subsequently wishing to obtain the lock will block + * until this process releases it. + * + * If the mutex is busy (held by some other process) and nblock == 0, + * the function will block until the mutex is freed by the process + * holding it, returning only when the mutex has been grabbed. + * + * If the mutex is busy and nblock != 0, the function will not block. + * Instead it will return -1 immediately, indicating that the + * operation failed. + + * Returns 0 on success, -1 on failure. + */ +int ei_mutex_lock(ei_mutex_t *l, int nblock) +{ +#ifdef __WIN32__ + /* check valid values for timeout: is 0 ok? */ + if (WaitForSingleObject(l->lock,(nblock? 0 : INFINITE)) != WAIT_OBJECT_0) + return -1; + +#elif VXWORKS + if (semTake(l->lock,(nblock? NO_WAIT : WAIT_FOREVER)) == ERROR) + return -1; + +#else /* unix */ + if (nblock) { + if (ei_m_trylock(l->lock) < 0) return -1; + } + else ei_m_lock(l->lock); +#endif + + return 0; +} + +/* Release a mutex */ +int ei_mutex_unlock(ei_mutex_t *l) +{ +#ifdef __WIN32__ + ReleaseMutex(l->lock); + +#elif VXWORKS + semGive(l->lock); + +#else /* unix */ + ei_m_unlock(l->lock); +#endif + + return 0; +} + +#endif /* _REENTRANT */ diff --git a/lib/erl_interface/src/misc/ei_locking.h b/lib/erl_interface/src/misc/ei_locking.h new file mode 100644 index 0000000000..f97683e40d --- /dev/null +++ b/lib/erl_interface/src/misc/ei_locking.h @@ -0,0 +1,76 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1997-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#ifndef _EI_LOCKING_H +#define _EI_LOCKING_H + +#include "config.h" + +#if defined(VXWORKS) +#include +#include +#endif + +#ifdef __WIN32__ +#include +#include +#include +#endif + +#ifdef HAVE_MIT_PTHREAD_H +#include +#elif HAVE_PTHREAD_H +#include +#endif + + +typedef struct ei_mutex_s { +#ifdef __WIN32__ + HANDLE lock; +#elif VXWORKS + SEM_ID lock; +#else /* unix */ +#if defined(HAVE_MIT_PTHREAD_H) || defined(HAVE_PTHREAD_H) + pthread_mutex_t *lock; +#else /* ! (HAVE_MIT_PTHREAD_H || HAVE_PTHREAD_H) */ + void *dummy; /* Actually never used */ +#endif /* ! (HAVE_MIT_PTHREAD_H || HAVE_PTHREAD_H) */ +#endif /* unix */ +} ei_mutex_t; + +extern ei_mutex_t* ei_sockets_lock; /* FIXME global variable! */ + +ei_mutex_t *ei_mutex_create(void); +int ei_mutex_free(ei_mutex_t *l, int nblock); +int ei_mutex_lock(ei_mutex_t *l, int nblock); +int ei_mutex_unlock(ei_mutex_t *l); + + +#if defined(_REENTRANT) && !defined(VXWORKS) && !defined(__WIN32__) + +void *ei_m_create(void); +int ei_m_destroy(void *l); +int ei_m_lock(void *l); +int ei_m_trylock(void *l); +int ei_m_unlock(void *l); + +#endif /* _REENTRANT && !VXWORKS && !__WIN32__ */ + +#endif /* _EI_LOCKING_H */ diff --git a/lib/erl_interface/src/misc/ei_malloc.c b/lib/erl_interface/src/misc/ei_malloc.c new file mode 100644 index 0000000000..b122c0f7b8 --- /dev/null +++ b/lib/erl_interface/src/misc/ei_malloc.c @@ -0,0 +1,41 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ + +#include "eidef.h" + +#include +#include +#include "ei_malloc.h" + +void* ei_malloc (long size) +{ + return malloc(size); +} + +void* ei_realloc(void* orig, long size) +{ + return realloc(orig, size); +} + +void ei_free (void *ptr) +{ + free(ptr); +} diff --git a/lib/erl_interface/src/misc/ei_malloc.h b/lib/erl_interface/src/misc/ei_malloc.h new file mode 100644 index 0000000000..ef8efaf9ea --- /dev/null +++ b/lib/erl_interface/src/misc/ei_malloc.h @@ -0,0 +1,28 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2002-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#ifndef _EI_MALLOC_H +#define _EI_MALLOC_H + +void* ei_malloc (long size); +void* ei_realloc(void* orig, long size); +void ei_free (void *ptr); + +#endif /* _EI_MALLOC_H */ diff --git a/lib/erl_interface/src/misc/ei_portio.c b/lib/erl_interface/src/misc/ei_portio.c new file mode 100644 index 0000000000..b73ebebbe1 --- /dev/null +++ b/lib/erl_interface/src/misc/ei_portio.c @@ -0,0 +1,377 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1996-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#ifdef __WIN32__ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned long param_zero = 0; +static unsigned long param_one = 1; +#define SET_BLOCKING(Sock) ioctlsocket((Sock),FIONBIO,¶m_zero) +#define SET_NONBLOCKING(Sock) ioctlsocket((Sock),FIONBIO,¶m_one) + +#define ERROR_WOULDBLOCK WSAEWOULDBLOCK +#define ERROR_TIMEDOUT WSAETIMEDOUT +#define ERROR_INPROGRESS WSAEINPROGRESS +#define GET_SOCKET_ERROR() WSAGetLastError() +#define MEANS_SOCKET_ERROR(Ret) ((Ret == SOCKET_ERROR)) +#define IS_INVALID_SOCKET(Sock) ((Sock) == INVALID_SOCKET) + +#elif VXWORKS +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned long param_zero = 0; +static unsigned long param_one = 1; +#define SET_BLOCKING(Sock) ioctl((Sock),FIONBIO,(int)¶m_zero) +#define SET_NONBLOCKING(Sock) ioctl((Sock),FIONBIO,(int)¶m_one) +#define ERROR_WOULDBLOCK EWOULDBLOCK +#define ERROR_TIMEDOUT ETIMEDOUT +#define ERROR_INPROGRESS EINPROGRESS +#define GET_SOCKET_ERROR() (errno) +#define MEANS_SOCKET_ERROR(Ret) ((Ret) == ERROR) +#define IS_INVALID_SOCKET(Sock) ((Sock) < 0) + +#else /* other unix */ +#include +#include +#include +#include +#include +#include +#include + +#ifndef EWOULDBLOCK +#define ERROR_WOULDBLOCK EAGAIN +#else +#define ERROR_WOULDBLOCK EWOULDBLOCK +#endif +#define SET_BLOCKING(fd) fcntl((fd), F_SETFL, \ + fcntl((fd), F_GETFL, 0) & ~O_NONBLOCK) +#define SET_NONBLOCKING(fd) fcntl((fd), F_SETFL, \ + fcntl((fd), F_GETFL, 0) | O_NONBLOCK) +#define ERROR_TIMEDOUT ETIMEDOUT +#define ERROR_INPROGRESS EINPROGRESS +#define GET_SOCKET_ERROR() (errno) +#define MEANS_SOCKET_ERROR(Ret) ((Ret) < 0) +#define IS_INVALID_SOCKET(Sock) ((Sock) < 0) + +#endif + +/* common includes */ +#include "eidef.h" + +#include +#include +#include +#include "ei_portio.h" +#include "ei_internal.h" + +#ifdef HAVE_SYS_TIME_H +#include +#else +#include +#endif + +#ifdef HAVE_WRITEV +static int ei_writev_t(int fd, struct iovec *iov, int iovcnt, unsigned ms) +{ + int res; + if (ms != 0) { + fd_set writemask; + struct timeval tv; + tv.tv_sec = (time_t) (ms / 1000U); + ms %= 1000U; + tv.tv_usec = (time_t) (ms * 1000U); + FD_ZERO(&writemask); + FD_SET(fd,&writemask); + switch (select(fd+1, NULL, &writemask, NULL, &tv)) { + case -1 : + return -1; /* i/o error */ + case 0: + return -2; /* timeout */ + default: + if (!FD_ISSET(fd, &writemask)) { + return -1; /* Other error */ + } + } + } + res = writev(fd, iov, iovcnt); + return (res < 0) ? -1 : res; +} + +int ei_writev_fill_t(int fd, const struct iovec *iov, int iovcnt, unsigned ms) +{ + int i; + int done; + struct iovec *iov_base = NULL; + struct iovec *current_iov; + int current_iovcnt; + int sum; + + for (sum = 0, i = 0; i < iovcnt; ++i) { + sum += iov[i].iov_len; + } + if (ms != 0U) { + SET_NONBLOCKING(fd); + } + current_iovcnt = iovcnt; + current_iov = (struct iovec *) iov; + done = 0; + for (;;) { + i = ei_writev_t(fd, current_iov, current_iovcnt, ms); + if (i <= 0) { /* ei_writev_t should always return at least 1 */ + if (ms != 0U) { + SET_BLOCKING(fd); + } + if (iov_base != NULL) { + free(iov_base); + } + return (i); + } + done += i; + + if (done < sum) { + if (iov_base == NULL) { + iov_base = malloc(sizeof(struct iovec) * iovcnt); + memcpy(iov_base, iov, sizeof(struct iovec) * iovcnt); + current_iov = iov_base; + } + while (i > 0) { + if (i < current_iov[0].iov_len) { + current_iov[0].iov_len -= i; + i = 0; + } else { + i -= current_iov[0].iov_len; + current_iov++; + current_iovcnt--; + } + } + } else { + break; + } + } + if (ms != 0U) { + SET_BLOCKING(fd); + } + if (iov_base != NULL) { + free(iov_base); + } + return (sum); +} + + +#endif + +int ei_connect_t(int fd, void *sinp, int sin_siz, unsigned ms) +{ + int res; + int error; + int s_res; + struct timeval tv; + fd_set writefds; + fd_set exceptfds; + + if (ms == 0) { + res = connect(fd, sinp, sin_siz); + return (res < 0) ? -1 : res; + } else { + SET_NONBLOCKING(fd); + res = connect(fd, sinp, sin_siz); + error = GET_SOCKET_ERROR(); + SET_BLOCKING(fd); + if (!MEANS_SOCKET_ERROR(res)) { + return (res < 0) ? -1 : res; + } else { + if (error != ERROR_WOULDBLOCK && + error != ERROR_INPROGRESS) { + return -1; + } else { + tv.tv_sec = (long) (ms/1000U); + ms %= 1000U; + tv.tv_usec = (long) (ms * 1000U); + FD_ZERO(&writefds); + FD_SET(fd,&writefds); + FD_ZERO(&exceptfds); + FD_SET(fd,&exceptfds); + s_res = select(fd + 1, NULL, &writefds, &exceptfds, &tv); + switch (s_res) { + case 0: + return -2; + case 1: + if (FD_ISSET(fd, &exceptfds)) { + return -1; + } else { + return 0; /* Connect completed */ + } + default: + return -1; + } + } + } + } +} + +int ei_accept_t(int fd, void *addr, void *addrlen, unsigned ms) +{ + int res; + if (ms != 0) { + fd_set readmask; + struct timeval tv; + tv.tv_sec = (time_t) (ms / 1000U); + ms %= 1000U; + tv.tv_usec = (time_t) (ms * 1000U); + FD_ZERO(&readmask); + FD_SET(fd,&readmask); + switch (select(fd+1, &readmask, NULL, NULL, &tv)) { + case -1 : + return -1; /* i/o error */ + case 0: + return -2; /* timeout */ + default: + if (!FD_ISSET(fd, &readmask)) { + return -1; /* Other error */ + } + } + } + res = (int) accept(fd,addr,addrlen); + return (res < 0) ? -1 : res; +} + + + +static int ei_read_t(int fd, char* buf, int len, unsigned ms) +{ + int res; + if (ms != 0) { + fd_set readmask; + struct timeval tv; + tv.tv_sec = (time_t) (ms / 1000U); + ms %= 1000U; + tv.tv_usec = (time_t) (ms * 1000U); + FD_ZERO(&readmask); + FD_SET(fd,&readmask); + switch (select(fd+1, &readmask, NULL, NULL, &tv)) { + case -1 : + return -1; /* i/o error */ + case 0: + return -2; /* timeout */ + default: + if (!FD_ISSET(fd, &readmask)) { + return -1; /* Other error */ + } + } + } + res = readsocket(fd, buf, len); + return (res < 0) ? -1 : res; +} + +static int ei_write_t(int fd, const char* buf, int len, unsigned ms) +{ + int res; + if (ms != 0) { + fd_set writemask; + struct timeval tv; + tv.tv_sec = (time_t) (ms / 1000U); + ms %= 1000U; + tv.tv_usec = (time_t) (ms * 1000U); + FD_ZERO(&writemask); + FD_SET(fd,&writemask); + switch (select(fd+1, NULL, &writemask, NULL, &tv)) { + case -1 : + return -1; /* i/o error */ + case 0: + return -2; /* timeout */ + default: + if (!FD_ISSET(fd, &writemask)) { + return -1; /* Other error */ + } + } + } + res = writesocket(fd, buf, len); + return (res < 0) ? -1 : res; +} + +/* + * Fill buffer, return buffer length, 0 for EOF, < 0 (and sets errno) + * for error. */ +int ei_read_fill_t(int fd, char* buf, int len, unsigned ms) +{ + int i,got=0; + + do { + i = ei_read_t(fd, buf+got, len-got, ms); + if (i <= 0) + return (i); + got += i; + } while (got < len); + return (len); + +} /* read_fill */ + +int ei_read_fill(int fd, char* buf, int len) +{ + return ei_read_fill_t(fd, buf, len, 0); +} + +/* write entire buffer on fd or fail (setting errno) + */ +int ei_write_fill_t(int fd, const char *buf, int len, unsigned ms) +{ + int i,done=0; + if (ms != 0U) { + SET_NONBLOCKING(fd); + } + do { + i = ei_write_t(fd, buf+done, len-done, ms); + if (i <= 0) { + if (ms != 0U) { + SET_BLOCKING(fd); + } + return (i); + } + done += i; + } while (done < len); + if (ms != 0U) { + SET_BLOCKING(fd); + } + return (len); +} + +int ei_write_fill(int fd, const char *buf, int len) +{ + return ei_write_fill_t(fd, buf, len, 0); +} + diff --git a/lib/erl_interface/src/misc/ei_portio.h b/lib/erl_interface/src/misc/ei_portio.h new file mode 100644 index 0000000000..f2c92278db --- /dev/null +++ b/lib/erl_interface/src/misc/ei_portio.h @@ -0,0 +1,35 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1996-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#ifndef _EI_PORTIO_H +#define _EI_PORTIO_H + +int ei_accept_t(int fd, void *addr, void *addrlen, unsigned ms); +int ei_connect_t(int fd, void *sinp, int sin_siz, unsigned ms); +int ei_read_fill(int fd, char* buf, int len); +int ei_write_fill(int fd, const char *buf, int len); +int ei_read_fill_t(int fd, char* buf, int len, unsigned ms); +int ei_write_fill_t(int fd, const char *buf, int len, unsigned ms); +#ifdef HAVE_WRITEV +int ei_writev_fill_t(int fd, const struct iovec *iov, int iovcnt, + unsigned ms); +#endif + +#endif /* _EI_PORTIO_H */ diff --git a/lib/erl_interface/src/misc/ei_printterm.c b/lib/erl_interface/src/misc/ei_printterm.c new file mode 100644 index 0000000000..8d0eef5e79 --- /dev/null +++ b/lib/erl_interface/src/misc/ei_printterm.c @@ -0,0 +1,342 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +/* + * Function: + * ei_print_term to print out a binary coded term + */ + +#ifdef VXWORKS +#include +#endif + +#include +#include +#include +#include +#include + +#ifdef VRTX +#define __READY_EXTENSIONS__ +#include +#endif + +#include "eidef.h" +#include "eiext.h" +#include "ei_printterm.h" +#include "ei_malloc.h" + +#define BINPRINTSIZE 30 + +/* + * PRINT out a binary term (hacked from 'erl'_print_term) + */ + +static int print_string(FILE* fp, ei_x_buff* x, char* s, int len); +static int print_term(FILE* fp, ei_x_buff* x, + const char* buf, int* index); + +static void xputc(char c, FILE* fp, ei_x_buff* x) +{ + if (fp != NULL) + putc(c, fp); + else + ei_x_append_buf(x, &c, 1); +} + +static void xputs(const char* s, FILE* fp, ei_x_buff* x) +{ + if (fp != NULL) + fputs(s, fp); + else + ei_x_append_buf(x, s, strlen(s)); +} + +static int xprintf(FILE* fp, ei_x_buff* x, const char* fmt, ...) +{ + int r = 0; + va_list ap; + va_start(ap, fmt); + if (fp != NULL) { + r = vfprintf(fp, fmt, ap); + } else { + /* FIXME always enough in buffer??? */ + char tmpbuf[2000]; + r = vsprintf(tmpbuf, fmt, ap); + ei_x_append_buf(x, tmpbuf, strlen(tmpbuf)); + } + va_end(ap); + return r; +} + +static char *ei_big_to_str(erlang_big *b) +{ + int buf_len; + char *s,*buf; + unsigned short *sp; + int i; + + buf_len = 64+b->is_neg+10*b->arity; + if ( (buf=malloc(buf_len)) == NULL) return NULL; + + memset(buf,(char)0,buf_len); + + s = buf; + if ( b->is_neg ) + s += sprintf(s,"-"); + s += sprintf(s,"#integer(%d) = {",b->arity); + for(sp=b->digits,i=0;iarity;i++) { + s += sprintf(s,"%d",sp[i]); + if ( (i+1) != b->arity ) + s += sprintf(s,","); + } + s += sprintf(s,"}"); + return buf; +} + +static int print_term(FILE* fp, ei_x_buff* x, + const char* buf, int* index) +{ + int i, doquote, n, m, ty, r; + char a[MAXATOMLEN+1], *p; + int ch_written = 0; /* counter of written chars */ + erlang_pid pid; + erlang_port port; + erlang_ref ref; + double d; + long l; + + int tindex = *index; + + /* use temporary index for multiple (and failable) decodes */ + + if (fp == NULL && x == NULL) return -1; + + doquote = 0; + ei_get_type_internal(buf, index, &ty, &n); + switch (ty) { + case ERL_ATOM_EXT: + if (ei_decode_atom(buf, index, a) < 0) + goto err; + doquote = !islower((int)a[0]); + for (p = a; !doquote && *p != '\0'; ++p) + doquote = !(isalnum((int)*p) || *p == '_' || *p == '@'); + if (doquote) { + xputc('\'', fp, x); ++ch_written; + } + xputs(a, fp, x); ch_written += strlen(a); + if (doquote) { + xputc('\'', fp, x); ++ch_written; + } + break; + case ERL_PID_EXT: + if (ei_decode_pid(buf, index, &pid) < 0) goto err; + ch_written += xprintf(fp, x, "<%s.%d.%d>", pid.node, + pid.num, pid.serial); + break; + case ERL_PORT_EXT: + if (ei_decode_port(buf, index, &port) < 0) goto err; + ch_written += xprintf(fp, x, "#Port<%d.%d>", port.id, port.creation); + break; + case ERL_NEW_REFERENCE_EXT: + case ERL_REFERENCE_EXT: + if (ei_decode_ref(buf, index, &ref) < 0) goto err; + ch_written += xprintf(fp, x, "#Ref<"); + for (i = 0; i < ref.len; ++i) { + ch_written += xprintf(fp, x, "%d", ref.n[i]); + if (i < ref.len - 1) { + xputc('.', fp, x); ++ch_written; + } + } + xputc('>', fp, x); ++ch_written; + break; + case ERL_NIL_EXT: + if (ei_decode_list_header(buf, index, &n) < 0) goto err; + ch_written += xprintf(fp, x, "[]"); + break; + case ERL_LIST_EXT: + if (ei_decode_list_header(buf, &tindex, &n) < 0) goto err; + xputc('[', fp, x); ch_written++; + for (i = 0; i < n; ++i) { + r = print_term(fp, x, buf, &tindex); + if (r < 0) goto err; + ch_written += r; + if (i < n - 1) { + xputs(", ", fp, x); ch_written += 2; + } + } + if (ei_get_type_internal(buf, &tindex, &ty, &n) < 0) goto err; + if (ty != ERL_NIL_EXT) { + xputs(" | ", fp, x); ch_written += 3; + r = print_term(fp, x, buf, &tindex); + if (r < 0) goto err; + ch_written += r; + } else { + if (ei_decode_list_header(buf, &tindex, &n) < 0) goto err; + } + xputc(']', fp, x); ch_written++; + *index = tindex; + break; + case ERL_STRING_EXT: + p = ei_malloc(n+1); + if (p == NULL) goto err; + if (ei_decode_string(buf, index, p) < 0) { + ei_free(p); + goto err; + } + ch_written += print_string(fp, x, p, n); + ei_free(p); + break; + case ERL_SMALL_TUPLE_EXT: + case ERL_LARGE_TUPLE_EXT: + if (ei_decode_tuple_header(buf, &tindex, &n) < 0) goto err; + xputc('{', fp, x); ch_written++; + + for (i = 0; i < n; ++i) { + r = print_term(fp, x, buf, &tindex); + if (r < 0) goto err; + ch_written += r; + if (i < n-1) { + xputs(", ", fp, x); ch_written += 2; + } + } + *index = tindex; + xputc('}', fp, x); ch_written++; + break; + case ERL_BINARY_EXT: + p = ei_malloc(n); + if (p == NULL) goto err; + if (ei_decode_binary(buf, index, p, &l) < 0) { + ei_free(p); + goto err; + } + ch_written += xprintf(fp, x, "#Bin<"); + if (l > BINPRINTSIZE) + m = BINPRINTSIZE; + else + m = l; + --m; + for (i = 0; i < m; ++i) { + ch_written += xprintf(fp, x, "%d,", p[i]); + } + ch_written += xprintf(fp, x, "%d", p[i]); + if (l > BINPRINTSIZE) + ch_written += xprintf(fp, x, ",..."); + xputc('>', fp, x); ++ch_written; + ei_free(p); + break; + case ERL_SMALL_INTEGER_EXT: + case ERL_INTEGER_EXT: + if (ei_decode_long(buf, index, &l) < 0) goto err; + ch_written += xprintf(fp, x, "%ld", l); + break; + case ERL_SMALL_BIG_EXT: + case ERL_LARGE_BIG_EXT: + { + erlang_big *b; + char *ds; + + b = ei_alloc_big(n); + if (ei_decode_big(buf, index, b) < 0) { + ei_free_big(b); + goto err; + } + + if ( (ds = ei_big_to_str(b)) == NULL ) { + ei_free_big(b); + goto err; + } + + ch_written += xprintf(fp, x, ds); + free(ds); + ei_free_big(b); + + } + break; + + case ERL_FLOAT_EXT: + if (ei_decode_double(buf, index, &d) < 0) goto err; + ch_written += xprintf(fp, x, "%f", d); + break; + default: + goto err; + } + return ch_written; + err: + return -1; +} + +static int print_string(FILE* fp, ei_x_buff* x, char* s, int len) +{ + int ch_written = 0; /* counter of written chars */ + + xputc('"', fp, x); + ++ch_written; + for (; len > 0; ++s, --len) { + int c = *s; + if (c >= ' ') { + xputc((char)c, fp, x); ++ch_written; } + else { + switch (c) { + case '\n': xputs("\\n", fp, x); ch_written += 2; break; + case '\r': xputs("\\r", fp, x); ch_written += 2; break; + case '\t': xputs("\\t", fp, x); ch_written += 2; break; + case '\v': xputs("\\v", fp, x); ch_written += 2; break; + case '\b': xputs("\\b", fp, x); ch_written += 2; break; + case '\f': xputs("\\f", fp, x); ch_written += 2; break; + break; + default: + ch_written += xprintf(fp, x, "\\x%x", c); + break; + } + } + } + xputc('"', fp, x); ch_written++; + return ch_written; +} + +/* ------------------------------------------ */ + +/* + * skip a binary term + */ + + +int ei_print_term(FILE *fp, const char* buf, int* index) +{ + return print_term(fp, NULL, buf, index); +} + +int ei_s_print_term(char** s, const char* buf, int* index) +{ + int r; + ei_x_buff x; + if (*s != NULL) { + x.buff = *s; + x.index = 0; + x.buffsz = BUFSIZ; + } else { + ei_x_new(&x); + } + r = print_term(NULL, &x, buf, index); + ei_x_append_buf(&x, "", 1); /* append '\0' */ + *s = x.buff; + return r; +} diff --git a/lib/erl_interface/src/misc/ei_printterm.h b/lib/erl_interface/src/misc/ei_printterm.h new file mode 100644 index 0000000000..13350e3ecd --- /dev/null +++ b/lib/erl_interface/src/misc/ei_printterm.h @@ -0,0 +1,24 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#ifndef _EI_PRINTTERM_H +#define _EI_PRINTTERM_H + +#endif /* _EI_PRINTTERM_H */ diff --git a/lib/erl_interface/src/misc/ei_pthreads.c b/lib/erl_interface/src/misc/ei_pthreads.c new file mode 100644 index 0000000000..a741dfd5c2 --- /dev/null +++ b/lib/erl_interface/src/misc/ei_pthreads.c @@ -0,0 +1,226 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ + +/* FIXME why not use ei_malloc here? */ + +#include "eidef.h" + +#include +#include "ei.h" +#include "ei_locking.h" + +#ifdef __WIN32__ +#ifdef USE_DECLSPEC_THREAD +/* Define (and initialize) the variable __erl_errno */ +volatile __declspec(thread) int __erl_errno = 0; +#else +static volatile DWORD errno_tls_index = TLS_OUT_OF_INDEXES; +static LONG volatile tls_init_mutex = 0; +#endif +#endif + +#if defined(VXWORKS) + +/* + Moved to each of the erl_*threads.c files, as they seem to know how + to get thread-safety. +*/ +static volatile int __erl_errno; +volatile int *__erl_errno_place(void) +{ + /* This check is somewhat insufficient, double task var entries will occur + if __erl_errno is actually -1, which on the other hand is an invalid + error code. */ + if (taskVarGet(taskIdSelf(), &__erl_errno) == ERROR) { + taskVarAdd(taskIdSelf(), &__erl_errno); + } + return &__erl_errno; +} +#endif /* VXWORKS */ + +#if defined(__WIN32__) + +#ifdef USE_DECLSPEC_THREAD + +volatile int *__erl_errno_place(void) +{ + return &__erl_errno; +} + +#else +static void tls_init_once(void) +{ + + if (errno_tls_index != TLS_OUT_OF_INDEXES) { + return; + } + if (InterlockedExchange((LPLONG) &tls_init_mutex,1L) == 0) { + /* I was first */ + errno_tls_index = TlsAlloc(); + if (errno_tls_index == TLS_OUT_OF_INDEXES) { + fprintf(stderr, + "FATAL ERROR: can not allocate TLS index for " + "erl_errno (error code = %d)!\n",GetLastError()); + exit(1); + } + } else { + while (errno_tls_index == TLS_OUT_OF_INDEXES) { + SwitchToThread(); + } + } +} + +volatile int *__erl_errno_place(void) +{ + volatile int *ptr; + tls_init_once(); + ptr = TlsGetValue(errno_tls_index); + if (ptr == NULL) { + ptr = malloc(sizeof(int)); + *ptr = 0; + TlsSetValue(errno_tls_index, (PVOID) ptr); + } + return ptr; +} + +#endif /* USE_DECLSPEC_THREAD */ + +#endif /* __WIN32__ */ + +#if defined(_REENTRANT) && !defined(VXWORKS) && !defined(__WIN32__) + +#if defined(HAVE_PTHREAD_H) || defined(HAVE_MIT_PTHREAD_H) + +void *ei_m_create(void) +{ + pthread_mutex_t *l; + + if ((l = malloc(sizeof(*l)))) { /* FIXME get memory or abort */ + pthread_mutex_init(l,NULL); + } + + return l; +} + +int ei_m_destroy(void *l) +{ + int r = pthread_mutex_destroy(l); + free(l); + + return r; +} + +int ei_m_lock(void *l) +{ + return pthread_mutex_lock(l); +} + +int ei_m_trylock(void *l) +{ + return pthread_mutex_trylock(l); +} + +int ei_m_unlock(void *l) +{ + return pthread_mutex_unlock(l); +} + + +/* + * Thread-specific erl_errno variable. + * + * The second line below will give a "missing braces around initializer" + * on Solaris but the code will work. + */ + +static pthread_key_t erl_errno_key; +static pthread_once_t erl_errno_key_once = PTHREAD_ONCE_INIT; + +/* + * Destroy per-thread erl_errno locus + */ +static void erl_errno_destroy(void * ptr) +{ + free(ptr); +} + +/* + * Allocate erl_errno key. + * This will be done once for all threads + */ +static void erl_errno_key_alloc(void) +{ + pthread_key_create(&erl_errno_key, erl_errno_destroy); +} + +/* + * Return a pointer to the erl_errno locus. + * If pthread functions fail we fall back to using fallback_errno + * so that the main thread (actually not a thread in all ascpects) + * still will set and get an erl_errno value. + * Actually this is a bit to nice, it would be preferrable to exit fatal + * as we do on windows, but we might break some code with one thread + * but still compiled with -D_REENTRANT, so we'll leave it here. + */ +volatile int *__erl_errno_place(void) +{ + int *erl_errno_p; + static volatile int use_fallback = 0; + static volatile int fallback_errno = 0; + + if (use_fallback) { + return &fallback_errno; + } + + /* This will create the key once for all threads */ + if (pthread_once(&erl_errno_key_once, erl_errno_key_alloc) != 0) { + use_fallback = 1; + return &fallback_errno; + } + + /* This is the normal case, return the pointer to the data */ + if ((erl_errno_p = pthread_getspecific(erl_errno_key)) != NULL) { + return erl_errno_p; + } + + if ((erl_errno_p = malloc(sizeof(int))) == NULL) { + use_fallback = 1; + return &fallback_errno; + } + + if (pthread_setspecific(erl_errno_key, erl_errno_p) != 0 || + (erl_errno_p = pthread_getspecific(erl_errno_key)) == NULL) { + free(erl_errno_p); + return &fallback_errno; + } + + return erl_errno_p; +} + +#endif /* HAVE_PTHREAD_H || HAVE_MIT_PTHREAD_H */ + +#endif /* _REENTRANT && !VXWORKS && !__WIN32__ */ + +#if !defined(_REENTRANT) && !defined(VXWORKS) && !defined(__WIN32__) + +volatile int __erl_errno; + +#endif diff --git a/lib/erl_interface/src/misc/ei_trace.c b/lib/erl_interface/src/misc/ei_trace.c new file mode 100644 index 0000000000..fb183c8be4 --- /dev/null +++ b/lib/erl_interface/src/misc/ei_trace.c @@ -0,0 +1,56 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include "eidef.h" +#include "ei_trace.h" + +/* this is our lamport clock */ +erlang_trace *ei_trace(int query, erlang_trace *token) +{ + /* FIXME problem for threaded ? */ + static erlang_trace save_token; + static int tracing = 0; + static int clock = 0; + + + switch (query) { + case -1: /* we are no longer tracing */ + tracing = 0; + break; + + case 0: /* are we tracing? */ + if (tracing) { + clock++; + save_token.prev = save_token.serial++; + return &save_token; + } + break; + + case 1: /* we are now tracing */ + tracing = 1; + save_token = *token; + if (save_token.serial > clock) + save_token.prev = clock = token->serial; + break; + } + + return NULL; +} + diff --git a/lib/erl_interface/src/misc/ei_trace.h b/lib/erl_interface/src/misc/ei_trace.h new file mode 100644 index 0000000000..d3513c9353 --- /dev/null +++ b/lib/erl_interface/src/misc/ei_trace.h @@ -0,0 +1,26 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2002-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#ifndef _EI_TRACE_H +#define _EI_TRACE_H + +erlang_trace *ei_trace(int query, erlang_trace *token); + +#endif /* _EI_TRACE_H */ diff --git a/lib/erl_interface/src/misc/ei_x_encode.c b/lib/erl_interface/src/misc/ei_x_encode.c new file mode 100644 index 0000000000..fa1e26ccbb --- /dev/null +++ b/lib/erl_interface/src/misc/ei_x_encode.c @@ -0,0 +1,255 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +/* + * ei_x_encode to encode in a self-expanding buffer + */ + +#ifdef VXWORKS +#include +#endif + +#include +#include +#include +#include + +#ifdef VRTX +#define __READY_EXTENSIONS__ +#include +#endif + +#include "eidef.h" +#include "ei_x_encode.h" +#include "ei_malloc.h" + +int ei_x_extra = 100; + +int ei_x_new(ei_x_buff* x) +{ + x->buff = ei_malloc(ei_x_extra); + x->buffsz = ei_x_extra; + x->index = 0; + return x->buff != NULL ? 0 : -1; +} + +int ei_x_new_with_version(ei_x_buff* x) +{ + if (ei_x_new(x) < 0) + return -1; + return ei_encode_version(x->buff, &x->index); +} + +int ei_x_free(ei_x_buff* x) +{ + if (x->buff == NULL) + return -1; + ei_free(x->buff); + x->buff = NULL; + return 0; +} + +int x_fix_buff(ei_x_buff* x, int szneeded) +{ + int sz = szneeded + ei_x_extra; + if (sz > x->buffsz) { + sz += ei_x_extra; /* to avoid reallocating each and every time */ + x->buffsz = sz; + x->buff = ei_realloc(x->buff, sz); + } + return x->buff != NULL; +} + +int ei_x_append(ei_x_buff* x, const ei_x_buff* x2) +{ + return ei_x_append_buf(x, x2->buff, x2->index); +} + +int ei_x_append_buf(ei_x_buff* x, const char* buf, int len) +{ + if (!x_fix_buff(x, x->index+len)) + return -1; + memcpy(&x->buff[x->index], buf, len); + x->index += len; + return 0; +} + +int ei_x_encode_string(ei_x_buff* x, const char* s) +{ + return ei_x_encode_string_len(x, s, strlen(s)); +} + +int ei_x_encode_string_len(ei_x_buff* x, const char* s, int len) +{ + int i = x->index; + ei_encode_string_len(NULL, &i, s, len); + if (!x_fix_buff(x, i)) + return -1; + return ei_encode_string_len(x->buff, &x->index, s, len); +} + +int ei_x_encode_binary(ei_x_buff* x, const void* p, int len) +{ + int i = x->index; + ei_encode_binary(NULL, &i, p, len); + if (!x_fix_buff(x, i)) + return -1; + return ei_encode_binary(x->buff, &x->index, p, len); +} + +int ei_x_encode_long(ei_x_buff* x, long n) +{ + int i = x->index; + ei_encode_long(NULL, &i, n); + if (!x_fix_buff(x, i)) + return -1; + return ei_encode_long(x->buff, &x->index, n); +} + +int ei_x_encode_ulong(ei_x_buff* x, unsigned long n) +{ + int i = x->index; + ei_encode_ulong(NULL, &i, n); + if (!x_fix_buff(x, i)) + return -1; + return ei_encode_ulong(x->buff, &x->index, n); +} + +int ei_x_encode_char(ei_x_buff* x, char p) +{ + int i = x->index; + ei_encode_char(NULL, &i, p); + if (!x_fix_buff(x, i)) + return -1; + return ei_encode_char(x->buff, &x->index, p); +} + +int ei_x_encode_boolean(ei_x_buff* x, int p) +{ + int i = x->index; + ei_encode_boolean(NULL, &i, p); + if (!x_fix_buff(x, i)) + return -1; + return ei_encode_boolean(x->buff, &x->index, p); +} + +int ei_x_encode_double(ei_x_buff* x, double dbl) +{ + int i = x->index; + ei_encode_double(NULL, &i, dbl); + if (!x_fix_buff(x, i)) + return -1; + return ei_encode_double(x->buff, &x->index, dbl); +} + +int ei_x_encode_list_header(ei_x_buff* x, long n) +{ + int i = x->index; + ei_encode_list_header(NULL, &i, n); + if (!x_fix_buff(x, i)) + return -1; + return ei_encode_list_header(x->buff, &x->index, n); +} + +int ei_x_encode_empty_list(ei_x_buff* x) +{ + int i = x->index; + ei_encode_empty_list(NULL, &i); + if (!x_fix_buff(x, i)) + return -1; + return ei_encode_empty_list(x->buff, &x->index); +} + +int ei_x_encode_version(ei_x_buff* x) +{ + int i = x->index; + ei_encode_version(NULL, &i); + if (!x_fix_buff(x, i)) + return -1; + return ei_encode_version(x->buff, &x->index); +} + +int ei_x_encode_tuple_header(ei_x_buff* x, long n) +{ + int i = x->index; + ei_encode_tuple_header(NULL, &i, n); + if (!x_fix_buff(x, i)) + return -1; + return ei_encode_tuple_header(x->buff, &x->index, n); +} + +int ei_x_encode_atom(ei_x_buff* x, const char* s) +{ + return ei_x_encode_atom_len(x, s, strlen(s)); +} + +int ei_x_encode_atom_len(ei_x_buff* x, const char* s, int len) +{ + int i = x->index; + ei_encode_atom_len(NULL, &i, s, len); + if (!x_fix_buff(x, i)) + return -1; + return ei_encode_atom_len(x->buff, &x->index, s, len); +} + +int ei_x_encode_pid(ei_x_buff* x, const erlang_pid* pid) +{ + int i = x->index; + ei_encode_pid(NULL, &i, pid); + if (!x_fix_buff(x, i)) + return -1; + return ei_encode_pid(x->buff, &x->index, pid); +} + +int ei_x_encode_fun(ei_x_buff* x, const erlang_fun* fun) +{ + int i = x->index; + ei_encode_fun(NULL, &i, fun); + if (!x_fix_buff(x, i)) + return -1; + return ei_encode_fun(x->buff, &x->index, fun); +} + +int ei_x_encode_ref(ei_x_buff* x, const erlang_ref* ref) +{ + int i = x->index; + ei_encode_ref(NULL, &i, ref); + if (!x_fix_buff(x, i)) + return -1; + return ei_encode_ref(x->buff, &x->index, ref); +} + +int ei_x_encode_port(ei_x_buff* x, const erlang_port* port) +{ + int i = x->index; + ei_encode_port(NULL, &i, port); + if (!x_fix_buff(x, i)) + return -1; + return ei_encode_port(x->buff, &x->index, port); +} + +int ei_x_encode_trace(ei_x_buff* x, const erlang_trace* trace) +{ + int i = x->index; + ei_encode_trace(NULL, &i, trace); + if (!x_fix_buff(x, i)) + return -1; + return ei_encode_trace(x->buff, &x->index, trace); +} diff --git a/lib/erl_interface/src/misc/ei_x_encode.h b/lib/erl_interface/src/misc/ei_x_encode.h new file mode 100644 index 0000000000..3eab23ce0a --- /dev/null +++ b/lib/erl_interface/src/misc/ei_x_encode.h @@ -0,0 +1,31 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +/* + * Function: + * ei_x_encode to encode in a self-expanding buffer + */ + +#ifndef _EI_X_ENCODE_H +#define _EI_X_ENCODE_H + +int x_fix_buff(ei_x_buff* x, int szneeded); + +#endif /* _EI_X_ENCODE_H */ diff --git a/lib/erl_interface/src/misc/eidef.h b/lib/erl_interface/src/misc/eidef.h new file mode 100644 index 0000000000..bd3d0bf631 --- /dev/null +++ b/lib/erl_interface/src/misc/eidef.h @@ -0,0 +1,51 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2002-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ + +#ifndef _EIDEF_H +#define _EIDEF_H + +/* Common definitions used in ei user interface */ + +#include "config.h" /* Central include of config.h */ + +/* vxWorks.h needs to be before stddef.h */ +#ifdef VXWORKS +#include +#endif + +#include /* We want to get definition of NULL */ + +#include "ei.h" /* Want the API function declarations */ + +#define EISMALLBUF 2048 + +#ifndef HAVE_SOCKLEN_T +typedef int socklen_t; +#endif + +typedef unsigned char uint8; /* FIXME use configure */ +typedef unsigned short uint16; +typedef unsigned int uint32; +typedef signed char int8; +typedef signed short int16; +typedef signed int int32; + +#endif /* _EIDEF_H */ diff --git a/lib/erl_interface/src/misc/eiext.h b/lib/erl_interface/src/misc/eiext.h new file mode 100644 index 0000000000..85ed9e0d50 --- /dev/null +++ b/lib/erl_interface/src/misc/eiext.h @@ -0,0 +1,35 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#ifndef _EIEXT_H +#define _EIEXT_H + +/* FIXME maybe put into eidef.h */ + +#define ERL_VERSION_MAGIC 131 /* 130 in erlang 4.2 */ + +/* from erl_eterm.h */ +#define ERL_MAX ((1 << 27)-1) +#define ERL_MIN -(1 << 27) + +/* FIXME we removed lots of defines, maybe some C files don't need to include + this header any longer? */ + +#endif /* _EIEXT_H */ diff --git a/lib/erl_interface/src/misc/eimd5.c b/lib/erl_interface/src/misc/eimd5.c new file mode 100644 index 0000000000..426b96d962 --- /dev/null +++ b/lib/erl_interface/src/misc/eimd5.c @@ -0,0 +1,319 @@ +/* + * MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + * rights reserved. + * + * License to copy and use this software is granted provided that it + * is identified as the "RSA Data Security, Inc. MD5 Message-Digest + * Algorithm" in all material mentioning or referencing this software + * or this function. + * + * License is also granted to make and use derivative works provided + * that such works are identified as "derived from the RSA Data + * Security, Inc. MD5 Message-Digest Algorithm" in all material + * mentioning or referencing the derived work. + * + * RSA Data Security, Inc. makes no representations concerning either + * the merchantability of this software or the suitability of this + * software for any particular purpose. It is provided "as is" + * without express or implied warranty of any kind. + * + * These notices must be retained in any copies of any part of this + * documentation and/or software. + */ + +#include "eidef.h" + +#include +#include "eimd5.h" + +/* + * Constants for MD5Transform routine. + */ + +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +static void MD5Transform(UINT4 [4], unsigned char [64]); +static void Encode(unsigned char *, UINT4 *, unsigned int); +static void Decode(UINT4 *, unsigned char *, unsigned int); + +static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * F, G, H and I are basic MD5 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* + * ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* + * FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. + * Rotation is separate from addition to prevent recomputation. + */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ +} +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ +} +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ +} +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ +} + + +/* + * MD5 initialization. Begins an MD5 operation, writing a new context. + */ +void ei_MD5Init(MD5_CTX* context) +{ + context->count[0] = context->count[1] = 0; + + /* + * Load magic initialization constants. + */ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* + * MD5 block update operation. Continues an MD5 message-digest + * operation, processing another message block, and updating the + * context. + */ +void ei_MD5Update (MD5_CTX *context, unsigned char *input, + unsigned int inputLen) +{ + unsigned int i, index, partLen; + + /* + * Compute number of bytes mod 64 + */ + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((context->count[0] += ((UINT4)inputLen << 3)) + < ((UINT4)inputLen << 3)) + context->count[1]++; + context->count[1] += ((UINT4)inputLen >> 29); + + partLen = 64 - index; + + /* + * Transform as many times as possible. + */ + if (inputLen >= partLen) { + memcpy + ((POINTER)&context->buffer[index], (POINTER)input, partLen); + MD5Transform (context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD5Transform (context->state, &input[i]); + + index = 0; + } + else + i = 0; + + /* + * Buffer remaining input + */ + memcpy((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i); +} + +/* + * MD5 finalization. Ends an MD5 message-digest operation, writing the + the message digest and zeroizing the context. + */ +void ei_MD5Final (unsigned char digest[16], MD5_CTX *context) +{ + unsigned char bits[8]; + unsigned int index, padLen; + + /* + * Save number of bits + */ + Encode (bits, context->count, 8); + + /* + * Pad out to 56 mod 64. + */ + index = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + ei_MD5Update (context, PADDING, padLen); + + /* + * Append length (before padding) + */ + ei_MD5Update (context, bits, 8); + + /* + * Store state in digest + */ + Encode (digest, context->state, 16); + + /* + * Zeroize sensitive information. + */ + memset ((POINTER)context, 0, sizeof (*context)); +} + +/* + * MD5 basic transformation. Transforms state based on block. + */ +static void MD5Transform (UINT4 state[4], unsigned char block[64]) +{ + UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* + * Zeroize sensitive information. + */ + memset ((POINTER)x, 0, sizeof (x)); +} + +/* + * Encodes input (UINT4) into output (unsigned char). Assumes len is + * a multiple of 4. + */ +static void Encode (unsigned char *output, UINT4 *input, unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } +} + +/* + * Decodes input (unsigned char) into output (UINT4). Assumes len is + * a multiple of 4. + */ +static void Decode (UINT4 *output, unsigned char *input, unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | + (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); +} diff --git a/lib/erl_interface/src/misc/eimd5.h b/lib/erl_interface/src/misc/eimd5.h new file mode 100644 index 0000000000..746f06e236 --- /dev/null +++ b/lib/erl_interface/src/misc/eimd5.h @@ -0,0 +1,48 @@ +/* + * MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + * rights reserved. + * + * License to copy and use this software is granted provided that it + * is identified as the "RSA Data Security, Inc. MD5 Message-Digest + * Algorithm" in all material mentioning or referencing this software + * or this function. + * + * License is also granted to make and use derivative works provided + * that such works are identified as "derived from the RSA Data + * Security, Inc. MD5 Message-Digest Algorithm" in all material + * mentioning or referencing the derived work. + * + * RSA Data Security, Inc. makes no representations concerning either + * the merchantability of this software or the suitability of this + * software for any particular purpose. It is provided "as is" + * without express or implied warranty of any kind. + * + * These notices must be retained in any copies of any part of this + * documentation and/or software. + */ + +#ifndef _EIMD5_H +#define _EIMD5_H + +typedef unsigned UINT4; /* Should be 32 bits. */ +typedef void *POINTER; + + +/* + * MD5 context. + */ + +typedef struct { + UINT4 state[4]; /* state (ABCD) */ + UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} MD5_CTX; + +void ei_MD5Init(MD5_CTX *); +void ei_MD5Update(MD5_CTX *, unsigned char *, unsigned int); +void ei_MD5Final(unsigned char [16], MD5_CTX *); + +#endif /* _EIMD5_H */ diff --git a/lib/erl_interface/src/misc/get_type.c b/lib/erl_interface/src/misc/get_type.c new file mode 100644 index 0000000000..d67a6a80d3 --- /dev/null +++ b/lib/erl_interface/src/misc/get_type.c @@ -0,0 +1,149 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include "eidef.h" +#include "eiext.h" +#include "putget.h" + +/* report type identifier from the start of the buffer */ +/* for types with meaningful length attributes, return the length too. + In other cases, return length 0 */ + +/* FIXME working on this one.... */ + +int ei_get_type(const char *buf, const int *index, int *type, int *len) +{ + return ei_get_type_internal(buf, index, type, len); +} + +#if 0 +int ei_get_type(const char *buf, const int *index, int *type, int *len) +{ + const char *s = buf + *index; + int itype = get8(s); /* Internal type */ + + *len = 0; + + switch (*type) { + + case ERL_SMALL_INTEGER_EXT: + case ERL_INTEGER_EXT: + case ERL_SMALL_BIG_EXT: + case ERL_LARGE_BIG_EXT: + *type = EI_TYPE_INTEGER; + break; + + case ERL_FLOAT_EXT: + *type = EI_TYPE_FLOAT; + break; + + case ERL_SMALL_TUPLE_EXT: + *len = get8(s); + break; + + case ERL_ATOM_EXT: + case ERL_STRING_EXT: + *len = get16be(s); + break; + + case ERL_LARGE_TUPLE_EXT: + case ERL_LIST_EXT: + case ERL_BINARY_EXT: + *len = get32be(s); + break; + + case ERL_SMALL_BIG_EXT: + *len = (get8(s)+1)/2; /* big arity */ + break; + + case ERL_LARGE_BIG_EXT: + *len = (get32be(s)+1)/2; /* big arity */ + break; + + case ERL_BINARY_EXT: + *type = EI_TYPE_BINARY; + break; + + case ERL_PID_EXT: + *type = EI_TYPE_PID; + break; + + case ERL_PORT_EXT: + *type = EI_TYPE_PORT; + break; + + case ERL_REFERENCE_EXT: + case ERL_NEW_REFERENCE_EXT: + *type = EI_TYPE_REF; + break; + + default: + break; + } + + /* leave index unchanged */ + return 0; +} +#endif + + +/* Old definition of function above */ + +int ei_get_type_internal(const char *buf, const int *index, + int *type, int *len) +{ + const char *s = buf + *index; + + *type = get8(s); + + switch (*type) { + case ERL_SMALL_TUPLE_EXT: + *len = get8(s); + break; + + case ERL_ATOM_EXT: + case ERL_STRING_EXT: + *len = get16be(s); + break; + + case ERL_LARGE_TUPLE_EXT: + case ERL_LIST_EXT: + case ERL_BINARY_EXT: + *len = get32be(s); + break; + + case ERL_SMALL_BIG_EXT: + *len = get8(s); /* #digit_bytes */ + break; + + case ERL_LARGE_BIG_EXT: + *len = get32be(s); /* #digit_bytes */ + break; + + default: + *len = 0; + break; + } + + /* leave index unchanged */ + return 0; +} + + diff --git a/lib/erl_interface/src/misc/putget.h b/lib/erl_interface/src/misc/putget.h new file mode 100644 index 0000000000..98d9ebb64c --- /dev/null +++ b/lib/erl_interface/src/misc/putget.h @@ -0,0 +1,85 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#ifndef _PUTGET_H +#define _PUTGET_H + +#define put8(s,n) do { \ + (s)[0] = (char)((n) & 0xff); \ + (s) += 1; \ +} while (0) + +#define put16le(s,n) do { \ + (s)[0] = (n) & 0xff; \ + (s)[1] = ((n) >> 8) & 0xff; \ + (s) += 2; \ +} while (0) \ + +#define put32le(s,n) do { \ + (s)[0] = (n) & 0xff; \ + (s)[1] = ((n) >> 8) & 0xff; \ + (s)[2] = ((n) >> 16) & 0xff; \ + (s)[3] = ((n) >> 24) & 0xff; \ + (s) += 4; \ +} while (0) + +#define put16be(s,n) do { \ + (s)[0] = ((n) >> 8) & 0xff; \ + (s)[1] = (n) & 0xff; \ + (s) += 2; \ +} while (0) + +#define put32be(s,n) do { \ + (s)[0] = ((n) >> 24) & 0xff; \ + (s)[1] = ((n) >> 16) & 0xff; \ + (s)[2] = ((n) >> 8) & 0xff; \ + (s)[3] = (n) & 0xff; \ + (s) += 4; \ +} while (0) + +#define get8(s) \ + ((s) += 1, \ + ((unsigned char *)(s))[-1] & 0xff) + +#define get16le(s) \ + ((s) += 2, \ + (((((unsigned char *)(s))[-1] << 8) | \ + ((unsigned char *)(s))[-2])) & 0xffff) + +#define get32le(s) \ + ((s) += 4, \ + ((((unsigned char *)(s))[-1] << 24) | \ + (((unsigned char *)(s))[-2] << 16) | \ + (((unsigned char *)(s))[-3] << 8) | \ + ((unsigned char *)(s))[-4])) + +#define get16be(s) \ + ((s) += 2, \ + (((((unsigned char *)(s))[-2] << 8) | \ + ((unsigned char *)(s))[-1])) & 0xffff) + +#define get32be(s) \ + ((s) += 4, \ + ((((unsigned char *)(s))[-4] << 24) | \ + (((unsigned char *)(s))[-3] << 16) | \ + (((unsigned char *)(s))[-2] << 8) | \ + ((unsigned char *)(s))[-1])) + +#endif /* _PUTGET_H */ diff --git a/lib/erl_interface/src/misc/show_msg.c b/lib/erl_interface/src/misc/show_msg.c new file mode 100644 index 0000000000..25865d6f8e --- /dev/null +++ b/lib/erl_interface/src/misc/show_msg.c @@ -0,0 +1,584 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include +#include +#include +#include +#include + +#include + +#include "eidef.h" + +#ifndef __WIN32__ +# ifdef TIME_WITH_SYS_TIME +# include +# include +# else +# ifdef HAVE_SYS_TIME_H +# include +# else +# include +# endif +# endif +#endif + +#include "eiext.h" +#include "putget.h" +#include "ei_printterm.h" +#include "ei_internal.h" +#include "show_msg.h" + +#ifndef EISHOWBUF +#define EISHOWBUF 512 +#endif + +static void show_term(const char *termbuf, int *index, FILE *stream); +static void show_pid(FILE *stream, const erlang_pid *pid); +static void show_trace(FILE *stream, const erlang_trace *t); +static void show_msg(FILE *stream, int direction, const erlang_msg *msg, + const char *buf); +static void ei_efprint(FILE *stream, const char *termbuf); +static int ei_decode_skip_bignum(const char *buf, int *index, void *p); +static int printable_list_p(const uint8 *buf, int buflen); + + +/*************************************************************************** + * + * Write trace information to stderr + * + ***************************************************************************/ + +void ei_trace_printf(const char *name, int level, const char *format,...) +{ + time_t now; + char *timestr; + char buf[2048]; + int len; + va_list args; + + va_start(args, format); + + time(&now); + timestr = (char *)ctime(&now); + sprintf(buf, "%s: %.*s: ", name, (int) strlen(timestr)-1, timestr); + len = strlen(buf); + vsprintf(buf + len, format, args); + fprintf(stderr,"%s\r\n",buf); + va_end(args); +} + + +/*************************************************************************** + * + * Debug printing of incoming and outgoing messages + * + ***************************************************************************/ + +/* + * FIXME maybe this function should be rewritten to use ei_printterm instead + * (or the other way around) + */ + +/* + * the new TT stuff has been added, but when these messages are shown + * they will look just like the non-tt ones for now. + */ + +/* + * this should be long enough for longest atoms (256) but short enough for + * fprintf to handle all at once (a few kb probably). + */ + + +void ei_show_recmsg(FILE *stream, erlang_msg *msg, char *buf) +{ + show_msg(stream, 0, msg, buf); +} + + +/* decode the buffer again before showing it */ +int ei_show_sendmsg(FILE *stream, const char *header, const char *msgbuf) +{ + erlang_msg msg; + const char *mbuf = NULL; + int index = 0; + int arity = 0; + int version = 0; + + /* skip five bytes */ + index = 5; + ei_decode_version(header,&index,&version); + ei_decode_tuple_header(header,&index,&arity); + ei_decode_long(header,&index,&msg.msgtype); + + switch (msg.msgtype) { + case ERL_SEND: + if (ei_decode_atom(header,&index,msg.cookie) + || ei_decode_pid(header,&index,&msg.to)) return -1; + mbuf = msgbuf; + break; + + case ERL_SEND_TT: + if (ei_decode_atom(header,&index,msg.cookie) + || ei_decode_pid(header,&index,&msg.to) + || ei_decode_trace(header,&index,&msg.token)) return -1; + mbuf = msgbuf; + break; + + case ERL_REG_SEND: + if (ei_decode_pid(header,&index,&msg.from) + || ei_decode_atom(header,&index,msg.cookie) + || ei_decode_atom(header,&index,msg.toname)) return -1; + mbuf = msgbuf; + break; + + case ERL_REG_SEND_TT: + if (ei_decode_pid(header,&index,&msg.from) + || ei_decode_atom(header,&index,msg.cookie) + || ei_decode_atom(header,&index,msg.toname) + || ei_decode_trace(header,&index,&msg.token)) return -1; + mbuf = msgbuf; + break; + + case ERL_EXIT: + case ERL_EXIT2: + if (ei_decode_pid(header,&index,&msg.from) + || ei_decode_pid(header,&index,&msg.to)) return -1; + mbuf = header+index; + + case ERL_EXIT_TT: + case ERL_EXIT2_TT: + if (ei_decode_pid(header,&index,&msg.from) + || ei_decode_pid(header,&index,&msg.to) + || ei_decode_trace(header,&index,&msg.token)) return -1; + mbuf = header+index; + break; + + case ERL_LINK: + case ERL_UNLINK: + case ERL_GROUP_LEADER: + if (ei_decode_pid(header,&index,&msg.from) + || ei_decode_pid(header,&index,&msg.to)) return -1; + mbuf = header; + break; + + case ERL_NODE_LINK: + /* nothing to do */ + mbuf = header; + break; + + default: + break; + } + + show_msg(stream, 1, &msg, mbuf); + + return 0; +} + + +/*************************************************************************** + * + * Common function for ei_show_recmsg() and ei_show_sendmsg() + * + ***************************************************************************/ + +static void show_msg(FILE *stream, int direction, const erlang_msg *msg, + const char *buf) +{ + if (direction) fprintf(stream,"-> "); + else fprintf(stream,"<- "); + + switch (msg->msgtype) { + case ERL_LINK: + fprintf(stream,"LINK From: "); + show_pid(stream,&msg->from); + fprintf(stream," To: "); + show_pid(stream,&msg->to); + break; + + case ERL_SEND: + fprintf(stream,"SEND To: "); + show_pid(stream,&msg->to); + fprintf(stream,"\n "); + /* show the message */ + ei_efprint(stream,buf); + break; + + case ERL_EXIT: + fprintf(stream,"EXIT From: "); + show_pid(stream,&msg->from); + fprintf(stream," To: "); + show_pid(stream,&msg->to); + /* show the reason */ + fprintf(stream,"\n Reason: "); + ei_efprint(stream,buf); + break; + + case ERL_UNLINK: + fprintf(stream,"UNLINK From: "); + show_pid(stream,&msg->from); + fprintf(stream," To: "); + show_pid(stream,&msg->to); + break; + + case ERL_NODE_LINK: + fprintf(stream,"NODE_LINK"); + break; + + case ERL_REG_SEND: + fprintf(stream,"REG_SEND From: "); + show_pid(stream,&msg->from); + fprintf(stream," To: %s\n ",msg->toname); + /* show the message */ + ei_efprint(stream,buf); + break; + + case ERL_GROUP_LEADER: + fprintf(stream,"GROUP_LEADER From: "); + show_pid(stream,&msg->from); + fprintf(stream," To: "); + show_pid(stream,&msg->to); + break; + + case ERL_EXIT2: + fprintf(stream,"EXIT2 From: "); + show_pid(stream,&msg->from); + fprintf(stream," To: "); + show_pid(stream,&msg->to); + /* show the reason */ + fprintf(stream,"\n Reason: "); + ei_efprint(stream,buf); + break; + + /* the new TT stuff below */ + + case ERL_EXIT_TT: + fprintf(stream,"EXIT_TT From: "); + show_pid(stream,&msg->from); + fprintf(stream," To: "); + show_pid(stream,&msg->to); + fprintf(stream,"\n "); + show_trace(stream,&msg->token); + /* show the reason */ + fprintf(stream,"\n Reason: "); + ei_efprint(stream,buf); + break; + + case ERL_EXIT2_TT: + fprintf(stream,"EXIT2_TT From: "); + show_pid(stream,&msg->from); + fprintf(stream," To: "); + show_pid(stream,&msg->to); + fprintf(stream,"\n "); + show_trace(stream,&msg->token); + /* show the reason */ + fprintf(stream,"\n Reason: "); + ei_efprint(stream,buf); + break; + + case ERL_SEND_TT: + fprintf(stream,"SEND_TT To: "); + show_pid(stream,&msg->to); + fprintf(stream,"\n "); + show_trace(stream,&msg->token); + fprintf(stream,"\n "); + /* show the message */ + ei_efprint(stream,buf); + break; + + case ERL_REG_SEND_TT: + fprintf(stream,"REG_SEND_TT From: "); + show_pid(stream,&msg->from); + fprintf(stream," To: %s\n ",msg->toname); + show_trace(stream,&msg->token); + fprintf(stream,"\n "); + /* show the message */ + ei_efprint(stream,buf); + break; + + default: + fprintf(stream,"Unknown message type: %ld",msg->msgtype); + } + fprintf(stream,"\n"); +} + +/*************************************************************************** + * + * Print term to stream with fprintf + * + ***************************************************************************/ + + +static void ei_efprint(FILE *stream, const char *termbuf) +{ + int index = 0; + show_term(termbuf,&index,stream); +} + +static void show_term(const char *termbuf, int *index, FILE *stream) +{ + int type; + char smallbuf[EISHOWBUF]; + int version; + long num; + double fnum; + erlang_pid pid; + erlang_port port; + erlang_ref ref; + int i, len; + char *s; + + ei_get_type_internal(termbuf,index,&type,&len); + + switch (type) { + case ERL_VERSION_MAGIC: + /* just skip past this */ + ei_decode_version(termbuf,index,&version); + show_term(termbuf,index,stream); + break; + + case ERL_ATOM_EXT: + ei_decode_atom(termbuf,index,smallbuf); + fprintf(stream,"%s",smallbuf); + break; + + case ERL_STRING_EXT: + /* strings can be much longer than EISHOWBUF */ + if (len < EISHOWBUF) s = smallbuf; + else if (!(s = malloc(len+1))) break; /* FIXME just break if can't? */ + + ei_decode_string(termbuf,index,s); + + if (printable_list_p((uint8 *)s,len)) { + /* just show it as it is */ + fprintf(stream,"\"%s\"",s); + } else { + /* show it as a list instead */ + fprintf(stream,"["); + for (i=0; i 0) fprintf(stream,", "); + fprintf(stream,"%d",s[i]); + } + fprintf(stream,"]"); + } + + /* did we allocate anything? */ + if (s && (s != smallbuf)) free(s); + + break; + + /* FIXME add case using ei_decode_longlong */ + case ERL_SMALL_BIG_EXT: + case ERL_SMALL_INTEGER_EXT: + case ERL_INTEGER_EXT: + if (ei_decode_long(termbuf,index,&num) == 0) { + fprintf(stream,"%ld",num); + } else { + ei_decode_skip_bignum(termbuf,index,NULL); + fprintf(stream,"#Bignum"); + } + break; + + case ERL_FLOAT_EXT: + ei_decode_double(termbuf,index,&fnum); + fprintf(stream,"%f",fnum); + break; + + case ERL_PID_EXT: + ei_decode_pid(termbuf,index,&pid); + show_pid(stream,&pid); + break; + + case ERL_SMALL_TUPLE_EXT: + case ERL_LARGE_TUPLE_EXT: + ei_decode_tuple_header(termbuf,index,&len); + fprintf(stream,"{"); + for (i=0; i 0) fprintf(stream,", "); + show_term(termbuf,index,stream); + } + fprintf(stream,"}"); + break; + + case ERL_LIST_EXT: + ei_decode_list_header(termbuf,index,&len); + fprintf(stream,"["); + for (i=0; i 0) fprintf(stream,", "); + show_term(termbuf,index,stream); + } + /* get the empty list at the end */ + ei_decode_list_header(termbuf,index,&len); + fprintf(stream,"]"); + break; + + case ERL_NIL_EXT: + ei_decode_list_header(termbuf,index,&len); + fprintf(stream,"[]"); + break; + + case ERL_REFERENCE_EXT: + case ERL_NEW_REFERENCE_EXT: + ei_decode_ref(termbuf,index,&ref); + fprintf(stream,"#Ref<%s",ref.node); + for (i = 0; i < ref.len; i++) { + fprintf(stream,".%u",ref.n[i]); + } + fprintf(stream,".%u>",ref.creation); + break; + + case ERL_PORT_EXT: + ei_decode_port(termbuf,index,&port); + fprintf(stream,"#Port<%s.%u.%u>",port.node,port.id,port.creation); + break; + + case ERL_BINARY_EXT: + ei_decode_binary(termbuf,index,NULL,&num); + fprintf(stream,"#Bin<%ld>",num); + break; + + case ERL_LARGE_BIG_EXT: + /* doesn't actually decode - just skip over it */ + /* FIXME if GMP, what to do here?? */ + ei_decode_skip_bignum(termbuf,index,NULL); + fprintf(stream,"#Bignum"); + break; + + case ERL_FUN_EXT: { + char atom[MAXATOMLEN+1]; + long idx; + long uniq; + const char* s = termbuf + *index, * s0 = s; + int n_free; + + ++s; + n_free = get32be(s); + *index += s - s0; + ei_decode_pid(termbuf, index, NULL); /* skip pid */ + ei_decode_atom(termbuf, index, atom); /* get module, index, uniq */ + ei_decode_long(termbuf, index, &idx); + ei_decode_long(termbuf, index, &uniq); + fprintf(stream,"#Fun<%s.%ld.%ld>", atom, idx, uniq); + for (i = 0; i < n_free; ++i) { + /* FIXME how to report error ?! */ + if (ei_skip_term(termbuf, index) != 0) + fprintf(stderr," show_msg: unknown type of term !"); + } + break; + } + default: + fprintf(stream,"#Unknown<%d.%d>",type,len); + /* unfortunately we don't know how to skip over this type in + * the buffer if we don't even know what it is, so we return. + */ + return; + break; + } +} + +/*************************************************************************** + * + * this help function does the actual decoding of the + * terms and is used by both ei_efprint and ei_sprintt. + * + * termbuf contains the undecoded term. + * idx is the current position in termbuf. + * stream is print destination, e.g. a FILE* + * + ***************************************************************************/ + +static void show_pid(FILE *stream, const erlang_pid *pid) +{ + fprintf(stream,"#Pid<%s.%u.%u.%u>", + pid->node,pid->num,pid->serial,pid->creation); +} + +static void show_trace(FILE *stream, const erlang_trace *t) +{ + fprintf(stream, + "Trace: Label: %ld, Flags: 0x%lx serial: %ld, prev: %ld From: ", + t->label,t->flags,t->serial,t->prev); + show_pid(stream,&t->from); +} + +/*************************************************************************** + * + * Try do decide if a buffer only contains printable characters + * + ***************************************************************************/ + +/* we only need to initialize some of these (after 32 everything printable) */ +/* FIXME they are not!!!! We use isprint() for now but we could create a */ +/* custom print function that escape some non printable like \t and \n */ +#if 0 +static int non_printable[256] = { + /* 1 2 3 */ + /* 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 */ + 1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + /* \b\t\n\v\f\r */ +}; +#endif + +static int printable_list_p(const uint8 *buf, int buflen) +{ + int i; + + for (i=0; i +#include +#include + +#elif VXWORKS +#include +#include + +#else /* unix */ +#include +#include +#include +#endif + +#include "eidef.h" +#include "eiext.h" +#include "ei_connect.h" +#include "ei_internal.h" +#include "putget.h" +#include "ei_trace.h" +#include "show_msg.h" + +/* FIXME this is not useed !!!!! */ + +/* length (4), PASS_THROUGH (1), header, message */ +int ei_ei_send_encoded(ei_cnode* ec, int fd, const erlang_pid *to, + const char *msg, int msglen) +{ + char *s, header[1200]; /* see size calculation below */ + erlang_trace *token = NULL; + int index = 5; /* reserve 5 bytes for control message */ +#ifdef HAVE_WRITEV + struct iovec v[2]; +#endif + + /* are we tracing? */ + /* check that he can receive trace tokens first */ + if (ei_distversion(fd) > 0) + token = ei_trace(0,(erlang_trace *)NULL); + + /* header = SEND, cookie, to max sizes: */ + ei_encode_version(header,&index); /* 1 */ + if (token) { + ei_encode_tuple_header(header,&index,4); /* 2 */ + ei_encode_long(header,&index,ERL_SEND_TT); /* 2 */ + } else { + ei_encode_tuple_header(header,&index,3); + ei_encode_long(header,&index,ERL_SEND); + } + ei_encode_atom(header,&index, "" /*ei_getfdcookie(ec, fd)*/); /* 258 */ + ei_encode_pid(header,&index,to); /* 268 */ + + if (token) ei_encode_trace(header,&index,token); /* 534 */ + + /* control message (precedes header actually) */ + /* length = 1 ('p') + header len + message len */ + s = header; + put32be(s, index + msglen - 4); /* 4 */ + put8(s, ERL_PASS_THROUGH); /* 1 */ + /*** sum: 1070 */ + +#ifdef DEBUG_DIST + if (ei_trace_distribution > 0) ei_show_sendmsg(stderr,header,msg); +#endif + +#ifdef HAVE_WRITEV + + v[0].iov_base = (char *)header; + v[0].iov_len = index; + v[1].iov_base = (char *)msg; + v[1].iov_len = msglen; + + if (writev(fd,v,2) != index+msglen) return -1; + +#else /* !HAVE_WRITEV */ + + if (writesocket(fd,header,index) != index) return -1; + if (writesocket(fd,msg,msglen) != msglen) return -1; + +#endif /* !HAVE_WRITEV */ + + return 0; +} diff --git a/lib/erl_interface/src/not_used/ei_send_reg.c b/lib/erl_interface/src/not_used/ei_send_reg.c new file mode 100644 index 0000000000..af68549c6d --- /dev/null +++ b/lib/erl_interface/src/not_used/ei_send_reg.c @@ -0,0 +1,107 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#ifdef __WIN32__ +#include +#include +#include + +#elif VXWORKS +#include +#include + +#else /* unix */ +#include +#include +#include +#endif + +#include "eidef.h" +#include "eiext.h" +#include "ei_connect.h" +#include "ei_internal.h" +#include "putget.h" +#include "ei_trace.h" +#include "show_msg.h" + +/* FIXME this is not useed !!!!! */ +/* FIXME merge with ei_send.c */ + +/* length (4), PASS_THROUGH (1), header, message */ +int ei_ei_send_reg_encoded(ei_cnode* ec, int fd, const erlang_pid *from, + const char *to, const char *msg, int msglen) +{ + char *s, header[1400]; /* see size calculation below */ + erlang_trace *token = NULL; + int index = 5; /* reserve 5 bytes for control message */ +#ifdef HAVE_WRITEV + struct iovec v[2]; +#endif + + /* are we tracing? */ + /* check that he can receive trace tokens first */ + if (ei_distversion(fd) > 0) + token = ei_trace(0,(erlang_trace *)NULL); + + /* header = REG_SEND, from, cookie, toname max sizes: */ + ei_encode_version(header,&index); /* 1 */ + if (token) { + ei_encode_tuple_header(header,&index,5); /* 2 */ + ei_encode_long(header,&index,ERL_REG_SEND_TT); /* 2 */ + } else { + ei_encode_tuple_header(header,&index,4); + ei_encode_long(header,&index,ERL_REG_SEND); + } + ei_encode_pid(header,&index,from); /* 268 */ + ei_encode_atom(header,&index,"" /*ei_getfdcookie(ec, fd)*/ ); /* 258 */ + ei_encode_atom(header,&index,to); /* 268 */ + + if (token) ei_encode_trace(header,&index,token); /* 534 */ + + /* control message (precedes header actually) */ + /* length = 1 ('p') + header len + message len */ + s = header; + put32be(s, index + msglen - 4); /* 4 */ + put8(s, ERL_PASS_THROUGH); /* 1 */ + /*** sum: 1336 */ + +#ifdef DEBUG_DIST + if (ei_trace_distribution > 0) ei_show_sendmsg(stderr,header,msg); +#endif + +#ifdef HAVE_WRITEV + + v[0].iov_base = (char *)header; + v[0].iov_len = index; + v[1].iov_base = (char *)msg; + v[1].iov_len = msglen; + + if (writev(fd,v,2) != index+msglen) return -1; + +#else + + /* no writev() */ + if (writesocket(fd,header,index) != index) return -1; + if (writesocket(fd,msg,msglen) != msglen) return -1; + +#endif + + return 0; +} diff --git a/lib/erl_interface/src/not_used/send_link.c b/lib/erl_interface/src/not_used/send_link.c new file mode 100644 index 0000000000..4b43b2f0cc --- /dev/null +++ b/lib/erl_interface/src/not_used/send_link.c @@ -0,0 +1,102 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#ifdef __WIN32__ +#include +#include +#include + +#elif VXWORKS +#include + +#else /* unix */ +#include + +#endif + +#include +#include +#include "eidef.h" +#include "eiext.h" +#include "eisend.h" +#include "ei_internal.h" +#include "putget.h" +#include "erl_rport.h" + + +/* this sends either link or unlink ('which' decides) */ +static int link_unlink(int fd, const erlang_pid *from, const erlang_pid *to, + int which, unsigned ms) +{ + char msgbuf[EISMALLBUF]; + char *s; + int index = 0; + int n; + + index = 5; /* max sizes: */ + ei_encode_version(msgbuf,&index); /* 1 */ + ei_encode_tuple_header(msgbuf,&index,3); + ei_encode_long(msgbuf,&index,which); + ei_encode_pid(msgbuf,&index,from); /* 268 */ + ei_encode_pid(msgbuf,&index,to); /* 268 */ + + /* 5 byte header missing */ + s = msgbuf; + put32be(s, index - 4); /* 4 */ + put8(s, ERL_PASS_THROUGH); /* 1 */ + /* sum: 542 */ + + +#ifdef DEBUG_DIST + if (ei_trace_distribution > 1) ei_show_sendmsg(stderr,msgbuf,NULL); +#endif + + n = ei_write_fill_t(fd,msgbuf,index,ms); + + return (n==index ? 0 : -1); +} + +/* FIXME not used? */ +#if 0 +/* use this to send a link */ +int ei_send_unlink(int fd, const erlang_pid *from, const erlang_pid *to) +{ + return link_unlink(fd, from, to, ERL_UNLINK,0); +} + +/* use this to send an unlink */ +int ei_send_link(int fd, const erlang_pid *from, const erlang_pid *to) +{ + return link_unlink(fd, from, to, ERL_LINK,0); +} +/* use this to send a link */ +int ei_send_unlink_tmo(int fd, const erlang_pid *from, const erlang_pid *to, + unsigned ms) +{ + return link_unlink(fd, from, to, ERL_UNLINK,ms); +} + +/* use this to send an unlink */ +int ei_send_link_tmo(int fd, const erlang_pid *from, const erlang_pid *to, + unsigned ms) +{ + return link_unlink(fd, from, to, ERL_LINK,ms); +} +#endif diff --git a/lib/erl_interface/src/not_used/whereis.c b/lib/erl_interface/src/not_used/whereis.c new file mode 100644 index 0000000000..a4dd73e952 --- /dev/null +++ b/lib/erl_interface/src/not_used/whereis.c @@ -0,0 +1,70 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#ifdef __WIN32__ +#include +#include +#include + +#elif VXWORKS +#include + +#else /* unix */ +#include + +#endif + +#include +#include +#include "erl_interface.h" +#include "erl_connect.h" +#include "erl_format.h" +#include "erl_eterm.h" +#include "erl_malloc.h" + +/* FIXME rewrite to ei functions */ +/* FIXME not used */ + +erlang_pid *erl_whereis(int fd, const char *name) +{ + ETERM *reply; + ETERM *n; + /* FIXME problem for threaded ? */ + static erlang_pid pid; + + n = erl_format("[~a]",name); + reply = erl_rpc(fd,"erlang","whereis",n); + erl_free_term(n); + + if (reply && (ERL_IS_PID(reply))) { + char *node; + node = ERL_PID_NODE(reply); + strcpy(pid.node,node); + pid.num = ERL_PID_NUMBER(reply); + pid.serial = ERL_PID_SERIAL(reply); + pid.creation = ERL_PID_CREATION(reply); + erl_free_term(reply); + return &pid; + } + + if (reply) erl_free_term(reply); + return NULL; +} + diff --git a/lib/erl_interface/src/prog/ei_fake_prog.c b/lib/erl_interface/src/prog/ei_fake_prog.c new file mode 100644 index 0000000000..68eb537211 --- /dev/null +++ b/lib/erl_interface/src/prog/ei_fake_prog.c @@ -0,0 +1,303 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2002-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +/*************************************************************************** + * + * This is a fake program that contains all functions, variables and + * defined symbols mentioned in the manual. We compile this file to see + * that the header files and created library is complete. + * + * You can't run this program, it is for compiling and linking only. + * + ***************************************************************************/ + +/* This is a link and header file test. Including "ei.h" and linking + with libei.a should be enough */ + +/* Use most of + * CFLAGS="-I../include -g -O2 + * -ansi -pedantic + * -Wall + * -Wshadow + * -Wstrict-prototypes + * -Wmissing-prototypes + * -Wmissing-declarations + * -Wnested-externs + * -Winline + * -Werror" + */ + +/* An exception from using eidef.h, use config.h directly */ +#include "config.h" + +#if defined(HAVE_GMP_H) && defined(HAVE_LIBGMP) +#include +#endif /* HAVE_GMP_H && HAVE_LIBGMP */ + +/* #include now included by ei.h */ +#include "ei.h" + +#ifdef VXWORKS +int ei_fake_prog_main(void) +#else +int main(void) +#endif +{ + ErlConnect conp; + Erl_IpAddr thisipaddr = (Erl_IpAddr)0; + FILE *fp = (FILE *)0; + char* charp = "foo"; + double *doublep = NULL; + double doublex = 0.0; + ei_cnode xec; + ei_reg *ei_regp = NULL; + ei_term eterm; + ei_x_buff eix; + erlang_big *bigp = NULL; + erlang_fun efun; + erlang_msg *msgp = NULL; + erlang_msg emsg; + erlang_pid *pidp = NULL; + erlang_pid epid; + erlang_port eport; + erlang_ref eref; + erlang_trace etrace; + int *intp = NULL; + int intx = 0; + long *longp = NULL; + long longx = 0; + short creation = 0; + struct ei_reg_stat *ei_reg_statp = NULL; + struct ei_reg_tabstat *ei_reg_tabstatp = NULL; + struct hostent *hostp = NULL; + unsigned char * ucharp = (unsigned char *)"foo"; + unsigned long *ulongp = NULL; + unsigned long ulongx = 0; + void *voidp = NULL; +#ifndef VXWORKS + EI_LONGLONG *longlongp = (EI_LONGLONG*)NULL; + EI_LONGLONG longlongx = 0; + EI_ULONGLONG *ulonglongp = (EI_ULONGLONG*)NULL; + EI_ULONGLONG ulonglongx = 0; +#endif + + intx = erl_errno; + + ei_connect_init(&xec, charp, charp, creation); + ei_connect_xinit (&xec, charp, charp, charp, thisipaddr, charp, creation); + + ei_connect(&xec, charp); + ei_xconnect (&xec, thisipaddr, charp); + + ei_receive(intx, ucharp, intx); + ei_receive_msg(intx, &emsg, &eix); + ei_xreceive_msg(intx, &emsg, &eix); + + ei_send(intx, &epid, charp, intx); + ei_reg_send(&xec, intx, charp, charp, intx); + + ei_rpc(&xec, intx, charp, charp, charp, intx, &eix); + ei_rpc_to(&xec, intx, charp, charp, charp, intx); + ei_rpc_from(&xec, intx, intx, &emsg, &eix); + + ei_publish(&xec, intx); + ei_accept(&xec, intx, &conp); + ei_unpublish(&xec); + + ei_thisnodename(&xec); + ei_thishostname(&xec); + ei_thisalivename(&xec); + + ei_self(&xec); + + ei_gethostbyname(charp); + ei_gethostbyaddr(charp, intx, intx); + ei_gethostbyname_r(charp, hostp, charp, intx, intp); + ei_gethostbyaddr_r(charp, intx, intx, hostp, charp, intx, intp); + + ei_encode_version(charp, intp); + ei_x_encode_version(&eix); + ei_encode_long(charp, intp, longx); + ei_x_encode_long(&eix, longx); + ei_encode_ulong(charp, intp, ulongx); + ei_x_encode_ulong(&eix, ulongx); + ei_encode_double(charp, intp, doublex); + ei_x_encode_double(&eix, doublex); + ei_encode_boolean(charp, intp, intx); + ei_x_encode_boolean(&eix, intx); + ei_encode_char(charp, intp, 'a'); + ei_x_encode_char(&eix, 'a'); + ei_encode_string(charp, intp, charp); + ei_encode_string_len(charp, intp, charp, intx); + ei_x_encode_string(&eix, charp); + ei_x_encode_string_len(&eix, charp, intx); + ei_encode_atom(charp, intp, charp); + ei_encode_atom_len(charp, intp, charp, intx); + ei_x_encode_atom(&eix, charp); + ei_x_encode_atom_len(&eix, charp, intx); + ei_encode_binary(charp, intp, (void *)0, longx); + ei_x_encode_binary(&eix, (void*)0, intx); + ei_encode_pid(charp, intp, &epid); + ei_x_encode_pid(&eix, &epid); + ei_encode_fun(charp, intp, &efun); + ei_x_encode_fun(&eix, &efun); + ei_encode_port(charp, intp, &eport); + ei_x_encode_port(&eix, &eport); + ei_encode_ref(charp, intp, &eref); + ei_x_encode_ref(&eix, &eref); + ei_encode_trace(charp, intp, &etrace); + ei_x_encode_trace(&eix, &etrace); + ei_encode_tuple_header(charp, intp, intx); + ei_x_encode_tuple_header(&eix, longx); + ei_encode_list_header(charp, intp, intx); + ei_x_encode_list_header(&eix, longx); +/* #define ei_encode_empty_list(buf,i) ei_encode_list_header(buf,i,0) */ + ei_x_encode_empty_list(&eix); + + ei_get_type(charp, intp, intp, intp); + ei_get_type_internal(charp, intp, intp, intp); + + ei_decode_version(charp, intp, intp); + ei_decode_long(charp, intp, longp); + ei_decode_ulong(charp, intp, ulongp); + ei_decode_double(charp, intp, doublep); + ei_decode_boolean(charp, intp, intp); + ei_decode_char(charp, intp, charp); + ei_decode_string(charp, intp, charp); + ei_decode_atom(charp, intp, charp); + ei_decode_binary(charp, intp, (void *)0, longp); + ei_decode_fun(charp, intp, &efun); + free_fun(&efun); + ei_decode_pid(charp, intp, &epid); + ei_decode_port(charp, intp, &eport); + ei_decode_ref(charp, intp, &eref); + ei_decode_trace(charp, intp, &etrace); + ei_decode_tuple_header(charp, intp, intp); + ei_decode_list_header(charp, intp, intp); + + ei_decode_ei_term(charp, intp, &eterm); + + ei_print_term(fp, charp, intp); + ei_s_print_term(&charp, charp, intp); + + ei_x_format(&eix, charp); + ei_x_format_wo_ver(&eix, charp); + + ei_x_new(&eix); + ei_x_new_with_version(&eix); + ei_x_free(&eix); + ei_x_append(&eix, &eix); + ei_x_append_buf(&eix, charp, intx); + ei_skip_term(charp, intp); + + ei_reg_open(intx); + ei_reg_resize(ei_regp, intx); + ei_reg_close(ei_regp); + + ei_reg_setival(ei_regp, charp, longx); + ei_reg_setfval(ei_regp, charp, doublex); + ei_reg_setsval(ei_regp, charp, charp); + ei_reg_setpval(ei_regp, charp, voidp, intx); + + ei_reg_setval(ei_regp, charp, intx); + + ei_reg_getival(ei_regp, charp); + ei_reg_getfval(ei_regp, charp); + ei_reg_getsval(ei_regp, charp); + ei_reg_getpval(ei_regp, charp, intp); + + ei_reg_getval(ei_regp, charp, intx); + + ei_reg_markdirty(ei_regp, charp); + + ei_reg_delete(ei_regp, charp); + + ei_reg_stat(ei_regp, charp, ei_reg_statp); + + ei_reg_tabstat(ei_regp, ei_reg_tabstatp); + + ei_reg_dump(intx, ei_regp, charp, intx); + ei_reg_restore(intx, ei_regp, charp); + ei_reg_purge(ei_regp); + +#if defined(HAVE_GMP_H) && defined(HAVE_LIBGMP) + { + mpz_t obj; + ei_decode_bignum(charp, intp, obj); + ei_encode_bignum(charp, intp, obj); + ei_x_encode_bignum(&eix, obj); + } +#endif /* HAVE_GMP_H && HAVE_LIBGMP */ + +#ifndef VXWORKS + + ei_decode_longlong(charp, intp, longlongp); + ei_decode_ulonglong(charp, intp, ulonglongp); + ei_encode_longlong(charp, intp, longlongx); + ei_encode_ulonglong(charp, intp, ulonglongx); + ei_x_encode_longlong(&eix, longlongx); + ei_x_encode_ulonglong(&eix, ulonglongx); + +#endif + +#ifdef USE_EI_UNDOCUMENTED + + ei_decode_intlist(charp, intp, longp, intp); + + ei_receive_encoded(intx, &charp, intp, msgp, intp); + ei_send_encoded(intx, pidp, charp, intx); + ei_send_reg_encoded(intx, pidp, charp, charp, intx); + + ei_decode_big(charp, intp, bigp); + ei_big_comp(bigp, bigp); + ei_big_to_double(bigp, doublep); + ei_small_to_big(intx, bigp); + ei_alloc_big(intx); + ei_free_big(bigp); + +#endif /* USE_EI_UNDOCUMENTED */ + + return + BUFSIZ + + EAGAIN + + EHOSTUNREACH + + EIO + + EI_BIN + + EI_DELET + + EI_DIRTY + + EI_FLT + + EI_FORCE + + EI_INT + + EI_NOPURGE + + EI_STR + + EMSGSIZE + + ENOMEM + + ERL_ERROR + + ERL_EXIT + + ERL_LINK + + ERL_MSG + + ERL_NO_TIMEOUT + + ERL_REG_SEND + + ERL_SEND + + ERL_TICK + + ERL_TIMEOUT + + ERL_UNLINK + + ETIMEDOUT + + MAXATOMLEN; +} diff --git a/lib/erl_interface/src/prog/erl_call.c b/lib/erl_interface/src/prog/erl_call.c new file mode 100644 index 0000000000..f0d638324d --- /dev/null +++ b/lib/erl_interface/src/prog/erl_call.c @@ -0,0 +1,906 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1996-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +/* + * Function: Makes it possible to send and receive Erlang + * messages from the (Unix) command line. + * Note: We don't free any memory at all since we only + * live for a short while. + * + */ + +#ifdef __WIN32__ +#include +#include +#include +#include + +#elif VXWORKS + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#else /* unix */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#endif + +#include +#include + +#include +#include +#include +#include + +#include "ei.h" +#include "ei_resolve.h" +#include "erl_start.h" /* FIXME remove dependency */ + +#ifdef __WIN32__ +static void initWinSock(void); +#endif + +/* + * Some nice global variables + * (I don't think "nice" is the right word actually... -gordon) + */ +/* FIXME problem for threaded ? */ + +struct call_flags { + int startp; + int cookiep; + int modp; + int evalp; + int randomp; + int use_long_name; /* indicates if -name was used, else -sname or -n */ + int debugp; + int verbosep; + int haltp; + char *cookie; + char *node; + char *hidden; + char *apply; + char *script; +}; + +static void usage_arg(const char *progname, const char *switchname); +static void usage_error(const char *progname, const char *switchname); +static void usage(const char *progname); +static int get_module(char **mbuf, char **mname); +static struct hostent* get_hostent(char *host); +static int do_connect(ei_cnode *ec, char *nodename, struct call_flags *flags); +static int read_stdin(char **buf); +static void split_apply_string(char *str, char **mod, + char **fun, char **args); + + +/*************************************************************************** + * + * XXXXX + * + ***************************************************************************/ + +/* FIXME isn't VxWorks to handle arguments differently? */ +/* FIXME check errors from malloc */ + +#if !defined(VXWORKS) +int main(int argc, char *argv[]) +#else +int erl_call(int argc, char **argv) +#endif +{ + int i = 1,fd,creation; + struct hostent *hp; + char host_name[EI_MAXHOSTNAMELEN+1]; + char nodename[MAXNODELEN+1]; + char *p = NULL; + char *ct = NULL; /* temporary used when truncating nodename */ + int modsize = 0; + char *host = NULL; + char *module = NULL; + char *modname = NULL; + struct call_flags flags = {0}; /* Default 0 and NULL in all fields */ + char* progname = argv[0]; + ei_cnode ec; + + /* Get the command line options */ + while (i < argc) { + if (argv[i][0] != '-') { + usage_error(progname, argv[i]); + } + + if (strcmp(argv[i], "-sname") == 0) { /* -sname NAME */ + if (i+1 >= argc) { + usage_arg(progname, "-sname "); + } + + flags.node = (char *) malloc(strlen(argv[i+1]) + 1); + strcpy(flags.node, argv[i+1]); + i++; + flags.use_long_name = 0; + } else if (strcmp(argv[i], "-name") == 0) { /* -name NAME */ + if (i+1 >= argc) { + usage_arg(progname, "-name "); + } + + flags.node = (char *) malloc(strlen(argv[i+1]) + 1); + strcpy(flags.node, argv[i+1]); + i++; + flags.use_long_name = 1; + } else { + if (strlen(argv[i]) != 2) { + usage_error(progname, argv[i]); + } + + switch (argv[i][1]) { + case 's': + flags.startp = 1; + break; + case 'q': + flags.haltp = 1; + break; + case 'v': + flags.verbosep = 1; + break; + case 'd': + flags.debugp = 1; + break; + case 'r': + flags.randomp = 1; + break; + case 'e': + flags.evalp = 1; + break; + case 'm': + flags.modp = 1; + break; + case 'c': + if (i+1 >= argc) { + usage_arg(progname, "-c "); + } + flags.cookiep = 1; + flags.cookie = (char *) malloc(strlen(argv[i+1]) + 1); + strcpy(flags.cookie, argv[i+1]); + i++; + break; + case 'n': + if (i+1 >= argc) { + usage_arg(progname, "-n "); + } + flags.node = (char *) malloc(strlen(argv[i+1]) + 1); + strcpy(flags.node, argv[i+1]); + flags.use_long_name = 1; + i++; + break; + case 'h': + if (i+1 >= argc) { + usage_arg(progname, "-h "); + } + flags.hidden = (char *) malloc(strlen(argv[i+1]) + 1); + strcpy(flags.hidden, argv[i+1]); + i++; + break; + case 'x': + if (i+1 >= argc) { + usage_arg(progname, "-x "); + } + flags.script = (char *) malloc(strlen(argv[i+1]) + 1); + strcpy(flags.script, argv[i+1]); + i++; + break; + case 'a': + if (i+1 >= argc) { + usage_arg(progname, "-a "); + } + flags.apply = (char *) malloc(strlen(argv[i+1]) + 1); + strcpy(flags.apply, argv[i+1]); + i++; + break; + case '?': + usage(progname); + default: + usage_error(progname, argv[i]); + } + } + i++; + + } /* while */ + + + /* + * Can't have them both ! + */ + if (flags.modp && flags.evalp) { + usage(progname); + } + + /* + * Read an Erlang module from stdin. + */ + if (flags.modp) { + modsize = get_module(&module, &modname); + } + + if (flags.verbosep || flags.debugp) { + fprintf(stderr,"erl_call: " + "node = %s\nCookie = %s\n" + "flags = %s %s %s\n" + "module: name = %s , size = %d\n" + "apply = %s\n", + (flags.node ? flags.node : ""), + (flags.cookie ? flags.cookie : ""), + (flags.startp ? "startp" : ""), + (flags.verbosep ? "verbosep" : ""), + (flags.debugp ? "debugp" : ""), + (modname ? modname : ""), modsize, + (flags.apply ? flags.apply : "" )); + } + + /* + * What we, at least, requires ! + */ + if (flags.node == NULL) { + usage(progname); + } + + if (!flags.cookiep) { + flags.cookie = NULL; + } + + /* FIXME decide how many bits etc or leave to connect_xinit? */ + creation = (time(NULL) % 3) + 1; /* "random" */ + + if (flags.hidden == NULL) { + /* As default we are c17@gethostname */ + i = flags.randomp ? (time(NULL) % 997) : 17; + /* FIXME allocates to small !!! */ + flags.hidden = (char *) malloc(3 + 2 ); /* c17 or cXYZ */ +#if defined(VXWORKS) + sprintf(flags.hidden, "c%d", + i < 0 ? (int) taskIdSelf() : i); +#else + sprintf(flags.hidden, "c%d", + i < 0 ? (int) getpid() : i); +#endif + } + { + /* A name for our hidden node was specified */ + char h_hostname[EI_MAXHOSTNAMELEN+1]; + char h_nodename[MAXNODELEN+1]; + char *h_alivename=flags.hidden; + struct in_addr h_ipadr; + char* ct; + +#ifdef __WIN32__ + /* + * FIXME Extremly ugly, but needed to get ei_gethostbyname() below + * to work. + */ + initWinSock(); +#endif + + gethostname(h_hostname, EI_MAXHOSTNAMELEN); + if ((hp = ei_gethostbyname(h_hostname)) == 0) { + fprintf(stderr,"erl_call: can't resolve hostname %s\n", h_hostname); + exit(1); + } + /* If shortnames cut of the name at first '.' */ + if (flags.use_long_name == 0 && (ct = strchr(hp->h_name, '.')) != NULL) { + *ct = '\0'; + } + strcpy(h_hostname, hp->h_name); + memcpy(&h_ipadr.s_addr, *hp->h_addr_list, sizeof(struct in_addr)); + sprintf(h_nodename, "%s@%s", h_alivename, h_hostname); + + if (ei_connect_xinit(&ec, h_hostname, h_alivename, h_nodename, + (Erl_IpAddr)&h_ipadr, flags.cookie, + (short) creation) < 0) { + fprintf(stderr,"erl_call: can't create C node %s; %d\n", + h_nodename, erl_errno); + exit(1); + } + + } + if ((p = strchr((const char *)flags.node, (int) '@')) == 0) { + strcpy(host_name, ei_thishostname(&ec)); + host = host_name; + } else { + *p = 0; + host = p+1; + } + + /* + * Expand name to a real name (may be ip-address) + */ + /* FIXME better error string */ + if ((hp = get_hostent(host)) == 0) { + fprintf(stderr,"erl_call: can't get_hostent(%s)\n", host); + exit(1); + } + /* If shortnames cut of the name at first '.' */ + if (flags.use_long_name == 0 && (ct = strchr(hp->h_name, '.')) != NULL) { + *ct = '\0'; + } + strcpy(host_name, hp->h_name); + sprintf(nodename, "%s@%s", flags.node, host_name); + + /* + * Try to connect. Start an Erlang system if the + * start option is on and no system is running. + */ + if (flags.startp && !flags.haltp) { + fd = do_connect(&ec, nodename, &flags); + } else if ((fd = ei_connect(&ec, nodename)) < 0) { + /* We failed to connect ourself */ + /* FIXME do we really know we failed because of node not up? */ + if (flags.haltp) { + exit(0); + } else { + fprintf(stderr,"erl_call: failed to connect to node %s\n", + nodename); + exit(1); + } + } + + /* If we are connected and the halt switch is set */ + if (fd && flags.haltp) { + int i = 0; + char *p; + ei_x_buff reply; + + ei_encode_empty_list(NULL, &i); + + p = (char *)malloc(i); + i = 0; /* Reset */ + + ei_encode_empty_list(p, &i); + + ei_x_new_with_version(&reply); + + /* FIXME if fails we want to exit != 0 ? */ + ei_rpc(&ec, fd, "erlang", "halt", p, i, &reply); + free(p); + ei_x_free(&reply); + exit(0); + } + + if (flags.verbosep) { + fprintf(stderr,"erl_call: we are now connected to node \"%s\"\n", + nodename); + } + + /* + * Compile the module read from stdin. + */ + if (flags.modp && (modname != NULL)) { + char fname[256]; + + strcpy(fname, modname); + strcat(fname, ".erl"); + + /* + * ei_format("[~s,~w]", fname, erl_mk_binary(module, modsize)); + */ + + { + int i = 0; + char *p; + ei_x_buff reply; + + ei_encode_list_header(NULL, &i, 2); + ei_encode_string(NULL, &i, fname); + ei_encode_binary(NULL, &i, module, modsize); + ei_encode_empty_list(NULL, &i); + + p = (char *)malloc(i); + i = 0; /* Reset */ + + ei_encode_list_header(p, &i, 2); + ei_encode_string(p, &i, fname); + ei_encode_binary(p, &i, module, modsize); + ei_encode_empty_list(p, &i); + + ei_x_new_with_version(&reply); + + if (ei_rpc(&ec, fd, "file", "write_file", p, i, &reply) < 0) { + free(p); + ei_x_free(&reply); + fprintf(stderr,"erl_call: can't write to source file %s\n", + fname); + exit(1); + } + free(p); + ei_x_free(&reply); + } + + /* Compile AND load file on other node */ + + { + int i = 0; + char *p; + ei_x_buff reply; + + ei_encode_list_header(NULL, &i, 2); + ei_encode_atom(NULL, &i, fname); + ei_encode_empty_list(NULL, &i); + ei_encode_empty_list(NULL, &i); + + p = (char *)malloc(i); + i = 0; /* Reset */ + + ei_encode_list_header(p, &i, 2); + ei_encode_atom(p, &i, fname); + ei_encode_empty_list(p, &i); + ei_encode_empty_list(p, &i); + + ei_x_new_with_version(&reply); + + /* erl_format("[~a,[]]", modname) */ + + if (ei_rpc(&ec, fd, "c", "c", p, i, &reply) < 0) { + free(p); + ei_x_free(&reply); + fprintf(stderr,"erl_call: can't compile file %s\n", fname); + } + free(p); + /* FIXME complete this code + FIXME print out error message as term + if (!erl_match(erl_format("{ok,_}"), reply)) { + fprintf(stderr,"erl_call: compiler errors\n"); + } + */ + ei_x_free(&reply); + } + + } + /* + * Eval the Erlang functions read from stdin/ + */ + if (flags.evalp) { + char *evalbuf; + int len; + + len = read_stdin(&evalbuf); + { + int i = 0; + char *p; + ei_x_buff reply; + + ei_encode_list_header(NULL, &i, 1); + ei_encode_binary(NULL, &i, evalbuf, len); + ei_encode_empty_list(NULL, &i); + + p = (char *)malloc(i); + i = 0; /* Reset */ + + ei_encode_list_header(p, &i, 1); + ei_encode_binary(p, &i, evalbuf, len); + ei_encode_empty_list(p, &i); + + ei_x_new_with_version(&reply); + + /* erl_format("[~w]", erl_mk_binary(evalbuf,len))) */ + + if (ei_rpc(&ec, fd, "lib", "eval_str", p, i, &reply) < 0) { + fprintf(stderr,"erl_call: evaluating input failed: %s\n", + evalbuf); + free(p); + free(evalbuf); /* Allocated in read_stdin() */ + ei_x_free(&reply); + exit(1); + } + i = 0; + ei_print_term(stdout,reply.buff,&i); + free(p); + free(evalbuf); /* Allocated in read_stdin() */ + ei_x_free(&reply); + } + } + /* + * Any Erlang call to be made ? + */ + if (flags.apply != NULL) { + char *mod,*fun,*args; + ei_x_buff e, reply; + + split_apply_string(flags.apply, &mod, &fun, &args); + if (flags.verbosep) { + fprintf(stderr,"erl_call: module = %s, function = %s, args = %s\n", + mod, fun, args); + } + + ei_x_new(&e); /* No version to ei_rpc() */ + + if (ei_x_format_wo_ver(&e, args) < 0) { + /* FIXME no error message and why -1 ? */ + exit(-1); + } + + ei_x_new_with_version(&reply); + + if (ei_rpc(&ec, fd, mod, fun, e.buff, e.index, &reply) < 0) { + /* FIXME no error message and why -1 ? */ + ei_x_free(&e); + ei_x_free(&reply); + exit(-1); + } else { + int i = 0; + ei_print_term(stdout,reply.buff,&i); + ei_x_free(&e); + ei_x_free(&reply); + } + } + + return(0); +} + + +/*************************************************************************** + * + * XXXXX + * + ***************************************************************************/ + +/* + * Get host entry (by address or name) + */ +/* FIXME: will fail on names like '2fun4you'. */ +static struct hostent* get_hostent(char *host) +{ + if (isdigit((int)*host)) { + struct in_addr ip_addr; + int b1, b2, b3, b4; + long addr; + + /* FIXME: Use inet_aton() (or inet_pton() and get v6 for free). */ + if (sscanf(host, "%d.%d.%d.%d", &b1, &b2, &b3, &b4) != 4) { + return NULL; + } + addr = inet_addr(host); + ip_addr.s_addr = htonl(addr); + + return ei_gethostbyaddr((char *)&ip_addr,sizeof(struct in_addr), AF_INET); + } + + return ei_gethostbyname(host); +} /* get_hostent */ + + + + +/* + * This function does only return on success. + */ +static int do_connect(ei_cnode *ec, char *nodename, struct call_flags *flags) +{ + int fd; + int start_flags; + int r; + + start_flags = ERL_START_ENODE | + (flags->use_long_name? ERL_START_LONG : 0) | + (flags->verbosep? ERL_START_VERBOSE : 0) | + (flags->debugp? ERL_START_DEBUG : 0); + + if ((fd = ei_connect(ec, nodename)) >= 0) { + /* success */ + if (flags->verbosep) { + fprintf(stderr,"erl_call: now connected to node %s\n", nodename); + } + } else { + char alive[EI_MAXALIVELEN+1]; + char *hostname; + struct hostent *h; + char *cookieargs[3]; + char **args; + + cookieargs[0] = "-setcookie"; + cookieargs[1] = flags->cookie; + cookieargs[2] = NULL; + + args = (flags->cookie) ? cookieargs : NULL; + + if (!(hostname = strrchr(nodename,'@'))) { + return ERL_BADARG; + } + strncpy(alive,nodename,hostname-nodename); + alive[hostname-nodename] = 0x0; + hostname++; + + h = ei_gethostbyname(hostname); + + + if ((r=erl_start_sys(ec,alive,(Erl_IpAddr)(h->h_addr_list[0]), + start_flags,flags->script,args)) < 0) { + fprintf(stderr,"erl_call: unable to start node, error = %d\n", r); + exit(1); + } + + if ((fd=ei_connect(ec, nodename)) >= 0) { + /* success */ + if (flags->verbosep) { + fprintf(stderr,"erl_call: now connected to node \"%s\"\n", + nodename); + } + } else { + /* (failure) */ + switch (fd) { + case ERL_NO_DAEMON: + fprintf(stderr,"erl_call: no epmd running\n"); + exit(1); + case ERL_CONNECT_FAIL: + fprintf(stderr,"erl_call: connect failed\n"); + exit(1); + case ERL_NO_PORT: + fprintf(stderr,"erl_call: node is not running\n"); + exit(1); + case ERL_TIMEOUT: + fprintf(stderr,"erl_call: connect timed out\n"); + exit(1); + default: + fprintf(stderr,"erl_call: error during connect\n"); + exit(1); + } + } + } + + return fd; +} /* do_connect */ + +#define SKIP_SPACE(s) while(isspace((int)*(s))) (s)++ +#define EAT(s) while (!isspace((int)*(s)) && (*(s) != '\0')) (s)++ + +static void split_apply_string(char *str, + char **mod, + char **fun, + char **args) +{ + char *begin=str; + char *start="start"; + char *empty_list="[]"; + int len; + + SKIP_SPACE(str); + if (*str == '\0') { + fprintf(stderr,"erl_call: wrong format of apply string (1)\n"); + exit(1); + } + + EAT(str); + len = str-begin; + *mod = (char *) calloc(len + 1, sizeof(char)); + memcpy(*mod, begin, len); + + SKIP_SPACE(str); + if (*str == '\0') { + *fun = (char *) calloc(strlen(start)+1, sizeof(char)); + strcpy(*fun, start); + *args = (char *) calloc(strlen(empty_list)+1, sizeof(char)); + strcpy(*args, empty_list); + return; + } + begin = str; + EAT(str); + len = str-begin; + *fun = (char *) calloc(len + 1, sizeof(char)); + memcpy(*fun, begin, len); + + SKIP_SPACE(str); + if (*str == '\0') { + *args = (char *) calloc(strlen(empty_list)+1, sizeof(char)); + strcpy(*args, empty_list); + return; + } + + *args = (char *) calloc(strlen(str) + 1, sizeof(char)); + strcpy(*args, str); + + return; + +} /* split_apply_string */ + + +/* + * Read from stdin until EOF is reached. + * Allocate the buffer needed. + */ +static int read_stdin(char **buf) +{ + int bsize = BUFSIZ; + int len = 0; + int i; + char *tmp = (char *) malloc(bsize); + + while (1) { + if ((i = read(0, &tmp[len], bsize-len)) < 0) { + fprintf(stderr,"erl_call: can't read stdin, errno = %d", errno); + exit(1); + } else if (i == 0) { + break; + } else { + len += i; + if ((len+50) > bsize) { + bsize = len * 2; + tmp = (char *) realloc(tmp, bsize); + } else { + continue; + } + } + } /* while */ + *buf = tmp; + return len; + +} /* read_stdin */ + +/* + * Get the module from stdin. + */ +static int get_module(char **mbuf, char **mname) +{ + char *tmp; + int len,i; + + len = read_stdin(mbuf); + /* + * Now, get the module name. + */ + if ((tmp = strstr(*mbuf, "-module(")) != NULL) { + char *start; + tmp += strlen("-module("); + while ((*tmp) == ' ') tmp++; /* eat space */ + start = tmp; + while (1) { + if (isalnum((int)*tmp) || (*tmp == '_')) { + tmp++; + continue; + } else { + break; + } + } /* while */ + i = tmp - start; + *mname = (char *) calloc(i+1, sizeof(char)); + memcpy(*mname, start, i); + } + free(mbuf); /* Allocated in read_stdin() */ + + return len; + +} /* get_module */ + + +/*************************************************************************** + * + * Different error reporting functions that output usage + * + ***************************************************************************/ + +static void usage_noexit(const char *progname) { + fprintf(stderr,"\nUsage: %s [-[demqrsv]] [-c Cookie] [-h HiddenName] \n", progname); + fprintf(stderr," [-x ErlScript] [-a [Mod [Fun [Args]]]]\n"); + fprintf(stderr," (-n Node | -sname Node | -name Node)\n\n"); +#ifdef __WIN32__ + fprintf(stderr," where: -a apply(Mod,Fun,Args) (e.g -a \"erlang length [[a,b,c]]\"\n"); +#else + fprintf(stderr," where: -a apply(Mod,Fun,Args) (e.g -a 'erlang length [[a,b,c]]'\n"); +#endif + fprintf(stderr," -c cookie string; by default read from ~/.erlang.cookie\n"); + fprintf(stderr," -d direct Erlang output to ~/.erl_call.out.\n"); + fprintf(stderr," -e evaluate contents of standard input (e.g echo \"X=1,Y=2,{X,Y}.\"|erl_call -e ...)\n"); + fprintf(stderr," -h specify a name for the erl_call client node\n"); + fprintf(stderr," -m read and compile Erlang module from stdin\n"); + fprintf(stderr," -n name of Erlang node, same as -name\n"); + fprintf(stderr," -name name of Erlang node, expanded to a fully qualified\n"); + fprintf(stderr," -sname name of Erlang node, short form will be used\n"); + fprintf(stderr," -q halt the Erlang node (overrides the -s switch)\n"); + fprintf(stderr," -r use a random name for the erl_call client node\n"); + fprintf(stderr," -s start a new Erlang node if necessary\n"); + fprintf(stderr," -v verbose mode, i.e print some information on stderr\n"); + fprintf(stderr," -x use specified erl start script, default is erl\n"); +} + +static void usage_arg(const char *progname, const char *switchname) { + fprintf(stderr, "Missing argument(s) for \'%s\'.\n", switchname); + usage_noexit(progname); + exit(1); +} + +static void usage_error(const char *progname, const char *switchname) { + fprintf(stderr, "Illegal argument \'%s\'.\n", switchname); + usage_noexit(progname); + exit(1); +} + +static void usage(const char *progname) { + usage_noexit(progname); + exit(0); +} + + +/*************************************************************************** + * + * OS specific functions + * + ***************************************************************************/ + +#ifdef __WIN32__ +/* + * FIXME This should not be here. This is a quick fix to make erl_call + * work at all on Windows NT. + */ +static void initWinSock(void) +{ + WORD wVersionRequested; + WSADATA wsaData; + int err; + static int initialized; + + wVersionRequested = MAKEWORD(1, 1); + if (!initialized) { + initialized = 1; + err = WSAStartup(wVersionRequested, &wsaData); + + if (err != 0) { + fprintf(stderr,"erl_call: " + "Can't initialize windows sockets: %d\n", err); + } + + if ( LOBYTE( wsaData.wVersion ) != 1 || + HIBYTE( wsaData.wVersion ) != 1 ) { + fprintf(stderr,"erl_call: This version of " + "windows sockets not supported\n"); + WSACleanup(); + } + } +} +#endif diff --git a/lib/erl_interface/src/prog/erl_fake_prog.c b/lib/erl_interface/src/prog/erl_fake_prog.c new file mode 100644 index 0000000000..a2b49a0ed9 --- /dev/null +++ b/lib/erl_interface/src/prog/erl_fake_prog.c @@ -0,0 +1,250 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2002-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +/*************************************************************************** + * + * This is a fake program that contains all functions, variables and + * defined symbols mentioned in the manual. We compile this file to see + * that the header files and created library is complete. + * + * You can't run this program, it is for compiling and linking only. + * + ***************************************************************************/ + +/* Use most of + * CFLAGS="-I../include -g -O2 + * -ansi -pedantic + * -Wall + * -Wshadow + * -Wstrict-prototypes + * -Wmissing-prototypes + * -Wmissing-declarations + * -Wnested-externs + * -Winline + * -Werror" + */ + +/* #include now included by ei.h */ +#include "erl_interface.h" + +#ifdef VXWORKS +int erl_fake_prog_main(void) +#else +int main(void) +#endif +{ + ei_x_buff eix; + int index = 0; + ETERM **etermpp = NULL, *etermp = NULL; + char *charp = NULL; + unsigned char uchar, **ucharpp = NULL, *ucharp = NULL; + void *voidp = NULL; + Erl_Heap *erl_heapp = NULL; + int intx = 0; + int *intp = NULL; + unsigned int uintx, *uintp; + unsigned long *ulongp = NULL; + long longx = 0; + double doublex = 0.0; + short shortx = 42; + FILE *filep = NULL; + Erl_IpAddr erl_ipaddr = NULL; + ErlMessage *erlmessagep = NULL; + ErlConnect *erlconnectp = NULL; + struct hostent *hostp = NULL; + struct in_addr *inaddrp = NULL; + + /* Converion to erl_interface format is in liberl_interface */ + + intx = erl_errno; + + ei_encode_term(charp, &index, voidp); + ei_x_encode_term(&eix, voidp); + ei_decode_term(charp, &index, voidp); + + erl_init(voidp, longx); + erl_connect_init(intx, charp,shortx); + erl_connect_xinit(charp,charp,charp,erl_ipaddr,charp,shortx); + erl_connect(charp); + erl_xconnect(erl_ipaddr,charp); + erl_close_connection(intx); + erl_receive(intx, ucharp, intx); + erl_receive_msg(intx, ucharp, intx, erlmessagep); + erl_xreceive_msg(intx, ucharpp, intp, erlmessagep); + erl_send(intx, etermp, etermp); + erl_reg_send(intx, charp, etermp); + erl_rpc(intx,charp,charp,etermp); + erl_rpc_to(intx,charp,charp,etermp); + erl_rpc_from(intx,intx,erlmessagep); + + erl_publish(intx); + erl_accept(intx,erlconnectp); + + erl_thiscookie(); + erl_thisnodename(); + erl_thishostname(); + erl_thisalivename(); + erl_thiscreation(); + erl_unpublish(charp); + erl_err_msg(charp); + erl_err_quit(charp); + erl_err_ret(charp); + erl_err_sys(charp); + + erl_cons(etermp,etermp); + erl_copy_term(etermp); + erl_element(intx,etermp); + + erl_hd(etermp); + erl_iolist_to_binary(etermp); + erl_iolist_to_string(etermp); + erl_iolist_length(etermp); + erl_length(etermp); + erl_mk_atom(charp); + erl_mk_binary(charp,intx); + erl_mk_empty_list(); + erl_mk_estring(charp, intx); + erl_mk_float(doublex); + erl_mk_int(intx); + erl_mk_list(etermpp,intx); + erl_mk_pid(charp,uintx,uintx,uchar); + erl_mk_port(charp,uintx,uchar); + erl_mk_ref(charp,uintx,uchar); + erl_mk_long_ref(charp,uintx,uintx,uintx,uchar); + erl_mk_string(charp); + erl_mk_tuple(etermpp,intx); + erl_mk_uint(uintx); + erl_mk_var(charp); + erl_print_term(filep,etermp); + /* erl_sprint_term(charp,etermp); */ + erl_size(etermp); + erl_tl(etermp); + erl_var_content(etermp, charp); + + erl_format(charp); + erl_match(etermp, etermp); + + erl_global_names(intx, intp); + erl_global_register(intx, charp, etermp); + erl_global_unregister(intx, charp); + erl_global_whereis(intx, charp, charp); + + erl_init_malloc(erl_heapp,longx); + erl_alloc_eterm(uchar); + erl_eterm_release(); + erl_eterm_statistics(ulongp,ulongp); + erl_free_array(etermpp,intx); + erl_free_term(etermp); + erl_free_compound(etermp); + erl_malloc(longx); + erl_free(voidp); + + erl_compare_ext(ucharp, ucharp); + erl_decode(ucharp); + erl_decode_buf(ucharpp); + erl_encode(etermp,ucharp); + erl_encode_buf(etermp,ucharpp); + erl_ext_size(ucharp); + erl_ext_type(ucharp); + erl_peek_ext(ucharp,intx); + erl_term_len(etermp); + + erl_gethostbyname(charp); + erl_gethostbyaddr(charp, intx, intx); + erl_gethostbyname_r(charp, hostp, charp, intx, intp); + erl_gethostbyaddr_r(charp, intx, intx, hostp, charp, intx, intp); + + erl_init_resolve(); + erl_distversion(intx); + + erl_epmd_connect(inaddrp); + erl_epmd_port(inaddrp, charp, intp); + + charp = ERL_ATOM_PTR(etermp); + intx = ERL_ATOM_SIZE(etermp); + ucharp = ERL_BIN_PTR(etermp); + intx = ERL_BIN_SIZE(etermp); + etermp = ERL_CONS_HEAD(etermp); + etermp = ERL_CONS_TAIL(etermp); + intx = ERL_COUNT(etermp); + doublex= ERL_FLOAT_VALUE(etermp); + uintx = ERL_INT_UVALUE(etermp); + intx = ERL_INT_VALUE(etermp); + intx = ERL_IS_ATOM(etermp); + intx = ERL_IS_BINARY(etermp); + intx = ERL_IS_CONS(etermp); + intx = ERL_IS_EMPTY_LIST(etermp); + intx = ERL_IS_FLOAT(etermp); + intx = ERL_IS_INTEGER(etermp); + intx = ERL_IS_LIST(etermp); + intx = ERL_IS_PID(etermp); + intx = ERL_IS_PORT(etermp); + intx = ERL_IS_REF(etermp); + intx = ERL_IS_TUPLE(etermp); + intx = ERL_IS_UNSIGNED_INTEGER(etermp); + uchar = ERL_PID_CREATION(etermp); + charp = ERL_PID_NODE(etermp); + uintx = ERL_PID_NUMBER(etermp); + uintx = ERL_PID_SERIAL(etermp); + uchar = ERL_PORT_CREATION(etermp); + charp = ERL_PORT_NODE(etermp); + uintx = ERL_PORT_NUMBER(etermp); + uchar = ERL_REF_CREATION(etermp); + intx = ERL_REF_LEN(etermp); + charp = ERL_REF_NODE(etermp); + uintx = ERL_REF_NUMBER(etermp); + uintp = ERL_REF_NUMBERS(etermp); + etermp = ERL_TUPLE_ELEMENT(etermp,intx); + intx = ERL_TUPLE_SIZE(etermp); + + return + BUFSIZ + + EAGAIN + + EHOSTUNREACH + + EINVAL + + EIO + + EMSGSIZE + + ENOMEM + + ERL_ATOM + + ERL_BINARY + + ERL_ERROR + + ERL_EXIT + + ERL_FLOAT + + ERL_INTEGER + + ERL_LINK + + ERL_LIST + + ERL_MSG + + ERL_NO_TIMEOUT + + ERL_PID + + ERL_PORT + + ERL_REF + + ERL_REG_SEND + + ERL_SEND + + ERL_SMALL_BIG + + ERL_TICK + + ERL_TIMEOUT + + ERL_TUPLE + + ERL_UNLINK + + ERL_U_INTEGER + + ERL_U_SMALL_BIG + + ERL_VARIABLE + + ETIMEDOUT + + MAXNODELEN + + MAXREGLEN; +} diff --git a/lib/erl_interface/src/prog/erl_start.c b/lib/erl_interface/src/prog/erl_start.c new file mode 100644 index 0000000000..a53aab9ac7 --- /dev/null +++ b/lib/erl_interface/src/prog/erl_start.c @@ -0,0 +1,735 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1997-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ + +/* An exception from using eidef.h, use config.h directly */ +#include "config.h" + +#include +#include +#include + +#ifdef __WIN32__ +#include +#include +#include + +#elif VXWORKS +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#include + +/* #include "netdb.h" */ +#else /* other unix */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include "ei.h" +#include "ei_resolve.h" +#include "erl_start.h" + +/* FIXME is this a case a vfork can be used? */ +#if !HAVE_WORKING_VFORK +# define vfork fork +#endif + +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif + +#ifndef RSH +#define RSH "/usr/bin/rsh" +#endif + +#ifndef HAVE_SOCKLEN_T +typedef int SocklenType; +#else +typedef socklen_t SocklenType; +#endif + +/* FIXME check errors from malloc */ + +static struct in_addr *get_addr(const char *hostname, struct in_addr *oaddr); + +static int wait_for_erlang(int sockd, int magic, struct timeval *timeout); +#if defined(VXWORKS) || defined(__WIN32__) +static int unique_id(void); +static unsigned long spawn_erlang_epmd(ei_cnode *ec, + char *alive, + Erl_IpAddr adr, + int flags, + char *erl_or_epmd, + char *args[], + int port, + int is_erlang); +#else +static int exec_erlang(ei_cnode *ec, char *alive, Erl_IpAddr adr, int flags, + char *erl, char *args[],int port); +#endif +/* Start an Erlang node. return value 0 indicates that node was + * started successfully, negative values indicate error. + * + * node - the name of the remote node to start (alivename@hostname). + * flags - turn on or off certain options. See erl_start.h for a list. + * erl - is the name of the erl script to call. If NULL, the default + * name "erl" will be used. + * args - a NULL-terminated list of strings containing + * additional arguments to be sent to the remote Erlang node. These + * strings are simply appended to the end of the command line, so any + * quoting of special characters, etc must be done by the caller. + * There may be some conflicts between some of these arguments and the + * default arguments hard-coded into this function, so be careful. + */ +int erl_start_sys(ei_cnode *ec, char *alive, Erl_IpAddr adr, int flags, + char *erl, char *args[]) +{ + struct timeval timeout; + struct sockaddr_in addr; + SocklenType namelen; + int port; + int sockd = 0; + int one = 1; +#if defined(VXWORKS) || defined(__WIN32__) + unsigned long pid = 0; +#else + int pid = 0; +#endif + int r = 0; + + if (((sockd = socket(AF_INET, SOCK_STREAM, 0)) < 0) || + (setsockopt(sockd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)) < 0)) { + r = ERL_SYS_ERROR; + goto done; + } + + memset(&addr,0,sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = 0; + + if (bind(sockd,(struct sockaddr *)&addr,sizeof(addr))<0) { + return ERL_SYS_ERROR; + } + namelen = sizeof(addr); + if (getsockname(sockd,(struct sockaddr *)&addr,&namelen)<0) { + return ERL_SYS_ERROR; + } + port = ntohs(addr.sin_port); + + listen(sockd,5); + +#if defined(VXWORKS) || defined(__WIN32__) + if((pid = spawn_erlang_epmd(ec,alive,adr,flags,erl,args,port,1)) + == 0) + return ERL_SYS_ERROR; + timeout.tv_usec = 0; + timeout.tv_sec = 10; /* ignoring ERL_START_TIME */ + if((r = wait_for_erlang(sockd,unique_id(),&timeout)) + == ERL_TIMEOUT) { +#if defined(VXWORKS) + taskDelete((int) pid); + if(taskIdVerify((int) pid) != ERROR) + taskDeleteForce((int) pid); +#else /* Windows */ + /* Well, this is not a nice way to do it, and it does not + always kill the emulator, but the alternatives are few.*/ + TerminateProcess((HANDLE) pid,1); +#endif /* defined(VXWORKS) */ + } +#else /* Unix */ + switch ((pid = fork())) { + case -1: + r = ERL_SYS_ERROR; + break; + + case 0: + /* child - start the erlang node */ + exec_erlang(ec, alive, adr, flags, erl, args, port); + + /* error if reached - parent reports back to caller after timeout + so we just exit here */ + exit(1); + break; + + default: + + /* parent - waits for response from Erlang node */ + /* child pid used here as magic number */ + timeout.tv_usec = 0; + timeout.tv_sec = 10; /* ignoring ERL_START_TIME */ + if ((r = wait_for_erlang(sockd,pid,&timeout)) == ERL_TIMEOUT) { + /* kill child if no response */ + kill(pid,SIGINT); + sleep(1); + if (waitpid(pid,NULL,WNOHANG) != pid) { + /* no luck - try harder */ + kill(pid,SIGKILL); + sleep(1); + waitpid(pid,NULL,WNOHANG); + } + } + + } +#endif /* defined(VXWORKS) || defined(__WIN32__) */ + +done: +#if defined(__WIN32__) + if (sockd) closesocket(sockd); +#else + if (sockd) close(sockd); +#endif + return r; +} /* erl_start_sys() */ + +#if defined(VXWORKS) || defined(__WIN32__) +#if defined(VXWORKS) +#define DEF_ERL_COMMAND "" +#define DEF_EPMD_COMMAND "" +#define ERLANG_SYM "start_erl" +#define EPMD_SYM "start_epmd" +#define ERL_REPLY_FMT "-s erl_reply reply %s %d %d" +#else +#define DEF_ERL_COMMAND "erl" +#define DEF_EPMD_COMMAND "epmd" +#define ERL_REPLY_FMT "-s erl_reply reply \"%s\" \"%d\" \"%d\"" +#endif +#define ERL_NAME_FMT "-noinput -name %s" +#define ERL_SNAME_FMT "-noinput -sname %s" + +#define IP_ADDR_CHARS 15 +#define FORMATTED_INT_LEN 10 + +static int unique_id(void){ +#if defined(VXWORKS) + return taskIdSelf(); +#else + return (int) GetCurrentThreadId(); +#endif +} + +static int enquote_args(char **oargs, char ***qargs){ + char **args; + int len; + int i; + int qwhole; + int extra; + char *ptr; + char *ptr2; + + if(oargs == NULL){ + *qargs = malloc(sizeof(char *)); + **qargs = NULL; + return 0; + }; + + for(len=0;oargs[len] != NULL; ++len) + ; + args = malloc(sizeof(char *) * (len + 1)); + + for(i = 0; i < len; ++i){ + qwhole = strchr(oargs[i],' ') != NULL; + extra = qwhole * 2; + for(ptr = oargs[i]; *ptr != '\0'; ++ptr) + extra += (*ptr == '"'); + args[i] = malloc(strlen(oargs[i]) + + extra + + 1); + ptr2 = args[i]; + if(qwhole) + *(ptr2++) = '"'; + for(ptr = oargs[i]; *ptr != '\0'; ++ptr){ + if(*ptr == '"') + *(ptr2++) = '\\'; + *(ptr2++) = *ptr; + } + if(qwhole) + *(ptr2++) = '"'; + *ptr2 = '\0'; + } + args[len] = NULL; + *qargs = args; + return len; +} + +static void free_args(char **args){ + char **ptr = args; + while(*ptr != NULL) + free(*(ptr++)); + free(args); +} + +#if defined(VXWORKS) +static FUNCPTR lookup_function(char *symname){ + char *value; + SYM_TYPE type; + if(symFindByName(sysSymTbl, + symname, + &value, + &type) == ERROR /*|| type != N_TEXT*/) + return NULL; + return (FUNCPTR) value; +} +#endif /* defined(VXWORKS) */ + +/* In NT and VxWorks, we cannot fork(), Erlang and Epmd gets + spawned by this function instead. */ + +static unsigned long spawn_erlang_epmd(ei_cnode *ec, + char *alive, + Erl_IpAddr adr, + int flags, + char *erl_or_epmd, + char *args[], + int port, + int is_erlang) +{ +#if defined(VXWORKS) + FUNCPTR erlfunc; +#else /* Windows */ + STARTUPINFO sinfo; + SECURITY_ATTRIBUTES sa; + PROCESS_INFORMATION pinfo; +#endif + char *cmdbuf; + int cmdlen; + char *ptr; + int i; + int num_args; + char *name_format; + struct in_addr myaddr; + struct in_addr *hisaddr = (struct in_addr *)adr; + char iaddrbuf[IP_ADDR_CHARS + 1]; + int ret; + + if(is_erlang){ + get_addr(ei_thishostname(ec), &myaddr); +#if defined(VXWORKS) + inet_ntoa_b(myaddr, iaddrbuf); +#else /* Windows */ + if((ptr = inet_ntoa(myaddr)) == NULL) + return 0; + else + strcpy(iaddrbuf,ptr); +#endif + } + if ((flags & ERL_START_REMOTE) || + (is_erlang && (hisaddr->s_addr != myaddr.s_addr))) { + return 0; + } else { + num_args = enquote_args(args, &args); + for(cmdlen = i = 0; args[i] != NULL; ++i) + cmdlen += strlen(args[i]) + 1; +#if !defined(VXWORKS) + /* On VxWorks, we dont actually run a command, + we call start_erl() */ + if(!erl_or_epmd) +#endif + erl_or_epmd = (is_erlang) ? DEF_ERL_COMMAND : + DEF_EPMD_COMMAND; + if(is_erlang){ + name_format = (flags & ERL_START_LONG) ? ERL_NAME_FMT : + ERL_SNAME_FMT; + cmdlen += + strlen(erl_or_epmd) + (*erl_or_epmd != '\0') + + strlen(name_format) + 1 + strlen(alive) + + strlen(ERL_REPLY_FMT) + 1 + strlen(iaddrbuf) + + 2 * FORMATTED_INT_LEN + + 1; + ptr = cmdbuf = malloc(cmdlen); + if(*erl_or_epmd != '\0') + ptr += sprintf(ptr,"%s ",erl_or_epmd); + ptr += sprintf(ptr, name_format, + alive); + ptr += sprintf(ptr, " " ERL_REPLY_FMT, + iaddrbuf, port, unique_id()); + } else { /* epmd */ + cmdlen += strlen(erl_or_epmd) + (*erl_or_epmd != '\0') + 1; + ptr = cmdbuf = malloc(cmdlen); + if(*erl_or_epmd != '\0') + ptr += sprintf(ptr,"%s ",erl_or_epmd); + else + *(ptr++) = '\0'; + } + for(i= 0; args[i] != NULL; ++i){ + *(ptr++) = ' '; + strcpy(ptr,args[i]); + ptr += strlen(args[i]); + } + free_args(args); + if (flags & ERL_START_VERBOSE) { + fprintf(stderr,"erl_call: commands are %s\n",cmdbuf); + } + /* OK, one single command line... */ +#if defined(VXWORKS) + erlfunc = lookup_function((is_erlang) ? ERLANG_SYM : + EPMD_SYM); + if(erlfunc == NULL){ + if (flags & ERL_START_VERBOSE) { + fprintf(stderr,"erl_call: failed to find symbol %s\n", + (is_erlang) ? ERLANG_SYM : EPMD_SYM); + } + ret = 0; + } else { + /* Just call it, it spawns itself... */ + ret = (unsigned long) + (*erlfunc)((int) cmdbuf,0,0,0,0,0,0,0,0,0); + if(ret == (unsigned long) ERROR) + ret = 0; + } +#else /* Windows */ + /* Hmmm, hidden or unhidden window??? */ + memset(&sinfo,0,sizeof(sinfo)); + sinfo.cb = sizeof(STARTUPINFO); + sinfo.dwFlags = STARTF_USESHOWWINDOW /*| + STARTF_USESTDHANDLES*/; + sinfo.wShowWindow = SW_HIDE; /* Hidden! */ + sinfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + sinfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); + sinfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = /*TRUE*/ FALSE; + if(!CreateProcess( + NULL, + cmdbuf, + &sa, + NULL, + /*TRUE*/ FALSE, + 0 | CREATE_NEW_CONSOLE, + NULL, + NULL, + &sinfo, + &pinfo)) + ret = 0; + else + ret = (unsigned long) pinfo.hProcess; +#endif + free(cmdbuf); + return ret; + } + /* NOTREACHED */ +} +#else /* Unix */ + +/* call this from the child process to start an erlang system. This + * function just builds the erlang command line and then calls it. + * + * node - the nodename for the new node + * flags - various options that can be set (see erl_start.h) + * erl - name of the erlang executable, or NULL for default ("erl") + * args - additional arguments to pass to erlang executable + * port - the port number where we wait for acknowledgment from the enode + * + * we have a potential problem if args conflicts with any of the + * arguments we use here. + */ +static int exec_erlang(ei_cnode *ec, + char *alive, + Erl_IpAddr adr, + int flags, + char *erl, + char *args[], + int port) +{ +#if !defined(__WIN32__) && !defined(VXWORKS) + int fd,len,l,i; + char **s; + char *argv[4]; + char argbuf[BUFSIZ]; + struct in_addr myaddr; + struct in_addr *hisaddr = (struct in_addr *)adr; + + get_addr(ei_thishostname(ec), &myaddr); + + /* on this host? */ + /* compare ip addresses, unless forced by flag setting to use rsh */ + if ((flags & ERL_START_REMOTE) || (hisaddr->s_addr != myaddr.s_addr)) { + argv[0] = RSH; + len = strlen(inet_ntoa(*hisaddr)); + argv[1] = malloc(len+1); + strcpy(argv[1],inet_ntoa(*hisaddr)); + } + else { + /* Yes - use sh to start local Erlang */ + argv[0] = "sh"; + argv[1] = "-c"; + } + argv[2] = argbuf; + argv[3] = NULL; + + len = 0; + *argbuf=(char)0; + + sprintf(argbuf,"exec %s ", (erl? erl: "erl")); + len = strlen(argbuf); + + /* *must* be noinput or node (seems to) hang... */ + /* long or short names? */ + sprintf(&argbuf[len], "-noinput %s %s ", + ((flags & ERL_START_LONG) ? "-name" : "-sname"), + alive); + len = strlen(argbuf); + + /* now make the new node report back when it's ready */ + /* add: myip, myport and replymsg */ + sprintf(&argbuf[len], + "-s erl_reply reply %s %d %d ", + inet_ntoa(myaddr),port,(int)getpid()); +#ifdef DEBUG + fprintf(stderr,"erl_call: debug %s\n",&argbuf[len]); +#endif + len = strlen(argbuf); + + /* additional arguments to be passed to the other system */ + /* make sure that they will fit first */ + for (l=0, s = args; s && *s; s++) l+= strlen(*s) + 1; + + if (len + l + 1 > BUFSIZ) return ERL_BADARG; + else { + for (s = args; s && *s; s++) { + strcat(argbuf," "); + strcat(argbuf,*s); + } + len += l + 1; + } + + if (flags & ERL_START_VERBOSE) { + fprintf(stderr,"erl_call: %s %s %s\n",argv[0],argv[1],argv[2]); + } + + /* close all descriptors in child */ + for (i=0; i<64; i++) close(i); + + /* debug output to file? */ + if (flags & ERL_START_DEBUG) { + char debugfile[MAXPATHLEN+1]; + char *home=getenv("HOME"); + sprintf(debugfile,"%s/%s.%s",home,ERL_START_LOGFILE,alive); + if ((fd=open(debugfile, O_WRONLY | O_CREAT | O_APPEND, 0644)) >= 0) { + time_t t = time(NULL); + dup2(fd,1); + dup2(fd,2); + fprintf(stderr,"\n\n===== Log started ======\n%s \n",ctime(&t)); + fprintf(stderr,"erl_call: %s %s %s\n",argv[0],argv[1],argv[2]); + } + } + + /* start the system */ + execvp(argv[0], argv); + + if (flags & ERL_START_DEBUG) { + fprintf(stderr,"erl_call: exec failed: (%d) %s %s %s\n", + errno,argv[0],argv[1],argv[2]); + } + +#endif + /* (hopefully) NOT REACHED */ + return ERL_SYS_ERROR; +} /* exec_erlang() */ + +#endif /* defined(VXWORKS) || defined(WINDOWS) */ + +#if defined(__WIN32__) +static void gettimeofday(struct timeval *now,void *dummy){ + SYSTEMTIME systime; + FILETIME ft; + DWORD x; + GetSystemTime(&systime); + SystemTimeToFileTime(&systime,&ft); + x = ft.dwLowDateTime / 10; + now->tv_sec = x / 1000000; + now->tv_usec = x % 1000000; +} + +#elif defined(VXWORKS) +static void gettimeofday(struct timeval *now, void *dummy){ + int rate = sysClkRateGet(); /* Ticks per second */ + unsigned long ctick = tickGet(); + now->tv_sec = ctick / rate; /* secs since reboot */ + now->tv_usec = ((ctick - (now->tv_sec * rate))*1000000)/rate; +} +#endif + + +/* wait for the remote system to reply */ +/* + * sockd - an open socket where we expect a connection from the e-node + * magic - sign on message the e-node must provide for verification + * timeout - how long to wait before returning failure + * + * OBS: the socket is blocking, and there is a potential deadlock if we + * get an accept but the peer sends no data (and does not close). + * in normal cases the timeout will work ok however, i.e. either we + * never get any connection, or we get connection then close(). + */ +static int wait_for_erlang(int sockd, int magic, struct timeval *timeout) +{ + struct timeval to; + struct timeval stop_time; + struct timeval now; + fd_set rdset; + int fd; + int n,i; + char buf[16]; + struct sockaddr_in peer; + SocklenType len = (SocklenType) sizeof(peer); + + /* determine when we should exit this function */ + gettimeofday(&now,NULL); + stop_time.tv_sec = now.tv_sec + timeout->tv_sec; + stop_time.tv_usec = now.tv_usec + timeout->tv_usec; + while (stop_time.tv_usec > 1000000) { + stop_time.tv_sec++; + stop_time.tv_usec -= 1000000; + } + +#ifdef DEBUG + fprintf(stderr,"erl_call: debug time is %ld.%06ld, " + "will timeout at %ld.%06ld\n", + now.tv_sec,now.tv_usec,stop_time.tv_sec,stop_time.tv_usec); +#endif + + while (1) { + FD_ZERO(&rdset); + FD_SET(sockd,&rdset); + + /* adjust the timeout to (stoptime - now) */ + gettimeofday(&now,NULL); + to.tv_sec = stop_time.tv_sec - now.tv_sec; + to.tv_usec = stop_time.tv_usec - now.tv_usec; + while ((to.tv_usec <= 0) && (to.tv_sec >= 0)) { + to.tv_usec += 1000000; + to.tv_sec--; + } + if (to.tv_sec < 0) return ERL_TIMEOUT; + +#ifdef DEBUG + fprintf(stderr,"erl_call: debug remaining to timeout: %ld.%06ld\n", + to.tv_sec,to.tv_usec); +#endif + switch ((i = select(sockd+1,&rdset,NULL,NULL,&to))) { + case -1: + return ERL_SYS_ERROR; + break; + + case 0: /* timeout */ +#ifdef DEBUG + gettimeofday(&now,NULL); + fprintf(stderr,"erl_call: debug timed out at %ld.%06ld\n", + now.tv_sec,now.tv_usec); +#endif + return ERL_TIMEOUT; + break; + + default: /* ready descriptors */ +#ifdef DEBUG + gettimeofday(&now,NULL); + fprintf(stderr,"erl_call: debug got select at %ld.%06ld\n", + now.tv_sec,now.tv_usec); +#endif + if (FD_ISSET(sockd,&rdset)) { + if ((fd = accept(sockd,(struct sockaddr *)&peer,&len)) < 0) + return ERL_SYS_ERROR; + + /* now get sign-on message and terminate it */ +#if defined(__WIN32__) + if ((n=recv(fd,buf,16,0)) >= 0) buf[n]=0x0; + closesocket(fd); +#else + if ((n=read(fd,buf,16)) >= 0) buf[n]=0x0; + close(fd); +#endif +#ifdef DEBUG + fprintf(stderr,"erl_call: debug got %d, expected %d\n", + atoi(buf),magic); +#endif + + if (atoi(buf) == magic) return 0; /* success */ + } /* if FD_SET */ + } /* switch */ + } /* while */ + + /* unreached? */ + return ERL_SYS_ERROR; +} /* wait_for_erlang() */ + + +static struct in_addr *get_addr(const char *hostname, struct in_addr *oaddr) +{ + struct hostent *hp; + +#if !defined (__WIN32__) + char buf[1024]; + struct hostent host; + int herror; + + hp = ei_gethostbyname_r(hostname,&host,buf,1024,&herror); +#else + hp = ei_gethostbyname(hostname); +#endif + + if (hp) { + memmove(oaddr,hp->h_addr_list[0],sizeof(*oaddr)); + return oaddr; + } + return NULL; +} diff --git a/lib/erl_interface/src/prog/erl_start.h b/lib/erl_interface/src/prog/erl_start.h new file mode 100644 index 0000000000..05f34864a7 --- /dev/null +++ b/lib/erl_interface/src/prog/erl_start.h @@ -0,0 +1,46 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1997-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#ifndef _ERL_START_H +#define _ERL_START_H + +#define ERL_START_MSG "gurka" /* make something up */ +#define ERL_START_TIME 10000 /* wait this long (ms) */ +#define ERL_START_LOGFILE ".erl_start.out" /* basename of logfile */ + +/* flags used by erl_connect and erl_xconnect */ +#define ERL_START_ENODE 0x0001 +#define ERL_START_EPMD 0x0002 +#define ERL_START_LONG 0x0004 +#define ERL_START_COOKIE 0x0008 +#define ERL_START_DEBUG 0x0010 +#define ERL_START_VERBOSE 0x0020 +#define ERL_START_REMOTE 0x0040 + +/* error return values */ +#define ERL_S_TIMEOUT -51 /* a timeout occurred */ +#define ERL_BADARG -52 /* an argument contained an incorrect value */ +#define ERL_SYS_ERROR -99 /* a system error occurred (check errno) */ + +/* start an erlang system */ +int erl_start_sys(ei_cnode *ec, char *alive, Erl_IpAddr addr, int flags, + char *erl, char *add_args[]); + +#endif /* _ERL_START_H */ diff --git a/lib/erl_interface/src/registry/hash.h b/lib/erl_interface/src/registry/hash.h new file mode 100644 index 0000000000..3886e8664b --- /dev/null +++ b/lib/erl_interface/src/registry/hash.h @@ -0,0 +1,47 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#ifndef _HASH_H +#define _HASH_H + +#include + +#include "ei.h" /* We need our types there */ + +#define ei_hash_size(tab) ((tab)->size) +#define ei_hash_count(tab) ((tab)->count) + +#define ALIGN_QUAD 0x7 +#define ei_align(size) while (((unsigned)size) & ALIGN_QUAD) (size)++ + +int ei_isprime(int n); +int ei_dohash(const char *key); +void *ei_hash_lookup(ei_hash *tab, const char *key); +const char *ei_hash_rlookup(ei_hash *tab, const void *value); +int ei_hash_foreach(ei_hash *tab, int (*f)(const char *key, const void *value)); +void *ei_hash_insert(ei_hash *tab, const char *key, const void *value); +void *ei_hash_remove(ei_hash *tab, const char *key); +ei_hash *ei_hash_newtab(int tabsize); +ei_hash *ei_hash_resize(ei_hash *oldtab, int newsize); +int ei_hash_freetab(ei_hash *tab, void (*f)(void *)); +void ei_hash_stats(ei_hash *tab, FILE *out); +void ei_hash_bfree(ei_hash *tab, ei_bucket *b); + +#endif /* _HASH_H */ diff --git a/lib/erl_interface/src/registry/hash_dohash.c b/lib/erl_interface/src/registry/hash_dohash.c new file mode 100644 index 0000000000..f672dce9b3 --- /dev/null +++ b/lib/erl_interface/src/registry/hash_dohash.c @@ -0,0 +1,45 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include "hash.h" + +/* This is hashpjw, from the dragon book */ +/* Note that this function is only used as a default hash function. + * All calls are made through the hash pointer in the tab structure. + * The only place this function is explicitly referenced is in + * hash_newtab(); Users can use hash_setfunc() to change the hash function. + */ +int ei_dohash(const char *key) +{ + const char *s; + unsigned h = 0; + unsigned g; + + for (s=key; *s; s++) { + h = (h << 4) + *s; + if ((g = (h & 0xf0000000))) { /* assumes 32-bit int */ + h = h^(g >> 24); + h = h^g; + } + } + return h; +} + + diff --git a/lib/erl_interface/src/registry/hash_foreach.c b/lib/erl_interface/src/registry/hash_foreach.c new file mode 100644 index 0000000000..77afc7ade1 --- /dev/null +++ b/lib/erl_interface/src/registry/hash_foreach.c @@ -0,0 +1,44 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include "hash.h" + +/* perform f(key,value) on each key-value pair in the table. + * hash_foreach() will traverse the table until the end is reached or + * until f() returns a non-zero value, whichever comes first. The + * return value from f() will be returned to the caller, or 0 if the + * entire table was traversed. + */ +int ei_hash_foreach(ei_hash *tab, int (*f)(const char *key, const void *value)) +{ + ei_bucket *b; + int i; + int r; + + for (i=0; isize; i++) { + b=tab->tab[i]; + while (b) { + if (f && (r=f(b->key,b->value))) return r; + b = b->next; + } + } + return 0; +} + diff --git a/lib/erl_interface/src/registry/hash_freetab.c b/lib/erl_interface/src/registry/hash_freetab.c new file mode 100644 index 0000000000..cd428e55cf --- /dev/null +++ b/lib/erl_interface/src/registry/hash_freetab.c @@ -0,0 +1,58 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include +#include "hash.h" + +/* remove all the key-values from a table. The + * values are removed with + * the user-provided function f. + */ +int ei_hash_freetab(ei_hash *tab, void (*f)(void *)) +{ + ei_bucket *b, *next; + int i; + + for (i=0; isize; i++) { + b=tab->tab[i]; + while (b) { + next = b->next; + + if (f) f((void *)b->value); + + /* no point in saving these buckets on freelist */ + free(b); + b = next; + } + } + + /* remove the freelist */ + b = tab->freelist; + while (b) { + next = b->next; + free(b); + b = next; + } + + /* remove the table */ + free(tab); + + return 0; +} diff --git a/lib/erl_interface/src/registry/hash_insert.c b/lib/erl_interface/src/registry/hash_insert.c new file mode 100644 index 0000000000..dbe76282ae --- /dev/null +++ b/lib/erl_interface/src/registry/hash_insert.c @@ -0,0 +1,108 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include +#include +#include "hash.h" + +/* this function returns a bucket - from the freelist if one was found + * there, or from malloc(). Only "small" buckets, i.e. those whose + * keys are short enough to be stored in the bucket itself, are saved + * on the freelist. + */ +static ei_bucket *ei_hash_bmalloc(ei_hash *tab) +{ + ei_bucket *new; + + if (tab->freelist) { + new = tab->freelist; + tab->freelist = new->next; + /* fprintf(stderr,"getting bucket from freelist\n"); */ + } + else { + new = malloc(sizeof(*new)); + /* fprintf(stderr,"allocating new (small) bucket\n"); */ + } + + return new; +} + +/* insert a new key-value pair. The old value (if any) is returned. If + * the malloc fails the function returns NULL. This is potentially a + * problem since the function returns the same thing when malloc fails + * as when a item is inserted that did not previously exist in the + * table. */ +void *ei_hash_insert(ei_hash *tab, const char *key, const void *value) +{ + const void *oldval=NULL; + ei_bucket *b=NULL; + int h, rh; + + rh = tab->hash(key); + h = rh % tab->size; + + b=tab->tab[h]; + while (b) { + if ((rh == b->rawhash) && (!strcmp(key,b->key))) + break; + b=b->next; + } + + if (b) { + /* replace existing value, return old value */ + oldval = b->value; + b->value = value; + } + else { + int keylen = strlen(key); + + /* this element is new */ + if (keylen < EI_SMALLKEY) { + /* short keys stored directly in bucket */ + /* try to get bucket from freelist */ + if ((b = ei_hash_bmalloc(tab)) == NULL) return NULL; + b->key = b->keybuf; + } + else { + /* for longer keys we allocate space */ + int keypos=sizeof(*b); + + ei_align(keypos); + if ((b = malloc(keypos+keylen+1)) == NULL) return NULL; + b->key = (char *)b + keypos; + /* fprintf(stderr,"allocating new (large) bucket\n"); */ + } + + /* fill in the blanks */ + b->rawhash = rh; + strcpy((char *)b->key,key); + b->value = value; + + /* some statistiscs */ + if (!tab->tab[h]) tab->npos++; + tab->nelem++; + + /* link in the new element */ + b->next = tab->tab[h]; + tab->tab[h] = b; + } + return (void *)oldval; +} + diff --git a/lib/erl_interface/src/registry/hash_isprime.c b/lib/erl_interface/src/registry/hash_isprime.c new file mode 100644 index 0000000000..cdef2591ab --- /dev/null +++ b/lib/erl_interface/src/registry/hash_isprime.c @@ -0,0 +1,57 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include "hash.h" + +/* this is a general prime factoring function + * we get one prime factor each time we call it + * we only use it here to determine if n is prime, + * by checking if factor(n) == n . + */ +static int factor(int n) +{ + /* FIXME problem for threaded?! */ + static int a[] = { 0, 4, 1, 2, 0, 2 }; + static int m = 0; + static int d = 0; + + if (n) { + m = n; + d = 2; + } + + while ((d*d) <= m) { + if (!(m%d)) { + m /= d; + return d; + } + d += a[d%6]; + } + n = m; + m = 0; + + return n; +} + +/* true if n prime */ +int ei_isprime(int n) +{ + return (n == factor(n)); +} diff --git a/lib/erl_interface/src/registry/hash_lookup.c b/lib/erl_interface/src/registry/hash_lookup.c new file mode 100644 index 0000000000..0a466cc519 --- /dev/null +++ b/lib/erl_interface/src/registry/hash_lookup.c @@ -0,0 +1,42 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include +#include +#include "hash.h" + +void *ei_hash_lookup(ei_hash *tab, const char *key) +{ + int h, rh; + ei_bucket *b=NULL; + + rh = tab->hash(key); + h = rh % tab->size; + + b=tab->tab[h]; + while (b) { + if ((rh == b->rawhash) && (!strcmp(key,b->key))) + return (void *)b->value; + b=b->next; + } + return NULL; +} + + diff --git a/lib/erl_interface/src/registry/hash_newtab.c b/lib/erl_interface/src/registry/hash_newtab.c new file mode 100644 index 0000000000..b900de1f69 --- /dev/null +++ b/lib/erl_interface/src/registry/hash_newtab.c @@ -0,0 +1,52 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include +#include +#include "hash.h" + +ei_hash *ei_hash_newtab(int tabsize) +{ + ei_hash *tab=NULL; + int bucketpos=sizeof(*tab); + + /* make sure size is odd, then increase until prime */ + tabsize |= 0x1; + while (!ei_isprime(tabsize)) tabsize +=2; + + /* we will only do one malloc, so "sizeof(*tab)" + * must be adjusted to align tab->tab properly + */ + ei_align(bucketpos); + + /* single malloc, then fill in all fields */ + if ((tab = malloc(bucketpos + (tabsize * (sizeof(*(tab->tab))))))) { + tab->tab = (ei_bucket **)((char *)tab + bucketpos); + memset(tab->tab,0,tabsize*sizeof(*(tab->tab))); + tab->hash = ei_dohash; + tab->size = tabsize; + tab->npos = 0; + tab->nelem = 0; + tab->freelist = NULL; + } + + return tab; +} + diff --git a/lib/erl_interface/src/registry/hash_remove.c b/lib/erl_interface/src/registry/hash_remove.c new file mode 100644 index 0000000000..cebe00da1c --- /dev/null +++ b/lib/erl_interface/src/registry/hash_remove.c @@ -0,0 +1,87 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include +#include +#include "hash.h" + +/* free a hash bucket. If the bucket contained a long key (more that + * EI_SMALLKEY) the bucket is thrown away (really freed). If the + * bucket contained a short key, then it can be saved on the freelist + * for later use. Buckets with short keys have (key == keybuf). + */ +void ei_hash_bfree(ei_hash *tab, ei_bucket *b) +{ + if (!b) return; + + /* we throw away buckets with long keys (i.e. non-standard buckets) */ + if (b->key != b->keybuf) { + /* fprintf(stderr,"freeing bucket with long key (%s)\n",b->key); */ + free(b); + } + + else { + /* others we save on (tab-local) freelist */ + /* fprintf(stderr,"saving bucket with short key (%s)\n",b->key); */ + b->next = tab->freelist; + tab->freelist = b; + } + + return; +} + +void *ei_hash_remove(ei_hash *tab, const char *key) +{ + ei_bucket *b=NULL, *tmp=NULL; + const void *oldval=NULL; + int h, rh; + + rh = tab->hash(key); + h = rh % tab->size; + + /* is it in the first position? */ + if ((b=tab->tab[h])) { + if ((rh == b->rawhash) && (!strcmp(key,b->key))) { + tab->tab[h] = b->next; + oldval = b->value; + ei_hash_bfree(tab,b); + + tab->nelem--; + if (!tab->tab[h]) tab->npos--; + } + else { + /* is it later in the chain? */ + while (b->next) { + if ((rh == b->next->rawhash) && (!strcmp(key,b->next->key))) { + tmp = b->next; + b->next = tmp->next; + oldval = tmp->value; + ei_hash_bfree(tab,tmp); + + tab->nelem--; + break; + } + b=b->next; + } + } + } + return (void *)oldval; +} + diff --git a/lib/erl_interface/src/registry/hash_resize.c b/lib/erl_interface/src/registry/hash_resize.c new file mode 100644 index 0000000000..9c34a0d41c --- /dev/null +++ b/lib/erl_interface/src/registry/hash_resize.c @@ -0,0 +1,67 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include +#include "hash.h" + +/* move the elements from oldtab to a new table newsize. The old table + * is freed and the caller should discard the pointer. On failure + * (i.e. if malloc fails) return the old table and do nothing. +*/ +ei_hash *ei_hash_resize(ei_hash *oldtab, int newsize) +{ + ei_hash *newtab=NULL; + ei_bucket *b, *next; + int i,h; + + /* make sure size is odd, then increase until prime */ + newsize |= 0x1; + while (!ei_isprime(newsize)) newsize +=2; + + if (newsize == oldtab->size) return oldtab; + + /* make a new table */ + if (!(newtab = ei_hash_newtab(newsize))) return oldtab; + newtab->hash = oldtab->hash; + + /* move the buckets, rehashing */ + /* note that this will reverse the order of any chains */ + for (i=0; isize; i++) { + b=oldtab->tab[i]; + while (b) { + next = b->next; + h = b->rawhash % newtab->size; + b->next=newtab->tab[h]; + if (!newtab->tab[h]) newtab->npos++; + newtab->tab[h]=b; + b = next; + } + } + /* the new table has the same number of elements as the old one */ + newtab->nelem = oldtab->nelem; + + /* the new table takes over the freelist from the old one */ + newtab->freelist = oldtab->freelist; + + /* now it's safe to remove the old table */ + free(oldtab); + + return newtab; +} diff --git a/lib/erl_interface/src/registry/hash_rlookup.c b/lib/erl_interface/src/registry/hash_rlookup.c new file mode 100644 index 0000000000..5d401555d8 --- /dev/null +++ b/lib/erl_interface/src/registry/hash_rlookup.c @@ -0,0 +1,43 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include +#include "hash.h" + +/* this function does a reverse lookup and returns the first key whose + * value matches value. This operation may be lengthy! Also, there is + * no guarantee that the *values* are unique in the hash table, so the + * returned key might not be the one you expect. + */ +const char *ei_hash_rlookup(ei_hash *tab, const void *value) +{ + ei_bucket *b; + int i; + + for (i=0; isize; i++) { + b=tab->tab[i]; + while (b) { + if (b->value == value) return b->key; + b = b->next; + } + } + return NULL; +} + diff --git a/lib/erl_interface/src/registry/reg.h b/lib/erl_interface/src/registry/reg.h new file mode 100644 index 0000000000..cb7685506c --- /dev/null +++ b/lib/erl_interface/src/registry/reg.h @@ -0,0 +1,46 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#ifndef _REG_H +#define _REG_H + +#include "ei.h" /* Our public defines, types and declarations */ +#include "hash.h" + +#define EI_MNESIA_MODULE "mnesia_registry" + +#define EI_MNESIA_DUMP "start_dump" +#define EI_MNESIA_WRITE "write" +#define EI_MNESIA_DELETE "delete" +#define EI_MNESIA_COMMIT "commit" + +#define EI_MNESIA_RESTORE "start_restore" +#define EI_MNESIA_SEND "send_records" +#define EI_MNESIA_RECV "restore" +#define EI_MNESIA_SIZE "size" + +#define EI_REG_TYPEMASK 0xf8 /* all but lowest bits */ +#define ei_reg_typeof(r) (r->attr & EI_REG_TYPEMASK) + +ei_reg_obj *ei_reg_make(ei_reg *reg, int attr); + +void ei_reg_free(ei_reg *reg, ei_reg_obj *obj); + +#endif /* _REG_H */ diff --git a/lib/erl_interface/src/registry/reg_close.c b/lib/erl_interface/src/registry/reg_close.c new file mode 100644 index 0000000000..b699e59ac8 --- /dev/null +++ b/lib/erl_interface/src/registry/reg_close.c @@ -0,0 +1,68 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include +#include "reg.h" + +/* really remove an object (help function to hash_freetab) */ +static void obj_free(void *p) +{ + ei_reg_obj *obj = p; + + if (obj) { + switch (ei_reg_typeof(obj)) { + case EI_STR: + free(obj->val.s); + break; + + case EI_BIN: + free(obj->val.p); + break; + } + + /* really remove the inode (don't use freelist here) */ + free(obj); + } + return; +} + +/* close an open registry */ +int ei_reg_close(ei_reg *reg) +{ + ei_reg_obj *obj, *next; + + if (!reg) return -1; /* return EI_BADARG; */ + + /* remove hash_table */ + ei_hash_freetab(reg->tab,obj_free); + + /* remove freelist */ + obj = reg->freelist; + while (obj) { + next = obj->next; + free(obj); + obj = next; + } + + /* remove registry */ + free(reg); + + return 0; +} diff --git a/lib/erl_interface/src/registry/reg_delete.c b/lib/erl_interface/src/registry/reg_delete.c new file mode 100644 index 0000000000..8e84e205ee --- /dev/null +++ b/lib/erl_interface/src/registry/reg_delete.c @@ -0,0 +1,36 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include "reg.h" + +int ei_reg_delete(ei_reg *reg, const char *key) +{ + ei_hash *tab; + ei_reg_obj *obj; + + if (!key || !reg) return -1; /* return EI_BADARG; */ + tab = reg->tab; + if (!(obj = ei_hash_lookup(tab,key))) return -1; /* return EI_NOTFOUND; */ + + /* just mark the object deleted */ + obj->attr |= (EI_DELET | EI_DIRTY); + + return 0; +} diff --git a/lib/erl_interface/src/registry/reg_dirty.c b/lib/erl_interface/src/registry/reg_dirty.c new file mode 100644 index 0000000000..730b4445c6 --- /dev/null +++ b/lib/erl_interface/src/registry/reg_dirty.c @@ -0,0 +1,36 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include "reg.h" + +int ei_reg_markdirty(ei_reg *reg, const char *key) +{ + ei_hash *tab; + ei_reg_obj *obj; + + if (!key || !reg) return -1; /* EI_BADARG; */ + tab = reg->tab; + if (!(obj = ei_hash_lookup(tab,key))) return -1; /* return EI_NOTFOUND; */ + + /* just mark the object dirty */ + obj->attr |= EI_DIRTY; + + return 0; +} diff --git a/lib/erl_interface/src/registry/reg_dump.c b/lib/erl_interface/src/registry/reg_dump.c new file mode 100644 index 0000000000..50a6949177 --- /dev/null +++ b/lib/erl_interface/src/registry/reg_dump.c @@ -0,0 +1,321 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include +#include +#include "eidef.h" +#include "eiext.h" +#include "reg.h" +#include "eisend.h" +#include "eirecv.h" +#include "ei_connect_int.h" + +static int mn_start_dump(int fd, const erlang_pid *self, + erlang_pid *mnesia, const char *mntab) +{ + char buf[EISMALLBUF]; + char *bufp = buf; + char tmpbuf[64]; + int index = 0; + erlang_msg msg; + int type; + int arity; + int version; + int msglen; + int i; + int needlink; + int needpid; + + /* set up rpc arguments */ + /* { PidFrom, { call, Mod, Fun, Args, user }} */ + ei_encode_version(buf,&index); + ei_encode_tuple_header(buf,&index,2); + ei_encode_pid(buf,&index,self); /* PidFrom */ + ei_encode_tuple_header(buf,&index,5); + ei_encode_atom(buf,&index,"call"); /* call */ + ei_encode_atom(buf,&index,EI_MNESIA_MODULE); /* Mod */ + ei_encode_atom(buf,&index,EI_MNESIA_DUMP); /* Fun */ + ei_encode_list_header(buf,&index,2); /* Args: [ table, self() ] */ + ei_encode_atom(buf,&index,mntab); + ei_encode_pid(buf,&index,self); + ei_encode_empty_list(buf,&index); + ei_encode_atom(buf,&index,"user"); /* user */ + + /* make the rpc call */ + if (ei_send_reg_encoded(fd,self,"rex",buf,index)) return -1; + + /* get the reply: expect link and pid (not sure which will come first though) */ + needlink = needpid = 1; + while (needlink || needpid) { + /* get message */ + while (1) { + index = EISMALLBUF; + if (!(i = ei_recv_internal(fd,&bufp,&index,&msg,&msglen,1,0))) continue; + else break; + } + + switch (i) { + case ERL_LINK: + /* got link */ + if (!needlink) return -1; + needlink = 0; + break; + + case ERL_SEND: + /* got message - does it contain a pid? */ + if (!needpid) return -1; + else { + /* expecting { rex, } */ + index = 0; + if (ei_decode_version(buf,&index,&version) + || ei_decode_tuple_header(buf,&index,&arity) + || (arity != 2) + || ei_decode_atom(buf,&index,tmpbuf) + || strcmp(tmpbuf,"rex") + || ei_get_type_internal(buf,&index,&type,&arity) + || (type != ERL_PID_EXT)) + return -1; /* bad response from other side */ + + if (ei_decode_pid(buf,&index,mnesia)) return -1; + + /* got pid */ + needpid = 0; + } + break; + + default: + return -1; /* wasn't link or pid */ + } + } + return 0; +} + +static int mn_send_commit(int fd, erlang_pid *mnesia, erlang_pid *self) +{ + char buf[EISMALLBUF]; + char *bufp=buf; + char string[256]; + int index = 0; + int version,arity; + int msglen; + erlang_msg msg; + int i; + + /* set up commit message { commit, self() } */ + ei_encode_version(buf,&index); + ei_encode_tuple_header(buf,&index,2); + ei_encode_atom(buf,&index,EI_MNESIA_COMMIT); + ei_encode_pid(buf,&index,self); + + /* send it */ + if (ei_send_encoded(fd,mnesia,buf,index)) return -1; + + /* get reply */ + while (1) { + index = EISMALLBUF; + if (!(i=ei_recv_internal(fd,&bufp,&index,&msg,&msglen,1,0))) continue; + else if (i < 0) return -1; + else break; + } + + if (i == ERL_SEND) { + index = 0; + if (ei_decode_version(buf,&index,&version) + || ei_decode_tuple_header(buf,&index,&arity) + || ei_decode_atom(buf,&index,string)) + return -1; + + if (!strcmp(string,"ok")) return 0; + } + /* wrong message type */ + return -1; +} + +static int mn_send_delete(int fd, erlang_pid *mnesia, const char *key) +{ + char sbuf[EISMALLBUF]; + char *dbuf = NULL; + char *msgbuf; + int index = 0; + int len = strlen(key) + 32; /* 32 is a slight overestimate */ + + if (len > EISMALLBUF) + if (!(dbuf = malloc(index))) + return -1; + msgbuf = (dbuf ? dbuf : sbuf); + + /* set up delete message { delete, Key } */ + ei_encode_version(msgbuf,&index); + ei_encode_tuple_header(msgbuf,&index,2); + ei_encode_atom(msgbuf,&index,EI_MNESIA_DELETE); + ei_encode_string(msgbuf,&index,key); + + /* send it */ + if (ei_send_encoded(fd,mnesia,msgbuf,index)) { + if (dbuf) free(dbuf); + return -1; + } + + if (dbuf) free(dbuf); + return 0; +} + +static int mn_send_write(int fd, erlang_pid *mnesia, const char *key, ei_reg_obj *obj) +{ + char sbuf[EISMALLBUF]; + char *dbuf = NULL; + char *msgbuf; + int index = 0; + int keylen = strlen(key) + 1; + int len = 32 + keylen + obj->size; + + if (len > EISMALLBUF) + if (!(dbuf = malloc(index))) + return -1; + msgbuf = (dbuf ? dbuf : sbuf); + + ei_encode_version(msgbuf,&index); + ei_encode_tuple_header(msgbuf,&index,6); + ei_encode_atom(msgbuf,&index,EI_MNESIA_WRITE); + ei_encode_string(msgbuf,&index,key); + ei_encode_long(msgbuf,&index,keylen); + ei_encode_long(msgbuf,&index,obj->attr); + ei_encode_long(msgbuf,&index,obj->size); + + switch (ei_reg_typeof(obj)) { + case EI_INT: + ei_encode_long(msgbuf,&index,obj->val.i); + break; + case EI_FLT: + ei_encode_double(msgbuf,&index,obj->val.f); + break; + case EI_STR: + if (obj->size > 0) ei_encode_string(msgbuf,&index,obj->val.s); + else ei_encode_long(msgbuf,&index, (long)NULL); /* just the NULL pointer */ + break; + case EI_BIN: + if (obj->size > 0) ei_encode_binary(msgbuf,&index,obj->val.p,obj->size); + else ei_encode_long(msgbuf,&index,(long)(obj->val.p)); /* just the pointer */ + break; + default: + return -1; + } + + /* send it */ + if (ei_send_encoded(fd,mnesia,msgbuf,index)) { + if (dbuf) free(dbuf); + return -1; + } + + if (dbuf) free(dbuf); + return 0; +} + +static int mn_get_unlink(int fd) +{ + erlang_msg msg; + char buf[EISMALLBUF]; + char *bufp=buf; + int index; + int msglen; + + /* wait for unlink or exit */ + while (1) { + index = EISMALLBUF; + switch (ei_recv_internal(fd,&bufp,&index,&msg,&msglen,1,0)) { + case 0: continue; + case ERL_UNLINK: return 0; + default: return -1; + } + } + return 0; +} + +/* dump to backup */ +/* fd is open connection to erlang node */ +int ei_reg_dump(int fd, ei_reg *reg, const char *mntab, int flags) +{ + ei_hash *tab; + erlang_pid self; + erlang_pid mnesia; + ei_bucket *b; + ei_reg_obj *obj; + const char *key; + ei_cnode *ec; + int i; + + if (!reg || !mntab) return -1; /* return EI_BADARG; */ + tab = reg->tab; + + /* make a self pid */ + + if ((ec = ei_fd_to_cnode(fd)) == NULL) { + return -1; + } + strcpy(self.node,ei_thisnodename(ec)); + self.num = fd; + self.serial = 0; + self.creation = ei_thiscreation(ec); + + if (mn_start_dump(fd,&self,&mnesia,mntab)) return -1; + + /* traverse the table, passing objects to mnesia */ + for (i=0; isize; i++) { + b=tab->tab[i]; + while (b) { + obj = (ei_reg_obj*)(b->value); /* cast to eliminate 'const' warning */ + key = b->key; + + if ((flags & EI_FORCE) || (obj->attr & EI_DIRTY)) { + if (obj->attr & EI_DELET) { + if (mn_send_delete(fd,&mnesia,key)) { + ei_send_exit(fd,&self,&mnesia,"delete failed"); + return -1; + } + } + else { + if (mn_send_write(fd,&mnesia,key,obj)) { + ei_send_exit(fd,&self,&mnesia,"update failed"); + return -1; + } + } + } + b = b->next; + } + } + + /* end the transaction */ + if (mn_send_commit(fd,&mnesia,&self)) { + ei_send_exit(fd,&self,&mnesia,"commit failed"); + return -1; + } + + /* wait for unlink */ + if (mn_get_unlink(fd)) return -1; + + /* this point only reached if all went ok so far... */ + + /* now remove all deleted objects, unless the caller asked us not to */ + if (!(flags & EI_NOPURGE)) ei_reg_purge(reg); + + /* success */ + return 0; + +} diff --git a/lib/erl_interface/src/registry/reg_free.c b/lib/erl_interface/src/registry/reg_free.c new file mode 100644 index 0000000000..e3245577a5 --- /dev/null +++ b/lib/erl_interface/src/registry/reg_free.c @@ -0,0 +1,47 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include +#include "reg.h" + +/* free a registry object (inode) on the freelist. The "value" + * contained by the object is removed. + */ +void ei_reg_free(ei_reg *reg, ei_reg_obj *obj) +{ + /* free the value part */ + switch (ei_reg_typeof(obj)) { + case EI_STR: + free(obj->val.s); + break; + + case EI_BIN: + free(obj->val.p); + break; + } + + /* fprintf(stderr,"%s:%d: saving %p on freelist\n",__FILE__,__LINE__,obj);*/ + + /* save the rest on the freelist */ + obj->next = reg->freelist; + reg->freelist = obj; + + return; +} diff --git a/lib/erl_interface/src/registry/reg_get.c b/lib/erl_interface/src/registry/reg_get.c new file mode 100644 index 0000000000..d1909b3fed --- /dev/null +++ b/lib/erl_interface/src/registry/reg_get.c @@ -0,0 +1,94 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#ifdef VXWORKS +#include +#endif + +#include +#include "reg.h" + +/* this is the general "get" function. Values are copied into a buffer + * provided by the caller, and the return value indicates success or + * failure. This function can get all types except directorys. The user + * must specify the type of data he is expecting, or 0 if he doesn't + * care. On success, the data type is returned. If the requested data + * type does not match the data found, EI_TYPE is returned. + */ +int ei_reg_getval(ei_reg *reg, const char *key, int flags, ...) +{ + ei_hash *tab; + ei_reg_obj *obj=NULL; + va_list ap; + int rval; + int objtype; + + if (!key || !reg) return -1; /* return EI_BADARG; */ + tab = reg->tab; + if (!(obj=ei_hash_lookup(tab,key))) return -1; /* return EI_NOTFOUND; */ + if (obj->attr & EI_DELET) return -1; /* return EI_NOTFOUND; */ + + /* if type was specified then it must match object */ + objtype = ei_reg_typeof(obj); + if (flags && (flags != objtype)) return -1; /* return EI_TYPE; */ + + va_start(ap,flags); + + switch ((rval = objtype)) { + case EI_INT: { + long *ip; + + if (!(ip = va_arg(ap,long*))) rval = -1; /* EI_BADARG; */ + else *ip = obj->val.i; + break; + } + case EI_FLT: { + double *fp; + + if (!(fp = va_arg(ap,double*))) rval = -1; /* EI_BADARG; */ + else *fp = obj->val.f; + break; + } + case EI_STR: { + char **sp; + + if (!(sp = va_arg(ap,char**))) rval = -1; /* EI_BADARG; */ + else *sp = obj->val.s; + break; + } + case EI_BIN: { + void **pp; + int *size; + + if (!(pp = va_arg(ap,void**))) rval = -1; /* EI_BADARG; */ + else *pp = obj->val.p; + if ((size=va_arg(ap,int*))) *size=obj->size; + break; + } + default: + /* can't (should never) happen */ + rval = -1; + /* rval = EI_UNKNOWN; */ + } + + /* clean up & return */ + va_end(ap); + return rval; +} diff --git a/lib/erl_interface/src/registry/reg_getf.c b/lib/erl_interface/src/registry/reg_getf.c new file mode 100644 index 0000000000..faed2f2df9 --- /dev/null +++ b/lib/erl_interface/src/registry/reg_getf.c @@ -0,0 +1,35 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include "reg.h" + +double ei_reg_getfval(ei_reg *reg, const char *key) +{ + ei_hash *tab; + ei_reg_obj *obj=NULL; + + if (!key || !reg) return -1; /* return (double)EI_BADARG; */ + tab = reg->tab; + if (!(obj=ei_hash_lookup(tab,key))) return -1; /* return EI_NOTFOUND; */ + if (obj->attr & EI_DELET) return -1; /* return EI_NOTFOUND; */ + if (ei_reg_typeof(obj) != EI_FLT) return -1; /* return (double)EI_TYPE; */ + + return obj->val.f; +} diff --git a/lib/erl_interface/src/registry/reg_geti.c b/lib/erl_interface/src/registry/reg_geti.c new file mode 100644 index 0000000000..b746a4a92b --- /dev/null +++ b/lib/erl_interface/src/registry/reg_geti.c @@ -0,0 +1,35 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include "reg.h" + +long ei_reg_getival(ei_reg *reg, const char *key) +{ + ei_hash *tab; + ei_reg_obj *obj=NULL; + + if (!key || !reg) return -1; /* return EI_BADARG; */ + tab = reg->tab; + if (!(obj=ei_hash_lookup(tab,key))) return -1; /* return EI_NOTFOUND; */ + if (obj->attr & EI_DELET) return -1; /* return EI_NOTFOUND; */ + if (ei_reg_typeof(obj) != EI_INT) return -1; /* return EI_TYPE; */ + + return obj->val.i; +} diff --git a/lib/erl_interface/src/registry/reg_getp.c b/lib/erl_interface/src/registry/reg_getp.c new file mode 100644 index 0000000000..bacfdc05c4 --- /dev/null +++ b/lib/erl_interface/src/registry/reg_getp.c @@ -0,0 +1,39 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include +#include "reg.h" + +const void *ei_reg_getpval(ei_reg *reg, const char *key, int *size) +{ + ei_hash *tab; + ei_reg_obj *obj; + + if (!key || !reg) return NULL; + tab = reg->tab; + + if ((!(obj=ei_hash_lookup(tab,key))) || /* return (const void *)EI_NOTFOUND; */ + (obj->attr & EI_DELET) || /* return (const void *)EI_NOTFOUND; */ + (ei_reg_typeof(obj) != EI_BIN)) /* return (const void *)EI_TYPE; */ + return NULL; + + if (size) *size=obj->size; + return obj->val.p; +} diff --git a/lib/erl_interface/src/registry/reg_gets.c b/lib/erl_interface/src/registry/reg_gets.c new file mode 100644 index 0000000000..d6e6d67ebe --- /dev/null +++ b/lib/erl_interface/src/registry/reg_gets.c @@ -0,0 +1,38 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include +#include "reg.h" + +const char *ei_reg_getsval(ei_reg *reg, const char *key) +{ + ei_hash *tab; + ei_reg_obj *obj=NULL; + + if (!key || !reg) return NULL; /* return (const char *)EI_BADARG; */ + tab = reg->tab; + + if ((!(obj=ei_hash_lookup(tab,key))) || /* return (const char *)EI_NOTFOUND; */ + (obj->attr & EI_DELET) || /* return (const char *)EI_NOTFOUND; */ + (ei_reg_typeof(obj) != EI_STR)) /* return (const char *)EI_TYPE; */ + return NULL; + + return obj->val.s; +} diff --git a/lib/erl_interface/src/registry/reg_make.c b/lib/erl_interface/src/registry/reg_make.c new file mode 100644 index 0000000000..179cb8bf47 --- /dev/null +++ b/lib/erl_interface/src/registry/reg_make.c @@ -0,0 +1,49 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include +#include "reg.h" + + +/* make a new ei_reg_obj object. If the freelist for this registry is + * not empty, an object will be returned from there. Otherwise one + * will be created with malloc(). + */ +ei_reg_obj *ei_reg_make(ei_reg *reg, int attr) +{ + ei_reg_obj *new=NULL; + + if (reg->freelist) { + new = reg->freelist; + reg->freelist = new->next; + /* fprintf(stderr,"%s:%d: found %p on freelist\n",__FILE__,__LINE__,new); */ + } + else { + new = malloc(sizeof(*new)); + /* fprintf(stderr,"%s:%d: allocated %p\n",__FILE__,__LINE__,new); */ + } + + if (new) { + new->attr=attr | EI_DIRTY; + new->size=0; + new->next = NULL; + } + return new; +} diff --git a/lib/erl_interface/src/registry/reg_open.c b/lib/erl_interface/src/registry/reg_open.c new file mode 100644 index 0000000000..0c2031707d --- /dev/null +++ b/lib/erl_interface/src/registry/reg_open.c @@ -0,0 +1,41 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include +#include "reg.h" + +/* open a registry */ +ei_reg *ei_reg_open(int size) +{ + ei_reg *new; + + if (size <= 0) return NULL; + + if (!(new = malloc(sizeof(*new)))) return NULL; + + new->freelist = NULL; + + if (!(new->tab = ei_hash_newtab(size))) { + free(new); + return NULL; + } + + return new; +} diff --git a/lib/erl_interface/src/registry/reg_purge.c b/lib/erl_interface/src/registry/reg_purge.c new file mode 100644 index 0000000000..329fd32f23 --- /dev/null +++ b/lib/erl_interface/src/registry/reg_purge.c @@ -0,0 +1,76 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include +#include "reg.h" + +static ei_bucket *do_purge(ei_reg *reg, int i) +{ + ei_hash *tab = reg->tab; + ei_bucket *head = tab->tab[i]; + ei_bucket *this, *next; + ei_reg_obj *obj; + + /* first position special case */ + while ((this=head)) { + obj = (ei_reg_obj*)(this->value); /* cast to eliminate 'const' warning */ + if (obj->attr & EI_DELET) { + head = this->next; + ei_reg_free(reg,obj); /* free obj to freelist */ + ei_hash_bfree(tab,this); /* free bucket to freelist */ + tab->nelem--; + } + else break; + } + + /* check remaining positions */ + this = head; + while (this && this->next) { + next = this->next; + obj = (ei_reg_obj*)(next->value); /* cast to eliminate 'const' warning */ + if (obj->attr & EI_DELET) { + this->next = next->next; + ei_reg_free(reg,obj); /* free object to freelist */ + ei_hash_bfree(tab,next); /* free bucket to freelist */ + tab->nelem--; + } + else this = this->next; + } + + return head; +} + +int ei_reg_purge(ei_reg *reg) +{ + ei_hash *tab; + int i; + + if (!reg) return -1; + tab = reg->tab; + + for (i=0;isize;i++) { + if ((tab->tab[i])) { + tab->tab[i] = do_purge(reg,i); + if (!tab->tab[i]) tab->npos--; + } + } + + return 0; +} diff --git a/lib/erl_interface/src/registry/reg_resize.c b/lib/erl_interface/src/registry/reg_resize.c new file mode 100644 index 0000000000..8e4794ccf7 --- /dev/null +++ b/lib/erl_interface/src/registry/reg_resize.c @@ -0,0 +1,36 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include "reg.h" + +/* resize a registry - return the new size or -1 on error */ +int ei_reg_resize(ei_reg *reg, int newsize) +{ + ei_hash *newtab=NULL; + + if (!reg) return -1; + if (newsize <= 0) return -1; + + if ((newtab=ei_hash_resize(reg->tab,newsize))) { + reg->tab = newtab; + } + + return reg->tab->size; +} diff --git a/lib/erl_interface/src/registry/reg_restore.c b/lib/erl_interface/src/registry/reg_restore.c new file mode 100644 index 0000000000..27918d2364 --- /dev/null +++ b/lib/erl_interface/src/registry/reg_restore.c @@ -0,0 +1,323 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include +#include +#include "eidef.h" +#include "eiext.h" +#include "reg.h" +#include "eisend.h" +#include "eirecv.h" +#include "ei_connect_int.h" + +static int mn_start_restore(int fd, const erlang_pid *self, erlang_pid *mnesia, const char *mntab, long *count, long *maxkey,long *maxobj) +{ + char buf[EISMALLBUF]; + char *bufp=buf; + char tmpbuf[64]; + int index = 0; + erlang_msg msg; + int arity; + int version; + int i; + int needlink; + int needmsg; + int msglen; + + /* set up rpc arguments */ + /* { PidFrom, { call, Mod, Fun, Args, user }} */ + ei_encode_version(buf,&index); + ei_encode_tuple_header(buf,&index,2); + ei_encode_pid(buf,&index,self); /* PidFrom */ + ei_encode_tuple_header(buf,&index,5); + ei_encode_atom(buf,&index,"call"); /* call */ + ei_encode_atom(buf,&index,EI_MNESIA_MODULE); /* Mod */ + ei_encode_atom(buf,&index,EI_MNESIA_RESTORE); /* Fun */ + ei_encode_list_header(buf,&index,2); /* Args: [ table, self() ] */ + ei_encode_atom(buf,&index,mntab); + ei_encode_pid(buf,&index,self); + ei_encode_empty_list(buf,&index); + ei_encode_atom(buf,&index,"user"); /* user */ + + /* make the rpc call */ + if (ei_send_reg_encoded(fd,self,"rex",buf,index)) return -1; + + /* get the reply: expect link and message (not sure which will come first though) */ + needlink = needmsg = 1; + while (needlink || needmsg) { + /* get message */ + index = EISMALLBUF; + while (!(i = ei_recv_internal(fd,&bufp,&index,&msg,&msglen,1,0))) index = EISMALLBUF; + + switch (i) { + case ERL_LINK: + /* got link */ + if (!needlink) return -1; + needlink = 0; + break; + + case ERL_SEND: + /* got message - is it the right one? */ + if (!needmsg) return -1; + else { + /* expecting { rex, { size, Pid, Count, MaxKey, MaxObj }} */ + index = 0; + if (ei_decode_version(buf,&index,&version) + || ei_decode_tuple_header(buf,&index,&arity) + || (arity != 2) + || ei_decode_atom(buf,&index,tmpbuf) + || strcmp(tmpbuf,"rex") + || ei_decode_tuple_header(buf,&index,&arity) + || (arity != 5) + || ei_decode_atom(buf,&index,tmpbuf) + || strcmp(tmpbuf,EI_MNESIA_SIZE) + || ei_decode_pid(buf,&index,mnesia) + || ei_decode_long(buf,&index,count) + || ei_decode_long(buf,&index,maxkey) + || ei_decode_long(buf,&index,maxobj)) + return -1; /* bad response from other side */ + + /* got msg */ + needmsg = 0; + } + break; + + default: + return -1; /* wasn't link or pid */ + } + } + return 0; +} + +static int mn_unlink(int fd) +{ + erlang_msg msg; + char buf[EISMALLBUF]; + char *bufp=buf; + int index; + int msglen; + + /* wait for unlink or exit */ + while (1) { + index = EISMALLBUF; + switch (ei_recv_internal(fd,&bufp,&index,&msg,&msglen,1,0)) { + case 0: continue; + case ERL_UNLINK: return 0; + default: return -1; + } + } + return 0; +} + +/* decode an object and insert it into the table */ +static int mn_decode_insert(ei_reg *reg, const char *msgbuf, int *index, char *key) +{ + long keylen; + long objlen; + long objtype; + void *objbuf = NULL; + long i; + double f; + + if (ei_decode_long(msgbuf,index,&keylen) + || ei_decode_long(msgbuf,index,&objlen) + || ei_decode_long(msgbuf,index,&objtype)) + return -1; + + + /* decode key */ + if (ei_decode_string(msgbuf,index,key)) { + if (objbuf) free(objbuf); + return -1; + } + + /* finally! decode object and insert in table */ + /* don't forget to fix attributes (dirty bit for example) */ + + /* FIXME: added cast but 64 bit trouble I think */ + switch ((int)objtype & EI_REG_TYPEMASK) { + case EI_INT: + if (ei_decode_long(msgbuf,index,&i)) return -1; + ei_reg_setival(reg,key,i); + break; + + case EI_FLT: + if (ei_decode_double(msgbuf,index,&f)) return -1; + ei_reg_setfval(reg,key,f); + break; + + case EI_STR: + objbuf = NULL; + if (objlen > 0) { + if (!(objbuf = malloc(objlen))) return -1; + if (ei_decode_string(msgbuf,index,objbuf)) { + free(objbuf); + return -1; + } + ei_reg_setsval(reg,key,objbuf); + } + else { + /* just a pointer to nothing */ + if (ei_decode_long(msgbuf,index,&i)) return -1; + ei_reg_setsval(reg,key,NULL); + } + break; + + case EI_BIN: + objbuf = NULL; + if (objlen > 0) { + if (!(objbuf = malloc(objlen))) return -1; + if (ei_decode_binary(msgbuf,index,objbuf,&i)) { + free(objbuf); + return -1; + } + /* assert(i == objlen) */ + ei_reg_setpval(reg,key,objbuf,objlen); + } + else { + /* just a pointer to nothing */ + if (ei_decode_long(msgbuf,index,&i)) return -1; + ei_reg_setpval(reg,key,(void *)i,0); + } + break; + + default: + /* unknown type */ + if (objbuf) free(objbuf); + return -1; + } /* switch */ + + return 0; +} + +/* help function passed to hash_foreach, to clear dirty bits */ +/* use after successful restore */ +static int clean_obj(const char *key, const void *p) +{ + ei_reg_obj *obj = (ei_reg_obj *)p; + + if (obj) obj->attr &= ~EI_DIRTY; + + return 0; +} + +int ei_reg_restore(int fd, ei_reg *reg, const char *mntab) +{ + int i,j; + char tag[32]; + char sbuf[EISMALLBUF]; + char *dbuf = NULL; + char *msgbuf = NULL; + char *keybuf = NULL; + erlang_pid self; + erlang_pid mnesia = {"",0,0,0}; + erlang_msg msg; + int index = 0; + int len = 0; + int msglen; + int version = 0; + int arity = 0; + long count = 0; + long maxkey = 0; + long maxobj = 0; + ei_cnode *ec; + + if (!reg || !mntab) return -1; /* return EI_BADARG; */ + + /* make a self pid */ + + if ((ec = ei_fd_to_cnode(fd)) == NULL) { + return -1; + } + strcpy(self.node,ei_thisnodename(ec)); + self.num = fd; + self.serial = 0; + self.creation = ei_thiscreation(ec); + + + if (mn_start_restore(fd,&self,&mnesia,mntab,&count,&maxkey,&maxobj)) { + /* send exit *only* if we have pid */ + if (mnesia.node[0]) ei_send_exit(fd,&self,&mnesia,"bad response from rpc start"); + return -1; + } + + if (count <= 0) { + ei_send_exit(fd,&self,&mnesia,"nothing to do"); + return 0; + } + + /* make sure receive buffer can handle largest expected message */ + len = maxkey + maxobj + 512; + if (len > EISMALLBUF) + if (!(dbuf = malloc(index))) { + ei_send_exit(fd,&self,&mnesia,"cannot allocate space for incoming data"); + return -1; + } + msgbuf = (dbuf ? dbuf : sbuf); + + /* allocate space for largest key */ + if (!(keybuf = malloc(maxkey+1))) goto restore_failure; + + /* get this ball rolling */ + index = 0; + ei_encode_version(msgbuf,&index); + ei_encode_tuple_header(msgbuf,&index,2); + ei_encode_atom(msgbuf,&index,"send_records"); + ei_encode_pid(msgbuf,&index,&self); + if (ei_send_encoded(fd,&mnesia,msgbuf,index)) goto restore_failure; + + /* read as much as possible, until count or EXIT */ + for (i=0; itab,clean_obj); + + /* success */ + if (keybuf) free(keybuf); + if (dbuf) free(dbuf); + return 0; + +restore_failure: + ei_send_exit(fd,&self,&mnesia,"restore failure"); + if (keybuf) free(keybuf); + if (dbuf) free(dbuf); + return -1; +} + diff --git a/lib/erl_interface/src/registry/reg_set.c b/lib/erl_interface/src/registry/reg_set.c new file mode 100644 index 0000000000..70ade09ffa --- /dev/null +++ b/lib/erl_interface/src/registry/reg_set.c @@ -0,0 +1,78 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#ifdef VXWORKS +#include +#endif + +#include +#include "reg.h" + +int ei_reg_setval(ei_reg *reg, const char *key, int flags, ...) +{ + va_list ap; + int rval = 0; + + if (!key || !reg) return -1; /* return EI_BADARG; */ + + va_start(ap,flags); + + switch (flags & EI_REG_TYPEMASK) { + case EI_INT: { + long i; + + i = va_arg(ap,long); + rval = ei_reg_setival(reg,key,i); + break; + } + case EI_FLT: { + double f; + + f = va_arg(ap,double); + rval = ei_reg_setfval(reg,key,f); + break; + } + case EI_STR: { + char *s; + + s = va_arg(ap,char*); + rval = ei_reg_setsval(reg,key,s); + break; + } + case EI_BIN: { + void *p; + int len; + + p = va_arg(ap,void*); + len = va_arg(ap,int); + rval = ei_reg_setpval(reg,key,p,len); + break; + } + + default: + rval = -1; + /* rval = EI_BADARG; */ + } + + /* clean up & return */ + va_end(ap); + return rval; +} + diff --git a/lib/erl_interface/src/registry/reg_setf.c b/lib/erl_interface/src/registry/reg_setf.c new file mode 100644 index 0000000000..1021174074 --- /dev/null +++ b/lib/erl_interface/src/registry/reg_setf.c @@ -0,0 +1,61 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include +#include "reg.h" + +int ei_reg_setfval(ei_reg *reg, const char *key, double f) +{ + ei_hash *tab; + ei_reg_obj *obj=NULL; + + if (!key || !reg) return -1; /* return EI_BADARG; */ + tab = reg->tab; + + if ((obj=ei_hash_lookup(tab,key))) { + /* object with same name already exists */ + switch (ei_reg_typeof(obj)) { + case EI_INT: + break; + case EI_FLT: + break; + case EI_STR: + if (obj->size > 0) free(obj->val.s); + break; + case EI_BIN: + if (obj->size > 0) free(obj->val.p); + break; + default: + return -1; + /* return EI_UNKNOWN; */ + } + } + else { + /* object is new */ + if (!(obj=ei_reg_make(reg,EI_FLT))) return -1; /* return EI_NOMEM; */ + ei_hash_insert(tab,key,obj); + } + + obj->attr = EI_FLT | EI_DIRTY; + obj->val.f=f; + obj->size = 0; + + return 0; +} diff --git a/lib/erl_interface/src/registry/reg_seti.c b/lib/erl_interface/src/registry/reg_seti.c new file mode 100644 index 0000000000..430a3b6d47 --- /dev/null +++ b/lib/erl_interface/src/registry/reg_seti.c @@ -0,0 +1,62 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include +#include "reg.h" + +/* set and get values */ +int ei_reg_setival(ei_reg *reg, const char *key, long i) +{ + ei_hash *tab; + ei_reg_obj *obj=NULL; + + if (!key || !reg) return -1; /* return EI_BADARG; */ + tab = reg->tab; + + if ((obj=ei_hash_lookup(tab,key))) { + /* object with same name already exists */ + switch (ei_reg_typeof(obj)) { + case EI_INT: + break; + case EI_FLT: + break; + case EI_STR: + if (obj->size > 0) free(obj->val.s); + break; + case EI_BIN: + if (obj->size > 0) free(obj->val.p); + break; + default: + return -1; + /* return EI_UNKNOWN; */ + } + } + else { + /* object is new */ + if (!(obj=ei_reg_make(reg,EI_INT))) return -1; /* return EI_NOMEM; */ + ei_hash_insert(tab,key,obj); + } + + obj->attr = EI_INT | EI_DIRTY; + obj->val.i=i; + obj->size = 0; + + return 0; +} diff --git a/lib/erl_interface/src/registry/reg_setp.c b/lib/erl_interface/src/registry/reg_setp.c new file mode 100644 index 0000000000..a994c14c78 --- /dev/null +++ b/lib/erl_interface/src/registry/reg_setp.c @@ -0,0 +1,62 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include +#include "reg.h" + +int ei_reg_setpval(ei_reg *reg, const char *key, const void *p, int size) +{ + ei_hash *tab; + ei_reg_obj *obj=NULL; + + if (size < 0) return -1; + if (!key || !reg) return -1; /* return EI_BADARG; */ + tab = reg->tab; + + if ((obj=ei_hash_lookup(tab,key))) { + /* object with same name already exists */ + switch (ei_reg_typeof(obj)) { + case EI_INT: + break; + case EI_FLT: + break; + case EI_STR: + if (obj->size > 0) free(obj->val.s); + break; + case EI_BIN: + if (obj->size > 0) free(obj->val.p); + break; + default: + return -1; + /* return EI_UNKNOWN; */ + } + } + else { + /* object is new */ + if (!(obj=ei_reg_make(reg,EI_BIN))) return -1; /* return EI_NOMEM; */ + ei_hash_insert(tab,key,obj); + } + + obj->attr = EI_BIN | EI_DIRTY; + obj->val.p=(void *)p; + obj->size=size; + + return 0; +} diff --git a/lib/erl_interface/src/registry/reg_sets.c b/lib/erl_interface/src/registry/reg_sets.c new file mode 100644 index 0000000000..14bdb2699d --- /dev/null +++ b/lib/erl_interface/src/registry/reg_sets.c @@ -0,0 +1,65 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include +#include +#include "reg.h" + +int ei_reg_setsval(ei_reg *reg, const char *key, const char *s) +{ + ei_hash *tab; + ei_reg_obj *obj=NULL; + int len = 0; + + + if (!key || !reg) return -1; /* return EI_BADARG; */ + tab = reg->tab; + if (s) len = strlen(s) +1; + + if ((obj=ei_hash_lookup(tab,key))) { + /* object with same name already exists */ + switch (ei_reg_typeof(obj)) { + case EI_INT: + break; + case EI_FLT: + break; + case EI_STR: + if (obj->size > 0) free(obj->val.s); + break; + case EI_BIN: + if (obj->size > 0) free(obj->val.p); + break; + default: + return -1; + /* return EI_UNKNOWN; */ + } + } + else { + /* object is new */ + if (!(obj=ei_reg_make(reg,EI_STR))) return -1; /* return EI_NOMEM; */ + ei_hash_insert(tab,key,obj); + } + + obj->attr = EI_STR | EI_DIRTY; + obj->val.s=(char *)s; + obj->size = len; + + return 0; +} diff --git a/lib/erl_interface/src/registry/reg_stat.c b/lib/erl_interface/src/registry/reg_stat.c new file mode 100644 index 0000000000..c3f669fd4f --- /dev/null +++ b/lib/erl_interface/src/registry/reg_stat.c @@ -0,0 +1,41 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include "reg.h" + +/* Get object attributes. + * This function returns a COPY of the ei_reg_obj + * struct for an object. + */ +int ei_reg_stat(ei_reg *reg, const char *key, struct ei_reg_stat *obuf) +{ + ei_hash *tab; + ei_reg_obj *obj; + + if (!key || !obuf || !reg) return -1; /* return EI_BADARG; */ + tab = reg->tab; + + if (!(obj=ei_hash_lookup(tab,key))) return -1; /* return EI_NOTFOUND; */ + + obuf->attr = obj->attr; + obuf->size = obj->size; + + return 0; +} diff --git a/lib/erl_interface/src/registry/reg_tabstat.c b/lib/erl_interface/src/registry/reg_tabstat.c new file mode 100644 index 0000000000..edfb19fa00 --- /dev/null +++ b/lib/erl_interface/src/registry/reg_tabstat.c @@ -0,0 +1,37 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#include "reg.h" + +/* get table information */ +int ei_reg_tabstat(ei_reg *reg, struct ei_reg_tabstat *obuf) +{ + ei_hash *tab; + + if (!reg || !obuf) return -1; /* return EI_BADARG; */ + tab = reg->tab; + + obuf->npos = tab-> npos; + obuf->size = tab->size; + obuf->nelem = tab->nelem; + obuf->collisions = tab->nelem - tab->npos; + + return 0; +} diff --git a/lib/erl_interface/vsn.mk b/lib/erl_interface/vsn.mk new file mode 100644 index 0000000000..c5f4c06037 --- /dev/null +++ b/lib/erl_interface/vsn.mk @@ -0,0 +1 @@ +EI_VSN = 3.6.4 -- cgit v1.2.3