diff options
Diffstat (limited to 'lib/erl_interface/src')
166 files changed, 25352 insertions, 0 deletions
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 <stdio.h> 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 <alloca.h> and it should be used (not on Ultrix). + */ +#undef HAVE_ALLOCA_H + +/* Define to 1 if you have the <arpa/inet.h> 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 <fcntl.h> 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 <gmp.h> 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 <inttypes.h> 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 <limits.h> 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 <malloc.h> 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 <memory.h> 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 <netdb.h> header file. */ +#undef HAVE_NETDB_H + +/* Define to 1 if you have the <netinet/in.h> header file. */ +#undef HAVE_NETINET_IN_H + +/* Define to 1 if you have the <pthread/mit/pthread.h> header file. */ +#undef HAVE_MIT_PTHREAD_H + +/* Define to 1 if you have the <pthread.h> 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 <stddef.h> header file. */ +#undef HAVE_STDDEF_H + +/* Define to 1 if you have the <stdint.h> header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the <stdlib.h> 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 <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the <string.h> 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 <sys/param.h> header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the <sys/select.h> header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define to 1 if you have the <sys/socket.h> header file. */ +#undef HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the <sys/time.h> header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the <sys/types.h> header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have <sys/wait.h> 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 <unistd.h> 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 <vfork.h> 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 <sys/time.h> and <time.h>. */ +#undef TIME_WITH_SYS_TIME + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `int' if <sys/types.h> doesn't define. */ +#undef gid_t + +/* Define to rpl_malloc if the replacement function should be used. */ +#undef malloc + +/* Define to `int' if <sys/types.h> does not define. */ +#undef pid_t + +/* Define to rpl_realloc if the replacement function should be used. */ +#undef realloc + +/* Define to `unsigned' if <sys/types.h> does not define. */ +#undef size_t + +/* Define to `int' if <sys/types.h> 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 <stdlib.h> +#include <sys/types.h> +#include <fcntl.h> + +#ifdef __WIN32__ +#include <winsock2.h> +#include <windows.h> +#include <winbase.h> + +#elif VXWORKS +#include <vxWorks.h> +#include <hostLib.h> +#include <selectLib.h> +#include <ifLib.h> +#include <sockLib.h> +#include <taskLib.h> +#include <inetLib.h> + +#include <unistd.h> +#include <sys/types.h> +#include <sys/times.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <timers.h> + +#define getpid() taskIdSelf() + +#else /* some other unix */ +#include <unistd.h> +#include <sys/types.h> +#include <sys/times.h> + +#if TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif + +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <sys/utsname.h> /* for gen_challenge (NEED FIX?) */ +#include <time.h> +#endif + +/* common includes */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> + +#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,"<ERROR> get_cookie: too long path to home"); + return 0; + } + + strcat(fname, COOKIE_FILE); + if ((fd = open(fname, O_RDONLY, 0777)) < 0) { + fprintf(stderr,"<ERROR> get_cookie: can't open cookie file"); + return 0; + } + + if ((len = read(fd, buf, bufsize-1)) < 0) { + fprintf(stderr,"<ERROR> 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,"<ERROR> 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 <stdlib.h> +#include <sys/types.h> +#include <fcntl.h> + +#ifdef __WIN32__ +#include <winsock2.h> +#include <windows.h> +#include <winbase.h> + +#elif VXWORKS +#include <vxWorks.h> +#include <hostLib.h> +#include <selectLib.h> +#include <ifLib.h> +#include <sockLib.h> +#include <taskLib.h> +#include <inetLib.h> +#include <ioLib.h> + +#include <unistd.h> +#include <sys/types.h> +#include <sys/times.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <timers.h> + +#define getpid() taskIdSelf() +extern int h_errno; + +#else /* some other unix */ +#include <unistd.h> +#include <sys/types.h> +#include <sys/times.h> + +#if TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif + +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <sys/utsname.h> /* 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 <vxWorks.h> +#include <stdio.h> +#include <semLib.h> +#include <hostLib.h> +#include <resolvLib.h> +#include <string.h> +#include <sys/socket.h> +#include <errno.h> +#include <symLib.h> +#include <sysSymTbl.h> + +#elif __WIN32__ +#include <winsock2.h> +#include <windows.h> +#include <winbase.h> + +#else /* unix of some kind */ +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <sys/param.h> +#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 <winsock2.h> +# include <windows.h> +# include <winbase.h> +#else /* Unix/VxWorks */ +# include <unistd.h> +#endif + +/* common */ +#include <string.h> +#include <stdlib.h> +#include <errno.h> + +#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 <errno.h> + +#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 <winsock2.h> +# include <windows.h> +# include <winbase.h> + +#elif VXWORKS + +# include <sys/types.h> +# include <unistd.h> +# include <sysLib.h> +# include <tickLib.h> + +#else /* unix */ + +# include <sys/types.h> +# include <unistd.h> +# include <sys/uio.h> + +#endif + +#include <string.h> + +#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 <winsock2.h> +# include <windows.h> +# include <winbase.h> +#else /* Unix/VxWorks */ +#include <unistd.h> +#endif + +#include <string.h> +#include <stdlib.h> +#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 <winsock2.h> +#include <windows.h> +#include <winbase.h> + +#elif VXWORKS +#include <sys/types.h> +#include <unistd.h> + +#else /* unix */ +#include <sys/types.h> +#include <unistd.h> +#include <sys/uio.h> +#endif + +#include <stdio.h> + +#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 <string.h> +#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 <string.h> +#include <stdlib.h> + +#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 (xl<yl) { + return -1; + } else if (xl>yl) { + 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) + +#define D_DECIMAL_EXP 4 /* 10^4 == 10000 */ +#define D_DECIMAL_BASE 10000 /* Max decimal exponent in a digit */ + +#define DLOW(x) ((digit_t)((x) & (D_BASE-1))) +#define DHIGH(x) ((digit_t)((x) >> 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 <gmp.h> + +#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 <string.h> +#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 <string.h> +#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 <stdio.h> +#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 <string.h> +#include <stdlib.h> + +#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<len; i++) { + a[i] = (long)(s[i]); + } + } + if (count) *count = len; + s += len; + break; + + case ERL_LIST_EXT: + len = get32be(s); + idx = 0; + + if (a) { + for (i=0; i<len; i++) { + if (ei_decode_long((char*)s,&idx,a+i) < 0) { + if (count) *count = i; + return -1; + } + } + } + else { + for (i=0; i<len; i++) { + if (ei_decode_long((char*)s,&idx,NULL) < 0) { + if (count) *count = i; + return -1; + } + } + } + + if (count) *count = len; + s += idx; + break; + + default: + return -1; + } + + + *index += s-s0; + + return 0; +} diff --git a/lib/erl_interface/src/decode/decode_list_header.c b/lib/erl_interface/src/decode/decode_list_header.c new file mode 100644 index 0000000000..dda711f9fd --- /dev/null +++ b/lib/erl_interface/src/decode/decode_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_decode_list_header(const char *buf, int *index, int *arity) +{ + const char *s = buf + *index; + const char *s0 = s; + + switch (get8(s)) { + case ERL_NIL_EXT: + if (arity) *arity = 0; + break; + + case ERL_LIST_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_long.c b/lib/erl_interface/src/decode/decode_long.c new file mode 100644 index 0000000000..b4138247e0 --- /dev/null +++ b/lib/erl_interface/src/decode/decode_long.c @@ -0,0 +1,86 @@ +/* + * %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_long(const char *buf, int *index, long *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); + 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; + unsigned long u = 0; + + /* Little Endian, and n always positive, except for LONG_MIN */ + for (i = 0; i < arity; i++) { + if (i < 4) { + u |= 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 > 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 <string.h> +#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 <string.h> +#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 <string.h> +#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; (i<count) && (i<3); i++) { + p->n[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 <string.h> +#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; i<len; i++) { + if ((etype = get8(s)) != ERL_SMALL_INTEGER_EXT) { + p[i] = (char)0; + return -1; + } + p[i] = get8(s); + } + p[i] = (char)0; + } + else { + for (i=0; i<len; i++) { + if ((etype = get8(s)) != ERL_SMALL_INTEGER_EXT) return -1; + s++; + } + } + /* Check NIL tail */ + if ((etype = get8(s)) != ERL_NIL_EXT) return -1; + break; + + case ERL_NIL_EXT: + if (p) p[0] = (char)0; + break; + + default: + return -1; + } + + + *index += s-s0; + + return 0; +} diff --git a/lib/erl_interface/src/decode/decode_trace.c b/lib/erl_interface/src/decode/decode_trace.c new file mode 100644 index 0000000000..ebaa78e29e --- /dev/null +++ b/lib/erl_interface/src/decode/decode_trace.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 "eidef.h" +#include "putget.h" + +int ei_decode_trace(const char *buf, int *index, erlang_trace *p) +{ + int arity = 0; + int tindex = *index; + + /* use a temporary index if any function should fail */ + + /* { Flags, Label, Serial, FromPid, Prev } */ + if (ei_decode_tuple_header(buf, &tindex, &arity) + || (arity != 5) + || ei_decode_long(buf, &tindex, &p->flags) + || 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 <string.h> +#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 <string.h> +#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 <gmp.h> + +#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 <string.h> +#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 <string.h> +#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 <stdio.h> +#include <string.h> +#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 <string.h> +#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 <string.h> +#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 <string.h> +#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 <string.h> +#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 <string.h> +#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; i<len; i++) { + put8(s,ERL_SMALL_INTEGER_EXT); + put8(s,p[i]); + } + put8(s,ERL_NIL_EXT); + } + + } + + *index += s-s0; + + return 0; +} + diff --git a/lib/erl_interface/src/encode/encode_trace.c b/lib/erl_interface/src/encode/encode_trace.c new file mode 100644 index 0000000000..de46f7fae8 --- /dev/null +++ b/lib/erl_interface/src/encode/encode_trace.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 "eidef.h" +#include "putget.h" + +int ei_encode_trace(char *buf, int *index, const erlang_trace *p) +{ + /* { Flags, Label, Serial, FromPid, Prev } */ + ei_encode_tuple_header(buf,index,5); + ei_encode_long(buf,index,p->flags); + 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 <winsock2.h> +#include <windows.h> +#include <winbase.h> + +#elif VXWORKS +#include <vxWorks.h> +#include <ifLib.h> +#include <sockLib.h> +#include <inetLib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> + +#else +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#endif + +#include <stdlib.h> +#include <string.h> + +#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 <winsock2.h> +#include <windows.h> +#include <winbase.h> + +#elif VXWORKS +#include <vxWorks.h> +#include <ifLib.h> +#include <sockLib.h> +#include <inetLib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> + +#else +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#endif + +#include <stdlib.h> +#include <string.h> + +#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 <winsock2.h> +#include <windows.h> +#include <winbase.h> + +#elif VXWORKS +#include <vxWorks.h> +#include <ifLib.h> +#include <sockLib.h> +#include <inetLib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> + +#else +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#endif + +#include <stdlib.h> +#include <string.h> + +#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; i<arity; i++) { + if (ei_decode_term(buf,index,NULL)) { + /* restore possibly changed index before returning */ + *index = tmpindex; + return -1; + } + } + return 0; + + case ERL_STRING_EXT: + return ei_decode_string(buf,index,NULL); + + case ERL_LIST_EXT: + case ERL_NIL_EXT: + if (ei_decode_list_header(buf,index,&arity) < 0) + return -1; + + if (arity) { + for (i=0; i<arity; i++) { + if (ei_decode_term(buf,index,NULL) < 0) { + /* restore possibly changed index before returning */ + *index = tmpindex; + return -1; + } + } + if (ei_decode_list_header(buf,index,&arity) < 0) { + *index = tmpindex; + return -1; + } + } + return 0; + + case ERL_BINARY_EXT: + return ei_decode_binary(buf,index,NULL,NULL); + + case ERL_LARGE_BIG_EXT: + default: + break; + } + } + + return -1; +} +#else +int ei_decode_term(const char *buf, int *index, void *t) +{ + const char *s = buf + *index; + const char *s0 = s; + ETERM *tmp; + + /* this decodes and advances s */ + if (!(tmp = erl_decode_buf((unsigned char **)&s))) return -1; + + if (t) *(ETERM **)t = tmp; + else erl_free_term(tmp); + + *index += s - s0; + + return 0; +} +#endif diff --git a/lib/erl_interface/src/legacy/encode_term.c b/lib/erl_interface/src/legacy/encode_term.c new file mode 100644 index 0000000000..c377d7b699 --- /dev/null +++ b/lib/erl_interface/src/legacy/encode_term.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 "eidef.h" +#include "eiext.h" +#include "putget.h" +#include "ei_x_encode.h" +#include "erl_interface.h" +#include "erl_marshal.h" + +/* FIXME: depends on old erl_interface */ + +int ei_x_encode_term(ei_x_buff* x, void* t) +{ + int i = x->index; + 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 <stdlib.h> +#include <sys/types.h> +#include <fcntl.h> + +#ifdef __WIN32__ +#include <winsock2.h> +#include <windows.h> +#include <winbase.h> + +#elif VXWORKS +#include <vxWorks.h> +#include <hostLib.h> +#include <selectLib.h> +#include <ifLib.h> +#include <sockLib.h> +#include <taskLib.h> +#include <inetLib.h> + +#include <unistd.h> +#include <sys/types.h> +#include <sys/times.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <timers.h> + +#include "erl_error.h" + +#else /* some other unix */ +#include <unistd.h> +#include <sys/types.h> +#include <sys/times.h> + +#if TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif + +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <sys/utsname.h> /* for gen_challenge (NEED FIX?) */ +#endif + +/* common includes */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +/* 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 <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> + +#ifdef VRTX /* What's VRIX? [sverkerw] */ +#define __READY_EXTENSIONS__ +#endif +#include <errno.h> + +#if defined(VXWORKS) +#include <taskLib.h> +#include <taskVarLib.h> +#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 <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#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<size; i++) if (!arr[i]) return NULL; + /* ASSERT(arr != NULL); */ + + ep = erl_alloc_eterm(ERL_TUPLE); + ERL_COUNT(ep) = 1; + ERL_TUPLE_SIZE(ep) = size; + ERL_TUPLE_ELEMS(ep) = (ETERM**) erl_malloc((size) * (sizeof(ETERM*))); + for (i = 0; i < size; i++) { + /* ASSERT(arr[i] != NULL); */ + ERL_COUNT(arr[i])++; + ERL_TUPLE_ELEMENT(ep, i) = arr[i]; + } + return ep; +} + +/* + * SET an ELEMENT in a TUPLE. Free the old element + * and bump the reference counter of the new one. + * Return 1 on success, otherwise 0. + */ +#if 0 +int erl_setelement (int ix, ETERM *ep, ETERM *vp) +{ + if ((!ep) || (!vp)) return 0; + /* ASSERT(ep != NULL); + * ASSERT(vp != NULL); + */ + + if ((ERL_TYPE(ep) == ERL_TUPLE) && (ix <= ERL_TUPLE_SIZE(ep))) { + erl_free_term(ERL_TUPLE_ELEMENT(ep, ix-1)); + ERL_TUPLE_ELEMENT(ep, ix-1) = vp; + ERL_COUNT(vp)++; + return 1; + } + erl_err_msg("<ERROR> 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<size; i++) if (!arr[i]) return NULL; + + /* ASSERT(arr != NULL); */ + ep = erl_mk_empty_list(); + if (size > 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("<ERROR> 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("<ERROR> 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("<ERROR> 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 <stdio.h> +#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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#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 <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <ctype.h> + +#ifdef VRTX +#define __READY_EXTENSIONS__ +#include <errno.h> +#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("<ERROR> 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; i<erl_size(p); i++) + if (ematch(p->uval.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 <stddef.h> +#include <stdlib.h> + +#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("<ERROR> 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<size; i++) + erl_free_term(arr[i]); + +} /* erl_free_array */ + + +void* erl_malloc (long size) +{ + void *res; + + if ((res = ei_malloc(size)) == NULL) + erl_err_sys("<ERROR> 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("<ERROR> 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 <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <sys/types.h> +#include <string.h> + +#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 <limits.h> +#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; i<ep->uval.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("<ERROR> 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; i<ep->uval.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("<ERROR> 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("<WARNING> 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; i<ep->uval.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("<ERROR> 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("<ERROR> 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<j; k++) + if ((i = jump(ext)) == 0) + return(0); + if (**ext == ERL_NIL_EXT) { + *ext += 1; + break; + } + if (jump(ext) == 0) return 0; + break; + case ERL_STRING_EXT: + i = **ext << 8 | (*ext)[1]; + *ext += 2 + i; + break; + case ERL_SMALL_TUPLE_EXT: + i = *(*ext)++; + goto jump_tuple; + case ERL_LARGE_TUPLE_EXT: + i = (**ext << 24) | ((*ext)[1] << 16) |((*ext)[2] << 8) | (*ext)[3]; + *ext += 4; + jump_tuple: + for (j = 0; j < i; j++) + if ((k = jump(ext)) == 0) + return(0); + break; + case ERL_FLOAT_EXT: + *ext += 31; + break; + case ERL_BINARY_EXT: + i = (**ext << 24) | ((*ext)[1] << 16) |((*ext)[2] << 8) | (*ext)[3]; + *ext += 4+i; + break; + case ERL_FUN_EXT: + i = (**ext << 24) | ((*ext)[1] << 16) |((*ext)[2] << 8) | (*ext)[3]; + *ext += 4; + i += 4; + for (j = 0; j < i; j++) + if ((k = jump(ext)) == 0) + return(0); + break; + case ERL_NEW_FUN_EXT: + i = get32be(*ext); + *ext += i + 4; + break; + case ERL_SMALL_BIG_EXT: + i = *(*ext); + *ext += i + 1; + break; + case ERL_LARGE_BIG_EXT: + i = get32be(*ext); + *ext += i + 4; + break; + default: + return 0; + } /* switch */ + + return 1; + +} /* jump */ + +/* + * The actual PEEK engine. + */ +static unsigned char *peek_ext(unsigned char **ext, int jumps) +{ + int i; + + switch (*(*ext)++) + { + case ERL_VERSION_MAGIC: + return peek_ext(ext, jumps); + case ERL_SMALL_TUPLE_EXT: + i = *(*ext)++; + goto do_the_peek_stuff; + case ERL_LARGE_TUPLE_EXT: + case ERL_LIST_EXT: + i = (**ext << 24) | ((*ext)[1]) << 16| ((*ext)[2]) << 8| ((*ext)[3]) ; + *ext += 4; + do_the_peek_stuff: + if (i <= jumps) { +#ifdef DEBUG + erl_err_msg("<ERROR> peek_ext: Out of range"); +#endif + return NULL; + } + for(i=0; i<jumps; i++) + if (!jump(ext)) { +#ifdef DEBUG + erl_err_msg("<ERROR> peek_ext: Bad data"); +#endif + return NULL; + } + return *ext; + default: +#ifdef DEBUG + erl_err_msg("<ERROR> 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<e1_len;i++) { + bp[5+2*i] = ERL_SMALL_INTEGER_EXT; + bp[5+2*i+1] = (*e1)[3+i]; + } + + bp[5+2*e1_len] = ERL_NIL_EXT; + + res = cmp_exe2(&bp, e2); + + if ( e1_len >= 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 (f1<f2) return -1; + else if (f1>f2) 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 <stdio.h> +#include <stdlib.h> +#include <setjmp.h> +#include <signal.h> + +#if TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# 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 <setjmp.h> + +/* + 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 <stdlib.h> +#include <string.h> +#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<arity; i++) { + names[i] = s; /* insert the pointer */ + if (ei_decode_atom(buf,&index,s)) break; /* copy the data */ + if (count) (*count)++; + s += strlen(names[i]) + 1; /* advance pointer */ + } + names[i]=NULL; + + return names; +} diff --git a/lib/erl_interface/src/legacy/global_register.c b/lib/erl_interface/src/legacy/global_register.c new file mode 100644 index 0000000000..3a4de8b08e --- /dev/null +++ b/lib/erl_interface/src/legacy/global_register.c @@ -0,0 +1,110 @@ +/* + * %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 <string.h> +#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 <string.h> +#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 <stdlib.h> +#include <string.h> +#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 <string.h> + +#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; (i<term->value.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 <vxWorks.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <ctype.h> + +#ifdef VRTX +#define __READY_EXTENSIONS__ +#include <errno.h> +#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 <winsock2.h> +#include <windows.h> +#include <winbase.h> + +#elif VXWORKS +#include <vxWorks.h> +#include <semLib.h> + +#else /* unix */ +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#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 <taskLib.h> +#include <taskVarLib.h> +#endif + +#ifdef __WIN32__ +#include <winsock2.h> +#include <windows.h> +#include <winbase.h> +#endif + +#ifdef HAVE_MIT_PTHREAD_H +#include <pthread/mit/pthread.h> +#elif HAVE_PTHREAD_H +#include <pthread.h> +#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 <stddef.h> +#include <stdlib.h> +#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 <winsock2.h> +#include <windows.h> +#include <process.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <time.h> +#include <errno.h> + +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 <vxWorks.h> +#include <hostLib.h> +#include <ifLib.h> +#include <sockLib.h> +#include <taskLib.h> +#include <inetLib.h> +#include <selectLib.h> +#include <sys/types.h> +#include <ioLib.h> +#include <unistd.h> + +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 <stdlib.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> + +#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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "ei_portio.h" +#include "ei_internal.h" + +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#else +#include <time.h> +#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 <vxWorks.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <ctype.h> + +#ifdef VRTX +#define __READY_EXTENSIONS__ +#include <errno.h> +#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;i<b->arity;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 <stdlib.h> +#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 <vxWorks.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#ifdef VRTX +#define __READY_EXTENSIONS__ +#include <errno.h> +#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 <vxWorks.h> +#endif + +#include <stddef.h> /* 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 <string.h> +#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 <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> + +#include <sys/types.h> + +#include "eidef.h" + +#ifndef __WIN32__ +# ifdef TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +# else +# ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# 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<len; i++) { + if (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<len; i++) { + if (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<len; i++) { + if (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,"<ERROR> 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<buflen; i++) if (!isprint(buf[i])) return 0; + + /* is printable */ + return 1; +} + +/*************************************************************************** + * + * Skip over bignums, we can't print them + * + ***************************************************************************/ + +/* FIXME we can if bignum small enough or if we use Per's functions or + if we have compiled in gmp support */ + +/* this function doesn't do anything but skip over the number in the buffer */ +/* it doesn't really belong here either... */ + +static int ei_decode_skip_bignum(const char *buf, int *index, void *p) +{ + const char *s = buf + *index; + const char *s0 = s; + long n; + + switch (get8(s)) { + case ERL_LARGE_BIG_EXT: + n = get32be(s); + s += n+1; + break; + + default: + erl_errno = EIO; + return -1; + } + + *index += s-s0; + + return 0; +} diff --git a/lib/erl_interface/src/misc/show_msg.h b/lib/erl_interface/src/misc/show_msg.h new file mode 100644 index 0000000000..fac51f3278 --- /dev/null +++ b/lib/erl_interface/src/misc/show_msg.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% + * + + */ +#ifndef _SHOW_MSG_H +#define _SHOW_MSG_H + +void ei_show_recmsg(FILE *dest, erlang_msg *msg, char *buf); +int ei_show_sendmsg(FILE *dest, const char *header, const char *msgbuf); + +#endif /* _SHOW_MSG_H */ diff --git a/lib/erl_interface/src/not_used/ei_send.c b/lib/erl_interface/src/not_used/ei_send.c new file mode 100644 index 0000000000..2701b4404c --- /dev/null +++ b/lib/erl_interface/src/not_used/ei_send.c @@ -0,0 +1,104 @@ +/* + * %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 <winsock2.h> +#include <windows.h> +#include <winbase.h> + +#elif VXWORKS +#include <sys/types.h> +#include <unistd.h> + +#else /* unix */ +#include <sys/types.h> +#include <unistd.h> +#include <sys/uio.h> +#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 <winsock2.h> +#include <windows.h> +#include <winbase.h> + +#elif VXWORKS +#include <sys/types.h> +#include <unistd.h> + +#else /* unix */ +#include <sys/types.h> +#include <unistd.h> +#include <sys/uio.h> +#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 <winsock2.h> +#include <windows.h> +#include <winbase.h> + +#elif VXWORKS +#include <unistd.h> + +#else /* unix */ +#include <unistd.h> + +#endif + +#include <string.h> +#include <stdlib.h> +#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 <winsock2.h> +#include <windows.h> +#include <winbase.h> + +#elif VXWORKS +#include <unistd.h> + +#else /* unix */ +#include <unistd.h> + +#endif + +#include <string.h> +#include <stdlib.h> +#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 <gmp.h> +#endif /* HAVE_GMP_H && HAVE_LIBGMP */ + +/* #include <netdb.h> 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 <winsock2.h> +#include <direct.h> +#include <windows.h> +#include <winbase.h> + +#elif VXWORKS + +#include <stdio.h> +#include <string.h> +#include <vxWorks.h> +#include <hostLib.h> +#include <selectLib.h> +#include <ifLib.h> +#include <sockLib.h> +#include <taskLib.h> +#include <inetLib.h> +#include <unistd.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <time.h> + +#else /* unix */ + +#include <sys/types.h> +#include <sys/uio.h> +#include <sys/time.h> +#include <unistd.h> +#include <sys/param.h> +#include <netdb.h> +#include <sys/times.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#if TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif + +#endif + +#include <stdio.h> +#include <stdlib.h> + +#include <string.h> +#include <ctype.h> +#include <fcntl.h> +#include <signal.h> + +#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.<Nodename>\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 <netdb.h> 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 <stdlib.h> +#include <sys/types.h> +#include <fcntl.h> + +#ifdef __WIN32__ +#include <winsock2.h> +#include <windows.h> +#include <winbase.h> + +#elif VXWORKS +#include <stdio.h> +#include <string.h> +#include <vxWorks.h> +#include <hostLib.h> +#include <selectLib.h> +#include <ifLib.h> +#include <sockLib.h> +#include <taskLib.h> +#include <inetLib.h> +#include <unistd.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <symLib.h> +#include <sysSymTbl.h> +#include <sysLib.h> +#include <tickLib.h> + +#if TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif + +#include <a_out.h> + +/* #include "netdb.h" */ +#else /* other unix */ +#include <errno.h> +#include <netdb.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <sys/time.h> +#include <time.h> +#include <unistd.h> +#include <sys/types.h> +#include <signal.h> +#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 <stdio.h> + +#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; i<tab->size; 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 <stdlib.h> +#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; i<tab->size; 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 <stdlib.h> +#include <string.h> +#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 <stdlib.h> +#include <string.h> +#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 <stdlib.h> +#include <string.h> +#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 <stdlib.h> +#include <string.h> +#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 <stdlib.h> +#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; i<oldtab->size; 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 <stdlib.h> +#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; i<tab->size; 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 <stdlib.h> +#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 <stdlib.h> +#include <string.h> +#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, <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_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; i<tab->size; 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 <stdlib.h> +#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 <vxWorks.h> +#endif + +#include <stdarg.h> +#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 <stdlib.h> +#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 <stdlib.h> +#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 <stdlib.h> +#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 <stdlib.h> +#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 <stdlib.h> +#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;i<tab->size;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 <stdlib.h> +#include <string.h> +#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; i<count; i++) { + index = len; + while ((j = ei_recv_internal(fd,&msgbuf,&index,&msg,&msglen,1,0)) == 0) index = len; + if (j<0) goto restore_failure; + + /* decode the first part of the message */ + index = 0; + if ((msg.msgtype != ERL_SEND) + || ei_decode_version(msgbuf,&index,&version) + || ei_decode_tuple_header(msgbuf,&index,&arity) + || (arity != 6) + || ei_decode_atom(msgbuf,&index,tag) + || strcmp(tag,EI_MNESIA_RECV)) + goto restore_failure; + + /* decode the rest of the message and insert data into table */ + if (mn_decode_insert(reg,msgbuf,&index,keybuf)) goto restore_failure; + } + + /* wait for unlink */ + if (mn_unlink(fd)) return -1; + + /* clear all the dirty bits */ + ei_hash_foreach(reg->tab,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 <vxWorks.h> +#endif + +#include <stdarg.h> +#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 <stdlib.h> +#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 <stdlib.h> +#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 <stdlib.h> +#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 <stdlib.h> +#include <string.h> +#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; +} |