diff options
Diffstat (limited to 'lib/erl_interface')
209 files changed, 34134 insertions, 0 deletions
diff --git a/lib/erl_interface/AUTHORS b/lib/erl_interface/AUTHORS new file mode 100644 index 0000000000..c8ad36400d --- /dev/null +++ b/lib/erl_interface/AUTHORS @@ -0,0 +1,9 @@ +Original Authors and Contributors: + +Torbj�rn T�rnqvist +Claes Wikstr�m +Tony Rogval +Bj�rn Gustavsson +Kenneth Lundin +Jakob Cederlund +Gordon Beaton diff --git a/lib/erl_interface/Makefile b/lib/erl_interface/Makefile new file mode 100644 index 0000000000..256b0309cd --- /dev/null +++ b/lib/erl_interface/Makefile @@ -0,0 +1,32 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1996-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Common Macros +# ---------------------------------------------------- +SUB_DIRECTORIES = src doc/src + +SPECIAL_TARGETS = + +# ---------------------------------------------------- +# Default Subdir Targets +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_subdir.mk diff --git a/lib/erl_interface/aclocal.m4 b/lib/erl_interface/aclocal.m4 new file mode 120000 index 0000000000..151fd5ea5a --- /dev/null +++ b/lib/erl_interface/aclocal.m4 @@ -0,0 +1 @@ +../../erts/aclocal.m4
\ No newline at end of file diff --git a/lib/erl_interface/configure.in b/lib/erl_interface/configure.in new file mode 100644 index 0000000000..80b229c1c3 --- /dev/null +++ b/lib/erl_interface/configure.in @@ -0,0 +1,443 @@ +# -*- Autoconf -*- +# %CopyrightBegin% +# +# Copyright Ericsson AB 2000-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# Process this file with autoconf to produce a configure script. +# The starting point for this file was the output from 'autoscan'. + +# Strange, VxWorks HAVE_SENS not set here, see "ei_resolve.h" + +# Find the erl_interface version number and set m4 macro to it. +# We do this because AC_INIT can't handle shell variables. Still broken. +dnl m4_define(EI_VERSION,`grep EI_VSN ../vsn.mk | sed 's/^.*=[ ]*//'`) +dnl m4_define(EI_VERSION,regexp(m4_include(VERSION),[version \([-.0-9A-Za-z]+\)],[\1])) + +AC_INIT() + +if test "x$no_recursion" != "xyes" -a "x$OVERRIDE_CONFIG_CACHE" = "x"; then + # We do not want to use a common cache! + cache_file=/dev/null +fi + +dnl How to set srcdir absolute is taken from the GNU Emacs distribution +#### Make srcdir absolute, if it isn't already. It's important to +#### avoid running the path through pwd unnecessary, since pwd can +#### give you automounter prefixes, which can go away. +case "${srcdir}" in + /* ) ;; + . ) + ## We may be able to use the $PWD environment variable to make this + ## absolute. But sometimes PWD is inaccurate. + ## Make sure CDPATH doesn't affect cd (in case PWD is relative). + CDPATH= + if test "${PWD}" != "" && test "`(cd ${PWD} ; sh -c pwd)`" = "`pwd`" ; + then + srcdir="$PWD" + else + srcdir="`(cd ${srcdir}; pwd)`" + fi + ;; + * ) srcdir="`(cd ${srcdir}; pwd)`" ;; +esac + +AC_CONFIG_AUX_DIR([$srcdir/src/auxdir]) + +if test "X$host" != "Xfree_source" -a "X$host" != "Xwin32"; then + AC_CANONICAL_HOST +else + host_os=win32 +fi + +TARGET=$host +AC_SUBST(TARGET) + +AC_CONFIG_HEADER([src/$host/config.h:src/auxdir/config.h.in]) + +dnl ---------------------------------------------------------------------- +dnl Optional features +dnl ---------------------------------------------------------------------- + +AC_ARG_WITH(xcomp-conf, +[ --with-xcompconf=PATH path to cross compilation configuration]) +if test "x$with_xcompconf" != "xno" -a "x$with_xcompconf" != "x" ; then + . $with_xcompconf +fi + +# Use --disable-threads to force building single threaded libs even +# if pthreads exists (for test purposes). +AC_ARG_ENABLE(threads, +[ --disable-threads use to only build single threaded libs], +[ case "$enableval" in + no) threads_disabled=yes ;; + *) threads_disabled=no ;; + esac ], +[ threads_disabled=no ]) + +dnl ---------------------------------------------------------------------- +dnl Checks for programs +dnl ---------------------------------------------------------------------- + +AC_PROG_CC +AC_PROG_CPP +dnl AC_PROG_LIBTOOL +AC_PROG_RANLIB +if test "x$LD" = "x"; then + AC_CHECK_TOOL([LD],[ld],[ld]) +fi +AC_SUBST(LD) + +AC_CHECK_SIZEOF(short, $erl_xcomp_short) +AC_CHECK_SIZEOF(int, $erl_xcomp_int) +AC_CHECK_SIZEOF(long, $erl_xcomp_long) +AC_CHECK_SIZEOF(void *, $erl_xcomp_void_p) +AC_CHECK_SIZEOF(long long, $erl_xcomp_long_long) + +if test $ac_cv_sizeof_void_p = 8; then + CFLAGS="$CFLAGS -DEI_64BIT" +fi + +AC_CHECK_PROG(AR, ar, ar, false) +if test "$ac_cv_prog_AR" = false; then + AC_MSG_ERROR([No 'ar' command found in PATH]) +fi + +dnl +dnl We can live with Solaris /usr/ucb/install +dnl +case $host in + *-*-solaris*|free_source) + if test -x /usr/ucb/install; then + INSTALL="/usr/ucb/install -c" + fi + ;; + *) + ;; +esac + +AC_PROG_INSTALL +LM_PROG_INSTALL_DIR +AC_SUBST(INSTALL_DIR) + +case $host_os in + darwin*) + dnl Need to preserve modification time on archives; + dnl otherwise, ranlib has to be run on archives + dnl again after installation. + INSTALL_DATA="$INSTALL_DATA -p";; + *) + ;; +esac + +# Checks for libraries. +AC_CHECK_LIB([nsl], [gethostbyname]) +AC_CHECK_LIB([socket], [getpeername]) + +# Checks for header files. +AC_HEADER_STDC +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h malloc.h netdb.h netinet/in.h stddef.h stdlib.h string.h sys/param.h sys/socket.h sys/select.h sys/time.h unistd.h sys/types.h]) + +# Checks for typedefs, structures, and compiler characteristics. +# fixme AC_C_CONST & AC_C_VOLATILE needed for Windows? +dnl AC_C_CONST +dnl AC_C_VOLATILE +AC_TYPE_UID_T +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_HEADER_TIME +AC_MSG_CHECKING([for socklen_t usability]) +AC_TRY_COMPILE([#include <sys/types.h> +#include <sys/socket.h>], +[socklen_t mylen;], +[AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SOCKLEN_T)], +[AC_MSG_RESULT(no)]) + +# Checks for library functions. +AC_FUNC_ALLOCA +dnl AC_FUNC_FORK +# FIXME check that this isn't set in normal cases +AC_PROG_GCC_TRADITIONAL +# Check if malloc(0) is ok +dnl AC_FUNC_MALLOC +dnl AC_FUNC_REALLOC +AC_FUNC_MEMCMP +dnl AC_FUNC_SELECT_ARGTYPES +dnl AC_TYPE_SIGNAL +dnl AC_FUNC_STRERROR_R +dnl AC_FUNC_VPRINTF +AC_CHECK_FUNCS([dup2 gethostbyaddr gethostbyname \ + gethostbyaddr_r \ + gethostbyname_r gethostname writev \ + gethrtime gettimeofday inet_ntoa memchr memmove memset select \ + socket strchr strerror strrchr strstr uname]) +AC_CHECK_FUNC(res_gethostbyname, [], + AC_CHECK_LIB(resolv, res_gethostbyname) +) +AC_CHECK_FUNC(clock_gettime, [], + AC_CHECK_LIB(rt, clock_gettime) +) + +# --------------------------------------------------------------------------- +# We don't link against libgmp except for "make check" +# but linking will also tell us that it is >= 4.1 +# --------------------------------------------------------------------------- + +AC_ARG_WITH(gmp, +[ --with-gmp=PATH specify location of GNU MP include and lib + --with-gmp use GNU MP (will search for it)]) + +# We don't just want any GNU MP version, we want 4.1 or later +# that contain the import/export functions we need. + +if test "x$with_gmp" = "xyes" ;then + for dir in /usr /usr/pkg /usr/local /usr/local/gmp /usr/lib/gmp /usr/gmp; do + AC_CHECK_HEADER($dir/include/gmp.h, ac_cv_gmp=yes, ac_cv_gmp=no) + if test $ac_cv_gmp = yes ; then + CFLAGS="$CFLAGS -I$dir/include -L$dir/lib" + AC_DEFINE(HAVE_GMP_H) + break + fi + done + if test $ac_cv_gmp = no ; then + AC_MSG_ERROR([No GNU MP installation found]) + fi + AC_CHECK_LIB(gmp, __gmpz_export) + # FIXME return ERROR if no lib +elif test "x$with_gmp" != "xno" -a -n "$with_gmp" ;then + # Option given with PATH to package + AC_MSG_CHECKING(for GNU MP) + if test ! -d "$with_gmp" ; then + AC_MSG_ERROR(Invalid path to option --with-gmp=PATH) + fi + AC_MSG_RESULT(yes) + CFLAGS="$CFLAGS -I$with_gmp/include -L$with_gmp/lib" + AC_DEFINE(HAVE_GMP_H) + AC_CHECK_LIB(gmp, __gmpz_export) + # FIXME return ERROR if no lib +fi + +MIXED_CYGWIN=no + +AC_MSG_CHECKING(for mixed cygwin and native VC++ environment) +if test "X$CC" = "Xcc.sh" -a "X$host" = "Xwin32" -a "x$GCC" != x"yes"; then + if test -x /usr/bin/cygpath; then + CFLAGS="-O2" + MIXED_CYGWIN=yes + AC_MSG_RESULT([yes]) + MIXED_CYGWIN_VC=yes + else + AC_MSG_RESULT([undeterminable]) + AC_MSG_ERROR(Seems to be mixed windows but not with cygwin, cannot handle this!) + fi +else + AC_MSG_RESULT([no]) + MIXED_CYGWIN_VC=no +fi +AC_SUBST(MIXED_CYGWIN_VC) + +AC_MSG_CHECKING(for mixed cygwin and native MinGW environment) +if test "X$CC" = "Xcc.sh" -a "X$host" = "Xwin32" -a "x$GCC" = x"yes"; then + if test -x /usr/bin/cygpath; then + CFLAGS="-O2" + MIXED_CYGWIN=yes + AC_MSG_RESULT([yes]) + MIXED_CYGWIN_MINGW=yes + else + AC_MSG_RESULT([undeterminable]) + AC_MSG_ERROR(Seems to be mixed windows but not with cygwin, cannot handle this!) + fi +else + AC_MSG_RESULT([no]) + MIXED_CYGWIN_MINGW=no +fi +AC_SUBST(MIXED_CYGWIN_MINGW) + +AC_MSG_CHECKING(if we mix cygwin with any native compiler) +if test "X$MIXED_CYGWIN" = "Xyes" ; then + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + +AC_SUBST(MIXED_CYGWIN) + +dnl +dnl Threads +dnl +found_threads=no +THR_LIBS= +THR_DEFS= +EI_THREADS="false" +AC_SUBST(THR_LIBS) +AC_SUBST(THR_DEFS) +AC_SUBST(EI_THREADS) + +case "$threads_disabled" in + no) + AC_MSG_CHECKING([for native win32 threads]) + if test "X$host_os" = "Xwin32"; then + THR_DEFS="-DWIN32_THREADS" + found_threads=yes + EI_THREADS="true" + AC_MSG_RESULT([yes]) + AC_MSG_CHECKING([for __declspec(thread) usability]) + if test "X$GCC" = "Xyes"; then + AC_MSG_RESULT([no]) + else + THR_DEFS="$THR_DEFS -DUSE_DECLSPEC_THREAD" + AC_MSG_RESULT([yes]) + fi + else + AC_MSG_RESULT(no) + + dnl Check for POSIX threads + + pthread_lib="" + AC_CHECK_LIB(pthread, + pthread_create, + [found_threads=yes + EI_THREADS="true" + THR_LIBS="-lpthread" + THR_DEFS="-D_REENTRANT -D_THREAD_SAFE -DPOSIX_THREADS" + pthread_lib=pthread]) + + # FreeBSD has pthreads in special c library, c_r + if test $found_threads = no; then + AC_CHECK_LIB(c_r, + pthread_create, + [found_threads=yes + EI_THREADS="true" + THR_LIBS="-lc_r" + THR_DEFS="-D_REENTRANT -D_THREAD_SAFE -DPOSIX_THREADS" + pthread_lib=c_r]) + fi + + if test "x$pthread_lib" != "x"; then + AC_CHECK_LIB($pthread_lib,pthread_atfork,AC_DEFINE(HAVE_PTHREAD_ATFORK)) + AC_CHECK_HEADER(pthread.h, AC_DEFINE(HAVE_PTHREAD_H)) + dnl Some Linuxes have <pthread/mit/pthread.h> instead of <pthread.h> + AC_CHECK_HEADER(pthread/mit/pthread.h, AC_DEFINE(HAVE_MIT_PTHREAD_H)) + case $host_os in + solaris*) + THR_DEFS="$THR_DEFS -D_POSIX_PTHREAD_SEMANTICS";; + linux*) + dnl NPTL test stolen from $ERL_TOP/erts/aclocal.m4 + AC_MSG_CHECKING(for Native POSIX Thread Library) + case `getconf GNU_LIBPTHREAD_VERSION 2>/dev/null` in + nptl*) nptl=yes;; + NPTL*) nptl=yes;; + *) nptl=no;; + esac + AC_MSG_RESULT($nptl) + if test $nptl = yes; then + need_nptl_incldir=no + AC_CHECK_HEADER(nptl/pthread.h, need_nptl_incldir=yes) + if test $need_nptl_incldir = yes; then + # Ahh... + nptl_path="$C_INCLUDE_PATH:$CPATH:/usr/local/include:/usr/include" + nptl_ws_path= + save_ifs="$IFS"; IFS=":" + for dir in $nptl_path; do + if test "x$dir" != "x"; then + nptl_ws_path="$nptl_ws_path $dir" + fi + done + IFS=$save_ifs + nptl_incldir= + for dir in $nptl_ws_path; do + AC_CHECK_HEADER($dir/nptl/pthread.h, + nptl_incldir=$dir/nptl) + if test "x$nptl_incldir" != "x"; then + THR_DEFS="$THR_DEFS -isystem $nptl_incldir" + break + fi + done + if test "x$nptl_incldir" = "x"; then + AC_MSG_ERROR(Failed to locate nptl system include directory) + fi + fi + fi + + ;; + *) + ;; + esac + fi + fi + ;; + yes) + # Threads disabled + ;; +esac + +# --------------------------------------------------------------------------- +# Warning flags to the C compiler +# --------------------------------------------------------------------------- +AC_SUBST(WFLAGS) + +if test "x$GCC" = xyes; then + WFLAGS="-Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Winline" + # check which GCC version + GCC_VERSION=`$CC -v 2>&1 | sed -n 's/gcc version //p'` + # GCC 3.3 and later supports C99 strict aliasing + # until all source is compliant with strict aliasing we disable it + case "$GCC_VERSION" in + 1*) ;; + 2*) ;; + 3.0*) ;; + 3.1*) ;; + 3.2*) ;; + *) + WFLAGS="$WFLAGS -fno-strict-aliasing";; + esac +else + WFLAGS="" +fi + +# --------------------------------------------------------------------------- +# FIXME We want to use libtool but until then.... +# --------------------------------------------------------------------------- + +AC_SUBST(DED_CFLAGS) +dnl AC_SUBST(DED_LD) +dnl AC_SUBST(DED_LDFLAGS) + +if test "X$host" = "Xwin32"; then + DED_CFLAGS="$CFLAGS" +else + case $host_os in + darwin*) + CFLAGS="$CFLAGS -no-cpp-precomp" + ;; + esac + + if test "x$GCC" = xyes; then + DED_CFLAGS="$CFLAGS -fPIC" + else + DED_CFLAGS="$CFLAGS" + fi +fi + +# --------------------------------------------------------------------------- +# XXX +# --------------------------------------------------------------------------- + +AC_OUTPUT( + src/$host/Makefile:src/Makefile.in + src/$host/eidefs.mk:src/eidefs.mk.in + ) diff --git a/lib/erl_interface/doc/html/.gitignore b/lib/erl_interface/doc/html/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/erl_interface/doc/html/.gitignore diff --git a/lib/erl_interface/doc/man1/.gitignore b/lib/erl_interface/doc/man1/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/erl_interface/doc/man1/.gitignore diff --git a/lib/erl_interface/doc/man3/.gitignore b/lib/erl_interface/doc/man3/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/erl_interface/doc/man3/.gitignore diff --git a/lib/erl_interface/doc/pdf/.gitignore b/lib/erl_interface/doc/pdf/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/erl_interface/doc/pdf/.gitignore diff --git a/lib/erl_interface/doc/src/Makefile b/lib/erl_interface/doc/src/Makefile new file mode 100644 index 0000000000..e05b647cb2 --- /dev/null +++ b/lib/erl_interface/doc/src/Makefile @@ -0,0 +1,129 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1998-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../../vsn.mk +VSN=$(EI_VSN) +APPLICATION=erl_interface + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +XML_REF1_FILES = erl_call.xml +XML_REF3_FILES = erl_connect.xml \ + erl_error.xml \ + erl_eterm.xml \ + erl_format.xml \ + erl_malloc.xml \ + erl_marshal.xml \ + erl_global.xml \ + ei.xml \ + ei_connect.xml \ + registry.xml + +BOOK_FILES = book.xml +XML_APPLICATION_FILES = ref_man.xml +#ref_man_ei.xml ref_man_erl_interface.xml +XML_PART_FILES = \ + part.xml \ + part_notes.xml \ + part_notes_history.xml +XML_CHAPTER_FILES = ei_users_guide.xml notes.xml notes_history.xml + +XML_FILES = $(XML_REF1_FILES) $(XML_REF3_FILES) $(BOOK_FILES) \ + $(XML_APPLICATION_FILES) $(XML_PART_FILES) $(XML_CHAPTER_FILES) +# ---------------------------------------------------- + +HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html) + +INFO_FILE = ../../info + +GIF_FILES = + +MAN1_FILES = $(XML_REF1_FILES:%.xml=$(MAN1DIR)/%.1) +MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) + +HTML_REF_MAN_FILE = $(HTMLDIR)/index.html + +TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +$(HTMLDIR)/%.gif: %.gif + $(INSTALL_DATA) $< $@ + +docs: pdf html man + +$(TOP_PDF_FILE): $(XML_FILES) + +pdf: $(TOP_PDF_FILE) + +html: gifs $(HTML_REF_MAN_FILE) + +man: $(MAN1_FILES) $(MAN3_FILES) + +gifs: $(GIF_FILES:%=$(HTMLDIR)/%) + +debug opt: + +clean clean_docs clean_tex: + rm -rf $(HTMLDIR)/* + rm -f $(MAN1DIR)/* + rm -f $(MAN3DIR)/* + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f errs core *~ + + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf + $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf + $(INSTALL_DIR) $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(HTMLDIR)/* \ + $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) + $(INSTALL_DIR) $(RELEASE_PATH)/man/man1 + $(INSTALL_DATA) $(MAN1_FILES) $(RELEASE_PATH)/man/man1 + $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 + $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 + + +release_spec: + diff --git a/lib/erl_interface/doc/src/book.xml b/lib/erl_interface/doc/src/book.xml new file mode 100644 index 0000000000..e911b6aa2b --- /dev/null +++ b/lib/erl_interface/doc/src/book.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book xmlns:xi="http://www.w3.org/2001/XInclude"> + <header titlestyle="normal"> + <copyright> + <year>1998</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Erlang Interface</title> + <prepared>Gordon Beaton</prepared> + <docno></docno> + <date>1998-11-30</date> + <rev>1.2</rev> + <file>book.sgml</file> + </header> + <insidecover> + </insidecover> + <pagetext>Erlang Interface</pagetext> + <preamble> + <contents level="2"></contents> + </preamble> + <parts lift="no"> + <xi:include href="part.xml"/> + </parts> + <applications> + <xi:include href="ref_man.xml"/> + </applications> + <releasenotes> + <xi:include href="notes.xml"/> + </releasenotes> + <listofterms></listofterms> + <index></index> +</book> + diff --git a/lib/erl_interface/doc/src/ei.xml b/lib/erl_interface/doc/src/ei.xml new file mode 100644 index 0000000000..2f65a8c375 --- /dev/null +++ b/lib/erl_interface/doc/src/ei.xml @@ -0,0 +1,728 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE cref SYSTEM "cref.dtd"> + +<cref> + <header> + <copyright> + <year>2001</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>ei</title> + <prepared>Jakob Cederlund</prepared> + <responsible>Kent Boortz</responsible> + <docno>1</docno> + <approved>Kenneth Lundin</approved> + <checked></checked> + <date>2000-11-27</date> + <rev>PA1</rev> + <file>ei.sgml</file> + </header> + <lib>ei</lib> + <libsummary>routines for handling the erlang binary term format</libsummary> + <description> + <p>The library <c><![CDATA[ei]]></c> contains macros and functions to encode + and decode the erlang binary term format.</p> + <p>With <c><![CDATA[ei]]></c>, you can convert atoms, lists, numbers and + binaries to and from the binary format. This is useful when + writing port programs and drivers. <c><![CDATA[ei]]></c> uses a given + buffer, and no dynamic memory (with the exception of + <c><![CDATA[ei_decode_fun()]]></c>), and is often quite fast.</p> + <p>It also handles C-nodes, C-programs that talks erlang + distribution with erlang nodes (or other C-nodes) using the + erlang distribution format. The difference between <c><![CDATA[ei]]></c> and + <c><![CDATA[erl_interface]]></c> is that <c><![CDATA[ei]]></c> uses the binary format + directly when sending and receiving terms. It is also thread + safe, and using threads, one process can handle multiple + C-nodes. The <c><![CDATA[erl_interface]]></c> library is built on top of + <c><![CDATA[ei]]></c>, but of legacy reasons, it doesn't allow for multiple + C-nodes. In general, <c><![CDATA[ei]]></c> is the preferred way of doing + C-nodes.</p> + <p>The decode and encode functions use a buffer an index into the + buffer, which points at the point where to encode and + decode. The index is updated to point right after the term + encoded/decoded. No checking is done whether the term fits in + the buffer or not. If encoding goes outside the buffer, the + program may crash.</p> + <p>All functions takes two parameter, <c><![CDATA[buf]]></c> is a pointer to + the buffer where the binary data is / will be, <c><![CDATA[index]]></c> is a + pointer to an index into the buffer. This parameter will be + incremented with the size of the term decoded / encoded. The + data is thus at <c><![CDATA[buf[*index]]]></c> when an <c><![CDATA[ei]]></c> function is + called.</p> + <p>The encode functions all assumes that the <c><![CDATA[buf]]></c> and + <c><![CDATA[index]]></c> parameters points to a buffer big enough for the + data. To get the size of an encoded term, without encoding it, + pass <c><![CDATA[NULL]]></c> instead of a buffer pointer. The <c><![CDATA[index]]></c> + parameter will be incremented, but nothing will be encoded. This + is the way in <c><![CDATA[ei]]></c> to "preflight" term encoding.</p> + <p>There are also encode-functions that uses a dynamic buffer. It + is often more convenient to use these to encode data. All encode + functions comes in two versions: those starting with <c><![CDATA[ei_x]]></c>, + uses a dynamic buffer.</p> + <p>All functions return <c><![CDATA[0]]></c> if successful, and <c><![CDATA[-1]]></c> if + not. (For instance, if a term is not of the expected type, or + the data to decode is not a valid erlang term.)</p> + <p>Some of the decode-functions needs a preallocated buffer. This + buffer must be allocated big enough, and for non compound types + the <c><![CDATA[ei_get_type()]]></c> + function returns the size required (note that for strings an + extra byte is needed for the 0 string terminator).</p> + </description> + <funcs> + <func> + <name><ret>void</ret><nametext>ei_set_compat_rel(release_number)</nametext></name> + <fsummary>Set the ei library in compatibility mode</fsummary> + <type> + <v>unsigned release_number;</v> + </type> + <desc> + <marker id="ei_set_compat_rel"></marker> + <p>By default, the <c><![CDATA[ei]]></c> library is only guaranteed + to be compatible with other Erlang/OTP components from the same + release as the <c><![CDATA[ei]]></c> library itself. For example, <c><![CDATA[ei]]></c> from + the OTP R10 release is not compatible with an Erlang emulator + from the OTP R9 release by default.</p> + <p>A call to <c><![CDATA[ei_set_compat_rel(release_number)]]></c> sets the + <c><![CDATA[ei]]></c> library in compatibility mode of release + <c><![CDATA[release_number]]></c>. Valid range of <c><![CDATA[release_number]]></c> + is [7, current release]. This makes it possible to + communicate with Erlang/OTP components from earlier releases.</p> + <note> + <p>If this function is called, it may only be called once + and must be called before any other functions in the <c><![CDATA[ei]]></c> + library is called.</p> + </note> + <warning> + <p>You may run into trouble if this feature is used + carelessly. Always make sure that all communicating + components are either from the same Erlang/OTP release, or + from release X and release Y where all components + from release Y are in compatibility mode of release X.</p> + </warning> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_encode_version(char *buf, int *index)</nametext></name> + <name><ret>int</ret><nametext>ei_x_encode_version(ei_x_buff* x)</nametext></name> + <fsummary>Encode version</fsummary> + <desc> + <p>Encodes a version magic number for the binary format. Must + be the first token in a binary term.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_encode_long(char *buf, int *index, long p)</nametext></name> + <name><ret>int</ret><nametext>ei_x_encode_long(ei_x_buff* x, long p)</nametext></name> + <fsummary>Encode integer</fsummary> + <desc> + <p>Encodes a long integer in the binary format. + Note that if the code is 64 bits the function ei_encode_long() is + exactly the same as ei_encode_longlong().</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_encode_ulong(char *buf, int *index, unsigned long p)</nametext></name> + <name><ret>int</ret><nametext>ei_x_encode_ulong(ei_x_buff* x, unsigned long p)</nametext></name> + <fsummary>Encode unsigned integer</fsummary> + <desc> + <p>Encodes an unsigned long integer in the binary format. + Note that if the code is 64 bits the function ei_encode_ulong() is + exactly the same as ei_encode_ulonglong().</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_encode_longlong(char *buf, int *index, long long p)</nametext></name> + <name><ret>int</ret><nametext>ei_x_encode_longlong(ei_x_buff* x, long long p)</nametext></name> + <fsummary>Encode integer</fsummary> + <desc> + <p>Encodes a GCC <c><![CDATA[long long]]></c> or Visual C++ <c><![CDATA[__int64]]></c> (64 bit) + integer in the binary format. Note that this function is missing + in the VxWorks port.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_encode_ulonglong(char *buf, int *index, unsigned long long p)</nametext></name> + <name><ret>int</ret><nametext>ei_x_encode_ulonglong(ei_x_buff* x, unsigned long long p)</nametext></name> + <fsummary>Encode unsigned integer</fsummary> + <desc> + <p>Encodes a GCC <c><![CDATA[unsigned long long]]></c> or Visual C++ <c><![CDATA[unsigned __int64]]></c> (64 bit) integer in the binary format. Note that + this function is missing in the VxWorks port.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_encode_bignum(char *buf, int *index, mpz_t obj)</nametext></name> + <name><ret>int</ret><nametext>ei_x_encode_bignum(ei_x_buff *x, mpz_t obj)</nametext></name> + <fsummary>Encode an arbitrary precision integer</fsummary> + <desc> + <p>Encodes a GMP <c><![CDATA[mpz_t]]></c> integer to binary format. + To use this function the ei library needs to be configured and compiled + to use the GMP library. </p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_encode_double(char *buf, int *index, double p)</nametext></name> + <name><ret>int</ret><nametext>ei_x_encode_double(ei_x_buff* x, double p)</nametext></name> + <fsummary>Encode a double float</fsummary> + <desc> + <p>Encodes a double-precision (64 bit) floating point number in + the binary format.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_encode_boolean(char *buf, int *index, int p)</nametext></name> + <name><ret>int</ret><nametext>ei_x_encode_boolean(ei_x_buff* x, int p)</nametext></name> + <fsummary>Encode a boolean</fsummary> + <desc> + <p>Encodes a boolean value, as the atom <c><![CDATA[true]]></c> if p is not + zero or <c><![CDATA[false]]></c> if p is zero.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_encode_char(char *buf, int *index, char p)</nametext></name> + <name><ret>int</ret><nametext>ei_x_encode_char(ei_x_buff* x, char p)</nametext></name> + <fsummary>Encode an 8-bit integer between 0-255</fsummary> + <desc> + <p>Encodes a char (8-bit) as an integer between 0-255 in the binary format. + Note that for historical reasons the integer argument is of + type <c><![CDATA[char]]></c>. Your C code should consider the + given argument to be of type <c><![CDATA[unsigned char]]></c> even if + the C compilers and system may define <c><![CDATA[char]]></c> to be + signed.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_encode_string(char *buf, int *index, const char *p)</nametext></name> + <name><ret>int</ret><nametext>ei_encode_string_len(char *buf, int *index, const char *p, int len)</nametext></name> + <name><ret>int</ret><nametext>ei_x_encode_string(ei_x_buff* x, const char *p)</nametext></name> + <name><ret>int</ret><nametext>ei_x_encode_string_len(ei_x_buff* x, const char* s, int len)</nametext></name> + <fsummary>Encode a string</fsummary> + <desc> + <p>Encodes a string in the binary format. (A string in erlang + is a list, but is encoded as a character array in the binary + format.) The string should be zero-terminated, except for + the <c><![CDATA[ei_x_encode_string_len()]]></c> function.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_encode_atom(char *buf, int *index, const char *p)</nametext></name> + <name><ret>int</ret><nametext>ei_encode_atom_len(char *buf, int *index, const char *p, int len)</nametext></name> + <name><ret>int</ret><nametext>ei_x_encode_atom(ei_x_buff* x, const char *p)</nametext></name> + <name><ret>int</ret><nametext>ei_x_encode_atom_len(ei_x_buff* x, const char *p, int len)</nametext></name> + <fsummary>Encode an atom</fsummary> + <desc> + <p>Encodes an atom in the binary format. The <c><![CDATA[p]]></c> parameter + is the name of the atom. Only upto <c><![CDATA[MAXATOMLEN]]></c> bytes + are encoded. The name should be zero-terminated, except for + the <c><![CDATA[ei_x_encode_atom_len()]]></c> function.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_encode_binary(char *buf, int *index, const void *p, long len)</nametext></name> + <name><ret>int</ret><nametext>ei_x_encode_binary(ei_x_buff* x, const void *p, long len)</nametext></name> + <fsummary>Encode a binary</fsummary> + <desc> + <p>Encodes a binary in the binary format. The data is at + <c><![CDATA[p]]></c>, of <c><![CDATA[len]]></c> bytes length.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_encode_pid(char *buf, int *index, const erlang_pid *p)</nametext></name> + <name><ret>int</ret><nametext>ei_x_encode_pid(ei_x_buff* x, const erlang_pid *p)</nametext></name> + <fsummary>Encode a pid</fsummary> + <desc> + <p>Encodes an erlang process identifier, pid, in the binary + format. The <c><![CDATA[p]]></c> parameter points to an + <c><![CDATA[erlang_pid]]></c> structure (which should have been obtained + earlier with <c><![CDATA[ei_decode_pid()]]></c>).</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_encode_fun(char *buf, int *index, const erlang_fun *p)</nametext></name> + <name><ret>int</ret><nametext>ei_x_encode_fun(ei_x_buff* x, const erlang_fun* fun)</nametext></name> + <fsummary>Encode a fun</fsummary> + <desc> + <p>Encodes a fun in the binary format. The <c><![CDATA[p]]></c> parameter + points to an <c><![CDATA[erlang_fun]]></c> structure. The + <c><![CDATA[erlang_fun]]></c> is not freed automatically, the + <c><![CDATA[free_fun]]></c> should be called if the fun is not needed + after encoding.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_encode_port(char *buf, int *index, const erlang_port *p)</nametext></name> + <name><ret>int</ret><nametext>ei_x_encode_port(ei_x_buff* x, const erlang_port *p)</nametext></name> + <fsummary>Encodes a port</fsummary> + <desc> + <p>Encodes an erlang port in the binary format. The <c><![CDATA[p]]></c> + parameter points to a <c><![CDATA[erlang_port]]></c> structure (which + should have been obtained earlier with + <c><![CDATA[ei_decode_port()]]></c>.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_encode_ref(char *buf, int *index, const erlang_ref *p)</nametext></name> + <name><ret>int</ret><nametext>ei_x_encode_ref(ei_x_buff* x, const erlang_ref *p)</nametext></name> + <fsummary>Encodes a ref</fsummary> + <desc> + <p>Encodes an erlang reference in the binary format. The + <c><![CDATA[p]]></c> parameter points to a <c><![CDATA[erlang_ref]]></c> structure + (which should have been obtained earlier with + <c><![CDATA[ei_decode_ref()]]></c>.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_encode_term(char *buf, int *index, void *t)</nametext></name> + <name><ret>int</ret><nametext>ei_x_encode_term(ei_x_buff* x, void *t)</nametext></name> + <fsummary>Encode an <c><![CDATA[erl_interface]]></c>term</fsummary> + <desc> + <p>This function encodes an <c><![CDATA[ETERM]]></c>, as obtained from + <c><![CDATA[erl_interface]]></c>. The <c><![CDATA[t]]></c> parameter is actually an + <c><![CDATA[ETERM]]></c> pointer. This function doesn't free the + <c><![CDATA[ETERM]]></c>.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_encode_trace(char *buf, int *index, const erlang_trace *p)</nametext></name> + <name><ret>int</ret><nametext>ei_x_encode_trace(ei_x_buff* x, const erlang_trace *p)</nametext></name> + <fsummary>Encode a trace token</fsummary> + <desc> + <p>This function encodes an erlang trace token in the binary + format. The <c><![CDATA[p]]></c> parameter points to a + <c><![CDATA[erlang_trace]]></c> structure (which should have been + obtained earlier with <c><![CDATA[ei_decode_trace()]]></c>.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_encode_tuple_header(char *buf, int *index, int arity)</nametext></name> + <name><ret>int</ret><nametext>ei_x_encode_tuple_header(ei_x_buff* x, int arity)</nametext></name> + <fsummary>Encode a tuple</fsummary> + <desc> + <p>This function encodes a tuple header, with a specified + arity. The next <c><![CDATA[arity]]></c> terms encoded will be the + elements of the tuple. Tuples and lists are encoded + recursively, so that a tuple may contain another tuple or + list.</p> + <p>E.g. to encode the tuple <c><![CDATA[{a, {b, {}}}]]></c>:</p> + <pre> +ei_encode_tuple_header(buf, &i, 2); +ei_encode_atom(buf, &i, "a"); +ei_encode_tuple_header(buf, &i, 2); +ei_encode_atom(buf, &i, "b"); +ei_encode_tuple_header(buf, &i, 0); + </pre> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_encode_list_header(char *buf, int *index, int arity)</nametext></name> + <name><ret>int</ret><nametext>ei_x_encode_list_header(ei_x_buff* x, int arity)</nametext></name> + <fsummary>Encode a list</fsummary> + <desc> + <p>This function encodes a list header, with a specified + arity. The next <c><![CDATA[arity+1]]></c> terms are the elements + (actually it's <c><![CDATA[arity]]></c> cons cells) and the tail of the + list. Lists and tuples are encoded recursively, so that a + list may contain another list or tuple.</p> + <p>E.g. to encode the list <c><![CDATA[[c, d, [e | f]]]]></c>:</p> + <pre> +ei_encode_list_header(buf, &i, 3); +ei_encode_atom(buf, &i, "c"); +ei_encode_atom(buf, &i, "d"); +ei_encode_list_header(buf, &i, 1); +ei_encode_atom(buf, &i, "e"); +ei_encode_atom(buf, &i, "f"); +ei_encode_empty_list(buf, &i); + </pre> + <note> + <p>It may seem that there is no way to create a list without + knowing the number of elements in advance. But indeed + there is a way. Note that the list <c><![CDATA[[a, b, c]]]></c> can be + written as <c><![CDATA[[a | [b | [c]]]]]></c>. Using this, a list can + be written as conses.</p> + </note> + <p>To encode a list, without knowing the arity in advance:</p> + <pre> +while (something()) { + ei_x_encode_list_header(&x, 1); + ei_x_encode_ulong(&x, i); /* just an example */ +} +ei_x_encode_empty_list(&x); + </pre> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_encode_empty_list(char* buf, int* index)</nametext></name> + <name><ret>int</ret><nametext>ei_x_encode_empty_list(ei_x_buff* x)</nametext></name> + <fsummary>Encode an empty list (<c><![CDATA[nil]]></c>)</fsummary> + <desc> + <p>This function encodes an empty list. It's often used at the + tail of a list.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_get_type(const char *buf, const int *index, int *type, int *size)</nametext></name> + <fsummary>Fetch the type and size of an encoded term</fsummary> + <desc> + <p>This function returns the type in <c><![CDATA[type]]></c> and size in + <c><![CDATA[size]]></c> of the encoded term. + For strings and atoms, size + is the number of characters <em>not</em> including the + terminating 0. For binaries, <c><![CDATA[size]]></c> is the number of + bytes. For lists and tuples, <c><![CDATA[size]]></c> is the arity of the + object. For other types, <c><![CDATA[size]]></c> is 0. In all cases, + <c><![CDATA[index]]></c> is left unchanged.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_decode_version(const char *buf, int *index, int *version)</nametext></name> + <fsummary>Encode an empty list (<c><![CDATA[nil]]></c>)</fsummary> + <desc> + <p>This function decodes the version magic number for the + erlang binary term format. It must be the first token in a + binary term.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_decode_long(const char *buf, int *index, long *p)</nametext></name> + <fsummary>Decode integer</fsummary> + <desc> + <p>This function decodes a long integer from the binary format. + Note that if the code is 64 bits the function ei_decode_long() is + exactly the same as ei_decode_longlong().</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_decode_ulong(const char *buf, int *index, unsigned long *p)</nametext></name> + <fsummary>Decode unsigned integer</fsummary> + <desc> + <p>This function decodes an unsigned long integer from + the binary format. + Note that if the code is 64 bits the function ei_decode_ulong() is + exactly the same as ei_decode_ulonglong().</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_decode_longlong(const char *buf, int *index, long long *p)</nametext></name> + <fsummary>Decode integer</fsummary> + <desc> + <p>This function decodes a GCC <c><![CDATA[long long]]></c> or Visual C++ <c><![CDATA[__int64]]></c> + (64 bit) integer from the binary format. Note that this + function is missing in the VxWorks port.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_decode_ulonglong(const char *buf, int *index, unsigned long long *p)</nametext></name> + <fsummary>Decode unsigned integer</fsummary> + <desc> + <p>This function decodes a GCC <c><![CDATA[unsigned long long]]></c> or Visual C++ + <c><![CDATA[unsigned __int64]]></c> (64 bit) integer from the binary format. + Note that this function is missing in the VxWorks port.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_decode_bignum(const char *buf, int *index, mpz_t obj)</nametext></name> + <fsummary>Decode a GMP arbitrary precision integer</fsummary> + <desc> + <p>This function decodes an integer in the binary format to a GMP <c><![CDATA[mpz_t]]></c> integer. + To use this function the ei library needs to be configured and compiled + to use the GMP library. </p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_decode_double(const char *buf, int *index, double *p)</nametext></name> + <fsummary>Decode a double</fsummary> + <desc> + <p>This function decodes an double-precision (64 bit) floating + point number from the binary format.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_decode_boolean(const char *buf, int *index, int *p)</nametext></name> + <fsummary>Decode a boolean</fsummary> + <desc> + <p>This function decodes a boolean value from the binary + format. A boolean is actually an atom, <c><![CDATA[true]]></c> decodes 1 + and <c><![CDATA[false]]></c> decodes 0.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_decode_char(const char *buf, int *index, char *p)</nametext></name> + <fsummary>Decode an 8-bit integer between 0-255</fsummary> + <desc> + <p>This function decodes a char (8-bit) integer between 0-255 + from the binary format. + Note that for historical reasons the returned integer is of + type <c><![CDATA[char]]></c>. Your C code should consider the + returned value to be of type <c><![CDATA[unsigned char]]></c> even if + the C compilers and system may define <c><![CDATA[char]]></c> to be + signed.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_decode_string(const char *buf, int *index, char *p)</nametext></name> + <fsummary>Decode a string</fsummary> + <desc> + <p>This function decodes a string from the binary format. A + string in erlang is a list of integers between 0 and + 255. Note that since the string is just a list, sometimes + lists are encoded as strings by <c><![CDATA[term_to_binary/1]]></c>, + even if it was not intended.</p> + <p>The string is copied to <c><![CDATA[p]]></c>, and enough space must be + allocated. The returned string is null terminated so you + need to add an extra byte to the memory requirement.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_decode_atom(const char *buf, int *index, char *p)</nametext></name> + <fsummary>Decode an atom</fsummary> + <desc> + <p>This function decodes an atom from the binary format. The + name of the atom is placed at <c><![CDATA[p]]></c>. There can be at most + <c><![CDATA[MAXATOMLEN]]></c> bytes placed in the buffer.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_decode_binary(const char *buf, int *index, void *p, long *len)</nametext></name> + <fsummary>Decode a binary</fsummary> + <desc> + <p>This function decodes a binary from the binary format. The + <c><![CDATA[len]]></c> parameter is set to the actual size of the + binary. Note that <c><![CDATA[ei_decode_binary()]]></c> assumes that there + are enough room for the binary. The size required can be + fetched by <c><![CDATA[ei_get_type()]]></c>.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_decode_fun(const char *buf, int *index, erlang_fun *p)</nametext></name> + <name><ret>void</ret><nametext>free_fun(erlang_fun* f)</nametext></name> + <fsummary>Decode a fun</fsummary> + <desc> + <p>This function decodes a fun from the binary format. The + <c><![CDATA[p]]></c> parameter should be NULL or point to an + <c><![CDATA[erlang_fun]]></c> structure. This is the only decode + function that allocates memory; when the <c><![CDATA[erlang_fun]]></c> + is no longer needed, it should be freed with + <c><![CDATA[free_fun]]></c>. (This has to do with the arbitrary size of + the environment for a fun.)</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_decode_pid(const char *buf, int *index, erlang_pid *p)</nametext></name> + <fsummary>Decode a <c><![CDATA[pid]]></c></fsummary> + <desc> + <p>Decodes a pid, process identifier, from the binary format.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_decode_port(const char *buf, int *index, erlang_port *p)</nametext></name> + <fsummary>Decode a port</fsummary> + <desc> + <p>This function decodes a port identifier from the binary + format.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_decode_ref(const char *buf, int *index, erlang_ref *p)</nametext></name> + <fsummary>Decode a reference</fsummary> + <desc> + <p>This function decodes a reference from the binary format.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_decode_trace(const char *buf, int *index, erlang_trace *p)</nametext></name> + <fsummary>Decode a trace token</fsummary> + <desc> + <p>Decodes an erlang trace token from the binary format.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_decode_tuple_header(const char *buf, int *index, int *arity)</nametext></name> + <fsummary>Decode a tuple</fsummary> + <desc> + <p>This function decodes a tuple header, the number of elements + is returned in <c><![CDATA[arity]]></c>. The tuple elements follows in order in + the buffer.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_decode_list_header(const char *buf, int *index, int *arity)</nametext></name> + <fsummary>Decode a list</fsummary> + <desc> + <p>This function decodes a list header from the binary + format. The number of elements is returned in + <c><![CDATA[arity]]></c>. The <c><![CDATA[arity+1]]></c> elements follows (the last + one is the tail of the list, normally an empty list.) If + <c><![CDATA[arity]]></c> is <c><![CDATA[0]]></c>, it's an empty list.</p> + <p>Note that lists are encoded as strings, if they consist + entirely of integers in the range 0..255. This function will + not decode such strings, use <c><![CDATA[ei_decode_string()]]></c> + instead.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_decode_ei_term(const char* buf, int* index, ei_term* term)</nametext></name> + <fsummary>Decode a term, without prior knowledge of type</fsummary> + <desc> + <p>This function decodes any term, or at least tries to. If the + term pointed at by <c><![CDATA[*index]]></c> in <c><![CDATA[buf]]></c> fits in the + <c><![CDATA[term]]></c> union, it is decoded, and the appropriate field + in <c><![CDATA[term->value]]></c> is set, and <c><![CDATA[*index]]></c> is + incremented by the term size.</p> + <p>The function returns 0 on successful encoding, -1 on error, + and 1 if the term seems alright, but does not fit in the + <c><![CDATA[term]]></c> structure. If it returns 0, the <c><![CDATA[index]]></c> + will be incremented, and the <c><![CDATA[term]]></c> contains the + decoded term.</p> + <p>The <c><![CDATA[term]]></c> structure will contain the arity for a tuple + or list, size for a binary, string or atom. It will contains + a term if it's any of the following: integer, float, atom, + pid, port or ref.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_decode_term(const char *buf, int *index, void *t)</nametext></name> + <fsummary>Decode a <c><![CDATA[ETERM]]></c></fsummary> + <desc> + <p>This function decodes a term from the binary format. The + term is return in <c><![CDATA[t]]></c> as a <c><![CDATA[ETERM*]]></c>, so <c><![CDATA[t]]></c> + is actually an <c><![CDATA[ETERM**]]></c> (see + <c><![CDATA[erl_interface(3)]]></c>. The term should later be + deallocated.</p> + <p>Note that this function is located in the erl_interface + library.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_print_term(FILE* fp, const char* buf, int* index)</nametext></name> + <name><ret>int</ret><nametext>ei_s_print_term(char** s, const char* buf, int* index)</nametext></name> + <fsummary>Print a term in clear text</fsummary> + <desc> + <p>This function prints a term, in clear text, to the file + given by <c><![CDATA[fp]]></c>, or the buffer pointed to by <c><![CDATA[s]]></c>. It + tries to resemble the term printing in the erlang shell.</p> + <p>In <c><![CDATA[ei_s_print_term()]]></c>, the parameter <c><![CDATA[s]]></c> should + point to a dynamically (malloc) allocated string of + <c><![CDATA[BUFSIZ]]></c> bytes or a NULL pointer. The string may be + reallocated (and <c><![CDATA[*s]]></c> may be updated) by this function + if the result is more than <c><![CDATA[BUFSIZ]]></c> characters. The + string returned is zero-terminated.</p> + <p>The return value is the number of characters written to the + file or string, or -1 if <c><![CDATA[buf[index]]]></c> doesn't contain a + valid term. Unfortunately, I/O errors on <c><![CDATA[fp]]></c> is not + checked.</p> + <p>The argument <c><![CDATA[index]]></c> is updated, i.e. this function can + be viewed as en decode function that decodes a term into a + human readable format.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_x_format(ei_x_buff* x, const char* fmt, ...)</nametext></name> + <name><ret>int</ret><nametext>ei_x_format_wo_ver(ei_x_buff* x, const char *fmt, ... )</nametext></name> + <fsummary>Format a term from a format string and parameters.</fsummary> + <desc> + <p>Format a term, given as a string, to a buffer. This + functions works like a sprintf for erlang terms. The + <c><![CDATA[fmt]]></c> contains a format string, with arguments like + <c><![CDATA[~d]]></c>, to insert terms from variables. The following + formats are supported (with the C types given):</p> + <p></p> + <pre> +~a - an atom, char* +~s - a string, char* +~i - an integer, int +~l - a long integer, long int +~u - a unsigned long integer, unsigned long int +~f - a float, float +~d - a double float, double float + </pre> + <p>For instance, to encode a tuple with some stuff:</p> + <pre> +ei_x_format("{~a,~i,~d}", "numbers", 12, 3.14159) +encodes the tuple {numbers,12,3.14159} + </pre> + <p>The <c><![CDATA[ei_x_format_wo_ver()]]></c> formats into a buffer, without + the initial version byte.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_x_new(ei_x_buff* x)</nametext></name> + <name><ret>int</ret><nametext>ei_x_new_with_version(ei_x_buff* x)</nametext></name> + <fsummary>Allocate a new buffer</fsummary> + <desc> + <p>This function allocates a new <c><![CDATA[ei_x_buff]]></c> buffer. The + fields of the structure pointed to by <c><![CDATA[x]]></c> parameter is + filled in, and a default buffer is allocated. The + <c><![CDATA[ei_x_new_with_version()]]></c> also puts an initial version + byte, that is used in the binary format. (So that + <c><![CDATA[ei_x_encode_version()]]></c> won't be needed.)</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_x_free(ei_x_buff* x)</nametext></name> + <fsummary>Frees a buffer</fsummary> + <desc> + <p>This function frees an <c><![CDATA[ei_x_buff]]></c> buffer. The memory + used by the buffer is returned to the OS.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_x_append(ei_x_buff* x, const ei_x_buff* x2)</nametext></name> + <name><ret>int</ret><nametext>ei_x_append_buf(ei_x_buff* x, const char* buf, int len)</nametext></name> + <fsummary>Appends a buffer at the end</fsummary> + <desc> + <p>These functions appends data at the end of the buffer <c><![CDATA[x]]></c>.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_skip_term(const char* buf, int* index)</nametext></name> + <fsummary>skip a term</fsummary> + <desc> + <p>This function skips a term in the given buffer, it + recursively skips elements of lists and tuples, so that a + full term is skipped. This is a way to get the size of an + erlang term.</p> + <p><c><![CDATA[buf]]></c> is the buffer.</p> + <p><c><![CDATA[index]]></c> is updated to point right after the term in the + buffer.</p> + <note> + <p>This can be useful when you want to hold arbitrary + terms: just skip them and copy the binary term data to some + buffer.</p> + </note> + <p>The function returns <c><![CDATA[0]]></c> on success and <c><![CDATA[-1]]></c> on + failure.</p> + </desc> + </func> + </funcs> + + <section> + <title>Debug Information</title> + <p>Some tips on what to check when the emulator doesn't seem to + receive the terms that you send.</p> + <list type="bulleted"> + <item>be careful with the version header, use + <c><![CDATA[ei_x_new_with_version()]]></c> when appropriate</item> + <item>turn on distribution tracing on the erlang node</item> + <item>check the result codes from ei_decode_-calls</item> + </list> + </section> + + <section> + <title>See Also</title> + <p>erl_interface(3)</p> + </section> +</cref> + diff --git a/lib/erl_interface/doc/src/ei_connect.xml b/lib/erl_interface/doc/src/ei_connect.xml new file mode 100644 index 0000000000..08e7b122c6 --- /dev/null +++ b/lib/erl_interface/doc/src/ei_connect.xml @@ -0,0 +1,639 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE cref SYSTEM "cref.dtd"> + +<cref> + <header> + <copyright> + <year>2001</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>ei_connect</title> + <prepared>Jakob Cederlund</prepared> + <docno></docno> + <approved>?</approved> + <checked>?</checked> + <date>2001-09-01</date> + <rev>A</rev> + <file>ei_connect.sgml</file> + </header> + <lib>ei_connect</lib> + <libsummary>Communicate with distributed erlang</libsummary> + <description> + <p>This module enables C programs to communicate with erlang nodes, + using the erlang distribution over TCP/IP.</p> + <p>A C node appears to Erlang as a + <em>hidden node</em>. + That is, Erlang processes that know the name of the + C node are able to communicate with it in a normal manner, but + the node name will not appear in the listing provided by the + Erlang function <c><![CDATA[nodes/0]]></c>.</p> + <p>The environment variable <c><![CDATA[ERL_EPMD_PORT]]></c> can be used + to indicate which logical cluster a C node belongs to.</p> + </description> + + <section> + <title>Timeout functions</title> + <p>Most functions appear in a version with the suffix + <c><![CDATA[_tmo]]></c> appended to the function name. Those function take + an additional argument, a timeout in <em>milliseconds</em>. The + semantics is this; for each communication primitive involved in + the operation, if the primitive does not complete within the time + specified, the function will return an error and + <c><![CDATA[erl_errno]]></c> will be set to <c><![CDATA[ETIMEDOUT]]></c>. With + communication primitive is ment an operation on the socket, like + <c><![CDATA[connect]]></c>, <c><![CDATA[accept]]></c>, <c><![CDATA[recv]]></c> or <c><![CDATA[send]]></c>.</p> + <p>Obviously the timeouts are for implementing fault tolerance, + not to keep hard realtime promises. The <c><![CDATA[_tmo]]></c> functions + are for detecting non-responsive peers and to avoid blocking on + socket operations. </p> + <p>A timeout value of <c><![CDATA[0]]></c> (zero), means that timeouts are + disabled. Calling a <c><![CDATA[_tmo]]></c>-function with the last argument as + <c><![CDATA[0]]></c> is therefore exactly the same thing as calling the + function without the <c><![CDATA[_tmo]]></c> suffix.</p> + <p>As with all other ei functions, you are <em>not</em> expected + to put the socket in non blocking mode yourself in the program. Every + use of non blocking mode is embedded inside the timeout + functions. The socket will always be back in blocking mode after + the operations are completed (regardless of the result). To + avoid problems, leave the socket options alone. Ei will handle + any socket options that need modification.</p> + <p>In all other senses, the <c><![CDATA[_tmo]]></c> functions inherit all + the return values and the semantics from the functions without + the <c><![CDATA[_tmo]]></c> suffix.</p> + </section> + <funcs> + <func> + <name><ret>int</ret><nametext>ei_connect_init(ei_cnode* ec, const char* this_node_name, const char *cookie, short creation)</nametext></name> + <name><ret>int</ret><nametext>ei_connect_xinit(ei_cnode* ec, const char *thishostname, const char *thisalivename, const char *thisnodename, Erl_IpAddr thisipaddr, const char *cookie, short creation)</nametext></name> + <fsummary>Initialize for a connection.</fsummary> + <desc> + <p>These function initializes the <c><![CDATA[ec]]></c> structure, to + identify the node name and cookie of the server. One of them + has to be called before other functions that works on the + type <c><![CDATA[ei_cnode]]></c> or a file descriptor associated with a + connection to another node are used.</p> + <p><c><![CDATA[ec]]></c> is a structure containing information about the + C-node. It is used in other <c><![CDATA[ei]]></c> functions for + connecting and receiving data.</p> + <p><c><![CDATA[this_node_name]]></c> is the registered name of the process + (the name before '@').</p> + <p><c><![CDATA[cookie]]></c> is the cookie for the node.</p> + <p><c><![CDATA[creation]]></c> identifies a specific instance of a C + node. It can help prevent the node from receiving messages + sent to an earlier process with the same registered name.</p> + <p><c><![CDATA[thishostname]]></c> is the name of the machine we're running + on. If long names are to be used, it should be fully + qualified (i.e. <c><![CDATA[durin.erix.ericsson.se]]></c> instead of + <c><![CDATA[durin]]></c>).</p> + <p><c><![CDATA[thisalivename]]></c> is the registered name of the process.</p> + <p><c><![CDATA[thisnodename]]></c> is the full name of the node, + i.e. <c><![CDATA[einode@durin]]></c>.</p> + <p><c><![CDATA[thispaddr]]></c> if the IP address of the host.</p> + <p>A C node acting as a server will be assigned a creation + number when it calls <c><![CDATA[ei_publish()]]></c>.</p> + <p>A connection is closed by simply closing the socket. Refer + to system documentation to close the socket gracefully (when + there are outgoing packets before close).</p> + <p>This function return a negative value indicating that an error + occurred.</p> + <p>Example 1: + </p> + <code type="none"><![CDATA[ +int n = 0; +struct in_addr addr; +ei_cnode ec; +addr = inet_addr("150.236.14.75"); +if (ei_connect_xinit(&ec, + "chivas", + "madonna", + "[email protected]", + &addr; + "cookie...", + n++) < 0) { + fprintf(stderr,"ERROR when initializing: %d",erl_errno); + exit(-1); +} + ]]></code> + <p>Example 2: + </p> + <code type="none"><![CDATA[ +if (ei_connect_init(&ec, "madonna", "cookie...", n++) < 0) { + fprintf("ERROR when initializing: %d",erl_errno); + exit(-1); +} + ]]></code> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_connect(ei_cnode* ec, char *nodename)</nametext></name> + <name><ret>int</ret><nametext>ei_xconnect(ei_cnode* ec, Erl_IpAddr adr, char *alivename)</nametext></name> + <fsummary>Establishe a connection to an Erlang node</fsummary> + <desc> + <p>These functions set up a connection to an Erlang node.</p> + <p><c><![CDATA[ei_xconnect()]]></c> requires the IP address of the remote + host and the alive name of the remote node + to be specified. <c><![CDATA[ei_connect()]]></c> provides an alternative + interface, and determines the information from the node name + provided.</p> + <p><c><![CDATA[addr]]></c> is the 32-bit IP address of the remote host.</p> + <p><c><![CDATA[alive]]></c> is the alivename of the remote node.</p> + <p><c><![CDATA[node]]></c> is the name of the remote node.</p> + <p>These functions return an open file descriptor on success, or + a negative value indicating that an error occurred --- in + which case they will set <c><![CDATA[erl_errno]]></c> to one of:</p> + <taglist> + <tag><c><![CDATA[EHOSTUNREACH]]></c></tag> + <item>The remote host <c><![CDATA[node]]></c> is unreachable</item> + <tag><c><![CDATA[ENOMEM]]></c></tag> + <item>No more memory available.</item> + <tag><c><![CDATA[EIO]]></c></tag> + <item>I/O error.</item> + </taglist> + <p>Additionally, <c><![CDATA[errno]]></c> values from + <c><![CDATA[socket]]></c><em>(2)</em> and <c><![CDATA[connect]]></c><em>(2)</em> + system calls may be propagated into <c><![CDATA[erl_errno]]></c>.</p> + <p>Example:</p> + <code type="none"><![CDATA[ +#define NODE "[email protected]" +#define ALIVE "madonna" +#define IP_ADDR "150.236.14.75" + +/*** Variant 1 ***/ +int fd = ei_connect(&ec, NODE); + +/*** Variant 2 ***/ +struct in_addr addr; +addr = inet_addr(IP_ADDR); +fd = ei_xconnect(&ec, &addr, ALIVE); + ]]></code> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_connect_tmo(ei_cnode* ec, char *nodename, unsigned timeout_ms)</nametext></name> + <name><ret>int</ret><nametext>ei_xconnect_tmo(ei_cnode* ec, Erl_IpAddr adr, char *alivename, unsigned timeout_ms)</nametext></name> + <fsummary>Establish a connection to an Erlang node with optional timeout</fsummary> + <desc> + <p>ei_connect and ei_xconnect with an optional timeout argument, + see the description at the beginning of this document.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_receive(int fd, unsigned char* bufp, int bufsize)</nametext></name> + <fsummary>Receive a message</fsummary> + <desc> + <p>This function receives a message consisting of a sequence + of bytes in the Erlang external format.</p> + <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection. It + is obtained from a previous <c><![CDATA[ei_connect]]></c> or + <c><![CDATA[ei_accept]]></c>.</p> + <p><c><![CDATA[bufp]]></c> is a buffer large enough to hold the expected + message. </p> + <p><c><![CDATA[bufsize]]></c> indicates the size of <c><![CDATA[bufp]]></c>.</p> + <p>If a <em>tick</em> occurs, i.e., the Erlang node on the + other end of the connection has polled this node to see if it + is still alive, the function will return <c><![CDATA[ERL_TICK]]></c> and + no message will be placed in the buffer. Also, + <c><![CDATA[erl_errno]]></c> will be set to <c><![CDATA[EAGAIN]]></c>.</p> + <p>On success, the message is placed in the specified buffer + and the function returns the number of bytes actually read. On + failure, the function returns <c><![CDATA[ERL_ERROR]]></c> and will set + <c><![CDATA[erl_errno]]></c> to one of:</p> + <taglist> + <tag><c><![CDATA[EAGAIN]]></c></tag> + <item>Temporary error: Try again.</item> + <tag><c><![CDATA[EMSGSIZE]]></c></tag> + <item>Buffer too small.</item> + <tag><c><![CDATA[EIO]]></c></tag> + <item>I/O error.</item> + </taglist> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_receive_tmo(int fd, unsigned char* bufp, int bufsize, unsigned timeout_ms)</nametext></name> + <fsummary>Receive a message with optional timeout</fsummary> + <desc> + <p>ei_receive with an optional timeout argument, + see the description at the beginning of this document.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_receive_msg(int fd, erlang_msg* msg, ei_x_buff* x)</nametext></name> + <name><ret>int</ret><nametext>ei_xreceive_msg(int fd, erlang_msg* msg, ei_x_buff* x)</nametext></name> + <fsummary>Receive a message</fsummary> + <desc> + <p>These functions receives a message to the buffer in + <c><![CDATA[x]]></c>. <c><![CDATA[ei_xreceive_msg]]></c> allows the buffer in + <c><![CDATA[x]]></c> to grow, but <c><![CDATA[ei_receive_msg]]></c> fails if the + message is bigger than the preallocated buffer in <c><![CDATA[x]]></c>.</p> + <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.</p> + <p><c><![CDATA[msg]]></c> is a pointer to an <c><![CDATA[erlang_msg]]></c> structure + and contains information on the message received.</p> + <p><c><![CDATA[x]]></c> is buffer obtained from <c><![CDATA[ei_x_new]]></c>.</p> + <p>On success, the function returns <c><![CDATA[ERL_MSG]]></c> and the + <c><![CDATA[msg]]></c> struct will be initialized. <c><![CDATA[erlang_msg]]></c> + is defined as follows:</p> + <code type="none"><![CDATA[ +typedef struct { + long msgtype; + erlang_pid from; + erlang_pid to; + char toname[MAXATOMLEN+1]; + char cookie[MAXATOMLEN+1]; + erlang_trace token; +} erlang_msg; + ]]></code> + <p><c><![CDATA[msgtype]]></c> identifies the type of message, and is one of + <c><![CDATA[ERL_SEND]]></c>, <c><![CDATA[ERL_REG_SEND]]></c>, <c><![CDATA[ERL_LINK]]></c>, + <c><![CDATA[ERL_UNLINK]]></c> and <c><![CDATA[ERL_EXIT]]></c>.</p> + <p>If <c><![CDATA[msgtype]]></c> is <c><![CDATA[ERL_SEND]]></c> this indicates that an + ordinary send operation has taken place, and <c><![CDATA[msg->to]]></c> + contains the Pid of the recipient (the C-node). If + <c><![CDATA[type]]></c> is <c><![CDATA[ERL_REG_SEND]]></c> then a registered send + operation took place, and <c><![CDATA[msg->from]]></c> contains the Pid + of the sender.</p> + <p>If <c><![CDATA[msgtype]]></c> is <c><![CDATA[ERL_LINK]]></c> or <c><![CDATA[ERL_UNLINK]]></c>, then + <c><![CDATA[msg->to]]></c> and <c><![CDATA[msg->from]]></c> contain the pids of the + sender and recipient of the link or unlink.</p> + <p>If <c><![CDATA[msgtype]]></c> is <c><![CDATA[ERL_EXIT]]></c>, then this indicates that + a link has been broken. In this case, <c><![CDATA[msg->to]]></c> and + <c><![CDATA[msg->from]]></c> contain the pids of the linked processes.</p> + <p>The return value is the same as for <c><![CDATA[ei_receive]]></c>, see + above.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_receive_msg_tmo(int fd, erlang_msg* msg, ei_x_buff* x, unsigned imeout_ms)</nametext></name> + <name><ret>int</ret><nametext>ei_xreceive_msg_tmo(int fd, erlang_msg* msg, ei_x_buff* x, unsigned timeout_ms)</nametext></name> + <fsummary>Receive a message with optional timeout</fsummary> + <desc> + <p>ei_receive_msg and ei_xreceive_msg with an optional timeout argument, + see the description at the beginning of this document.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_receive_encoded(int fd, char **mbufp, int *bufsz, erlang_msg *msg, int *msglen)</nametext></name> + <fsummary>Obsolete function for receiving a message</fsummary> + <desc> + <p>This function is retained for compatibility with code + generated by the interface compiler and with code following + examples in the same application.</p> + <p>In essence the function performs the same operation as + <c><![CDATA[ei_xreceive_msg]]></c>, but instead of using an ei_x_buff, the + function expects a pointer to a character pointer + (<c><![CDATA[mbufp]]></c>), where the character pointer should point to a + memory area allocated by <c><![CDATA[malloc]]></c>. The argument + <c><![CDATA[bufsz]]></c> should be a pointer to an integer containing the + exact size (in bytes) of the memory area. The function may + reallocate the memory area and will in such cases put the new + size in <c><![CDATA[*bufsz]]></c> and update <c><![CDATA[*mbufp]]></c>.</p> + <p>Furthermore the function returns either ERL_TICK or the + <c><![CDATA[msgtype]]></c> field of the <c><![CDATA[erlang_msg *msg]]></c>. The actual + length of the message is put in <c><![CDATA[*msglen]]></c>. On error it + will return a value <c><![CDATA[< 0]]></c>.</p> + <p>It is recommended to use ei_xreceive_msg instead when + possible, for the sake of readability. The function will + however be retained in the interface for compatibility and + will <em>not</em> be removed not be removed in future releases + without notice.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_receive_encoded_tmo(int fd, char **mbufp, int *bufsz, erlang_msg *msg, int *msglen, unsigned timeout_ms)</nametext></name> + <fsummary>Obsolete function for receiving a message with timeout</fsummary> + <desc> + <p>ei_receive_encoded with an optional timeout argument, + see the description at the beginning of this document.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_send(int fd, erlang_pid* to, char* buf, int len)</nametext></name> + <fsummary>Send a message</fsummary> + <desc> + <p>This function sends an Erlang term to a process.</p> + <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.</p> + <p><c><![CDATA[to]]></c> is the Pid of the intended recipient of the + message.</p> + <p><c><![CDATA[buf]]></c> is the buffer containing the term in binary + format.</p> + <p><c><![CDATA[len]]></c> is the length of the message in bytes.</p> + <p>The function returns 0 if successful, otherwise -1, in the + latter case it will set <c><![CDATA[erl_errno]]></c> to <c><![CDATA[EIO]]></c>.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_send_tmo(int fd, erlang_pid* to, char* buf, int len, unsigned timeout_ms)</nametext></name> + <fsummary>Send a message with optional timeout</fsummary> + <desc> + <p>ei_send with an optional timeout argument, + see the description at the beginning of this document.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_send_encoded(int fd, erlang_pid* to, char* buf, int len)</nametext></name> + <fsummary>Obsolete function to send a message</fsummary> + <desc> + <p>Works exactly as ei_send, the alternative name retained for + backward compatibility. The function will <em>not</em> be + removed without notice.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_send_encoded_tmo(int fd, erlang_pid* to, char* buf, int len, unsigned timeout_ms)</nametext></name> + <fsummary>Obsolete function to send a message with optional timeout</fsummary> + <desc> + <p>ei_send_encoded with an optional timeout argument, + see the description at the beginning of this document.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_reg_send(ei_cnode* ec, int fd, char* server_name, char* buf, int len)</nametext></name> + <fsummary>Send a message to a registered name</fsummary> + <desc> + <p>This function sends an Erlang term to a registered process. + </p> + <p>This function sends an Erlang term to a process.</p> + <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.</p> + <p><c><![CDATA[server_name]]></c> is the registered name of the intended + recipient.</p> + <p><c><![CDATA[buf]]></c> is the buffer containing the term in binary + format.</p> + <p><c><![CDATA[len]]></c> is the length of the message in bytes.</p> + <p>The function returns 0 if successful, otherwise -1, in the + latter case it will set <c><![CDATA[erl_errno]]></c> to <c><![CDATA[EIO]]></c>.</p> + <p>Example, send the atom "ok" to the process "worker":</p> + <code type="none"><![CDATA[ +ei_x_buff x; +ei_x_new_with_version(&x); +ei_x_encode_atom(&x, "ok"); +if (ei_reg_send(&ec, fd, x.buff, x.index) < 0) + handle_error(); + ]]></code> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_reg_send_tmo(ei_cnode* ec, int fd, char* server_name, char* buf, int len, unsigned timeout_ms)</nametext></name> + <fsummary>Send a message to a registered name with optional timeout</fsummary> + <desc> + <p>ei_reg_send with an optional timeout argument, + see the description at the beginning of this document.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_send_reg_encoded(int fd, const erlang_pid *from, const char *to, const char *buf, int len)</nametext></name> + <fsummary>Obsolete function to send a message to a registered name</fsummary> + <desc> + <p>This function is retained for compatibility with code + generated by the interface compiler and with code following + examples in the same application.</p> + <p>The function works as <c><![CDATA[ei_reg_send]]></c> with one + exception. Instead of taking the <c><![CDATA[ei_cnode]]></c> as a first + argument, it takes a second argument, an <c><![CDATA[erlang_pid]]></c> + which should be the process identifier of the sending process + (in the erlang distribution protocol). </p> + <p>A suitable <c><![CDATA[erlang_pid]]></c> can be constructed from the + <c><![CDATA[ei_cnode]]></c> structure by the following example code:</p> + <code type="none"><![CDATA[ + ei_cnode ec; + erlang_pid *self; + int fd; /* the connection fd */ + ... + self = ei_self(&ec); + self->num = fd; + ]]></code> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_send_reg_encoded_tmo(int fd, const erlang_pid *from, const char *to, const char *buf, int len)</nametext></name> + <fsummary>Obsolete function to send a message to a registered name with timeout</fsummary> + <desc> + <p>ei_send_reg_encoded with an optional timeout argument, + see the description at the beginning of this document.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_rpc(ei_cnode *ec, int fd, char *mod, char *fun, const char *argbuf, int argbuflen, ei_x_buff *x)</nametext></name> + <name><ret>int</ret><nametext>ei_rpc_to(ei_cnode *ec, int fd, char *mod, char *fun, const char *argbuf, int argbuflen)</nametext></name> + <name><ret>int</ret><nametext>ei_rpc_from(ei_cnode *ec, int fd, int timeout, erlang_msg *msg, ei_x_buff *x)</nametext></name> + <fsummary>Remote Procedure Call from C to Erlang</fsummary> + <desc> + <p>These functions support calling Erlang functions on remote nodes. + <c><![CDATA[ei_rpc_to()]]></c> sends an rpc request to a remote node and + <c><![CDATA[ei_rpc_from()]]></c> receives the results of such a call. + <c><![CDATA[ei_rpc()]]></c> combines the functionality of these two functions + by sending an rpc request and waiting for the results. See also + <c><![CDATA[rpc:call/4]]></c>. </p> + <p><c><![CDATA[ec]]></c> is the C-node structure previously initiated by a + call to <c><![CDATA[ei_connect_init()]]></c> or + <c><![CDATA[ei_connect_xinit()]]></c></p> + <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.</p> + <p><c><![CDATA[timeout]]></c> is the maximum time (in ms) to wait for + results. Specify <c><![CDATA[ERL_NO_TIMEOUT]]></c> to wait forever. + <c><![CDATA[ei_rpc()]]></c> will wait infinitely for the answer, + i.e. the call will never time out.</p> + <p><c><![CDATA[mod]]></c> is the name of the module containing the function + to be run on the remote node.</p> + <p><c><![CDATA[fun]]></c> is the name of the function to run.</p> + <p><c><![CDATA[argbuf]]></c> is a pointer to a buffer with an encoded + Erlang list, without a version magic number, containing the + arguments to be passed to the function.</p> + <p><c><![CDATA[argbuflen]]></c> is the length of the buffer containing the + encoded Erlang list.</p> + <p><c><![CDATA[msg]]></c> structure of type <c><![CDATA[erlang_msg]]></c> and contains + information on the message received. See <c><![CDATA[ei_receive_msg()]]></c> + for a description of the <c><![CDATA[erlang_msg]]></c> format.</p> + <p><c><![CDATA[x]]></c> points to the dynamic buffer that receives the + result. For for <c><![CDATA[ei_rpc()]]></c> this will be the result + without the version magic number. For <c><![CDATA[ei_rpc_from()]]></c> + the result will return a version magic number and a 2-tuple + <c><![CDATA[{rex,Reply}]]></c>.</p> + <p><c><![CDATA[ei_rpc()]]></c> returns the number of bytes in the result + on success and -1 on failure. <c><![CDATA[ei_rpc_from()]]></c> returns + number of bytes or one of <c><![CDATA[ERL_TICK]]></c>, <c><![CDATA[ERL_TIMEOUT]]></c> + and <c><![CDATA[ERL_ERROR]]></c> otherwise. When failing, + all three functions set <c><![CDATA[erl_errno]]></c> to one of:</p> + <taglist> + <tag><c><![CDATA[EIO]]></c></tag> + <item>I/O error.</item> + <tag><c><![CDATA[ETIMEDOUT]]></c></tag> + <item>Timeout expired.</item> + <tag><c><![CDATA[EAGAIN]]></c></tag> + <item>Temporary error: Try again.</item> + </taglist> + <p>Example, check to see if an erlang process is alive:</p> + <code type="none"><![CDATA[ +int index = 0, is_alive; +ei_x_buff args, result; + +ei_x_new(&result); +ei_x_new(&args); +ei_x_encode_list_header(&args, 1); +ei_x_encode_pid(&args, &check_pid); +ei_x_encode_empty_list(&args); + +if (ei_rpc(&ec, fd, "erlang", "is_process_alive", + args.buff, args.index, &result) < 0) + handle_error(); + +if (ei_decode_version(result.buff, &index) < 0 + || ei_decode_bool(result.buff, &index, &is_alive) < 0) + handle_error(); + ]]></code> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_publish(ei_cnode *ec, int port)</nametext></name> + <fsummary>Publish a node name</fsummary> + <desc> + <p>These functions are used by a server process to register + with the local name server <em>epmd</em>, thereby allowing + other processes to send messages by using the registered name. + Before calling either of these functions, the process should + have called <c><![CDATA[bind()]]></c> and <c><![CDATA[listen()]]></c> on an open socket.</p> + <p><c><![CDATA[ec]]></c> is the C-node structure.</p> + <p><c><![CDATA[port]]></c> is the local name to register, and should be the + same as the port number that was previously bound to the socket.</p> + <p><c><![CDATA[addr]]></c> is the 32-bit IP address of the local host.</p> + <p>To unregister with epmd, simply close the returned + descriptor. See also <c><![CDATA[ei_unpublish()]]></c>.</p> + <p>On success, the functions return a descriptor connecting the + calling process to epmd. On failure, they return -1 and set + <c><![CDATA[erl_errno]]></c> to <c><![CDATA[EIO]]></c>.</p> + <p>Additionally, <c><![CDATA[errno]]></c> values from <c><![CDATA[socket]]></c><em>(2)</em> + and <c><![CDATA[connect]]></c><em>(2)</em> system calls may be propagated + into <c><![CDATA[erl_errno]]></c>.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_publish_tmo(ei_cnode *ec, int port, unsigned timeout_ms)</nametext></name> + <fsummary>Publish a node name with optional timeout</fsummary> + <desc> + <p>ei_publish with an optional timeout argument, + see the description at the beginning of this document.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_accept(ei_cnode *ec, int listensock, ErlConnect *conp)</nametext></name> + <fsummary>Accept a connection from another node</fsummary> + <desc> + <p>This function is used by a server process to accept a + connection from a client process.</p> + <p><c><![CDATA[ec]]></c> is the C-node structure.</p> + <p><c><![CDATA[listensock]]></c> is an open socket descriptor on which + <c><![CDATA[listen()]]></c> has previously been called.</p> + <p><c><![CDATA[conp]]></c> is a pointer to an <c><![CDATA[ErlConnect]]></c> struct, + described as follows:</p> + <code type="none"><![CDATA[ +typedef struct { + char ipadr[4]; + char nodename[MAXNODELEN]; +} ErlConnect; + ]]></code> + <p>On success, <c><![CDATA[conp]]></c> is filled in with the address and + node name of the connecting client and a file descriptor is + returned. On failure, <c><![CDATA[ERL_ERROR]]></c> is returned and + <c><![CDATA[erl_errno]]></c> is set to <c><![CDATA[EIO]]></c>.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_accept_tmo(ei_cnode *ec, int listensock, ErlConnect *conp, unsigned timeout_ms)</nametext></name> + <fsummary>Accept a connection from another node with optional timeout</fsummary> + <desc> + <p>ei_accept with an optional timeout argument, + see the description at the beginning of this document.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_unpublish(ei_cnode *ec)</nametext></name> + <fsummary>Unpublish a node name</fsummary> + <desc> + <p>This function can be called by a process to unregister a + specified node from epmd on the localhost. This may be + useful, for example, when epmd has not detected the failure of a + node, and will not allow the name to be reused. If you use this + function to unregister your own process, be sure to also close + the descriptor that was returned by <c><![CDATA[ei_publish()]]></c>.</p> + <note> + <p>Careless use of this function may have unpredictable + results, if the registered node is in fact still running.</p> + </note> + <p><c><![CDATA[ec]]></c> is the node structure of the node to unregister.</p> + <p>If the node was successfully unregistered from epmd, the + function returns 0. Otherwise, it returns -1 and sets + <c><![CDATA[erl_errno]]></c> is to <c><![CDATA[EIO]]></c>.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_unpublish_tmo(ei_cnode *ec, unsigned timeout_ms)</nametext></name> + <fsummary>Unpublish a node name with optional timeout</fsummary> + <desc> + <p>ei_unpublish with an optional timeout argument, + see the description at the beginning of this document.</p> + </desc> + </func> + <func> + <name><ret>const char *</ret><nametext>ei_thisnodename(ei_cnode *ec)</nametext></name> + <name><ret>const char *</ret><nametext>ei_thishostname(ei_cnode *ec)</nametext></name> + <name><ret>const char *</ret><nametext>ei_thisalivename(ei_cnode *ec)</nametext></name> + <fsummary>Retrieve some values</fsummary> + <desc> + <p>These functions can be used to retrieve information about + the C Node. These values are initially set with + <c><![CDATA[ei_connect_init()]]></c> or <c><![CDATA[ei_connect_xinit()]]></c>.</p> + <p>They simply fetches the appropriate field from the <c><![CDATA[ec]]></c> + structure. Read the field directly will probably be safe for + a long time, so these functions are not really needed.</p> + </desc> + </func> + <func> + <name><ret>erlang_pid *</ret><nametext>ei_self(ei_cnode *ec)</nametext></name> + <fsummary>Retrieve the Pid of the C-node</fsummary> + <desc> + <p>This function retrieves the Pid of the C-node. Every C-node + has a (pseudo) pid used in <c><![CDATA[ei_send_reg]]></c>, <c><![CDATA[ei_rpc]]></c> + and others. This is contained in a field in the <c><![CDATA[ec]]></c> + structure. It will be safe for a long time to fetch this + field directly from the <c><![CDATA[ei_cnode]]></c> structure.</p> + </desc> + </func> + <func> + <name><ret>struct hostent</ret><nametext>*ei_gethostbyname(const char *name)</nametext></name> + <name><ret>struct hostent</ret><nametext>*ei_gethostbyaddr(const char *addr, int len, int type)</nametext></name> + <name><ret>struct hostent</ret><nametext>*ei_gethostbyname_r(const char *name, struct hostent *hostp, char *buffer, int buflen, int *h_errnop)</nametext></name> + <name><ret>struct hostent</ret><nametext>*ei_gethostbyaddr_r(const char *addr, int length, int type, struct hostent *hostp, char *buffer, int buflen, int *h_errnop)</nametext></name> + <fsummary>Name lookup functions</fsummary> + <desc> + <p>These are convenience functions for some common name lookup functions.</p> + </desc> + </func> + </funcs> + + <section> + <title>Debug Information</title> + <p>If a connection attempt fails, the following can be checked:</p> + <list type="bulleted"> + <item><c><![CDATA[erl_errno]]></c></item> + <item>that the right cookie was used</item> + <item>that <em>epmd</em> is running</item> + <item>the remote Erlang node on the other side is running the + same version of Erlang as the <c><![CDATA[ei]]></c> + library.</item> + <item>the environment variable <c><![CDATA[ERL_EPMD_PORT]]></c> + is set correctly.</item> + </list> + </section> +</cref> + diff --git a/lib/erl_interface/doc/src/ei_users_guide.xml b/lib/erl_interface/doc/src/ei_users_guide.xml new file mode 100644 index 0000000000..5d18e356cb --- /dev/null +++ b/lib/erl_interface/doc/src/ei_users_guide.xml @@ -0,0 +1,612 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2002</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>The El Library User's Guide</title> + <prepared>Kent Boortz</prepared> + <responsible>Kent Boortz</responsible> + <docno></docno> + <approved></approved> + <checked></checked> + <date></date> + <rev></rev> + <file>ei_users_guide.xml</file> + </header> + <p>The Erl_Interface library contains functions. which help you + integrate programs written in C and Erlang. The functions in + Erl_Interface support the following:</p> + <list type="bulleted"> + <item>manipulation of data represented as Erlang data types</item> + <item>conversion of data between C and Erlang formats</item> + <item>encoding and decoding of Erlang data types for transmission or storage</item> + <item>communication between C nodes and Erlang processes</item> + <item>backup and restore of C node state to and from Mnesia</item> + </list> + <p>In the following sections, these topics are described:</p> + <list type="bulleted"> + <item>compiling your code for use with Erl_Interface</item> + <item>initializing Erl_Interface</item> + <item>encoding, decoding, and sending Erlang terms</item> + <item>building terms and patterns</item> + <item>pattern matching</item> + <item>connecting to a distributed Erlang node</item> + <item>using EPMD</item> + <item>sending and receiving Erlang messages</item> + <item>remote procedure calls</item> + <item>global names</item> + <item>the registry</item> + </list> + + <section> + <title>Compiling and Linking Your Code</title> + <p>In order to use any of the Erl_Interface functions, include the + following lines in your code:</p> + <code type="none"><![CDATA[ +#include "erl_interface.h" +#include "ei.h" ]]></code> + <p>Determine where the top directory of your OTP installation is. You + can find this out by starting Erlang and entering the following + command at the Eshell prompt:</p> + <code type="none"><![CDATA[ +Eshell V4.7.4 (abort with ^G) +1> code:root_dir(). +/usr/local/otp ]]></code> + <p>To compile your code, make sure that your C compiler knows where + to find <c><![CDATA[erl_interface.h]]></c> by specifying an appropriate <c><![CDATA[-I]]></c> + argument on the command line, or by adding it to the <c><![CDATA[CFLAGS]]></c> + definition in your <c><![CDATA[Makefile]]></c>. The correct value for this path is + <c><![CDATA[$OTPROOT/lib/erl_interface]]></c><em>Vsn</em><c><![CDATA[/include]]></c>, where <c><![CDATA[$OTPROOT]]></c> is the path + reported by <c><![CDATA[code:root_dir/0]]></c> in the above example, and <em>Vsn</em> is + the version of the Erl_interface application, for example + <c><![CDATA[erl_interface-3.2.3]]></c></p> + <code type="none"><![CDATA[ +$ cc -c -I/usr/local/otp/lib/erl_interface-3.2.3/include myprog.c ]]></code> + <p>When linking, you will need to specify the path to + <c><![CDATA[liberl_interface.a]]></c> and <c><![CDATA[libei.a]]></c> with + <c><![CDATA[-L$OTPROOT/lib/erl_interface-3.2.3/lib]]></c>, and you will need to specify the + name of the libraries with <c><![CDATA[-lerl_interface -lei]]></c>. You can do + this on the command line or by adding the flags to the <c><![CDATA[LDFLAGS]]></c> + definition in your <c><![CDATA[Makefile]]></c>.</p> + <code type="none"><![CDATA[ +$ ld -L/usr/local/otp/lib/erl_interface-3.2.3/ + lib myprog.o -lerl_interface -lei -o myprog ]]></code> + <p>Also, on some systems it may be necessary to link with some + additional libraries (e.g. <c><![CDATA[libnsl.a]]></c> and <c><![CDATA[libsocket.a]]></c> on + Solaris, or <c><![CDATA[wsock32.lib]]></c> on Windows) in order to use the + communication facilities of Erl_Interface.</p> + <p>If you are using Erl_Interface functions in a threaded + application based on POSIX threads or Solaris threads, then + Erl_Interface needs access to some of the synchronization + facilities in your threads package, and you will need to specify + additional compiler flags in order to indicate which of the packages + you are using. Define <c><![CDATA[_REENTRANT]]></c> and either <c><![CDATA[STHREADS]]></c> or + <c><![CDATA[PTHREADS]]></c>. The default is to use POSIX threads if + <c><![CDATA[_REENTRANT]]></c> is specified.</p> + </section> + + <section> + <title>Initializing the erl_interface Library</title> + <p>Before calling any of the other Erl_Interface functions, you + must call <c><![CDATA[erl_init()]]></c> exactly once to initialize the library. + <c><![CDATA[erl_init()]]></c> takes two arguments, however the arguments are no + longer used by Erl_Interface, and should therefore be specified + as <c><![CDATA[erl_init(NULL,0)]]></c>.</p> + </section> + + <section> + <title>Encoding, Decoding and Sending Erlang Terms</title> + <p>Data sent between distributed Erlang nodes is encoded in the + Erlang external format. Consequently, you have to encode and decode + Erlang terms into byte streams if you want to use the distribution + protocol to communicate between a C program and Erlang. </p> + <p>The Erl_Interface library supports this activity. It has a + number of C functions which create and manipulate Erlang data + structures. The library also contains an encode and a decode function. + The example below shows how to create and encode an Erlang tuple + <c><![CDATA[{tobbe,3928}]]></c>:</p> + <code type="none"><![CDATA[ + +ETERM *arr[2], *tuple; +char buf[BUFSIZ]; +int i; + +arr[0] = erl_mk_atom("tobbe"); +arr[1] = erl_mk_integer(3928); +tuple = erl_mk_tuple(arr, 2); +i = erl_encode(tuple, buf); ]]></code> + <p>Alternatively, you can use <c><![CDATA[erl_send()]]></c> and + <c><![CDATA[erl_receive_msg]]></c>, which handle the encoding and decoding of + messages transparently.</p> + <p>Refer to the Reference Manual for a complete description of the + following modules:</p> + <list type="bulleted"> + <item>the <c><![CDATA[erl_eterm]]></c> module for creating Erlang terms</item> + <item>the <c><![CDATA[erl_marshal]]></c> module for encoding and decoding routines.</item> + </list> + </section> + + <section> + <title>Building Terms and Patterns</title> + <p>The previous example can be simplified by using + <c><![CDATA[erl_format()]]></c> to create an Erlang term.</p> + <code type="none"><![CDATA[ + +ETERM *ep; +ep = erl_format("{~a,~i}", "tobbe", 3928); ]]></code> + <p>Refer to the Reference Manual, the <c><![CDATA[erl_format]]></c> module, for a + full description of the different format directives. The following + example is more complex:</p> + <code type="none"><![CDATA[ + +ETERM *ep; +ep = erl_format("[{name,~a},{age,~i},{data,~w}]", + "madonna", + 21, + erl_format("[{adr,~s,~i}]", "E-street", 42)); +erl_free_compound(ep); ]]></code> + <p>As in previous examples, it is your responsibility to free the + memory allocated for Erlang terms. In this example, + <c><![CDATA[erl_free_compound()]]></c> ensures that the complete term pointed to + by <c><![CDATA[ep]]></c> is released. This is necessary, because the pointer from + the second call to <c><![CDATA[erl_format()]]></c> is lost. </p> + <p>The following + example shows a slightly different solution:</p> + <code type="none"><![CDATA[ + +ETERM *ep,*ep2; +ep2 = erl_format("[{adr,~s,~i}]","E-street",42); +ep = erl_format("[{name,~a},{age,~i},{data,~w}]", + "madonna", 21, ep2); +erl_free_term(ep); +erl_free_term(ep2); ]]></code> + <p>In this case, you free the two terms independently. The order in + which you free the terms <c><![CDATA[ep]]></c> and <c><![CDATA[ep2]]></c> is not important, + because the Erl_Interface library uses reference counting to + determine when it is safe to actually remove objects. </p> + <p>If you are not sure whether you have freed the terms properly, you + can use the following function to see the status of the fixed term + allocator:</p> + <code type="none"><![CDATA[ +long allocated, freed; + +erl_eterm_statistics(&allocated,&freed); +printf("currently allocated blocks: %ld\n",allocated); +printf("length of freelist: %ld\n",freed); + +/* really free the freelist */ +erl_eterm_release(); + ]]></code> + <p>Refer to the Reference Manual, the <c><![CDATA[erl_malloc]]></c> module for more + information.</p> + </section> + + <section> + <title>Pattern Matching</title> + <p>An Erlang pattern is a term that may contain unbound variables or + <c><![CDATA["do not care"]]></c> symbols. Such a pattern can be matched against a + term and, if the match is successful, any unbound variables in the + pattern will be bound as a side effect. The content of a bound + variable can then be retrieved.</p> + <code type="none"><![CDATA[ + +ETERM *pattern; +pattern = erl_format("{madonna,Age,_}"); ]]></code> + <p><c><![CDATA[erl_match()]]></c> is used to perform pattern matching. It takes a + pattern and a term and tries to match them. As a side effect any unbound + variables in the pattern will be bound. In the following example, we + create a pattern with a variable <em>Age</em> which appears at two + positions in the tuple. The pattern match is performed as follows:</p> + <list type="ordered"> + <item><c><![CDATA[erl_match()]]></c> will bind the contents of + <em>Age</em> to <em>21</em> the first time it reaches the variable</item> + <item>the second occurrence of <em>Age</em> will cause a test for + equality between the terms since <em>Age</em> is already bound to + <em>21</em>. Since <em>Age</em> is bound to 21, the equality test will + succeed and the match continues until the end of the pattern.</item> + <item>if the end of the pattern is reached, the match succeeds and you + can retrieve the contents of the variable</item> + </list> + <code type="none"><![CDATA[ +ETERM *pattern,*term; +pattern = erl_format("{madonna,Age,Age}"); +term = erl_format("{madonna,21,21}"); +if (erl_match(pattern, term)) { + fprintf(stderr, "Yes, they matched: Age = "); + ep = erl_var_content(pattern, "Age"); + erl_print_term(stderr, ep); + fprintf(stderr,"\n"); + erl_free_term(ep); +} +erl_free_term(pattern); +erl_free_term(term); ]]></code> + <p>Refer to the Reference Manual, the <c><![CDATA[erl_match()]]></c> function for + more information.</p> + </section> + + <section> + <title>Connecting to a Distributed Erlang Node</title> + <p>In order to connect to a distributed Erlang node you need to first + initialize the connection routine with <c><![CDATA[erl_connect_init()]]></c>, + which stores information such as the host name, node name, and IP + address for later use:</p> + <code type="none"><![CDATA[ +int identification_number = 99; +int creation=1; +char *cookie="a secret cookie string"; /* An example */ +erl_connect_init(identification_number, cookie, creation); ]]></code> + <p>Refer to the Reference Manual, the <c><![CDATA[erl_connect]]></c> module for more information.</p> + <p>After initialization, you set up the connection to the Erlang node. + Use <c><![CDATA[erl_connect()]]></c> to specify the Erlang node you want to + connect to. The following example sets up the connection and should + result in a valid socket file descriptor:</p> + <code type="none"><![CDATA[ +int sockfd; +char *nodename="[email protected]"; /* An example */ +if ((sockfd = erl_connect(nodename)) < 0) + erl_err_quit("ERROR: erl_connect failed"); ]]></code> + <p><c><![CDATA[erl_err_quit()]]></c> prints the specified string and terminates + the program. Refer to the Reference Manual, the <c><![CDATA[erl_error()]]></c> + function for more information.</p> + </section> + + <section> + <title>Using EPMD</title> + <p><c><![CDATA[Epmd]]></c> is the Erlang Port Mapper Daemon. Distributed Erlang nodes + register with <c><![CDATA[epmd]]></c> on the localhost to indicate to other nodes that + they exist and can accept connections. <c><![CDATA[Epmd]]></c> maintains a register of + node and port number information, and when a node wishes to connect to + another node, it first contacts <c><![CDATA[epmd]]></c> in order to find out the correct + port number to connect to.</p> + <p>When you use <c><![CDATA[erl_connect()]]></c> to connect to an Erlang node, a + connection is first made to <c><![CDATA[epmd]]></c> and, if the node is known, a + connection is then made to the Erlang node.</p> + <p>C nodes can also register themselves with <c><![CDATA[epmd]]></c> if they want other + nodes in the system to be able to find and connect to them.</p> + <p>Before registering with <c><![CDATA[epmd]]></c>, you need to first create a listen socket + and bind it to a port. Then:</p> + <code type="none"><![CDATA[ +int pub; + +pub = erl_publish(port); ]]></code> + <p><c><![CDATA[pub]]></c> is a file descriptor now connected to <c><![CDATA[epmd]]></c>. <c><![CDATA[Epmd]]></c> + monitors the other end of the connection, and if it detects that the + connection has been closed, the node will be unregistered. So, if you + explicitly close the descriptor or if your node fails, it will be + unregistered from <c><![CDATA[epmd]]></c>.</p> + <p>Be aware that on some systems (such as VxWorks), a failed node will + not be detected by this mechanism since the operating system does not + automatically close descriptors that were left open when the node + failed. If a node has failed in this way, <c><![CDATA[epmd]]></c> will prevent you from + registering a new node with the old name, since it thinks that the old + name is still in use. In this case, you must unregister the name + explicitly:</p> + <code type="none"><![CDATA[ +erl_unpublish(node); ]]></code> + <p>This will cause <c><![CDATA[epmd]]></c> to close the connection from the far end. Note + that if the name was in fact still in use by a node, the results of + this operation are unpredictable. Also, doing this does not cause the + local end of the connection to close, so resources may be consumed.</p> + </section> + + <section> + <title>Sending and Receiving Erlang Messages</title> + <p>Use one of the following two functions to send messages:</p> + <list type="bulleted"> + <item><c><![CDATA[erl_send()]]></c></item> + <item><c><![CDATA[erl_reg_send()]]></c></item> + </list> + <p>As in Erlang, it is possible to send messages to a + <em>Pid</em> or to a registered name. It is easier to send a + message to a registered name because it avoids the problem of finding + a suitable <em>Pid</em>.</p> + <p>Use one of the following two functions to receive messages:</p> + <list type="bulleted"> + <item><c><![CDATA[erl_receive()]]></c></item> + <item><c><![CDATA[erl_receive_msg()]]></c></item> + </list> + <p><c><![CDATA[erl_receive()]]></c> receives the message into a buffer, while + <c><![CDATA[erl_receive_msg()]]></c> decodes the message into an Erlang term. </p> + + <section> + <title>Example of Sending Messages</title> + <p>In the following example, <c><![CDATA[{Pid, hello_world}]]></c> is + sent to a registered process <c><![CDATA[my_server]]></c>. The message is encoded + by <c><![CDATA[erl_send()]]></c>:</p> + <code type="none"><![CDATA[ +extern const char *erl_thisnodename(void); +extern short erl_thiscreation(void); +#define SELF(fd) erl_mk_pid(erl_thisnodename(),fd,0,erl_thiscreation()) +ETERM *arr[2], *emsg; +int sockfd, creation=1; + +arr[0] = SELF(sockfd); +arr[1] = erl_mk_atom("Hello world"); +emsg = erl_mk_tuple(arr, 2); + +erl_reg_send(sockfd, "my_server", emsg); +erl_free_term(emsg); ]]></code> + <p>The first element of the tuple that is sent is your own + <em>Pid</em>. This enables <c><![CDATA[my_server]]></c> to reply. Refer to the + Reference Manual, the <c><![CDATA[erl_connect]]></c> module for more information + about send primitives.</p> + </section> + + <section> + <title>Example of Receiving Messages</title> + <p>In this example <c><![CDATA[{Pid, Something}]]></c> is received. The + received Pid is then used to return <c><![CDATA[{goodbye,Pid}]]></c></p> + <code type="none"><![CDATA[ +ETERM *arr[2], *answer; +int sockfd,rc; +char buf[BUFSIZE]; +ErlMessage emsg; + +if ((rc = erl_receive_msg(sockfd , buf, BUFSIZE, &emsg)) == ERL_MSG) { + arr[0] = erl_mk_atom("goodbye"); + arr[1] = erl_element(1, emsg.msg); + answer = erl_mk_tuple(arr, 2); + erl_send(sockfd, arr[1], answer); + erl_free_term(answer); + erl_free_term(emsg.msg); + erl_free_term(emsg.to); +} ]]></code> + <p>In order to provide robustness, a distributed Erlang node + occasionally polls all its connected neighbours in an attempt to + detect failed nodes or communication links. A node which receives such + a message is expected to respond immediately with an <c><![CDATA[ERL_TICK]]></c> message. + This is done automatically by <c><![CDATA[erl_receive()]]></c>, however when this + has occurred <c><![CDATA[erl_receive]]></c> returns <c><![CDATA[ERL_TICK]]></c> to the caller + without storing a message into the <c><![CDATA[ErlMessage]]></c> structure.</p> + <p>When a message has been received, it is the caller's responsibility + to free the received message <c><![CDATA[emsg.msg]]></c> as well as <c><![CDATA[emsg.to]]></c> + or <c><![CDATA[emsg.from]]></c>, depending on the type of message received.</p> + <p>Refer to the Reference Manual for additional information about the + following modules:</p> + <list type="bulleted"> + <item><c><![CDATA[erl_connect]]></c></item> + <item><c><![CDATA[erl_eterm]]></c>.</item> + </list> + </section> + </section> + + <section> + <title>Remote Procedure Calls</title> + <p>An Erlang node acting as a client to another Erlang node + typically sends a request and waits for a reply. Such a request is + included in a function call at a remote node and is called a remote + procedure call. The following example shows how the + Erl_Interface library supports remote procedure calls:</p> + <code type="none"><![CDATA[ + +char modname[]=THE_MODNAME; +ETERM *reply,*ep; +ep = erl_format("[~a,[]]", modname); +if (!(reply = erl_rpc(fd, "c", "c", ep))) + erl_err_msg("<ERROR> when compiling file: %s.erl !\n", modname); +erl_free_term(ep); +ep = erl_format("{ok,_}"); +if (!erl_match(ep, reply)) + erl_err_msg("<ERROR> compiler errors !\n"); +erl_free_term(ep); +erl_free_term(reply); ]]></code> + <p><c><![CDATA[c:c/1]]></c> is called to compile the specified module on the + remote node. <c><![CDATA[erl_match()]]></c> checks that the compilation was + successful by testing for the expected <c><![CDATA[ok]]></c>.</p> + <p>Refer to the Reference Manual, the <c><![CDATA[erl_connect]]></c> module for + more information about <c><![CDATA[erl_rpc()]]></c>, and its companions + <c><![CDATA[erl_rpc_to()]]></c> and <c><![CDATA[erl_rpc_from()]]></c>.</p> + </section> + + <section> + <title>Using Global Names</title> + <p>A C node has access to names registered through the Erlang Global + module. Names can be looked up, allowing the C node to send messages + to named Erlang services. C nodes can also register global names, + allowing them to provide named services to Erlang processes or other C + nodes. </p> + <p>Erl_Interface does not provide a native implementation of the global + service. Instead it uses the global services provided by a "nearby" + Erlang node. In order to use the services described in this section, + it is necessary to first open a connection to an Erlang node.</p> + <p>To see what names there are:</p> + <code type="none"><![CDATA[ +char **names; +int count; +int i; + +names = erl_global_names(fd,&count); + +if (names) + for (i=0; i<count; i++) + printf("%s\n",names[i]); + +free(names); ]]></code> + <p><c><![CDATA[erl_global_names()]]></c> allocates and returns a buffer containing + all the names known to global. <c><![CDATA[count]]></c> will be initialized to + indicate how many names are in the array. The array of strings in + names is terminated by a NULL pointer, so it is not necessary to use + <c><![CDATA[count]]></c> to determine when the last name is reached.</p> + <p>It is the caller's responsibility to free the array. + <c><![CDATA[erl_global_names()]]></c> allocates the array and all of the strings + using a single call to <c><![CDATA[malloc()]]></c>, so <c><![CDATA[free(names)]]></c> is all + that is necessary.</p> + <p>To look up one of the names:</p> + <code type="none"><![CDATA[ +ETERM *pid; +char node[256]; + +pid = erl_global_whereis(fd,"schedule",node); ]]></code> + <p>If <c><![CDATA["schedule"]]></c> is known to global, an Erlang pid is returned + that can be used to send messages to the schedule service. + Additionally, <c><![CDATA[node]]></c> will be initialized to contain the name of + the node where the service is registered, so that you can make a + connection to it by simply passing the variable to <c><![CDATA[erl_connect()]]></c>.</p> + <p>Before registering a name, you should already have registered your + port number with <c><![CDATA[epmd]]></c>. This is not strictly necessary, but if you + neglect to do so, then other nodes wishing to communicate with your + service will be unable to find or connect to your process.</p> + <p>Create a pid that Erlang processes can use to communicate with your + service:</p> + <code type="none"><![CDATA[ +ETERM *pid; + +pid = erl_mk_pid(thisnode,14,0,0); +erl_global_register(fd,servicename,pid); ]]></code> + <p>After registering the name, you should use <c><![CDATA[erl_accept()]]></c> to wait for + incoming connections.</p> + <p>Do not forget to free <c><![CDATA[pid]]></c> later with <c><![CDATA[erl_free_term()]]></c>!</p> + <p>To unregister a name:</p> + <code type="none"><![CDATA[ +erl_global_unregister(fd,servicename); ]]></code> + </section> + + <section> + <title>The Registry</title> + <p>This section describes the use of the registry, a simple mechanism + for storing key-value pairs in a C-node, as well as backing them up or + restoring them from a Mnesia table on an Erlang node. More detailed + information about the individual API functions can be found in the + Reference Manual.</p> + <p>Keys are strings, i.e. 0-terminated arrays of characters, and values + are arbitrary objects. Although integers and floating point numbers + are treated specially by the registry, you can store strings or binary + objects of any type as pointers.</p> + <p>To start, you need to open a registry:</p> + <code type="none"><![CDATA[ +ei_reg *reg; + +reg = ei_reg_open(45); ]]></code> + <p>The number 45 in the example indicates the approximate number of + objects that you expect to store in the registry. Internally the + registry uses hash tables with collision chaining, so there is no + absolute upper limit on the number of objects that the registry can + contain, but if performance or memory usage are important, then you + should choose a number accordingly. The registry can be resized later.</p> + <p>You can open as many registries as you like (if memory permits).</p> + <p>Objects are stored and retrieved through set and get functions. In + the following examples you see how to store integers, floats, strings + and arbitrary binary objects:</p> + <code type="none"><![CDATA[ +struct bonk *b = malloc(sizeof(*b)); +char *name = malloc(7); + +ei_reg_setival(reg,"age",29); +ei_reg_setfval(reg,"height",1.85); + +strcpy(name,"Martin"); +ei_reg_setsval(reg,"name",name); + +b->l = 42; +b->m = 12; +ei_reg_setpval(reg,"jox",b,sizeof(*b)); ]]></code> + <p>If you attempt to store an object in the registry and there is an + existing object with the same key, the new value will replace the old + one. This is done regardless of whether the new object and the old one + have the same type, so you can, for example, replace a string with an + integer. If the existing value is a string or binary, it will be freed + before the new value is assigned.</p> + <p>Stored values are retrieved from the registry as follows:</p> + <code type="none"><![CDATA[ +long i; +double f; +char *s; +struct bonk *b; +int size; + +i = ei_reg_getival(reg,"age"); +f = ei_reg_getfval(reg,"height"); +s = ei_reg_getsval(reg,"name"); +b = ei_reg_getpval(reg,"jox",&size); ]]></code> + <p>In all of the above examples, the object must exist and it must be of + the right type for the specified operation. If you do not know the + type of a given object, you can ask:</p> + <code type="none"><![CDATA[ +struct ei_reg_stat buf; + +ei_reg_stat(reg,"name",&buf); ]]></code> + <p>Buf will be initialized to contain object attributes.</p> + <p>Objects can be removed from the registry:</p> + <code type="none"><![CDATA[ +ei_reg_delete(reg,"name"); ]]></code> + <p>When you are finished with a registry, close it to remove all the + objects and free the memory back to the system:</p> + <code type="none"><![CDATA[ +ei_reg_close(reg); ]]></code> + + <section> + <title>Backing Up the Registry to Mnesia</title> + <p>The contents of a registry can be backed up to Mnesia on a "nearby" + Erlang node. You need to provide an open connection to the Erlang node + (see <c><![CDATA[erl_connect()]]></c>). Also, Mnesia 3.0 or later must be running + on the Erlang node before the backup is initiated:</p> + <code type="none"><![CDATA[ +ei_reg_dump(fd, reg, "mtab", dumpflags); ]]></code> + <p>The example above will backup the contents of the registry to the + specified Mnesia table <c><![CDATA["mtab"]]></c>. Once a registry has been backed + up to Mnesia in this manner, additional backups will only affect + objects that have been modified since the most recent backup, i.e. + objects that have been created, changed or deleted. The backup + operation is done as a single atomic transaction, so that the entire + backup will be performed or none of it will.</p> + <p>In the same manner, a registry can be restored from a Mnesia table:</p> + <code type="none"><![CDATA[ +ei_reg_restore(fd, reg, "mtab"); ]]></code> + <p>This will read the entire contents of <c><![CDATA["mtab"]]></c> into the specified + registry. After the restore, all of the objects in the registry will + be marked as unmodified, so a subsequent backup will only affect + objects that you have modified since the restore.</p> + <p>Note that if you restore to a non-empty registry, objects in the + table will overwrite objects in the registry with the same keys. Also, + the <em>entire</em> contents of the registry is marked as unmodified + after the restore, including any modified objects that were not + overwritten by the restore operation. This may not be your intention.</p> + </section> + + <section> + <title>Storing Strings and Binaries</title> + <p>When string or binary objects are stored in the registry it is + important that a number of simple guidelines are followed. </p> + <p>Most importantly, the object must have been created with a single call + to <c><![CDATA[malloc()]]></c> (or similar), so that it can later be removed by a + single call to <c><![CDATA[free()]]></c>. Objects will be freed by the registry + when it is closed, or when you assign a new value to an object that + previously contained a string or binary.</p> + <p>You should also be aware that if you store binary objects that are + context-dependent (e.g. containing pointers or open file descriptors), + they will lose their meaning if they are backed up to a Mnesia table + and subsequently restored in a different context.</p> + <p>When you retrieve a stored string or binary value from the registry, + the registry maintains a pointer to the object and you are passed a + copy of that pointer. You should never free an object retrieved in + this manner because when the registry later attempts to free it, a + runtime error will occur that will likely cause the C-node to crash.</p> + <p>You are free to modify the contents of an object retrieved this way. + However when you do so, the registry will not be aware of the changes + you make, possibly causing it to be missed the next time you make a + Mnesia backup of the registry contents. This can be avoided if you + mark the object as dirty after any such changes with + <c><![CDATA[ei_reg_markdirty()]]></c>, or pass appropriate flags to + <c><![CDATA[ei_reg_dump()]]></c>.</p> + </section> + </section> +</chapter> + diff --git a/lib/erl_interface/doc/src/erl_call.xml b/lib/erl_interface/doc/src/erl_call.xml new file mode 100644 index 0000000000..2d88e7616a --- /dev/null +++ b/lib/erl_interface/doc/src/erl_call.xml @@ -0,0 +1,240 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE comref SYSTEM "comref.dtd"> + +<comref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>erl_call</title> + <prepared>Torbjörn Törnkvist</prepared> + <responsible>Torbjörn Törnkvist</responsible> + <docno></docno> + <approved>Bjarne Däcker</approved> + <checked>Torbjörn Törnkvist</checked> + <date>97-05-16</date> + <rev>B</rev> + <file>erl_call.sgml</file> + </header> + <com>erl_call</com> + <comsummary>Call/Start a Distributed Erlang Node</comsummary> + <description> + <p><c><![CDATA[erl_call]]></c> makes it possible to start and/or communicate with + a distributed Erlang node. It is built upon the <c><![CDATA[erl_interface]]></c> + library as an example application. Its purpose is to use an Unix shell script to interact with a distributed Erlang node. It performs all + communication with the Erlang <em>rex server</em>, using the standard Erlang RPC facility. It does not require any special + software to be run at the Erlang target node.</p> + <p>The main use is to either start a distributed Erlang node + or to make an ordinary function call. However, it is also + possible to pipe an Erlang module to <c><![CDATA[erl_call]]></c> and have it + compiled, or to pipe a sequence of Erlang expressions to be evaluated + (similar to the Erlang shell).</p> + <p>Options, which cause <c><![CDATA[stdin]]></c> to be read, can be used with + advantage + as scripts from within (Unix) shell scripts. Another + nice use of <c><![CDATA[erl_call]]></c> could be from (http) CGI-bin scripts.</p> + </description> + <funcs> + <func> + <name>erl_call <options></name> + <fsummary>Start/Call Erlang</fsummary> + <desc> + <p>Each option flag is described below with its name, type and + meaning. </p> + <taglist> + <tag>-a [Mod [Fun [Args]]]]</tag> + <item> + <p>(<em>optional</em>): Applies the specified function + and returns the result. <c><![CDATA[Mod]]></c> must be specified, however + <em>[]</em> is assumed for unspecified <c><![CDATA[Fun]]></c> and <c><![CDATA[Args]]></c>. <c><![CDATA[Args]]></c> should + be in the same format as for <c><![CDATA[erlang:apply/3]]></c>. Note + that this flag takes exactly one argument, so quoting + may be necessary in order to group <c><![CDATA[Mod]]></c>, <c><![CDATA[Fun]]></c> + and <c><![CDATA[Args]]></c>, in a manner dependent on the behavior + of your command shell.</p> + <p></p> + </item> + <tag>-c Cookie</tag> + <item> + <p>(<em>optional</em>): Use this option to specify a certain cookie. If no cookie is specified, the <c><![CDATA[~/.erlang.cookie]]></c> file is read and its content are used as cookie. The Erlang node we want to communicate with must have the same cookie.</p> + </item> + <tag>-d</tag> + <item> + <p>(<em>optional</em>): Debug mode. This causes all IO to be output + to the file <c><![CDATA[~/.erl_call.out.Nodename]]></c>, where <c><![CDATA[Nodename]]></c> + is the node name of the Erlang node in question.</p> + <p></p> + </item> + <tag>-e</tag> + <item> + <p>(<em>optional</em>): Reads a sequence of Erlang expressions, separated + by '<em>,</em>' and ended with a '<em>.</em>', from <c><![CDATA[stdin]]></c> until + EOF (Control-D). Evaluates the expressions and returns the result from + the last expression. Returns <c><![CDATA[{ok,Result}]]></c> if successful.</p> + <p></p> + </item> + <tag>-h HiddenName</tag> + <item> + <p>(<em>optional</em>): Specifies the name of the hidden node + that <c><![CDATA[erl_call]]></c> represents.</p> + <p></p> + </item> + <tag>-m</tag> + <item> + <p>(<em>optional</em>): Reads an Erlang module from <c><![CDATA[stdin]]></c> and + compiles it.</p> + <p></p> + </item> + <tag>-n Node</tag> + <item> + <p>(one of <c><![CDATA[-n, -name, -sname]]></c> is required): + Has the same meaning as <c><![CDATA[-name]]></c> and can still be used for + backwards compatibility reasons.</p> + <p></p> + </item> + <tag>-name Node</tag> + <item> + <p>(one of <c><![CDATA[-n, -name, -sname]]></c> is required): <c><![CDATA[Node]]></c> is the name of the node to be + started or communicated with. It is assumed that + <c><![CDATA[Node]]></c> is started with <c><![CDATA[erl -name]]></c>, which means that fully + qualified long node names are used. + If the <c><![CDATA[-s]]></c> option is given, an Erlang node will (if necessary) + be started with <c><![CDATA[erl -name]]></c>.</p> + <p></p> + </item> + <tag>-q</tag> + <item> + <p>(<em>optional</em>): Halts the Erlang node specified + with the -n switch. This switch overrides the -s switch.</p> + <p></p> + </item> + <tag>-r</tag> + <item> + <p>(<em>optional</em>): Generates a random name of the hidden node + that <c><![CDATA[erl_call]]></c> represents.</p> + <p></p> + </item> + <tag>-s</tag> + <item> + <p>(<em>optional</em>): Starts a distributed Erlang node if necessary. + This means that in a sequence of calls, where the '<c><![CDATA[-s]]></c>' + and '<c><![CDATA[-n Node]]></c>' are constant, only the first call will start + the Erlang node. This makes the rest of the communication + very fast. This flag is currently only available on the Unix platform.</p> + <p></p> + </item> + <tag>-sname Node</tag> + <item> + <p>(one of <c><![CDATA[-n, -name, -sname]]></c> is required): <c><![CDATA[Node]]></c> is the name of the node to + be started or communicated with. It is assumed that <c><![CDATA[Node]]></c> is started with <c><![CDATA[erl -sname]]></c> which means that short node names are used. + If <c><![CDATA[-s]]></c> option is given, an Erlang node will be started (if necessary) with <c><![CDATA[erl -sname]]></c>.</p> + <p></p> + </item> + <tag>-v</tag> + <item> + <p>(<em>optional</em>): Prints a lot of <c><![CDATA[verbose]]></c> information. + This is only useful for the developer and maintainer of <c><![CDATA[erl_call]]></c>.</p> + <p></p> + </item> + <tag>-x ErlScript</tag> + <item> + <p>(<em>optional</em>): Specifies another name of the Erlang start-up script + to be used. If not specified, the standard <c><![CDATA[erl]]></c> start-up script + is used.</p> + </item> + </taglist> + </desc> + </func> + </funcs> + + <section> + <title>Examples</title> + <p>Starts an Erlang node and calls <c><![CDATA[erlang:time/0]]></c>.</p> + <code type="none"><![CDATA[ +erl_call -s -a 'erlang time' -n madonna +{18,27,34} + ]]></code> + <p>Terminates an Erlang node by calling <c><![CDATA[erlang:halt/0]]></c>.</p> + <code type="none"><![CDATA[ +erl_call -s -a 'erlang halt' -n madonna + ]]></code> + <p>An apply with several arguments.</p> + <code type="none"><![CDATA[ +erl_call -s -a 'lists map [{math,sqrt},[1,4,9,16,25]]' -n madonna + ]]></code> + <p>Evaluates a couple of expressions. <b>The input ends with EOF (Control-D)</b>.</p> + <code type="none"><![CDATA[ +erl_call -s -e -n madonna +statistics(runtime), +X=1, +Y=2, +{_,T}=statistics(runtime), +{X+Y,T}. +^D +{ok,{3,0}} + ]]></code> + <p>Compiles a module and runs it. <b>Again, the input ends with EOF (Control-D)</b>. (In the example shown, the output has been formatted afterwards).</p> + <code type="none"><![CDATA[ +erl_call -s -m -a lolita -n madonna +-module(lolita). +-compile(export_all). +start() -> + P = processes(), + F = fun(X) -> {X,process_info(X,registered_name)} end, + lists:map(F,[],P). +^D +[{<[email protected],0,0>, + {registered_name,init}}, + {<[email protected],2,0>, + {registered_name,erl_prim_loader}}, + {<[email protected],4,0>, + {registered_name,error_logger}}, + {<[email protected],5,0>, + {registered_name,application_controller}}, + {<[email protected],6,0>, + {registered_name,kernel}}, + {<[email protected],7,0>, + []}, + {<[email protected],8,0>, + {registered_name,kernel_sup}}, + {<[email protected],9,0>, + {registered_name,net_sup}}, + {<[email protected],10,0>, + {registered_name,net_kernel}}, + {<[email protected],11,0>, + []}, + {<[email protected],12,0>, + {registered_name,global_name_server}}, + {<[email protected],13,0>, + {registered_name,auth}}, + {<[email protected],14,0>, + {registered_name,rex}}, + {<[email protected],15,0>, + []}, + {<[email protected],16,0>, + {registered_name,file_server}}, + {<[email protected],17,0>, + {registered_name,code_server}}, + {<[email protected],20,0>, + {registered_name,user}}, + {<[email protected],38,0>, + []}] + ]]></code> + </section> +</comref> + diff --git a/lib/erl_interface/doc/src/erl_connect.xml b/lib/erl_interface/doc/src/erl_connect.xml new file mode 100644 index 0000000000..b2235925b2 --- /dev/null +++ b/lib/erl_interface/doc/src/erl_connect.xml @@ -0,0 +1,566 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE cref SYSTEM "cref.dtd"> + +<cref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>erl_connect</title> + <prepared>Torbjörn Törnkvist</prepared> + <responsible>Torbjörn Törnkvist</responsible> + <docno></docno> + <approved>Bjarne Däcker</approved> + <checked>Torbjörn Törnkvist</checked> + <date>980703</date> + <rev>A</rev> + <file>erl_connect.sgml</file> + </header> + <lib>erl_connect</lib> + <libsummary>Communicate with Distributed Erlang</libsummary> + <description> + <p>This module provides support for communication between distributed + Erlang nodes and C nodes, in a manner that is transparent to Erlang + processes.</p> + <p>A C node appears to Erlang as a + <em>hidden node</em>. + That is, Erlang processes that know the name of the + C node are able to communicate with it in a normal manner, but + the node name will not appear in the listing provided by the + Erlang function <c><![CDATA[nodes/0]]></c>.</p> + </description> + <funcs> + <func> + <name><ret>int</ret><nametext>erl_connect_init(number, cookie, creation)</nametext></name> + <name><ret>int</ret><nametext>erl_connect_xinit(host, alive, node, addr, cookie, creation)</nametext></name> + <fsummary>Initialize communication</fsummary> + <type> + <v>int number;</v> + <v>char *cookie;</v> + <v>short creation;</v> + <v>char *host,*alive,*node;</v> + <v>struct in_addr *addr;</v> + </type> + <desc> + <p>These functions initialize the <c><![CDATA[erl_connect]]></c> + module. In particular, they are used to identify the name of the + C-node from which they are called. One of these functions must + be called before any of the other functions in the erl_connect + module are used.</p> + <p><c><![CDATA[erl_connect_xinit()]]></c> stores for later use information about + the node's host name <c><![CDATA[host]]></c>, alive name <c><![CDATA[alive]]></c>, node + name <c><![CDATA[node]]></c>, IP address <c><![CDATA[addr]]></c>, cookie <c><![CDATA[cookie]]></c>, + and creation number <c><![CDATA[creation]]></c>. <c><![CDATA[erl_connect_init()]]></c> + provides an alternative interface which does not require as much + information from the caller. Instead, <c><![CDATA[erl_connect_init()]]></c> + uses <c><![CDATA[gethostbyname()]]></c> to obtain default values. + </p> + <p>If you use <c><![CDATA[erl_connect_init()]]></c> your node will have a + short name, i.e., it will not be fully qualified. If you need to + use fully qualified (a.k.a. long) names, use + <c><![CDATA[erl_connect_xinit()]]></c> instead. + </p> + <p><c><![CDATA[host]]></c> is the name of the host on which the node is running.</p> + <p><c><![CDATA[alive]]></c> is the alivename of the node.</p> + <p><c><![CDATA[node]]></c> is the name of the node. The nodename should + be of the form <em>alivename@hostname</em>.</p> + <p><c><![CDATA[addr]]></c> is the 32-bit IP address of <c><![CDATA[host]]></c>.</p> + <p><c><![CDATA[cookie]]></c> is the authorization string required for access + to the remote node. If NULL the user HOME directory is + searched for a cookie file <c><![CDATA[.erlang.cookie]]></c>. The path to + the home directory is retrieved from the environment variable + <c><![CDATA[HOME]]></c> on Unix and from the <c><![CDATA[HOMEDRIVE]]></c> and + <c><![CDATA[HOMEPATH]]></c> variables on Windows. Refer to the <c><![CDATA[auth]]></c> + module for more details.</p> + <p><c><![CDATA[creation]]></c> helps identify a particular instance of a C + node. In particular, it can help prevent us from receiving + messages sent to an earlier process with the same registered + name.</p> + <p>A C node acting as a server will be assigned a creation number + when it calls <c><![CDATA[erl_publish()]]></c>.</p> + <p><c><![CDATA[number]]></c> is used by <c><![CDATA[erl_connect_init()]]></c> to + construct the actual node name. In the second example shown + below, <em>"[email protected]"</em> will be the resulting node + name.</p> + <p>Example 1:</p> + <code type="none"><![CDATA[ +struct in_addr addr; +addr = inet_addr("150.236.14.75"); +if (!erl_connect_xinit("chivas", + "madonna", + "[email protected]", + &addr; + "samplecookiestring..."), + 0) + erl_err_quit("<ERROR> when initializing !"); + ]]></code> + <p>Example 2:</p> + <code type="none"><![CDATA[ +if (!erl_connect_init(17, "samplecookiestring...", 0)) + erl_err_quit("<ERROR> when initializing !"); + ]]></code> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>erl_connect(node)</nametext></name> + <name><ret>int</ret><nametext>erl_xconnect(addr, alive)</nametext></name> + <fsummary>Establishe a connection to an Erlang node</fsummary> + <type> + <v>char *node, *alive;</v> + <v>struct in_addr *addr;</v> + </type> + <desc> + <p>These functions set up a connection to an Erlang node.</p> + <p><c><![CDATA[erl_xconnect()]]></c> requires the IP address of the remote + host and the alive name of the remote node + to be specified. <c><![CDATA[erl_connect()]]></c> provides an alternative + interface, and determines the information from the node name + provided.</p> + <p><c><![CDATA[addr]]></c> is the 32-bit IP address of the remote host.</p> + <p><c><![CDATA[alive]]></c> is the alivename of the remote node.</p> + <p><c><![CDATA[node]]></c> is the name of the remote node.</p> + <p>These functions return an open file descriptor on success, or + a negative value indicating that an error occurred --- in + which case they will set <c><![CDATA[erl_errno]]></c> to one of:</p> + <taglist> + <tag><c><![CDATA[EHOSTUNREACH]]></c></tag> + <item>The remote host <c><![CDATA[node]]></c> is unreachable</item> + <tag><c><![CDATA[ENOMEM]]></c></tag> + <item>No more memory available.</item> + <tag><c><![CDATA[EIO]]></c></tag> + <item>I/O error.</item> + </taglist> + <p>Additionally, <c><![CDATA[errno]]></c> values from + <c><![CDATA[socket]]></c><em>(2)</em> and <c><![CDATA[connect]]></c><em>(2)</em> + system calls may be propagated into <c><![CDATA[erl_errno]]></c>.</p> + <code type="none"><![CDATA[ +#define NODE "[email protected]" +#define ALIVE "madonna" +#define IP_ADDR "150.236.14.75" + +/*** Variant 1 ***/ +erl_connect( NODE ); + +/*** Variant 2 ***/ +struct in_addr addr; +addr = inet_addr(IP_ADDR); +erl_xconnect( &addr , ALIVE ); + ]]></code> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>erl_close_connection(fd)</nametext></name> + <fsummary>Close a connection to an Erlang node</fsummary> + <type> + <v>int fd;</v> + </type> + <desc> + <p>This function closes an open connection to an Erlang node.</p> + <p><c><![CDATA[Fd]]></c> is a file descriptor obtained from + <c><![CDATA[erl_connect()]]></c> or <c><![CDATA[erl_xconnect()]]></c>.</p> + <p>On success, 0 is returned. If the call fails, a non-zero value + is returned, and the reason for + the error can be obtained with the appropriate platform-dependent + call.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>erl_receive(fd, bufp, bufsize)</nametext></name> + <fsummary>Receive a message</fsummary> + <type> + <v>int fd;</v> + <v>char *bufp;</v> + <v>int bufsize;</v> + </type> + <desc> + <p>This function receives a message consisting of a sequence + of bytes in the Erlang external format.</p> + <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.</p> + <p><c><![CDATA[bufp]]></c> is a buffer large enough to hold the expected + message. </p> + <p><c><![CDATA[bufsize]]></c> indicates the size of <c><![CDATA[bufp]]></c>.</p> + <p>If a <em>tick</em> occurs, i.e., the Erlang node on the + other end of the connection has polled this node to see if it + is still alive, the function will return <c><![CDATA[ERL_TICK]]></c> and + no message will be placed in the buffer. Also, + <c><![CDATA[erl_errno]]></c> will be set to <c><![CDATA[EAGAIN]]></c>.</p> + <p>On success, the message is placed in the specified buffer + and the function returns the number of bytes actually read. On + failure, the function returns a negative value and will set + <c><![CDATA[erl_errno]]></c> to one of:</p> + <taglist> + <tag><c><![CDATA[EAGAIN]]></c></tag> + <item>Temporary error: Try again.</item> + <tag><c><![CDATA[EMSGSIZE]]></c></tag> + <item>Buffer too small.</item> + <tag><c><![CDATA[EIO]]></c></tag> + <item>I/O error.</item> + </taglist> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>erl_receive_msg(fd, bufp, bufsize, emsg)</nametext></name> + <fsummary>Receive and decodes a message</fsummary> + <type> + <v>int fd;</v> + <v>unsigned char *bufp;</v> + <v>int bufsize;</v> + <v>ErlMessage *emsg;</v> + </type> + <desc> + <p>This function receives the message into the specified buffer, + and decodes into the <c><![CDATA[(ErlMessage *) emsg]]></c>.</p> + <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.</p> + <p><c><![CDATA[bufp]]></c> is a buffer large enough to hold the expected message.</p> + <p><c><![CDATA[bufsize]]></c> indicates the size of <c><![CDATA[bufp]]></c>.</p> + <p><c><![CDATA[emsg]]></c> is a pointer to an <c><![CDATA[ErlMessage]]></c> structure, + into which the message will be decoded. <c><![CDATA[ErlMessage]]></c> is + defined as follows:</p> + <code type="none"><![CDATA[ +typedef struct { + int type; + ETERM *msg; + ETERM *to; + ETERM *from; + char to_name[MAXREGLEN]; +} ErlMessage; + ]]></code> + <note> + <p>The definition of <c><![CDATA[ErlMessage]]></c> has changed since + earlier versions of Erl_Interface.</p> + </note> + <p><c><![CDATA[type]]></c> identifies the type of message, one of + <c><![CDATA[ERL_SEND]]></c>, <c><![CDATA[ERL_REG_SEND]]></c>, <c><![CDATA[ERL_LINK]]></c>, + <c><![CDATA[ERL_UNLINK]]></c> and <c><![CDATA[ERL_EXIT]]></c>. + </p> + <p>If <c><![CDATA[type]]></c> contains <c><![CDATA[ERL_SEND]]></c> + this indicates that an ordinary send operation has taken + place, and <c><![CDATA[emsg->to]]></c> contains the Pid of the + recipient. If <c><![CDATA[type]]></c> contains <c><![CDATA[ERL_REG_SEND]]></c> then a + registered send operation took place, and <c><![CDATA[emsg->from]]></c> + contains the Pid of the sender. In both cases, the actual + message will be in <c><![CDATA[emsg->msg]]></c>. + </p> + <p>If <c><![CDATA[type]]></c> contains one of <c><![CDATA[ERL_LINK]]></c> or + <c><![CDATA[ERL_UNLINK]]></c>, then <c><![CDATA[emsg->to]]></c> and <c><![CDATA[emsg->from]]></c> + contain the pids of the sender and recipient of the link or unlink. + <c><![CDATA[emsg->msg]]></c> is not used in these cases. + </p> + <p>If <c><![CDATA[type]]></c> contains <c><![CDATA[ERL_EXIT]]></c>, then this + indicates that a link has been broken. In this case, + <c><![CDATA[emsg->to]]></c> and <c><![CDATA[emsg->from]]></c> contain the pids of the + linked processes, and <c><![CDATA[emsg->msg]]></c> contains the reason for + the exit. + </p> + <note> + <p>It is the caller's responsibility to release the + memory pointed to by <c><![CDATA[emsg->msg]]></c>, <c><![CDATA[emsg->to]]></c> and + <c><![CDATA[emsg->from]]></c>.</p> + </note> + <p>If a <em>tick</em> occurs, i.e., the Erlang node on the + other end of the connection has polled this node to see if it + is still alive, the function will return <c><![CDATA[ERL_TICK]]></c> + indicating that the tick has been received and responded to, + but no message will be placed in the buffer. In this case you + should call <c><![CDATA[erl_receive_msg()]]></c> again.</p> + <p>On success, the function returns <c><![CDATA[ERL_MSG]]></c> and the + <c><![CDATA[Emsg]]></c> struct will be initialized as described above, or + <c><![CDATA[ERL_TICK]]></c>, in which case no message is returned. On + failure, the function returns <c><![CDATA[ERL_ERROR]]></c> and will set + <c><![CDATA[erl_errno]]></c> to one of:</p> + <taglist> + <tag><c><![CDATA[EMSGSIZE]]></c></tag> + <item>Buffer too small.</item> + <tag><c><![CDATA[ENOMEM]]></c></tag> + <item>No more memory available.</item> + <tag><c><![CDATA[EIO]]></c></tag> + <item>I/O error.</item> + </taglist> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>erl_xreceive_msg(fd, bufpp, bufsizep, emsg)</nametext></name> + <fsummary>Receive and decodes a message</fsummary> + <type> + <v>int fd;</v> + <v>unsigned char **bufpp;</v> + <v>int *bufsizep;</v> + <v>ErlMessage *emsg;</v> + </type> + <desc> + <p>This function is similar to <c><![CDATA[erl_receive_msg]]></c>. The + difference is that <c><![CDATA[erl_xreceive_msg]]></c> expects the buffer to + have been allocated by <c><![CDATA[malloc]]></c>, and reallocates it if the received + message does not fit into the original buffer. For that reason, + both buffer and buffer length are given as pointers - their values + may change by the call. + </p> + <p>On success, the function returns <c><![CDATA[ERL_MSG]]></c> and the + <c><![CDATA[Emsg]]></c> struct will be initialized as described above, or + <c><![CDATA[ERL_TICK]]></c>, in which case no message is returned. On + failure, the function returns <c><![CDATA[ERL_ERROR]]></c> and will set + <c><![CDATA[erl_errno]]></c> to one of:</p> + <taglist> + <tag><c><![CDATA[EMSGSIZE]]></c></tag> + <item>Buffer too small.</item> + <tag><c><![CDATA[ENOMEM]]></c></tag> + <item>No more memory available.</item> + <tag><c><![CDATA[EIO]]></c></tag> + <item>I/O error.</item> + </taglist> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>erl_send(fd, to, msg)</nametext></name> + <fsummary>Send a message</fsummary> + <type> + <v>int fd;</v> + <v>ETERM *to, *msg;</v> + </type> + <desc> + <p>This function sends an Erlang term to a process.</p> + <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.</p> + <p><c><![CDATA[to]]></c> is an Erlang term containing the Pid of the + intended recipient of the message.</p> + <p><c><![CDATA[msg]]></c> is the Erlang term to be sent.</p> + <p>The function returns 1 if successful, otherwise 0 --- in + which case it will set <c><![CDATA[erl_errno]]></c> to one of:</p> + <taglist> + <tag><c><![CDATA[EINVAL]]></c></tag> + <item>Invalid argument: <c><![CDATA[to]]></c> is not a valid Erlang pid.</item> + <tag><c><![CDATA[ENOMEM]]></c></tag> + <item>No more memory available.</item> + <tag><c><![CDATA[EIO]]></c></tag> + <item>I/O error.</item> + </taglist> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>erl_reg_send(fd, to, msg)</nametext></name> + <fsummary>Send a message to a registered name</fsummary> + <type> + <v>int fd;</v> + <v>char *to;</v> + <v>ETERM *msg;</v> + </type> + <desc> + <p>This function sends an Erlang term to a registered process.</p> + <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.</p> + <p><c><![CDATA[to]]></c> is a string containing the registered name of + the intended recipient of the message.</p> + <p><c><![CDATA[msg]]></c> is the Erlang term to be sent.</p> + <p>The function returns 1 if successful, otherwise 0 --- in + which case it will set <c><![CDATA[erl_errno]]></c> to one of:</p> + <taglist> + <tag><c><![CDATA[ENOMEM]]></c></tag> + <item>No more memory available.</item> + <tag><c><![CDATA[EIO]]></c></tag> + <item>I/O error.</item> + </taglist> + </desc> + </func> + <func> + <name><ret>ETERM *</ret><nametext>erl_rpc(fd, mod, fun, args)</nametext></name> + <name><ret>int</ret><nametext>erl_rpc_to(fd, mod, fun, args)</nametext></name> + <name><ret>int</ret><nametext>erl_rpc_from(fd, timeout, emsg)</nametext></name> + <fsummary>Remote Procedure Call</fsummary> + <type> + <v>int fd, timeout;</v> + <v>char *mod, *fun;</v> + <v>ETERM *args;</v> + <v>ErlMessage *emsg;</v> + </type> + <desc> + <p>These functions support calling Erlang functions on remote nodes. + <c><![CDATA[erl_rpc_to()]]></c> sends an rpc request to a remote node and + <c><![CDATA[erl_rpc_from()]]></c> receives the results of such a call. + <c><![CDATA[erl_rpc()]]></c> combines the functionality of these two functions + by sending an rpc request and waiting for the results. See also + <c><![CDATA[rpc:call/4]]></c>. </p> + <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.</p> + <p><c><![CDATA[timeout]]></c> is the maximum time (in ms) to wait for + results. Specify <c><![CDATA[ERL_NO_TIMEOUT]]></c> to wait forever. + When erl_rpc() calls erl_rpc_from(), the call will never + timeout.</p> + <p><c><![CDATA[mod]]></c> is the name of the module containing the function + to be run on the remote node.</p> + <p><c><![CDATA[fun]]></c> is the name of the function to run.</p> + <p><c><![CDATA[args]]></c> is an Erlang list, containing the arguments to be + passed to the function. </p> + <p><c><![CDATA[emsg]]></c> is a message containing the result of the + function call.</p> + <p>The actual message returned by the rpc server + is a 2-tuple <c><![CDATA[{rex,Reply}]]></c>. If you are using + <c><![CDATA[erl_rpc_from()]]></c> in your code then this is the message you + will need to parse. If you are using <c><![CDATA[erl_rpc()]]></c> then the + tuple itself is parsed for you, and the message returned to your + program is the erlang term containing <c><![CDATA[Reply]]></c> only. Replies + to rpc requests are always ERL_SEND messages. + </p> + <note> + <p>It is the caller's responsibility to free the returned + <c><![CDATA[ETERM]]></c> structure as well as the memory pointed to by + <c><![CDATA[emsg->msg]]></c> and <c><![CDATA[emsg->to]]></c>. </p> + </note> + <p><c><![CDATA[erl_rpc()]]></c> returns the remote function's return value (or + <c><![CDATA[NULL]]></c> if it failed). <c><![CDATA[erl_rpc_to()]]></c> returns 0 on + success, and a negative number on failure. <c><![CDATA[erl_rcp_from()]]></c> + returns <c><![CDATA[ERL_MSG]]></c> when successful (with <c><![CDATA[Emsg]]></c> now + containing the reply tuple), and one of <c><![CDATA[ERL_TICK]]></c>, + <c><![CDATA[ERL_TIMEOUT]]></c> and <c><![CDATA[ERL_ERROR]]></c> otherwise. When failing, + all three functions set <c><![CDATA[erl_errno]]></c> to one of:</p> + <taglist> + <tag><c><![CDATA[ENOMEM]]></c></tag> + <item>No more memory available.</item> + <tag><c><![CDATA[EIO]]></c></tag> + <item>I/O error.</item> + <tag><c><![CDATA[ETIMEDOUT]]></c></tag> + <item>Timeout expired.</item> + <tag><c><![CDATA[EAGAIN]]></c></tag> + <item>Temporary error: Try again.</item> + </taglist> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>erl_publish(port)</nametext></name> + <fsummary>Publish a node name</fsummary> + <type> + <v>int port;</v> + </type> + <desc> + <p>These functions are used by a server process to register + with the local name server <em>epmd</em>, thereby allowing + other processes to send messages by using the registered name. + Before calling either of these functions, the process should + have called <c><![CDATA[bind()]]></c> and <c><![CDATA[listen()]]></c> on an open socket.</p> + <p><c><![CDATA[port]]></c> is the local name to register, and should be the + same as the port number that was previously bound to the socket.</p> + <p>To unregister with epmd, simply close the returned + descriptor. See also <c><![CDATA[erl_unpublish()]]></c>. + </p> + <p>On success, the functions return a descriptor connecting the + calling process to epmd. On failure, they return -1 and set + <c><![CDATA[erl_errno]]></c> to:</p> + <taglist> + <tag><c><![CDATA[EIO]]></c></tag> + <item>I/O error</item> + </taglist> + <p>Additionally, <c><![CDATA[errno]]></c> values from <c><![CDATA[socket]]></c><em>(2)</em> + and <c><![CDATA[connect]]></c><em>(2)</em> system calls may be propagated + into <c><![CDATA[erl_errno]]></c>. + </p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>erl_accept(listensock, conp)</nametext></name> + <fsummary>Accept a connection</fsummary> + <type> + <v>int listensock;</v> + <v>ErlConnect *conp;</v> + </type> + <desc> + <p>This function is used by a server process to accept a + connection from a client process.</p> + <p><c><![CDATA[listensock]]></c> is an open socket descriptor on which + <c><![CDATA[listen()]]></c> has previously been called.</p> + <p><c><![CDATA[conp]]></c> is a pointer to an <c><![CDATA[ErlConnect]]></c> struct, + described as follows:</p> + <code type="none"><![CDATA[ +typedef struct { + char ipadr[4]; + char nodename[MAXNODELEN]; +} ErlConnect; + ]]></code> + <p>On success, <c><![CDATA[conp]]></c> is filled in with the address and + node name of the connecting client and a file descriptor is + returned. On failure, <c><![CDATA[ERL_ERROR]]></c> is returned and + <c><![CDATA[erl_errno]]></c> is set to <c><![CDATA[EIO]]></c>.</p> + </desc> + </func> + <func> + <name><ret>const char *</ret><nametext>erl_thiscookie()</nametext></name> + <name><ret>const char *</ret><nametext>erl_thisnodename()</nametext></name> + <name><ret>const char *</ret><nametext>erl_thishostname()</nametext></name> + <name><ret>const char *</ret><nametext>erl_thisalivename()</nametext></name> + <name><ret>short</ret><nametext>erl_thiscreation()</nametext></name> + <fsummary>Retrieve some values</fsummary> + <desc> + <p>These functions can be used to retrieve information about + the C Node. These values are initially set with + <c><![CDATA[erl_connect_init()]]></c> or <c><![CDATA[erl_connect_xinit()]]></c>.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>erl_unpublish(alive)</nametext></name> + <fsummary>Unpublish a node name</fsummary> + <type> + <v>char *alive;</v> + </type> + <desc> + <p>This function can be called by a process to unregister a + specified node name from epmd on the localhost. This may be + useful, for example, when epmd has not detected the failure of a + node, and will not allow the name to be reused. If you use this + function to unregister your own process, be sure to also close + the descriptor that was returned by <c><![CDATA[erl_publish()]]></c>.</p> + <note> + <p>Careless use of this function may have unpredictable + results, if the registered node is in fact still running.</p> + </note> + <p><c><![CDATA[alive]]></c> is the name of the node to unregister, i.e., the + first component of the nodename, without the <c><![CDATA[@hostname]]></c>.</p> + <p>If the node was successfully unregistered from epmd, the + function returns 0. Otherwise, it returns -1 and sets + <c><![CDATA[erl_errno]]></c> is to <c><![CDATA[EIO]]></c>.</p> + </desc> + </func> + <func> + <name><ret>struct hostent</ret><nametext>*erl_gethostbyname(name)</nametext></name> + <name><ret>struct hostent</ret><nametext>*erl_gethostbyaddr(addr, length, type)</nametext></name> + <name><ret>struct hostent</ret><nametext>*erl_gethostbyname_r(name, hostp, buffer, buflen, h_errnop)</nametext></name> + <name><ret>struct hostent</ret><nametext>*erl_gethostbyaddr_r(addr, length, type, hostp, buffer, buflen, h_errnop)</nametext></name> + <fsummary>Name lookup functions</fsummary> + <type> + <v>const char *name;</v> + <v>const char *addr;</v> + <v>int length;</v> + <v>int type;</v> + <v>struct hostent *hostp;</v> + <v>char *buffer;</v> + <v>int buflen;</v> + <v>int *h_errnop;</v> + </type> + <desc> + <p>These are convenience functions for some common name lookup functions.</p> + </desc> + </func> + </funcs> + + <section> + <title>Debug Information</title> + <p>If a connection attempt fails, the following can be checked:</p> + <list type="bulleted"> + <item><c><![CDATA[erl_errno]]></c></item> + <item>that the right cookie was used</item> + <item>that <em>epmd</em> is running</item> + <item>the remote Erlang node on the other side is running the same + version of Erlang as the <c><![CDATA[erl_interface]]></c> library.</item> + </list> + </section> +</cref> + diff --git a/lib/erl_interface/doc/src/erl_error.xml b/lib/erl_interface/doc/src/erl_error.xml new file mode 100644 index 0000000000..4a3f34fac7 --- /dev/null +++ b/lib/erl_interface/doc/src/erl_error.xml @@ -0,0 +1,136 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE cref SYSTEM "cref.dtd"> + +<cref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>erl_error</title> + <prepared>Torbjörn Törnkvist</prepared> + <responsible>Torbjörn Törnkvist</responsible> + <docno></docno> + <approved>Bjarne Däcker</approved> + <checked>Torbjörn Törnkvist</checked> + <date>961014</date> + <rev>A</rev> + <file>erl_error.sgml</file> + </header> + <lib>erl_error</lib> + <libsummary>Error Print Routines</libsummary> + <description> + <p>This module contains some error printing routines taken + from <em>Advanced Programming in the UNIX Environment</em> + by W. Richard Stevens. </p> + <p>These functions are all called in the same manner as + <c><![CDATA[printf()]]></c>, i.e. with a string containing format specifiers + followed by a list of corresponding arguments. All output from + these functions is to <c><![CDATA[stderr]]></c>.</p> + </description> + <funcs> + <func> + <name><ret>void</ret><nametext>erl_err_msg(FormatStr, ... )</nametext></name> + <fsummary>Non-fatal error, and not system call error</fsummary> + <type> + <v>const char *FormatStr;</v> + </type> + <desc> + <p>The message provided by the caller is printed. This + function is simply a wrapper for <c><![CDATA[fprintf()]]></c>.</p> + </desc> + </func> + <func> + <name><ret>void</ret><nametext>erl_err_quit(FormatStr, ... )</nametext></name> + <fsummary>Fatal error, but not system call error</fsummary> + <type> + <v>const char *FormatStr;</v> + </type> + <desc> + <p>Use this function when a fatal error has occurred that + is not due to a system call. The message provided by the + caller is printed and the process terminates with an exit + value of 1. The function does not return.</p> + </desc> + </func> + <func> + <name><ret>void</ret><nametext>erl_err_ret(FormatStr, ... )</nametext></name> + <fsummary>Non-fatal system call error</fsummary> + <type> + <v>const char *FormatStr;</v> + </type> + <desc> + <p>Use this function after a failed system call. The message + provided by the caller is printed followed by a string + describing the reason for failure. </p> + </desc> + </func> + <func> + <name><ret>void</ret><nametext>erl_err_sys(FormatStr, ... )</nametext></name> + <fsummary>Fatal system call error</fsummary> + <type> + <v>const char *FormatStr;</v> + </type> + <desc> + <p>Use this function after a failed system call. The message + provided by the caller is printed followed by a string + describing the reason for failure, and the process + terminates with an exit value of 1. The function does not + return.</p> + </desc> + </func> + </funcs> + + <section> + <title>Error Reporting</title> + <p>Most functions in erl_interface report failures to the caller by + returning some otherwise meaningless value (typically <c><![CDATA[NULL]]></c> + or a negative number). As this only tells you that things did not + go well, you will have to examine the error code in + <c><![CDATA[erl_errno]]></c> if you want to find out more about the failure.</p> + </section> + <funcs> + <func> + <name><ret>volatile int</ret><nametext>erl_errno</nametext></name> + <fsummary>The variable <c><![CDATA[erl_errno]]></c>contains the erl_interface error number. You can change the value if you wish. </fsummary> + <desc> + <p><c><![CDATA[erl_errno]]></c> is initially (at program startup) zero and + is then set by many erl_interface functions on failure to a + non-zero error code to indicate what kind of error it + encountered. A successful function call might change + <c><![CDATA[erl_errno]]></c> (by calling some other function that + fails), but no function will ever set it to zero. This means + that you cannot use <c><![CDATA[erl_errno]]></c> to see <em>if</em> a + function call failed. Instead, each function reports failure + in its own way (usually by returning a negative number or + <c><![CDATA[NULL]]></c>), in which case you can examine <c><![CDATA[erl_errno]]></c> + for details.</p> + <p><c><![CDATA[erl_errno]]></c> uses the error codes defined in your + system's <c><![CDATA[<errno.h>]]></c>.</p> + <note> + <p>Actually, <c><![CDATA[erl_errno]]></c> is a "modifiable lvalue" (just + like ISO C defines <c><![CDATA[errno]]></c> to be) rather than a + variable. This means it might be implemented as a macro + (expanding to, e.g., <c><![CDATA[*_erl_errno()]]></c>). For reasons of + thread- (or task-)safety, this is exactly what we do on most + platforms.</p> + </note> + </desc> + </func> + </funcs> +</cref> + diff --git a/lib/erl_interface/doc/src/erl_eterm.xml b/lib/erl_interface/doc/src/erl_eterm.xml new file mode 100644 index 0000000000..ce14549672 --- /dev/null +++ b/lib/erl_interface/doc/src/erl_eterm.xml @@ -0,0 +1,675 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE cref SYSTEM "cref.dtd"> + +<cref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>erl_eterm</title> + <prepared>Torbjörn Törnkvist</prepared> + <responsible>Torbjörn Törnkvist</responsible> + <docno></docno> + <approved>Bjarne Däcker</approved> + <checked>Torbjörn Törnkvist</checked> + <date>980703</date> + <rev>A</rev> + <file>erl_eterm.sgml</file> + </header> + <lib>erl_eterm</lib> + <libsummary>Functions for Erlang Term Construction</libsummary> + <description> + <p>This module contains functions for creating and manipulating + Erlang terms. </p> + <p>An Erlang term is represented by a C structure of type + <c><![CDATA[ETERM]]></c>. Applications should not reference any fields in this + structure directly, because it may be changed in future releases + to provide faster and more compact term storage. Instead, + applications should us the macros and functions provided. </p> + <p>The following macros each take a single ETERM pointer as an + argument. They return a non-zero value if the test is true, and 0 + otherwise:</p> + <taglist> + <tag><c><![CDATA[ERL_IS_INTEGER(t)]]></c></tag> + <item>True if <c><![CDATA[t]]></c> is an integer.</item> + <tag><c><![CDATA[ERL_IS_UNSIGNED_INTEGER(t)]]></c></tag> + <item>True if <c><![CDATA[t]]></c> is an integer.</item> + <tag><c><![CDATA[ERL_IS_FLOAT(t)]]></c></tag> + <item>True if <c><![CDATA[t]]></c> is a floating point number.</item> + <tag><c><![CDATA[ERL_IS_ATOM(t)]]></c></tag> + <item>True if <c><![CDATA[t]]></c> is an atom.</item> + <tag><c><![CDATA[ERL_IS_PID(t)]]></c></tag> + <item>True if <c><![CDATA[t]]></c> is a Pid (process identifier).</item> + <tag><c><![CDATA[ERL_IS_PORT(t)]]></c></tag> + <item>True if <c><![CDATA[t]]></c> is a port.</item> + <tag><c><![CDATA[ERL_IS_REF(t)]]></c></tag> + <item>True if <c><![CDATA[t]]></c> is a reference.</item> + <tag><c><![CDATA[ERL_IS_TUPLE(t)]]></c></tag> + <item>True if <c><![CDATA[t]]></c> is a tuple.</item> + <tag><c><![CDATA[ERL_IS_BINARY(t)]]></c></tag> + <item>True if <c><![CDATA[t]]></c> is a binary.</item> + <tag><c><![CDATA[ERL_IS_LIST(t)]]></c></tag> + <item>True if <c><![CDATA[t]]></c> is a list with zero or more elements.</item> + <tag><c><![CDATA[ERL_IS_EMPTY_LIST(t)]]></c></tag> + <item>True if <c><![CDATA[t]]></c> is an empty list.</item> + <tag><c><![CDATA[ERL_IS_CONS(t)]]></c></tag> + <item>True if <c><![CDATA[t]]></c> is a list with at least one element.</item> + </taglist> + <p>The following macros can be used for retrieving parts of Erlang + terms. None of these do any type checking; results are undefined + if you pass an ETERM* containing the wrong type. For example, + passing a tuple to ERL_ATOM_PTR() will likely result in garbage. + </p> + <taglist> + <tag><c><![CDATA[char *ERL_ATOM_PTR(t)]]></c></tag> + <item>A string representing atom <c><![CDATA[t]]></c>. + </item> + <tag><c><![CDATA[int ERL_ATOM_SIZE(t)]]></c></tag> + <item>The length (in characters) of atom t.</item> + <tag><c><![CDATA[void *ERL_BIN_PTR(t)]]></c></tag> + <item>A pointer to the contents of <c><![CDATA[t]]></c></item> + <tag><c><![CDATA[int ERL_BIN_SIZE(t)]]></c></tag> + <item>The length (in bytes) of binary object <c><![CDATA[t]]></c>.</item> + <tag><c><![CDATA[int ERL_INT_VALUE(t)]]></c></tag> + <item>The integer of <c><![CDATA[t]]></c>.</item> + <tag><c><![CDATA[unsigned int ERL_INT_UVALUE(t)]]></c></tag> + <item>The unsigned integer value of <c><![CDATA[t]]></c>.</item> + <tag><c><![CDATA[double ERL_FLOAT_VALUE(t)]]></c></tag> + <item>The floating point value of <c><![CDATA[t]]></c>.</item> + <tag><c><![CDATA[ETERM *ERL_PID_NODE(t)]]></c></tag> + <item>The Node in pid <c><![CDATA[t]]></c>.</item> + <tag><c><![CDATA[int ERL_PID_NUMBER(t)]]></c></tag> + <item>The sequence number in pid <c><![CDATA[t]]></c>.</item> + <tag><c><![CDATA[int ERL_PID_SERIAL(t)]]></c></tag> + <item>The serial number in pid <c><![CDATA[t]]></c>.</item> + <tag><c><![CDATA[int ERL_PID_CREATION(t)]]></c></tag> + <item>The creation number in pid <c><![CDATA[t]]></c>.</item> + <tag><c><![CDATA[int ERL_PORT_NUMBER(t)]]></c></tag> + <item>The sequence number in port <c><![CDATA[t]]></c>.</item> + <tag><c><![CDATA[int ERL_PORT_CREATION(t)]]></c></tag> + <item>The creation number in port <c><![CDATA[t]]></c>.</item> + <tag><c><![CDATA[ETERM *ERL_PORT_NODE(t)]]></c></tag> + <item>The node in port <c><![CDATA[t]]></c>.</item> + <tag><c><![CDATA[int ERL_REF_NUMBER(t)]]></c></tag> + <item>The first part of the reference number in ref <c><![CDATA[t]]></c>. Use + only for compatibility.</item> + <tag><c><![CDATA[int ERL_REF_NUMBERS(t)]]></c></tag> + <item>Pointer to the array of reference numbers in ref <c><![CDATA[t]]></c>.</item> + <tag><c><![CDATA[int ERL_REF_LEN(t)]]></c></tag> + <item>The number of used reference numbers in ref <c><![CDATA[t]]></c>.</item> + <tag><c><![CDATA[int ERL_REF_CREATION(t)]]></c></tag> + <item>The creation number in ref <c><![CDATA[t]]></c>.</item> + <tag><c><![CDATA[int ERL_TUPLE_SIZE(t)]]></c></tag> + <item>The number of elements in tuple <c><![CDATA[t]]></c>.</item> + <tag><c><![CDATA[ETERM *ERL_CONS_HEAD(t)]]></c></tag> + <item>The head element of list <c><![CDATA[t]]></c>.</item> + <tag><c><![CDATA[ETERM *ERL_CONS_TAIL(t)]]></c></tag> + <item>A List representing the tail elements of list <c><![CDATA[t]]></c>.</item> + </taglist> + </description> + <funcs> + <func> + <name><ret>ETERM *</ret><nametext>erl_cons(head, tail)</nametext></name> + <fsummary>Prepends a term to the head of a list.</fsummary> + <type> + <v>ETERM *head;</v> + <v>ETERM *tail;</v> + </type> + <desc> + <p>This function concatenates two Erlang terms, prepending + <c><![CDATA[head]]></c> onto <c><![CDATA[tail]]></c> and thereby creating a <c><![CDATA[cons]]></c> cell. + To make a proper list, <c><![CDATA[tail]]></c> should always be a + list or an empty list. Note that NULL is not a valid list.</p> + <p><c><![CDATA[head]]></c> is the new term to be added.</p> + <p><c><![CDATA[tail]]></c> is the existing list to which <c><![CDATA[head]]></c> will + be concatenated.</p> + <p>The function returns a new list.</p> + <p><c><![CDATA[ERL_CONS_HEAD(list)]]></c> and <c><![CDATA[ERL_CONS_TAIL(list)]]></c> + can be used to retrieve the head and tail components + from the list. <c><![CDATA[erl_hd(list)]]></c> and <c><![CDATA[erl_tl(list)]]></c> will do + the same thing, but check that the argument really is a list.</p> + <p>For example:</p> + <code type="none"><![CDATA[ +ETERM *list,*anAtom,*anInt; +anAtom = erl_mk_atom("madonna"); +anInt = erl_mk_int(21); +list = erl_mk_empty_list(); +list = erl_cons(anAtom, list); +list = erl_cons(anInt, list); + ... /* do some work */ +erl_free_compound(list); + ]]></code> + </desc> + </func> + <func> + <name><ret>ETERM *</ret><nametext>erl_copy_term(term)</nametext></name> + <fsummary>Creates a copy of an Erlang term</fsummary> + <type> + <v>ETERM *term;</v> + </type> + <desc> + <p>This function creates and returns a copy of the Erlang term + <c><![CDATA[term]]></c>.</p> + </desc> + </func> + <func> + <name><ret>ETERM *</ret><nametext>erl_element(position, tuple)</nametext></name> + <fsummary>Extracts an element from an Erlang tuple</fsummary> + <type> + <v>int position;</v> + <v>ETERM *tuple;</v> + </type> + <desc> + <p>This function extracts a specified element from an Erlang + tuple. </p> + <p><c><![CDATA[position]]></c> specifies which element to retrieve from + <c><![CDATA[tuple]]></c>. The elements are numbered starting from 1.</p> + <p><c><![CDATA[tuple]]></c> is an Erlang term containing at least + <c><![CDATA[position]]></c> elements.</p> + <p>The function returns a new Erlang term corresponding to the + requested element, or NULL if <c><![CDATA[position]]></c> was greater than + the arity of <c><![CDATA[tuple]]></c>.</p> + </desc> + </func> + <func> + <name><ret>void</ret><nametext>erl_init(NULL, 0)</nametext></name> + <fsummary>Initialization routine</fsummary> + <type> + <v>void *NULL;</v> + <v>int 0;</v> + </type> + <desc> + <marker id="erl_init"></marker> + <p>This function must be called before any of the others in + the <c><![CDATA[erl_interface]]></c> library in order to initialize the + library functions. The arguments must be specified as + <c><![CDATA[erl_init(NULL,0)]]></c>.</p> + </desc> + </func> + <func> + <name><ret>ETERM *</ret><nametext>erl_hd(list)</nametext></name> + <fsummary>Extracts the first element from a list</fsummary> + <type> + <v>ETERM *list;</v> + </type> + <desc> + <p>Extracts the first element from a list.</p> + <p><c><![CDATA[list]]></c> is an Erlang term containing a list.</p> + <p>The function returns an Erlang term corresponding to the + head element in the list, or a NULL pointer if <c><![CDATA[list]]></c> was + not a list.</p> + </desc> + </func> + <func> + <name><ret>ETERM *</ret><nametext>erl_iolist_to_binary(term)</nametext></name> + <fsummary>Converts an IO list to a binary</fsummary> + <type> + <v>ETERM *list;</v> + </type> + <desc> + <p>This function converts an IO list to a binary term.</p> + <p><c><![CDATA[list]]></c> is an Erlang term containing a list.</p> + <p>This function an Erlang binary term, or NULL if <c><![CDATA[list]]></c> + was not an IO list. </p> + <p>Informally, an IO list is a deep list of characters and + binaries which can be sent to an Erlang port. In BNF, an IO + list is formally defined as follows: </p> + <code type="none"><![CDATA[ +iolist ::= [] + | Binary + | [iohead | iolist] + ; +iohead ::= Binary + | Byte (integer in the range [0..255]) + | iolist + ; + ]]></code> + </desc> + </func> + <func> + <name><ret>char *</ret><nametext>erl_iolist_to_string(list)</nametext></name> + <fsummary>Converts an IO list to a zero terminated string</fsummary> + <type> + <v>ETERM *list;</v> + </type> + <desc> + <p>This function converts an IO list to a '\\0' terminated C + string. </p> + <p><c><![CDATA[list]]></c> is an Erlang term containing an IO list. The IO + list must not contain the integer 0, since C strings may not + contain this value except as a terminating marker.</p> + <p>This function returns a pointer to a dynamically allocated + buffer containing a string. If <c><![CDATA[list]]></c> is not an IO list, + or if <c><![CDATA[list]]></c> contains the integer 0, NULL is returned. It + is the caller's responsibility free the allocated buffer + with <c><![CDATA[erl_free()]]></c>. </p> + <p>Refer to <c><![CDATA[erl_iolist_to_binary()]]></c> for the definition of an + IO list. </p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>erl_iolist_length(list)</nametext></name> + <fsummary>Return the length of an IO list</fsummary> + <type> + <v>ETERM *list;</v> + </type> + <desc> + <p>Returns the length of an IO list. + </p> + <p><c><![CDATA[list]]></c> is an Erlang term containing an IO list. </p> + <p>The function returns the length of <c><![CDATA[list]]></c>, or -1 if + <c><![CDATA[list]]></c> is not an IO list.</p> + <p>Refer to <c><![CDATA[erl_iolist_to_binary()]]></c> for the definition of + an IO list. </p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>erl_length(list)</nametext></name> + <fsummary>Determines the length of a list</fsummary> + <type> + <v>ETERM *list;</v> + </type> + <desc> + <p>Determines the length of a proper list.</p> + <p><c><![CDATA[list]]></c> is an Erlang term containing proper list. In a + proper list, all tails except the last point to another list + cell, and the last tail points to an empty list.</p> + <p>Returns -1 if <c><![CDATA[list]]></c> is not a proper list.</p> + </desc> + </func> + <func> + <name><ret>ETERM *</ret><nametext>erl_mk_atom(string)</nametext></name> + <fsummary>Creates an atom</fsummary> + <type> + <v>char *string;</v> + </type> + <desc> + <p>Creates an atom.</p> + <p><c><![CDATA[string]]></c> is the sequence of characters that will be + used to create the atom.</p> + <p>Returns an Erlang term containing an atom. Note that it is + the callers responsibility to make sure that <c><![CDATA[string]]></c> + contains a valid name for an atom.</p> + <p><c><![CDATA[ERL_ATOM_PTR(atom)]]></c> can be used to retrieve the + atom name (as a string). Note that the string is not + 0-terminated in the atom. <c><![CDATA[ERL_ATOM_SIZE(atom)]]></c>returns + the length of the atom name.</p> + </desc> + </func> + <func> + <name><ret>ETERM *</ret><nametext>erl_mk_binary(bptr, size)</nametext></name> + <fsummary>Creates a binary object</fsummary> + <type> + <v>char *bptr;</v> + <v>int size;</v> + </type> + <desc> + <p>This function produces an Erlang binary object from a + buffer containing a sequence of bytes.</p> + <p><c><![CDATA[bptr]]></c> is a pointer to a buffer containing data to be converted.</p> + <p><c><![CDATA[size]]></c> indicates the length of <c><![CDATA[bptr]]></c>.</p> + <p>The function returns an Erlang binary object.</p> + <p><c><![CDATA[ERL_BIN_PTR(bin)]]></c> retrieves a pointer to + the binary data. <c><![CDATA[ERL_BIN_SIZE(bin)]]></c> retrieves the + size. </p> + </desc> + </func> + <func> + <name><ret>ETERM *</ret><nametext>erl_mk_empty_list()</nametext></name> + <fsummary>Creates an empty Erlang list</fsummary> + <desc> + <p>This function creates and returns an empty Erlang list. + Note that NULL is not used to represent an empty list; + Use this function instead.</p> + </desc> + </func> + <func> + <name><ret>ETERM *</ret><nametext>erl_mk_estring(string, len)</nametext></name> + <fsummary>Creates an Erlang string</fsummary> + <type> + <v>char *string;</v> + <v>int len;</v> + </type> + <desc> + <p>This function creates a list from a sequence of bytes.</p> + <p><c><![CDATA[string]]></c> is a buffer containing a sequence of + bytes. The buffer does not need to be zero-terminated.</p> + <p><c><![CDATA[len]]></c> is the length of <c><![CDATA[string]]></c>.</p> + <p>The function returns an Erlang list object corresponding to + the character sequence in <c><![CDATA[string]]></c>.</p> + </desc> + </func> + <func> + <name><ret>ETERM *</ret><nametext>erl_mk_float(f)</nametext></name> + <fsummary>Creates an Erlang float</fsummary> + <type> + <v>double f;</v> + </type> + <desc> + <p>Creates an Erlang float.</p> + <p><c><![CDATA[f]]></c> is a value to be converted to an Erlang float.</p> + <p></p> + <p>The function returns an Erlang float object with the value + specified in <c><![CDATA[f]]></c>.</p> + <p><c><![CDATA[ERL_FLOAT_VALUE(t)]]></c> can be used to retrieve the + value from an Erlang float.</p> + </desc> + </func> + <func> + <name><ret>ETERM *</ret><nametext>erl_mk_int(n)</nametext></name> + <fsummary>Creates an Erlang integer</fsummary> + <type> + <v>int n;</v> + </type> + <desc> + <p>Creates an Erlang integer.</p> + <p><c><![CDATA[n]]></c> is a value to be converted to an Erlang integer.</p> + <p></p> + <p>The function returns an Erlang integer object with the + value specified in <c><![CDATA[n]]></c>.</p> + <p><c><![CDATA[ERL_INT_VALUE(t)]]></c> can be used to retrieve the value + value from an Erlang integer.</p> + </desc> + </func> + <func> + <name><ret>ETERM *</ret><nametext>erl_mk_list(array, arrsize)</nametext></name> + <fsummary>Creates a list from an array</fsummary> + <type> + <v>ETERM **array;</v> + <v>int arrsize;</v> + </type> + <desc> + <p>Creates an Erlang list from an array of Erlang terms, such + that each element in the list corresponds to one element in + the array. </p> + <p><c><![CDATA[array]]></c> is an array of Erlang terms.</p> + <p><c><![CDATA[arrsize]]></c> is the number of elements in <c><![CDATA[array]]></c>.</p> + <p>The function creates an Erlang list object, whose length + <c><![CDATA[arrsize]]></c> and whose elements are taken from the terms in + <c><![CDATA[array]]></c>.</p> + </desc> + </func> + <func> + <name><ret>ETERM *</ret><nametext>erl_mk_pid(node, number, serial, creation)</nametext></name> + <fsummary>Creates a process identifier</fsummary> + <type> + <v>const char *node;</v> + <v>unsigned int number;</v> + <v>unsigned int serial;</v> + <v>unsigned int creation;</v> + </type> + <desc> + <p>This function creates an Erlang process identifier. The + resulting pid can be used by Erlang processes wishing to + communicate with the C node.</p> + <p><c><![CDATA[node]]></c> is the name of the C node.</p> + <p><c><![CDATA[number]]></c>, <c><![CDATA[serial]]></c> and <c><![CDATA[creation]]></c> are + arbitrary numbers. Note though, that these are limited in + precision, so only the low 15, 3 and 2 bits of these numbers + are actually used.</p> + <p>The function returns an Erlang pid object.</p> + <p><c><![CDATA[ERL_PID_NODE(pid)]]></c>, <c><![CDATA[ERL_PID_NUMBER(pid)]]></c>, + <c><![CDATA[ERL_PID_SERIAL(pid)]]></c> and <c><![CDATA[ERL_PID_CREATION(pid)]]></c> + can be used to retrieve the four values used to create the pid.</p> + </desc> + </func> + <func> + <name><ret>ETERM *</ret><nametext>erl_mk_port(node, number, creation)</nametext></name> + <fsummary>Creates a port identifier</fsummary> + <type> + <v>const char *node;</v> + <v>unsigned int number;</v> + <v>unsigned int creation;</v> + </type> + <desc> + <p>This function creates an Erlang port identifier. </p> + <p><c><![CDATA[node]]></c> is the name of the C node.</p> + <p><c><![CDATA[number]]></c> and <c><![CDATA[creation]]></c> are arbitrary numbers. + Note though, that these are limited in + precision, so only the low 18 and 2 bits of these numbers + are actually used.</p> + <p>The function returns an Erlang port object.</p> + <p><c><![CDATA[ERL_PORT_NODE(port)]]></c>, <c><![CDATA[ERL_PORT_NUMBER(port)]]></c> + and <c><![CDATA[ERL_PORT_CREATION]]></c> can be used to retrieve the three + values used to create the port. </p> + </desc> + </func> + <func> + <name><ret>ETERM *</ret><nametext>erl_mk_ref(node, number, creation)</nametext></name> + <fsummary>Creates an old Erlang reference</fsummary> + <type> + <v>const char *node;</v> + <v>unsigned int number;</v> + <v>unsigned int creation;</v> + </type> + <desc> + <p>This function creates an old Erlang reference, with + only 18 bits - use <c><![CDATA[erl_mk_long_ref]]></c> instead.</p> + <p><c><![CDATA[node]]></c> is the name of the C node.</p> + <p><c><![CDATA[number]]></c> should be chosen uniquely for each reference + created for a given C node.</p> + <p><c><![CDATA[creation]]></c> is an arbitrary number.</p> + <p>Note that <c><![CDATA[number]]></c> and <c><![CDATA[creation]]></c> are limited in + precision, so only the low 18 and 2 bits of these numbers + are actually used. + </p> + <p>The function returns an Erlang reference object.</p> + <p><c><![CDATA[ERL_REF_NODE(ref)]]></c>, <c><![CDATA[ERL_REF_NUMBER(ref)]]></c>, and + <c><![CDATA[ERL_REF_CREATION(ref)]]></c> to retrieve the three values used + to create the reference. </p> + </desc> + </func> + <func> + <name><ret>ETERM *</ret><nametext>erl_mk_long_ref(node, n1, n2, n3, creation)</nametext></name> + <fsummary>Creates an Erlang reference</fsummary> + <type> + <v>const char *node;</v> + <v>unsigned int n1, n2, n3;</v> + <v>unsigned int creation;</v> + </type> + <desc> + <p>This function creates an Erlang reference, with 82 bits.</p> + <p><c><![CDATA[node]]></c> is the name of the C node.</p> + <p><c><![CDATA[n1]]></c>, <c><![CDATA[n2]]></c> and <c><![CDATA[n3]]></c> can be seen as one big number + <c><![CDATA[n1*2^64+n2*2^32+n3]]></c> which should be chosen uniquely for + each reference + created for a given C node.</p> + <p><c><![CDATA[creation]]></c> is an arbitrary number.</p> + <p>Note that <c><![CDATA[n3]]></c> and <c><![CDATA[creation]]></c> are limited in + precision, so only the low 18 and 2 bits of these numbers + are actually used. + </p> + <p>The function returns an Erlang reference object.</p> + <p><c><![CDATA[ERL_REF_NODE(ref)]]></c>, <c><![CDATA[ERL_REF_NUMBERS(ref)]]></c>, + <c><![CDATA[ERL_REF_LEN(ref)]]></c> and + <c><![CDATA[ERL_REF_CREATION(ref)]]></c> to retrieve the values used + to create the reference. </p> + </desc> + </func> + <func> + <name><ret>ETERM *</ret><nametext>erl_mk_string(string)</nametext></name> + <fsummary>Creates a string</fsummary> + <type> + <v>char *string;</v> + </type> + <desc> + <p>This function creates a list from a zero terminated string.</p> + <p><c><![CDATA[string]]></c> is the zero-terminated sequence of characters + (i.e. a C string) from which the list will be created.</p> + <p>The function returns an Erlang list.</p> + </desc> + </func> + <func> + <name><ret>ETERM *</ret><nametext>erl_mk_tuple(array, arrsize)</nametext></name> + <fsummary>Creates an Erlang tuple from an array</fsummary> + <type> + <v>ETERM **array;</v> + <v>int arrsize;</v> + </type> + <desc> + <p>Creates an Erlang tuple from an array of Erlang terms.</p> + <p><c><![CDATA[array]]></c> is an array of Erlang terms.</p> + <p><c><![CDATA[arrsize]]></c> is the number of elements in <c><![CDATA[array]]></c>.</p> + <p>The function creates an Erlang tuple, whose arity is + <c><![CDATA[size]]></c> and whose elements are taken from the terms in + <c><![CDATA[array]]></c>.</p> + <p>To retrieve the size of a tuple, either use the + <c><![CDATA[erl_size]]></c> function (which checks the type of the checked + term and works for a binary as well as for a tuple), or the + <c><![CDATA[ERL_TUPLE_SIZE(tuple)]]></c> returns the arity of a tuple. + <c><![CDATA[erl_size()]]></c> will do the same thing, but it checks that + the argument really is a tuple. + <c><![CDATA[erl_element(index,tuple)]]></c> returns the element + corresponding to a given position in the tuple. </p> + </desc> + </func> + <func> + <name><ret>ETERM *</ret><nametext>erl_mk_uint(n)</nametext></name> + <fsummary>Creates an unsigned integer</fsummary> + <type> + <v>unsigned int n;</v> + </type> + <desc> + <p>Creates an Erlang unsigned integer.</p> + <p><c><![CDATA[n]]></c> is a value to be converted to an Erlang + unsigned integer.</p> + <p></p> + <p>The function returns an Erlang unsigned integer object with + the value specified in <c><![CDATA[n]]></c>.</p> + <p><c><![CDATA[ERL_INT_UVALUE(t)]]></c> can be used to retrieve the + value from an Erlang unsigned integer.</p> + </desc> + </func> + <func> + <name><ret>ETERM *</ret><nametext>erl_mk_var(name)</nametext></name> + <fsummary>Creates an Erlang variable</fsummary> + <type> + <v>char *name;</v> + </type> + <desc> + <p>This function creates an unbound Erlang variable. The + variable can later be bound through pattern matching or assignment.</p> + <p><c><![CDATA[name]]></c> specifies a name for the variable.</p> + <p>The function returns an Erlang variable object with the + name <c><![CDATA[name]]></c>. </p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>erl_print_term(stream, term)</nametext></name> + <fsummary>Prints an Erlang term</fsummary> + <type> + <v>FILE *stream;</v> + <v>ETERM *term;</v> + </type> + <desc> + <p>This function prints the specified Erlang term to the given + output stream.</p> + <p><c><![CDATA[stream]]></c> indicates where the function should send its + output.</p> + <p><c><![CDATA[term]]></c> is the Erlang term to print.</p> + <p>The function returns the number of characters written, or a + negative value if there was an error.</p> + </desc> + </func> + <func> + <name><ret>void</ret><nametext>erl_set_compat_rel(release_number)</nametext></name> + <fsummary>Set the erl_interface library in compatibility mode</fsummary> + <type> + <v>unsigned release_number;</v> + </type> + <desc> + <marker id="erl_set_compat_rel"></marker> + <p>By default, the <c><![CDATA[erl_interface]]></c> library is only guaranteed + to be compatible with other Erlang/OTP components from the same + release as the <c><![CDATA[erl_interface]]></c> library itself. For example, + <c><![CDATA[erl_interface]]></c> from the OTP R10 release is not compatible + with an Erlang emulator from the OTP R9 release by default.</p> + <p>A call to <c><![CDATA[erl_set_compat_rel(release_number)]]></c> sets the + <c><![CDATA[erl_interface]]></c> library in compatibility mode of release + <c><![CDATA[release_number]]></c>. Valid range of <c><![CDATA[release_number]]></c> + is [7, current release]. This makes it possible to + communicate with Erlang/OTP components from earlier releases.</p> + <note> + <p>If this function is called, it may only be called once + directly after the call to the + <seealso marker="#erl_init">erl_init()</seealso> function.</p> + </note> + <warning> + <p>You may run into trouble if this feature is used + carelessly. Always make sure that all communicating + components are either from the same Erlang/OTP release, or + from release X and release Y where all components + from release Y are in compatibility mode of release X.</p> + </warning> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>erl_size(term)</nametext></name> + <fsummary>Return the arity of a tuple or binary</fsummary> + <type> + <v>ETERM *term;</v> + </type> + <desc> + <p>Returns the arity of an Erlang tuple, or the + number of bytes in an Erlang binary object. </p> + <p><c><![CDATA[term]]></c> is an Erlang tuple or an Erlang binary object.</p> + <p>The function returns the size of <c><![CDATA[term]]></c> as described + above, or -1 if <c><![CDATA[term]]></c> is not one of the two supported + types. </p> + </desc> + </func> + <func> + <name><ret>ETERM *</ret><nametext>erl_tl(list)</nametext></name> + <fsummary>Extracts the tail from a list</fsummary> + <type> + <v>ETERM *list;</v> + </type> + <desc> + <p>Extracts the tail from a list.</p> + <p><c><![CDATA[list]]></c> is an Erlang term containing a list.</p> + <p>The function returns an Erlang list corresponding to the + original list minus the first element, or NULL pointer if + <c><![CDATA[list]]></c> was not a list.</p> + </desc> + </func> + <func> + <name><ret>ETERM *</ret><nametext>erl_var_content(term, name)</nametext></name> + <fsummary>Extracts the content of a variable</fsummary> + <type> + <v>ETERM *term;</v> + <v>char *name;</v> + </type> + <desc> + <p>This function returns the contents of the specified + variable in an Erlang term. + </p> + <p><c><![CDATA[term]]></c> is an Erlang term. In order for this function + to succeed, <c><![CDATA[term]]></c> must be an Erlang variable with the + specified name, or it must be an Erlang list or tuple + containing a variable with the specified name. Other Erlang + types cannot contain variables.</p> + <p><c><![CDATA[name]]></c> is the name of an Erlang variable.</p> + <p>Returns the Erlang object corresponding to the value of + <c><![CDATA[name]]></c> in <c><![CDATA[term]]></c>. If no variable with the name + <c><![CDATA[name]]></c> was found in <c><![CDATA[term]]></c>, or if <c><![CDATA[term]]></c> is + not a valid Erlang term, NULL is returned.</p> + </desc> + </func> + </funcs> +</cref> + diff --git a/lib/erl_interface/doc/src/erl_format.xml b/lib/erl_interface/doc/src/erl_format.xml new file mode 100644 index 0000000000..5699485845 --- /dev/null +++ b/lib/erl_interface/doc/src/erl_format.xml @@ -0,0 +1,141 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE cref SYSTEM "cref.dtd"> + +<cref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>erl_format</title> + <prepared>Torbjörn Törnkvist</prepared> + <responsible>Torbjörn Törnkvist</responsible> + <docno></docno> + <approved>Bjarne Däcker</approved> + <checked>Torbjörn Törnkvist</checked> + <date>961016</date> + <rev>A</rev> + <file>erl_format.sgml</file> + </header> + <lib>erl_format</lib> + <libsummary>Create and Match Erlang Terms</libsummary> + <description> + <p>This module contains two routines - one general function for + creating Erlang terms and one for pattern matching Erlang terms.</p> + </description> + <funcs> + <func> + <name><ret>ETERM *</ret><nametext>erl_format(FormatStr, ... )</nametext></name> + <fsummary>Creates an Erlang term</fsummary> + <type> + <v>char *FormatStr;</v> + </type> + <desc> + <p>This is a general function for creating Erlang terms using + a format specifier and a corresponding set of arguments, much + in the way <c><![CDATA[printf()]]></c> works.</p> + <p><c><![CDATA[FormatStr]]></c> is a format specification string. The set + of valid format specifiers is as follows:</p> + <list type="bulleted"> + <item> + <p>~i - Integer</p> + </item> + <item> + <p>~f - Floating point</p> + </item> + <item> + <p>~a - Atom</p> + </item> + <item> + <p>~s - String</p> + </item> + <item> + <p>~w - Arbitrary Erlang term</p> + </item> + </list> + <p>For each format specifier that appears in <c><![CDATA[FormatStr]]></c>, + there must be a corresponding argument following + <c><![CDATA[FormatStr]]></c>. An Erlang term is built according to the + <c><![CDATA[FormatStr]]></c> with values and Erlang terms substituted from + the corresponding arguments and according to the individual + format specifiers. For example:</p> + <code type="none"><![CDATA[ +erl_format("[{name,~a},{age,~i},{data,~w}]", + "madonna", + 21, + erl_format("[{adr,~s,~i}]","E-street",42)); + ]]></code> + <p>This will create an <c><![CDATA[(ETERM *)]]></c> structure corresponding + to the Erlang term: + <c><![CDATA[[{name,madonna},{age,21},{data,[{adr,"E-street",42}]}]]]></c></p> + <p>The function returns an Erlang term, or NULL if + <c><![CDATA[FormatStr]]></c> does not describe a valid Erlang term.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>erl_match(Pattern, Term)</nametext></name> + <fsummary>Performs pattern matching</fsummary> + <type> + <v>ETERM *Pattern,*Term;</v> + </type> + <desc> + <p>This function is used to perform pattern matching similar + to that done in Erlang. Refer to an Erlang manual for matching + rules and more examples.</p> + <p><c><![CDATA[Pattern]]></c> is an Erlang term, possibly containing unbound + variables. </p> + <p><c><![CDATA[Term]]></c> is an Erlang term that we wish to match against + <c><![CDATA[Pattern]]></c>.</p> + <p><c><![CDATA[Term]]></c> and <c><![CDATA[Pattern]]></c> are compared, and any + unbound variables in <c><![CDATA[Pattern]]></c> are bound to corresponding + values in <c><![CDATA[Term]]></c>. </p> + <p>If <c><![CDATA[Term]]></c> and <c><![CDATA[Pattern]]></c> can be matched, the + function returns a non-zero value and binds any unbound + variables in <c><![CDATA[Pattern]]></c>. If <c><![CDATA[Term]]></c><c><![CDATA[Pattern]]></c> do + not match, the function returns 0. For example:</p> + <code type="none"><![CDATA[ +ETERM *term, *pattern, *pattern2; +term1 = erl_format("{14,21}"); +term2 = erl_format("{19,19}"); +pattern1 = erl_format("{A,B}"); +pattern2 = erl_format("{F,F}"); +if (erl_match(pattern1, term1)) { + /* match succeeds: + * A gets bound to 14, + * B gets bound to 21 + */ + ... +} +if (erl_match(pattern2, term1)) { + /* match fails because F cannot be + * bound to two separate values, 14 and 21 + */ + ... +} +if (erl_match(pattern2, term2)) { + /* match succeeds and F gets bound to 19 */ + ... +} + ]]></code> + <p><c><![CDATA[erl_var_content()]]></c> can be used to retrieve the + content of any variables bound as a result of a call to + <c><![CDATA[erl_match()]]></c>.</p> + </desc> + </func> + </funcs> +</cref> + diff --git a/lib/erl_interface/doc/src/erl_global.xml b/lib/erl_interface/doc/src/erl_global.xml new file mode 100644 index 0000000000..8f9a354b4f --- /dev/null +++ b/lib/erl_interface/doc/src/erl_global.xml @@ -0,0 +1,141 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE cref SYSTEM "cref.dtd"> + +<cref> + <header> + <copyright> + <year>1998</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>erl_global</title> + <prepared>Gordon Beaton</prepared> + <responsible>Gordon Beaton</responsible> + <docno></docno> + <approved>Gordon Beaton</approved> + <checked>Gordon Beaton</checked> + <date>980703</date> + <rev>A</rev> + <file>erl_global.sgml</file> + </header> + <lib>erl_global</lib> + <libsummary>Access globally registered names</libsummary> + <description> + <p>This module provides support for registering, looking + up and unregistering names in the Erlang Global module. For more + information, see the description of Global in the reference manual.</p> + <p>Note that the functions below perform an RPC using an open file + descriptor provided by the caller. This file descriptor must + not be used for other traffic during the global operation or the + function may receive unexpected data and fail.</p> + </description> + <funcs> + <func> + <name><ret>char **</ret><nametext>erl_global_names(fd,count)</nametext></name> + <fsummary>Obtain list of Global names</fsummary> + <type> + <v>int fd;</v> + <v>int *count;</v> + </type> + <desc> + <p>Retrieve a list of all known global names. + </p> + <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection. + </p> + <p><c><![CDATA[count]]></c> is the address of an integer, or NULL. If + <c><![CDATA[count]]></c> is not NULL, it will be set by the function to + the number of names found. + </p> + <p>On success, the function returns an array of strings, each + containing a single registered name, and sets <c><![CDATA[count]]></c> to + the number of names found. The array is terminated + by a single NULL pointer. On failure, the function returns + NULL and <c><![CDATA[count]]></c> is not modified. + </p> + <note> + <p>It is the caller's responsibility to free the array + afterwards. It has been allocated by the function with a + single call to <c><![CDATA[malloc()]]></c>, so a single <c><![CDATA[free()]]></c> is + all that is necessary.</p> + </note> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>erl_global_register(fd,name,pid)</nametext></name> + <fsummary>Register a name in Global</fsummary> + <type> + <v>int fd;</v> + <v>const char *name;</v> + <v>ETERM *pid;</v> + </type> + <desc> + <p>This function registers a name in Global. + </p> + <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection. + </p> + <p><c><![CDATA[name]]></c> is the name to register in Global. + </p> + <p><c><![CDATA[pid]]></c> is the pid that should be associated with + <c><![CDATA[name]]></c>. This is the value that Global will return when + processes request the location of <c><![CDATA[name]]></c>. + </p> + <p>The function returns 0 on success, or -1 on failure.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>erl_global_unregister(fd,name)</nametext></name> + <fsummary>Unregister a name in Global</fsummary> + <type> + <v>int fd;</v> + <v>const char *name;</v> + </type> + <desc> + <p>This function unregisters a name from Global. + </p> + <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection. + </p> + <p><c><![CDATA[name]]></c> is the name to unregister from Global. + </p> + <p>The function returns 0 on success, or -1 on failure.</p> + </desc> + </func> + <func> + <name><ret>ETERM *</ret><nametext>erl_global_whereis(fd,name,node)</nametext></name> + <fsummary>Look up a name in global</fsummary> + <type> + <v>int fd;</v> + <v>const char *name;</v> + <v>char *node;</v> + </type> + <desc> + <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection. + </p> + <p><c><![CDATA[name]]></c> is the name that is to be looked up in Global. + </p> + <p>If <c><![CDATA[node]]></c> is not NULL, it is a pointer to a buffer + where the function can fill in the name of the node where + <c><![CDATA[name]]></c> is found. <c><![CDATA[node]]></c> can be passed directly to + <c><![CDATA[erl_connect()]]></c> if necessary. + </p> + <p>On success, the function returns an Erlang Pid containing the address + of the given name, and node will be initialized to + the nodename where <c><![CDATA[name]]></c> is found. On failure NULL will be + returned and <c><![CDATA[node]]></c> will not be modified.</p> + </desc> + </func> + </funcs> +</cref> + diff --git a/lib/erl_interface/doc/src/erl_interface.xml b/lib/erl_interface/doc/src/erl_interface.xml new file mode 100644 index 0000000000..850a4127f4 --- /dev/null +++ b/lib/erl_interface/doc/src/erl_interface.xml @@ -0,0 +1,625 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>The Erl_Interface Library</title> + <prepared>Torbjörn Törnkvist</prepared> + <responsible>Torbjörn Törnkvist</responsible> + <docno></docno> + <approved>Bjarne Däcker</approved> + <checked>K.Lundin</checked> + <date>990113</date> + <rev>A</rev> + <file>erl_interface.sgml</file> + </header> + <p>The Erl_Interface library contains functions. which help you + integrate programs written in C and Erlang. The functions in + Erl_Interface support the following:</p> + <list type="bulleted"> + <item>manipulation of data represented as Erlang data types</item> + <item>conversion of data between C and Erlang formats</item> + <item>encoding and decoding of Erlang data types for transmission or storage</item> + <item>communication between C nodes and Erlang processes</item> + <item>backup and restore of C node state to and from Mnesia</item> + </list> + <p>In the following sections, these topics are described:</p> + <list type="bulleted"> + <item>compiling your code for use with Erl_Interface</item> + <item>initializing Erl_Interface</item> + <item>encoding, decoding, and sending Erlang terms</item> + <item>building terms and patterns</item> + <item>pattern matching</item> + <item>connecting to a distributed Erlang node</item> + <item>using EPMD</item> + <item>sending and receiving Erlang messages</item> + <item>remote procedure calls</item> + <item>global names</item> + <item>the registry</item> + </list> + + <section> + <title>Compiling and Linking Your Code</title> + <p>In order to use any of the Erl_Interface functions, include the + following lines in your code:</p> + <code type="none"><![CDATA[ +#include "erl_interface.h" +#include "ei.h" ]]></code> + <p>Determine where the top directory of your OTP installation is. You + can find this out by starting Erlang and entering the following + command at the Eshell prompt:</p> + <code type="none"><![CDATA[ +Eshell V4.7.4 (abort with ^G) +1> code:root_dir(). +/usr/local/otp ]]></code> + <p>To compile your code, make sure that your C compiler knows where + to find <c><![CDATA[erl_interface.h]]></c> by specifying an appropriate <c><![CDATA[-I]]></c> + argument on the command line, or by adding it to the <c><![CDATA[CFLAGS]]></c> + definition in your <c><![CDATA[Makefile]]></c>. The correct value for this path is + <c><![CDATA[$OTPROOT/lib/erl_interface]]></c><em>Vsn</em><c><![CDATA[/include]]></c>, where <c><![CDATA[$OTPROOT]]></c> is the path + reported by <c><![CDATA[code:root_dir/0]]></c> in the above example, and <em>Vsn</em> is + the version of the Erl_interface application, for example + <c><![CDATA[erl_interface-3.2.3]]></c></p> + <code type="none"><![CDATA[ +$ cc -c -I/usr/local/otp/lib/erl_interface-3.2.3/include myprog.c ]]></code> + <p>When linking, you will need to specify the path to + <c><![CDATA[liberl_interface.a]]></c> and <c><![CDATA[libei.a]]></c> with + <c><![CDATA[-L$OTPROOT/lib/erl_interface-3.2.3/lib]]></c>, and you will need to specify the + name of the libraries with <c><![CDATA[-lerl_interface -lei]]></c>. You can do + this on the command line or by adding the flags to the <c><![CDATA[LDFLAGS]]></c> + definition in your <c><![CDATA[Makefile]]></c>.</p> + <code type="none"><![CDATA[ +$ ld -L/usr/local/otp/lib/erl_interface-3.2.3/ + lib myprog.o -lerl_interface -lei -o myprog ]]></code> + <p>Also, on some systems it may be necessary to link with some + additional libraries (e.g. <c><![CDATA[libnsl.a]]></c> and <c><![CDATA[libsocket.a]]></c> on + Solaris, or <c><![CDATA[wsock32.lib]]></c> on Windows) in order to use the + communication facilities of Erl_Interface.</p> + <p>If you are using Erl_Interface functions in a threaded + application based on POSIX threads or Solaris threads, then + Erl_Interface needs access to some of the synchronization + facilities in your threads package, and you will need to specify + additional compiler flags in order to indicate which of the packages + you are using. Define <c><![CDATA[_REENTRANT]]></c> and either <c><![CDATA[STHREADS]]></c> or + <c><![CDATA[PTHREADS]]></c>. The default is to use POSIX threads if + <c><![CDATA[_REENTRANT]]></c> is specified.</p> + <p>Note that both single threaded and default versions of the Erl_interface + and Ei libraries are provided. (The single threaded versions are named + <c><![CDATA[liberl_interface_st]]></c> and <c><![CDATA[libei_st]]></c>). Whether the default + versions of the libraries have support for threads or not is determined by if + the platform in question has support for POSIX or Solaris threads. To check this, + have a look in the <c><![CDATA[eidefs.mk]]></c> file in the erl_interface src directory.</p> + </section> + + <section> + <title>Initializing the erl_interface Library</title> + <p>Before calling any of the other Erl_Interface functions, you + must call <c><![CDATA[erl_init()]]></c> exactly once to initialize the library. + <c><![CDATA[erl_init()]]></c> takes two arguments, however the arguments are no + longer used by Erl_Interface, and should therefore be specified + as <c><![CDATA[erl_init(NULL,0)]]></c>.</p> + </section> + + <section> + <title>Encoding, Decoding and Sending Erlang Terms</title> + <p>Data sent between distributed Erlang nodes is encoded in the + Erlang external format. Consequently, you have to encode and decode + Erlang terms into byte streams if you want to use the distribution + protocol to communicate between a C program and Erlang. </p> + <p>The Erl_Interface library supports this activity. It has a + number of C functions which create and manipulate Erlang data + structures. The library also contains an encode and a decode function. + The example below shows how to create and encode an Erlang tuple + <c><![CDATA[{tobbe,3928}]]></c>:</p> + <code type="none"><![CDATA[ + +ETERM *arr[2], *tuple; +char buf[BUFSIZ]; +int i; + +arr[0] = erl_mk_atom("tobbe"); +arr[1] = erl_mk_integer(3928); +tuple = erl_mk_tuple(arr, 2); +i = erl_encode(tuple, buf); ]]></code> + <p>Alternatively, you can use <c><![CDATA[erl_send()]]></c> and + <c><![CDATA[erl_receive_msg]]></c>, which handle the encoding and decoding of + messages transparently.</p> + <p>Refer to the Reference Manual for a complete description of the + following modules:</p> + <list type="bulleted"> + <item>the <c><![CDATA[erl_eterm]]></c> module for creating Erlang terms</item> + <item>the <c><![CDATA[erl_marshal]]></c> module for encoding and decoding routines.</item> + </list> + </section> + + <section> + <title>Building Terms and Patterns</title> + <p>The previous example can be simplified by using + <c><![CDATA[erl_format()]]></c> to create an Erlang term.</p> + <code type="none"><![CDATA[ + +ETERM *ep; +ep = erl_format("{~a,~i}", "tobbe", 3928); ]]></code> + <p>Refer to the Reference Manual, the <c><![CDATA[erl_format]]></c> module, for a + full description of the different format directives. The following + example is more complex:</p> + <code type="none"><![CDATA[ + +ETERM *ep; +ep = erl_format("[{name,~a},{age,~i},{data,~w}]", + "madonna", + 21, + erl_format("[{adr,~s,~i}]", "E-street", 42)); +erl_free_compound(ep); ]]></code> + <p>As in previous examples, it is your responsibility to free the + memory allocated for Erlang terms. In this example, + <c><![CDATA[erl_free_compound()]]></c> ensures that the complete term pointed to + by <c><![CDATA[ep]]></c> is released. This is necessary, because the pointer from + the second call to <c><![CDATA[erl_format()]]></c> is lost. </p> + <p>The following + example shows a slightly different solution:</p> + <code type="none"><![CDATA[ + +ETERM *ep,*ep2; +ep2 = erl_format("[{adr,~s,~i}]","E-street",42); +ep = erl_format("[{name,~a},{age,~i},{data,~w}]", + "madonna", 21, ep2); +erl_free_term(ep); +erl_free_term(ep2); ]]></code> + <p>In this case, you free the two terms independently. The order in + which you free the terms <c><![CDATA[ep]]></c> and <c><![CDATA[ep2]]></c> is not important, + because the Erl_Interface library uses reference counting to + determine when it is safe to actually remove objects. </p> + <p>If you are not sure whether you have freed the terms properly, you + can use the following function to see the status of the fixed term + allocator:</p> + <code type="none"><![CDATA[ +long allocated, freed; + +erl_eterm_statistics(&allocated,&freed); +printf("currently allocated blocks: %ld\ +",allocated); +printf("length of freelist: %ld\ +",freed); + +/* really free the freelist */ +erl_eterm_release(); + ]]></code> + <p>Refer to the Reference Manual, the <c><![CDATA[erl_malloc]]></c> module for more + information.</p> + </section> + + <section> + <title>Pattern Matching</title> + <p>An Erlang pattern is a term that may contain unbound variables or + <c><![CDATA["do not care"]]></c> symbols. Such a pattern can be matched against a + term and, if the match is successful, any unbound variables in the + pattern will be bound as a side effect. The content of a bound + variable can then be retrieved.</p> + <code type="none"><![CDATA[ + +ETERM *pattern; +pattern = erl_format("{madonna,Age,_}"); ]]></code> + <p><c><![CDATA[erl_match()]]></c> is used to perform pattern matching. It takes a + pattern and a term and tries to match them. As a side effect any unbound + variables in the pattern will be bound. In the following example, we + create a pattern with a variable <em>Age</em> which appears at two + positions in the tuple. The pattern match is performed as follows:</p> + <list type="ordered"> + <item><c><![CDATA[erl_match()]]></c> will bind the contents of + <em>Age</em> to <em>21</em> the first time it reaches the variable</item> + <item>the second occurrence of <em>Age</em> will cause a test for + equality between the terms since <em>Age</em> is already bound to + <em>21</em>. Since <em>Age</em> is bound to 21, the equality test will + succeed and the match continues until the end of the pattern.</item> + <item>if the end of the pattern is reached, the match succeeds and you + can retrieve the contents of the variable</item> + </list> + <code type="none"><![CDATA[ +ETERM *pattern,*term; +pattern = erl_format("{madonna,Age,Age}"); +term = erl_format("{madonna,21,21}"); +if (erl_match(pattern, term)) { + fprintf(stderr, "Yes, they matched: Age = "); + ep = erl_var_content(pattern, "Age"); + erl_print_term(stderr, ep); + fprintf(stderr,"\ +"); + erl_free_term(ep); +} +erl_free_term(pattern); +erl_free_term(term); ]]></code> + <p>Refer to the Reference Manual, the <c><![CDATA[erl_match()]]></c> function for + more information.</p> + </section> + + <section> + <title>Connecting to a Distributed Erlang Node</title> + <p>In order to connect to a distributed Erlang node you need to first + initialize the connection routine with <c><![CDATA[erl_connect_init()]]></c>, + which stores information such as the host name, node name, and IP + address for later use:</p> + <code type="none"><![CDATA[ +int identification_number = 99; +int creation=1; +char *cookie="a secret cookie string"; /* An example */ +erl_connect_init(identification_number, cookie, creation); ]]></code> + <p>Refer to the Reference Manual, the <c><![CDATA[erl_connect]]></c> module for more information.</p> + <p>After initialization, you set up the connection to the Erlang node. + Use <c><![CDATA[erl_connect()]]></c> to specify the Erlang node you want to + connect to. The following example sets up the connection and should + result in a valid socket file descriptor:</p> + <code type="none"><![CDATA[ +int sockfd; +char *nodename="[email protected]"; /* An example */ +if ((sockfd = erl_connect(nodename)) < 0) + erl_err_quit("ERROR: erl_connect failed"); ]]></code> + <p><c><![CDATA[erl_err_quit()]]></c> prints the specified string and terminates + the program. Refer to the Reference Manual, the <c><![CDATA[erl_error()]]></c> + function for more information.</p> + </section> + + <section> + <title>Using EPMD</title> + <p><c><![CDATA[Epmd]]></c> is the Erlang Port Mapper Daemon. Distributed Erlang nodes + register with <c><![CDATA[epmd]]></c> on the localhost to indicate to other nodes that + they exist and can accept connections. <c><![CDATA[Epmd]]></c> maintains a register of + node and port number information, and when a node wishes to connect to + another node, it first contacts <c><![CDATA[epmd]]></c> in order to find out the correct + port number to connect to.</p> + <p>When you use <c><![CDATA[erl_connect()]]></c> to connect to an Erlang node, a + connection is first made to <c><![CDATA[epmd]]></c> and, if the node is known, a + connection is then made to the Erlang node.</p> + <p>C nodes can also register themselves with <c><![CDATA[epmd]]></c> if they want other + nodes in the system to be able to find and connect to them.</p> + <p>Before registering with <c><![CDATA[epmd]]></c>, you need to first create a listen socket + and bind it to a port. Then:</p> + <code type="none"><![CDATA[ +int pub; + +pub = erl_publish(port); ]]></code> + <p><c><![CDATA[pub]]></c> is a file descriptor now connected to <c><![CDATA[epmd]]></c>. <c><![CDATA[Epmd]]></c> + monitors the other end of the connection, and if it detects that the + connection has been closed, the node will be unregistered. So, if you + explicitly close the descriptor or if your node fails, it will be + unregistered from <c><![CDATA[epmd]]></c>.</p> + <p>Be aware that on some systems (such as VxWorks), a failed node will + not be detected by this mechanism since the operating system does not + automatically close descriptors that were left open when the node + failed. If a node has failed in this way, <c><![CDATA[epmd]]></c> will prevent you from + registering a new node with the old name, since it thinks that the old + name is still in use. In this case, you must unregister the name + explicitly:</p> + <code type="none"><![CDATA[ +erl_unpublish(node); ]]></code> + <p>This will cause <c><![CDATA[epmd]]></c> to close the connection from the far end. Note + that if the name was in fact still in use by a node, the results of + this operation are unpredictable. Also, doing this does not cause the + local end of the connection to close, so resources may be consumed.</p> + </section> + + <section> + <title>Sending and Receiving Erlang Messages</title> + <p>Use one of the following two functions to send messages:</p> + <list type="bulleted"> + <item><c><![CDATA[erl_send()]]></c></item> + <item><c><![CDATA[erl_reg_send()]]></c></item> + </list> + <p>As in Erlang, it is possible to send messages to a + <em>Pid</em> or to a registered name. It is easier to send a + message to a registered name because it avoids the problem of finding + a suitable <em>Pid</em>.</p> + <p>Use one of the following two functions to receive messages:</p> + <list type="bulleted"> + <item><c><![CDATA[erl_receive()]]></c></item> + <item><c><![CDATA[erl_receive_msg()]]></c></item> + </list> + <p><c><![CDATA[erl_receive()]]></c> receives the message into a buffer, while + <c><![CDATA[erl_receive_msg()]]></c> decodes the message into an Erlang term. </p> + + <section> + <title>Example of Sending Messages</title> + <p>In the following example, <c><![CDATA[{Pid, hello_world}]]></c> is + sent to a registered process <c><![CDATA[my_server]]></c>. The message is encoded + by <c><![CDATA[erl_send()]]></c>:</p> + <code type="none"><![CDATA[ +extern const char *erl_thisnodename(void); +extern short erl_thiscreation(void); +#define SELF(fd) erl_mk_pid(erl_thisnodename(),fd,0,erl_thiscreation()) +ETERM *arr[2], *emsg; +int sockfd, creation=1; + +arr[0] = SELF(sockfd); +arr[1] = erl_mk_atom("Hello world"); +emsg = erl_mk_tuple(arr, 2); + +erl_reg_send(sockfd, "my_server", emsg); +erl_free_term(emsg); ]]></code> + <p>The first element of the tuple that is sent is your own + <em>Pid</em>. This enables <c><![CDATA[my_server]]></c> to reply. Refer to the + Reference Manual, the <c><![CDATA[erl_connect]]></c> module for more information + about send primitives.</p> + </section> + + <section> + <title>Example of Receiving Messages</title> + <p>In this example <c><![CDATA[{Pid, Something}]]></c> is received. The + received Pid is then used to return <c><![CDATA[{goodbye,Pid}]]></c></p> + <code type="none"><![CDATA[ +ETERM *arr[2], *answer; +int sockfd,rc; +char buf[BUFSIZE]; +ErlMessage emsg; + +if ((rc = erl_receive_msg(sockfd , buf, BUFSIZE, &emsg)) == ERL_MSG) { + arr[0] = erl_mk_atom("goodbye"); + arr[1] = erl_element(1, emsg.msg); + answer = erl_mk_tuple(arr, 2); + erl_send(sockfd, arr[1], answer); + erl_free_term(answer); + erl_free_term(emsg.msg); + erl_free_term(emsg.to); +} +} ]]></code> + <p>In order to provide robustness, a distributed Erlang node + occasionally polls all its connected neighbours in an attempt to + detect failed nodes or communication links. A node which receives such + a message is expected to respond immediately with an <c><![CDATA[ERL_TICK]]></c> message. + This is done automatically by <c><![CDATA[erl_receive()]]></c>, however when this + has occurred <c><![CDATA[erl_receive]]></c> returns <c><![CDATA[ERL_TICK]]></c> to the caller + without storing a message into the <c><![CDATA[ErlMessage]]></c> structure.</p> + <p>When a message has been received, it is the caller's responsibility + to free the received message <c><![CDATA[emsg.msg]]></c> as well as <c><![CDATA[emsg.to]]></c> + or <c><![CDATA[emsg.from]]></c>, depending on the type of message received.</p> + <p>Refer to the Reference Manual for additional information about the + following modules:</p> + <list type="bulleted"> + <item><c><![CDATA[erl_connect]]></c></item> + <item><c><![CDATA[erl_eterm]]></c>.</item> + </list> + </section> + </section> + + <section> + <title>Remote Procedure Calls</title> + <p>An Erlang node acting as a client to another Erlang node + typically sends a request and waits for a reply. Such a request is + included in a function call at a remote node and is called a remote + procedure call. The following example shows how the + Erl_Interface library supports remote procedure calls:</p> + <code type="none"><![CDATA[ + +char modname[]=THE_MODNAME; +ETERM *reply,*ep; +ep = erl_format("[~a,[]]", modname); +if (!(reply = erl_rpc(fd, "c", "c", ep))) + erl_err_msg("<ERROR> when compiling file: %s.erl !\ +", modname); +erl_free_term(ep); +ep = erl_format("{ok,_}"); +if (!erl_match(ep, reply)) + erl_err_msg("<ERROR> compiler errors !\ +"); +erl_free_term(ep); +erl_free_term(reply); ]]></code> + <p><c><![CDATA[c:c/1]]></c> is called to compile the specified module on the + remote node. <c><![CDATA[erl_match()]]></c> checks that the compilation was + successful by testing for the expected <c><![CDATA[ok]]></c>.</p> + <p>Refer to the Reference Manual, the <c><![CDATA[erl_connect]]></c> module for + more information about <c><![CDATA[erl_rpc()]]></c>, and its companions + <c><![CDATA[erl_rpc_to()]]></c> and <c><![CDATA[erl_rpc_from()]]></c>.</p> + </section> + + <section> + <title>Using Global Names</title> + <p>A C node has access to names registered through the Erlang Global + module. Names can be looked up, allowing the C node to send messages + to named Erlang services. C nodes can also register global names, + allowing them to provide named services to Erlang processes or other C + nodes. </p> + <p>Erl_Interface does not provide a native implementation of the global + service. Instead it uses the global services provided by a "nearby" + Erlang node. In order to use the services described in this section, + it is necessary to first open a connection to an Erlang node.</p> + <p>To see what names there are:</p> + <code type="none"><![CDATA[ +char **names; +int count; +int i; + +names = erl_global_names(fd,&count); + +if (names) + for (i=0; i<count; i++) + printf("%s\ +",names[i]); + +free(names); ]]></code> + <p><c><![CDATA[erl_global_names()]]></c> allocates and returns a buffer containing + all the names known to global. <c><![CDATA[count]]></c> will be initialized to + indicate how many names are in the array. The array of strings in + names is terminated by a NULL pointer, so it is not necessary to use + <c><![CDATA[count]]></c> to determine when the last name is reached.</p> + <p>It is the caller's responsibility to free the array. + <c><![CDATA[erl_global_names()]]></c> allocates the array and all of the strings + using a single call to <c><![CDATA[malloc()]]></c>, so <c><![CDATA[free(names)]]></c> is all + that is necessary.</p> + <p>To look up one of the names:</p> + <code type="none"><![CDATA[ +ETERM *pid; +char node[256]; + +pid = erl_global_whereis(fd,"schedule",node); ]]></code> + <p>If <c><![CDATA["schedule"]]></c> is known to global, an Erlang pid is returned + that can be used to send messages to the schedule service. + Additionally, <c><![CDATA[node]]></c> will be initialized to contain the name of + the node where the service is registered, so that you can make a + connection to it by simply passing the variable to <c><![CDATA[erl_connect()]]></c>.</p> + <p>Before registering a name, you should already have registered your + port number with <c><![CDATA[epmd]]></c>. This is not strictly necessary, but if you + neglect to do so, then other nodes wishing to communicate with your + service will be unable to find or connect to your process.</p> + <p>Create a pid that Erlang processes can use to communicate with your + service:</p> + <code type="none"><![CDATA[ +ETERM *pid; + +pid = erl_mk_pid(thisnode,14,0,0); +erl_global_register(fd,servicename,pid); ]]></code> + <p>After registering the name, you should use <c><![CDATA[erl_accept()]]></c> to wait for + incoming connections.</p> + <p>Do not forget to free <c><![CDATA[pid]]></c> later with <c><![CDATA[erl_free_term()]]></c>!</p> + <p>To unregister a name:</p> + <code type="none"><![CDATA[ +erl_global_unregister(fd,servicename); ]]></code> + </section> + + <section> + <title>The Registry</title> + <p>This section describes the use of the registry, a simple mechanism + for storing key-value pairs in a C-node, as well as backing them up or + restoring them from a Mnesia table on an Erlang node. More detailed + information about the individual API functions can be found in the + Reference Manual.</p> + <p>Keys are strings, i.e. 0-terminated arrays of characters, and values + are arbitrary objects. Although integers and floating point numbers + are treated specially by the registry, you can store strings or binary + objects of any type as pointers.</p> + <p>To start, you need to open a registry:</p> + <code type="none"><![CDATA[ +ei_reg *reg; + +reg = ei_reg_open(45); ]]></code> + <p>The number 45 in the example indicates the approximate number of + objects that you expect to store in the registry. Internally the + registry uses hash tables with collision chaining, so there is no + absolute upper limit on the number of objects that the registry can + contain, but if performance or memory usage are important, then you + should choose a number accordingly. The registry can be resized later.</p> + <p>You can open as many registries as you like (if memory permits).</p> + <p>Objects are stored and retrieved through set and get functions. In + the following examples you see how to store integers, floats, strings + and arbitrary binary objects:</p> + <code type="none"><![CDATA[ +struct bonk *b = malloc(sizeof(*b)); +char *name = malloc(7); + +ei_reg_setival(reg,"age",29); +ei_reg_setfval(reg,"height",1.85); + +strcpy(name,"Martin"); +ei_reg_setsval(reg,"name",name); + +b->l = 42; +b->m = 12; +ei_reg_setpval(reg,"jox",b,sizeof(*b)); ]]></code> + <p>If you attempt to store an object in the registry and there is an + existing object with the same key, the new value will replace the old + one. This is done regardless of whether the new object and the old one + have the same type, so you can, for example, replace a string with an + integer. If the existing value is a string or binary, it will be freed + before the new value is assigned.</p> + <p>Stored values are retrieved from the registry as follows:</p> + <code type="none"><![CDATA[ +long i; +double f; +char *s; +struct bonk *b; +int size; + +i = ei_reg_getival(reg,"age"); +f = ei_reg_getfval(reg,"height"); +s = ei_reg_getsval(reg,"name"); +b = ei_reg_getpval(reg,"jox",&size); ]]></code> + <p>In all of the above examples, the object must exist and it must be of + the right type for the specified operation. If you do not know the + type of a given object, you can ask:</p> + <code type="none"><![CDATA[ +struct ei_reg_stat buf; + +ei_reg_stat(reg,"name",&buf); ]]></code> + <p>Buf will be initialized to contain object attributes.</p> + <p>Objects can be removed from the registry:</p> + <code type="none"><![CDATA[ +ei_reg_delete(reg,"name"); ]]></code> + <p>When you are finished with a registry, close it to remove all the + objects and free the memory back to the system:</p> + <code type="none"><![CDATA[ +ei_reg_close(reg); ]]></code> + + <section> + <title>Backing Up the Registry to Mnesia</title> + <p>The contents of a registry can be backed up to Mnesia on a "nearby" + Erlang node. You need to provide an open connection to the Erlang node + (see <c><![CDATA[erl_connect()]]></c>). Also, Mnesia 3.0 or later must be running + on the Erlang node before the backup is initiated:</p> + <code type="none"><![CDATA[ +ei_reg_dump(fd, reg, "mtab", dumpflags); ]]></code> + <p>The example above will backup the contents of the registry to the + specified Mnesia table <c><![CDATA["mtab"]]></c>. Once a registry has been backed + up to Mnesia in this manner, additional backups will only affect + objects that have been modified since the most recent backup, i.e. + objects that have been created, changed or deleted. The backup + operation is done as a single atomic transaction, so that the entire + backup will be performed or none of it will.</p> + <p>In the same manner, a registry can be restored from a Mnesia table:</p> + <code type="none"><![CDATA[ +ei_reg_restore(fd, reg, "mtab"); ]]></code> + <p>This will read the entire contents of <c><![CDATA["mtab"]]></c> into the specified + registry. After the restore, all of the objects in the registry will + be marked as unmodified, so a subsequent backup will only affect + objects that you have modified since the restore.</p> + <p>Note that if you restore to a non-empty registry, objects in the + table will overwrite objects in the registry with the same keys. Also, + the <em>entire</em> contents of the registry is marked as unmodified + after the restore, including any modified objects that were not + overwritten by the restore operation. This may not be your intention.</p> + </section> + + <section> + <title>Storing Strings and Binaries</title> + <p>When string or binary objects are stored in the registry it is + important that a number of simple guidelines are followed. </p> + <p>Most importantly, the object must have been created with a single call + to <c><![CDATA[malloc()]]></c> (or similar), so that it can later be removed by a + single call to <c><![CDATA[free()]]></c>. Objects will be freed by the registry + when it is closed, or when you assign a new value to an object that + previously contained a string or binary.</p> + <p>You should also be aware that if you store binary objects that are + context-dependent (e.g. containing pointers or open file descriptors), + they will lose their meaning if they are backed up to a Mnesia table + and subsequently restored in a different context.</p> + <p>When you retrieve a stored string or binary value from the registry, + the registry maintains a pointer to the object and you are passed a + copy of that pointer. You should never free an object retrieved in + this manner because when the registry later attempts to free it, a + runtime error will occur that will likely cause the C-node to crash.</p> + <p>You are free to modify the contents of an object retrieved this way. + However when you do so, the registry will not be aware of the changes + you make, possibly causing it to be missed the next time you make a + Mnesia backup of the registry contents. This can be avoided if you + mark the object as dirty after any such changes with + <c><![CDATA[ei_reg_markdirty()]]></c>, or pass appropriate flags to + <c><![CDATA[ei_reg_dump()]]></c>.</p> + </section> + </section> +</chapter> + diff --git a/lib/erl_interface/doc/src/erl_malloc.xml b/lib/erl_interface/doc/src/erl_malloc.xml new file mode 100644 index 0000000000..8c8750d62a --- /dev/null +++ b/lib/erl_interface/doc/src/erl_malloc.xml @@ -0,0 +1,200 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE cref SYSTEM "cref.dtd"> + +<cref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>erl_malloc</title> + <prepared>Torbjörn Törnkvist</prepared> + <responsible>Torbjörn Törnkvist</responsible> + <docno></docno> + <approved>Bjarne Däcker</approved> + <checked>Torbjörn Törnkvist</checked> + <date>980703</date> + <rev>A</rev> + <file>erl_malloc.sgml</file> + </header> + <lib>erl_malloc</lib> + <libsummary>Memory Allocation Functions</libsummary> + <description> + <p>This module provides functions for allocating and deallocating + memory.</p> + </description> + <funcs> + <func> + <name><ret>ETERM *</ret><nametext>erl_alloc_eterm(etype)</nametext></name> + <fsummary>Allocates an ETERM structure</fsummary> + <type> + <v>unsigned char etype;</v> + </type> + <desc> + <p>This function allocates an <c><![CDATA[(ETERM)]]></c> structure. + Specify <c><![CDATA[etype]]></c> as one of the following constants:</p> + <list type="bulleted"> + <item> + <p>ERL_INTEGER</p> + </item> + <item> + <p>ERL_U_INTEGER <c><![CDATA[/* unsigned integer */]]></c></p> + </item> + <item> + <p>ERL_ATOM</p> + </item> + <item> + <p>ERL_PID <c><![CDATA[/* Erlang process identifier */]]></c></p> + </item> + <item> + <p>ERL_PORT</p> + </item> + <item> + <p>ERL_REF <c><![CDATA[/* Erlang reference */]]></c></p> + </item> + <item> + <p>ERL_LIST</p> + </item> + <item> + <p>ERL_EMPTY_LIST</p> + </item> + <item> + <p>ERL_TUPLE</p> + </item> + <item> + <p>ERL_BINARY</p> + </item> + <item> + <p>ERL_FLOAT</p> + </item> + <item> + <p>ERL_VARIABLE</p> + </item> + <item> + <p>ERL_SMALL_BIG <c><![CDATA[/* bignum */]]></c></p> + </item> + <item> + <p>ERL_U_SMALL_BIG <c><![CDATA[/* bignum */]]></c></p> + </item> + </list> + <p><c><![CDATA[ERL_SMALL_BIG]]></c> and <c><![CDATA[ERL_U_SMALL_BIG]]></c> are for + creating Erlang <c><![CDATA[bignums]]></c>, which can contain integers of + arbitrary size. The size of an integer in Erlang is machine + dependent, but in general any integer larger than 2^28 + requires a bignum.</p> + </desc> + </func> + <func> + <name><ret>void</ret><nametext>erl_eterm_release(void)</nametext></name> + <fsummary>Clears the ETERM freelist</fsummary> + <desc> + <p>Clears the + freelist, where blocks are placed when they are + released by <c><![CDATA[erl_free_term()]]></c> and + <c><![CDATA[erl_free_compound()]]></c>. </p> + </desc> + </func> + <func> + <name><ret>void</ret><nametext>erl_eterm_statistics(allocated, freed)</nametext></name> + <fsummary>Reports term allocation statistics</fsummary> + <type> + <v>long *allocated;</v> + <v>long *freed;</v> + </type> + <desc> + <p><c><![CDATA[allocated]]></c> and <c><![CDATA[freed]]></c> are initialized to + contain information about the fix-allocator used to allocate + ETERM components. <c><![CDATA[allocated]]></c> is the number of blocks + currently allocated to ETERM objects. <c><![CDATA[freed]]></c> is the + length of the freelist, where blocks are placed when they are + released by <c><![CDATA[erl_free_term()]]></c> and + <c><![CDATA[erl_free_compound()]]></c>. </p> + </desc> + </func> + <func> + <name><ret>void</ret><nametext>erl_free_array(array, size)</nametext></name> + <fsummary>Frees an array of ETERM structures</fsummary> + <type> + <v>ETERM **array;</v> + <v>int size;</v> + </type> + <desc> + <p>This function frees an array of Erlang terms.</p> + <p><c><![CDATA[array]]></c> is an array of ETERM* objects. + </p> + <p><c><![CDATA[size]]></c> is the number of terms in the array.</p> + </desc> + </func> + <func> + <name><ret>void</ret><nametext>erl_free_term(t)</nametext></name> + <fsummary>Frees an ETERM structure</fsummary> + <type> + <v>ETERM *t;</v> + </type> + <desc> + <p>Use this function to free an Erlang term.</p> + </desc> + </func> + <func> + <name><ret>void</ret><nametext>erl_free_compound(t)</nametext></name> + <fsummary>Frees an array of ETERM structures</fsummary> + <type> + <v>ETERM *t;</v> + </type> + <desc> + <p>Normally it is the programmer's responsibility to free each + Erlang term that has been returned from any of the + <c><![CDATA[erl_interface]]></c> functions. However since many of the + functions that build new Erlang terms in fact share objects + with other existing terms, it may be difficult for the + programmer to maintain pointers to all such terms in order to + free them individually. + </p> + <p><c><![CDATA[erl_free_compound()]]></c> will recursively free all of the + sub-terms associated with a given Erlang term, regardless of + whether we are still holding pointers to the sub-terms. + </p> + <p>There is an example in the User Manual under "Building + Terms and Patterns" + </p> + </desc> + </func> + <func> + <name><ret>void</ret><nametext>erl_malloc(size)</nametext></name> + <fsummary>Allocates some memory</fsummary> + <type> + <v>long size;</v> + </type> + <desc> + <p>This function calls the standard + <c><![CDATA[malloc()]]></c> function. </p> + </desc> + </func> + <func> + <name><ret>void</ret><nametext>erl_free(ptr)</nametext></name> + <fsummary>Frees some memory</fsummary> + <type> + <v>void *ptr;</v> + </type> + <desc> + <p>This function calls the standard + <c><![CDATA[free()]]></c> function. </p> + </desc> + </func> + </funcs> +</cref> + diff --git a/lib/erl_interface/doc/src/erl_marshal.xml b/lib/erl_interface/doc/src/erl_marshal.xml new file mode 100644 index 0000000000..a7eaf78f35 --- /dev/null +++ b/lib/erl_interface/doc/src/erl_marshal.xml @@ -0,0 +1,272 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE cref SYSTEM "cref.dtd"> + +<cref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>erl_marshal</title> + <prepared>Torbjörn Törnkvist</prepared> + <responsible>Torbjörn Törnkvist</responsible> + <docno></docno> + <approved>Bjarne Däcker</approved> + <checked>Torbjörn Törnkvist</checked> + <date>980703</date> + <rev>A</rev> + <file>erl_marshal.sgml</file> + </header> + <lib>erl_marshal</lib> + <libsummary>Encoding and Decoding of Erlang terms</libsummary> + <description> + <p>This module contains functions for encoding Erlang terms into + a sequence of bytes, and for decoding Erlang terms from a + sequence of bytes.</p> + </description> + <funcs> + <func> + <name><ret>int</ret><nametext>erl_compare_ext(bufp1, bufp2)</nametext></name> + <fsummary>Compares encoded byte sequences</fsummary> + <type> + <v>unsigned char *bufp1,*bufp2;</v> + </type> + <desc> + <p>This function compares two encoded terms. + </p> + <p><c><![CDATA[bufp1]]></c> is a buffer containing an encoded Erlang + term term1. + </p> + <p><c><![CDATA[bufp2]]></c> is a buffer containing an encoded Erlang + term term2. + </p> + <p>The function returns 0 if the terms are equal, -1 if term1 + is less than term2, or 1 if term2 is less than term1. + </p> + </desc> + </func> + <func> + <name><ret>ETERM *</ret><nametext>erl_decode(bufp)</nametext></name> + <name><ret>ETERM *</ret><nametext>erl_decode_buf(bufpp)</nametext></name> + <fsummary>Converts a term from Erlang external format</fsummary> + <type> + <v>unsigned char *bufp;</v> + <v>unsigned char **bufpp;</v> + </type> + <desc> + <p><c><![CDATA[erl_decode()]]></c> and <c><![CDATA[erl_decode_buf()]]></c> decode + the contents of a buffer and return the corresponding + Erlang term. <c><![CDATA[erl_decode_buf()]]></c> provides a simple + mechanism for dealing with several encoded terms stored + consecutively in the buffer.</p> + <p><c><![CDATA[bufp]]></c> is a pointer to a buffer containing one or + more encoded Erlang terms. + </p> + <p><c><![CDATA[bufpp]]></c> is the address of a buffer pointer. The buffer + contains one or more consecutively encoded Erlang terms. + Following a successful call to <c><![CDATA[erl_decode_buf()]]></c>, + <c><![CDATA[bufpp]]></c> will be updated so that it points to the next + encoded term. + </p> + <p><c><![CDATA[erl_decode()]]></c> returns an Erlang term + corresponding to the contents of <c><![CDATA[bufp]]></c> on success, or + NULL on failure. <c><![CDATA[erl_decode_buf()]]></c> returns an Erlang + term corresponding to the first of the consecutive terms in + <c><![CDATA[bufpp]]></c> and moves <c><![CDATA[bufpp]]></c> forward to point to the + next term in the buffer. On failure, each of the functions + returns NULL. + </p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>erl_encode(term, bufp)</nametext></name> + <name><ret>int</ret><nametext>erl_encode_buf(term, bufpp)</nametext></name> + <fsummary>Converts a term into Erlang external format</fsummary> + <type> + <v>ETERM *term;</v> + <v>unsigned char *bufp;</v> + <v>unsigned char **bufpp;</v> + </type> + <desc> + <p><c><![CDATA[erl_encode()]]></c> and <c><![CDATA[erl_encode_buf()]]></c> encode + Erlang terms into external format for storage or transmission. + <c><![CDATA[erl_encode_buf()]]></c> provides a simple mechanism for + encoding several terms consecutively in the same + buffer. + </p> + <p><c>term</c> is an Erlang term to be encoded. + </p> + <p><c>bufp</c> is a pointer to a buffer containing one or + more encoded Erlang terms. + </p> + <p><c>bufpp</c> is a pointer to a pointer to a buffer + containing one or more consecutively encoded Erlang terms. + Following a successful call to <c><![CDATA[erl_encode_buf()]]></c>, + <c>bufpp</c> will be updated so that it points to the + position for the next encoded term. + </p> + <p> + These functions returns the number of bytes written to buffer + if successful, otherwise returns 0. + </p> + <p>Note that no bounds checking is done on the buffer. It is + the caller's responsibility to make sure that the buffer is + large enough to hold the encoded terms. You can either use a + static buffer that is large enough to hold the terms you + expect to need in your program, or use <c><![CDATA[erl_term_len()]]></c> + to determine the exact requirements for a given term. + </p> + <p>The following can help you estimate the buffer + requirements for a term. Note that this information is + implementation specific, and may change in future versions. + If you are unsure, use <c><![CDATA[erl_term_len()]]></c>. + </p> + <p>Erlang terms are encoded with a 1 byte tag that + identifies the type of object, a 2- or 4-byte length field, + and then the data itself. Specifically: + </p> + <taglist> + <tag><c><![CDATA[Tuples]]></c></tag> + <item>need 5 bytes, plus the space for each element.</item> + <tag><c><![CDATA[Lists]]></c></tag> + <item>need 5 bytes, plus the space for each element, and 1 + additional byte for the empty list at the end.</item> + <tag><c><![CDATA[Strings and atoms]]></c></tag> + <item>need 3 bytes, plus 1 byte for each character (the + terminating 0 is not encoded). Really long strings (more + than 64k characters) are encoded as lists. Atoms cannot + contain more than 256 characters.</item> + <tag><c><![CDATA[Integers]]></c></tag> + <item>need 5 bytes.</item> + <tag><c><![CDATA[Characters]]></c></tag> + <item>(integers < 256) need 2 bytes.</item> + <tag><c><![CDATA[Floating point numbers]]></c></tag> + <item>need 32 bytes.</item> + <tag><c><![CDATA[Pids]]></c></tag> + <item>need 10 bytes, plus the space for the node name, which + is an atom.</item> + <tag><c><![CDATA[Ports and Refs]]></c></tag> + <item>need 6 bytes, plus the space for the node name, which + is an atom.</item> + </taglist> + <p>The total space required will be the result calculated + from the information above, plus 1 additional byte for a + version identifier. + </p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>erl_ext_size(bufp)</nametext></name> + <fsummary>Counts elements in encoded term</fsummary> + <type> + <v>unsigned char *bufp;</v> + </type> + <desc> + <p>This function returns the number of elements in an + encoded term.</p> + </desc> + </func> + <func> + <name><ret>unsigned char</ret><nametext>erl_ext_type(bufp)</nametext></name> + <fsummary>Determines type of an encoded byte sequence</fsummary> + <type> + <v>unsigned char *bufp;</v> + </type> + <desc> + <p>This function identifies and returns the type of Erlang term encoded + in a buffer. It will skip a trailing <em>magic</em> identifier. + Returns <c><![CDATA[0]]></c> if the type can't be determined or one of</p> + <list type="bulleted"> + <item> + <p>ERL_INTEGER</p> + </item> + <item> + <p>ERL_ATOM</p> + </item> + <item> + <p>ERL_PID <c><![CDATA[/* Erlang process identifier */]]></c></p> + </item> + <item> + <p>ERL_PORT</p> + </item> + <item> + <p>ERL_REF <c><![CDATA[/* Erlang reference */]]></c></p> + </item> + <item> + <p>ERL_EMPTY_LIST</p> + </item> + <item> + <p>ERL_LIST</p> + </item> + <item> + <p>ERL_TUPLE</p> + </item> + <item> + <p>ERL_FLOAT</p> + </item> + <item> + <p>ERL_BINARY</p> + </item> + <item> + <p>ERL_FUNCTION</p> + </item> + </list> + </desc> + </func> + <func> + <name><ret>unsigned char *</ret><nametext>erl_peek_ext(bufp, pos)</nametext></name> + <fsummary>Steps over encoded term</fsummary> + <type> + <v>unsigned char *bufp;</v> + <v>int pos;</v> + </type> + <desc> + <p>This function is used for stepping over one or more + encoded terms in a buffer, in order to directly access a + later term. + </p> + <p><c><![CDATA[bufp]]></c> is a pointer to a buffer containing one or + more encoded Erlang terms. + </p> + <p><c><![CDATA[pos]]></c> indicates how many terms to step over in the + buffer. + </p> + <p>The function returns a pointer to a sub-term that can be + used in a subsequent call to <c><![CDATA[erl_decode()]]></c> in order to retrieve + the term at that position. If there is no term, or <c><![CDATA[pos]]></c> + would exceed the size of the terms in the buffer, NULL is returned. + </p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>erl_term_len(t)</nametext></name> + <fsummary>Determines encoded size of term</fsummary> + <type> + <v>ETERM *t;</v> + </type> + <desc> + <p>This function determines the buffer space that would be + needed by <c><![CDATA[t]]></c> if it were encoded into Erlang external + format by <c><![CDATA[erl_encode()]]></c>. + </p> + <p>The size in bytes is returned. + </p> + </desc> + </func> + </funcs> +</cref> + diff --git a/lib/erl_interface/doc/src/fascicules.xml b/lib/erl_interface/doc/src/fascicules.xml new file mode 100644 index 0000000000..3d6219a2bd --- /dev/null +++ b/lib/erl_interface/doc/src/fascicules.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE fascicules SYSTEM "fascicules.dtd"> + +<fascicules> + <fascicule file="part_ei" href="part_ei_frame.html" entry="no"> + EI User's Guide + </fascicule> + <fascicule file="ref_man_ei" href="ref_man_ei_frame.html" entry="yes"> + EI Library Reference + </fascicule> + <fascicule file="ref_man_erl_interface" href="ref_man_erl_interface_frame.html" entry="no"> + Erl_interface Library Reference + </fascicule> + <fascicule file="ref_man" href="ref_man_frame.html" entry="no"> + Command Reference + </fascicule> + <fascicule file="part_notes" href="part_notes_frame.html" entry="no"> + Release Notes + </fascicule> + <fascicule file="" href="../../../../doc/print.html" entry="no"> + Off-Print + </fascicule> +</fascicules> + diff --git a/lib/erl_interface/doc/src/make.dep b/lib/erl_interface/doc/src/make.dep new file mode 100644 index 0000000000..3f43cf64fe --- /dev/null +++ b/lib/erl_interface/doc/src/make.dep @@ -0,0 +1,24 @@ +# ---------------------------------------------------- +# >>>> Do not edit this file <<<< +# This file was automaticly generated by +# /home/otp/bin//docdepend +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# TeX files that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: book.tex ei.tex ei_connect.tex ei_users_guide.tex \ + erl_call.tex erl_connect.tex erl_error.tex \ + erl_eterm.tex erl_format.tex erl_global.tex \ + erl_malloc.tex erl_marshal.tex part_ei.tex \ + ref_man.tex ref_man_ei.tex ref_man_erl_interface.tex \ + registry.tex + +# ---------------------------------------------------- +# Source inlined when transforming from source to LaTeX +# ---------------------------------------------------- + +book.tex: ref_man.xml ref_man_ei.xml ref_man_erl_interface.xml + diff --git a/lib/erl_interface/doc/src/note.gif b/lib/erl_interface/doc/src/note.gif Binary files differnew file mode 100644 index 0000000000..6fffe30419 --- /dev/null +++ b/lib/erl_interface/doc/src/note.gif diff --git a/lib/erl_interface/doc/src/notes.xml b/lib/erl_interface/doc/src/notes.xml new file mode 100644 index 0000000000..f2519fda0b --- /dev/null +++ b/lib/erl_interface/doc/src/notes.xml @@ -0,0 +1,535 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2004</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Erl_interface Release Notes</title> + <prepared>otp_appnotes</prepared> + <docno>nil</docno> + <date>nil</date> + <rev>nil</rev> + <file>notes.xml</file> + </header> + <p>This document describes the changes made to the Erl_interface application.</p> + +<section><title>Erl_Interface 3.6.4</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + The documentation is now built with open source tools + (xsltproc and fop) that exists on most platforms. One + visible change is that the frames are removed.</p> + <p> + Own Id: OTP-8201</p> + </item> + </list> + </section> + +</section> + +<section><title>Erl_Interface 3.6.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The manual states that erl_receive() return the reason in + the <c>ErlMessage</c> struct. This was not the case and + the function is now corrected.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-4969</p> + </item> + <item> + <p> + In <c>send_exit.c</c> an errorneous size of memory + allocation could occur when reallocating a buffer.</p> + <p> + In <c>ei_decode_trace.c</c> the index could be updated + when the decoding failed.</p> + <p> + In <c>ei_printterm.c</c> the index could be updated when + the decoding failed in lists and tuples.</p> + <p> + In <c>ei_decode_term.c</c> when decoding a double + (ERL_FLOAT_EXT) no check was done to ensure that the last + of the 31 bytes was null terminated.</p> + <p> + In <c>ei_decode_term.c</c> when decoding references, only + the first 3 bytes are read, but the index did not + increment by the total size.</p> + <p> + In <c>ei_decode_fun.c</c> no check of correct buffer + allocation or data length was done.</p> + <p> + In <c>ei_decode_string.c</c> the integer list string case + did not decode the NIL tail correctly.</p> + <p> + These errors has now been fixed. (Thanks to Romain + Lenglet, Paul Mineiro and Paul Guyot).</p> + <p> + Own Id: OTP-6117</p> + </item> + <item> + <p> + <c>ei_decode_big</c> could be decoded with a garbage + byte.</p> + <p> + <c>ei_encode_big</c> and <c>ei_x_encode_big</c> is now + available.</p> + <p> + Own Id: OTP-7554</p> + </item> + <item> + <p> + The function <c>erl_init_resolve()</c> did not conform to + C99 standard which caused a build error on some + platforms. This has now been fixed.</p> + <p> + Own Id: OTP-8093</p> + </item> + <item> + <p> + <c>Makefile.in</c> has been updated to use the LDFLAGS + environment variable (if set). (Thanks to Davide + Pesavento.)</p> + <p> + Own Id: OTP-8157</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Added support for 64-bit integers in encoding/decoding.</p> + <p> + Added support for better printouts of binaries.</p> + <p> + Own Id: OTP-6091</p> + </item> + </list> + </section> + +</section> + +<section><title>Erl_Interface 3.6.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + A problem with <c>gethostbyname</c> in <c>erl_start.c</c> + could cause a buffer overflow. This has now been fixed.</p> + <p> + Clean up of code and removed compiler warnings.</p> + <p> + Own Id: OTP-7978</p> + </item> + </list> + </section> + +</section> + +<section><title>Erl_Interface 3.6.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>A faulty validation in <c>ei_reg_getpval</c> caused it + to never return the key-value. This has now been fixed. + (Thanks to Matt Stancliff)</p> + <p> + Own Id: OTP-7960</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>Minor update to the <c>configure</c> script.</p> + <p> + Own Id: OTP-7959</p> + </item> + </list> + </section> + +</section> + +<section><title>Erl_Interface 3.6.1</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>Minor update to the <c>configure</c> script.</p> + <p> + Own Id: OTP-7959</p> + </item> + </list> + </section> + +</section> + +<section><title>Erl_Interface 3.6</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Nodes belonging to different independent clusters can now + co-exist on the same host with the help of a new + environment variable setting ERL_EPMD_PORT.</p> + <p> + Own Id: OTP-7826</p> + </item> + </list> + </section> + +</section> + +<section><title>Erl_Interface 3.5.9</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + A type-casting bug in ei_skip_term and ei_printterm on + 64bit platforms rendering undefined results is now + corrected.</p> + <p> + Own Id: OTP-7577</p> + </item> + <item> + <p> + A bug in the hostent copying code of erl_interface on + MacOS X/Darwin is now corrected.</p> + <p> + Own Id: OTP-7593</p> + </item> + <item> + <p>A problem with building <c>erl_interface</c> on + FreeBSD has been fixed (Thanks to Akira Kitada).</p> + <p> + Own Id: OTP-7611</p> + </item> + </list> + </section> + +</section> + +<section><title>Erl_Interface 3.5.8</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fixed bug in erl_interface when decoding broken data</p> + <p> + Own Id: OTP-7448</p> + </item> + </list> + </section> + +</section> + + +<section><title>Erl_Interface 3.5.7</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + An erroneous freeing of memory could occur when using + <c>ei_x_format_wo_ver</c> in erl_interface, resulting in + a segmentation fault.</p> + <p> + Own Id: OTP-6795</p> + </item> + <item> + <p> + A faulty compare in <c>erl_marshal</c> has now been + fixed. (Thanks to Simon Cornish and Paul Mineiro)</p> + <p> + Own Id: OTP-7368</p> + </item> + </list> + </section> + +</section> + +<section><title>Erl_Interface 3.5.6</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Minor documentation fixes.</p> + <p> + Own Id: OTP-7183 Aux Id: OTP-7118 </p> + </item> + </list> + </section> + +</section> + +<section><title>Erl_Interface 3.5.5.4</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The symbol __erl_errno was undefined in the single thread + version of the ei library, but is now defined.</p> + <p> + Own Id: OTP-6887</p> + </item> + <item> + <p> + Corrected FreeBSD build error.</p> + <p> + Own Id: OTP-7093</p> + </item> + </list> + </section> + +</section> + + <section> + <title>Erl_Interface 3.5.5.3</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>Calls to alloca in erl_marshal.c have been removed. A + static buffer is now used instead to store node names + temporarily.</p> + <p>Own Id: OTP-6331 Aux Id: seq10468 </p> + </item> + <item> + <p>ei_print_term interprets a list of integers with values + from 0 to 255 as a string. If the original list contains + the integer 0, this is considered terminator of the + string. This is incorrect. The function has now been + modified to not look for '\\0' in a string, but always + print all characters.</p> + <p>Own Id: OTP-6339 Aux Id: seq10492 </p> + </item> + </list> + </section> + </section> + + <section> + <title>Erl_Interface 3.5.5.2</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>The combination of xeon processors with 64bit x86 + extensions and a 32bit linux could cause ei_decode_long + and ei_decode_longlong to fail for the value LONG_MIN and + LONGLONG_MIN. The conversion is now made more portable.</p> + <p>Own Id: OTP-6216</p> + </item> + </list> + </section> + </section> + + <section> + <title>Erl_Interface 3.5.5.1</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>Portability enhancements.</p> + <p>Own Id: OTP-6132</p> + </item> + </list> + </section> + </section> + + <section> + <title>Erl_Interface 3.5.5</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>Different (and old) <c><![CDATA[config.guess]]></c> files in the + <c><![CDATA[erts]]></c> and <c><![CDATA[erl_interface]]></c> applications would + cause build problems on the new Intel-based iMacs. + (Thanks to Sebastion Strollo.)</p> + <p>Own Id: OTP-5967</p> + </item> + <item> + <p>pthread header and library mismatch on linux systems (at + least some SuSE and Debian) with both NPTL and + Linuxthreads libraries installed.</p> + <p>Own Id: OTP-5981</p> + </item> + </list> + </section> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>Support for a C node to connect to an Erlang node on a + standalone host has been added.</p> + <p>Own Id: OTP-5883 Aux Id: seq10170 </p> + </item> + </list> + </section> + </section> + + <section> + <title>Erl_interface 3.5.2</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>A configuration test error caused erl_interface to be + built without support for threads. This has been + corrected.</p> + <p>Own Id: OTP-5456</p> + </item> + </list> + </section> + </section> + + <section> + <title>Erl_interface 3.5.1</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>Changes and improvements have been made to the build and + test environment to solve problems with failing + erl_interface test cases.</p> + <p>Own Id: OTP-5295 Aux Id: OTP-5387 </p> + </item> + </list> + </section> + </section> + + <section> + <title>Erl_interface 3.5</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>Process identifiers and port identifiers have been + made more unique. Previously 18 bits were used as id in + the internal representation of process and port + identifiers. Now 28 bits are used. </p> + <p>The maximum + limit on the number of concurrently existing processes + due to the representation of pids has been increased to + 268435456 processes. The same is true for ports. This + limit will at least on a 32-bit architecture be + impossible to reach due to memory shortage. </p> + <p><em>NOTE:</em> By default, the <c><![CDATA[ERTS]]></c>, and the + <c><![CDATA[erl_interface]]></c>, <c><![CDATA[ei]]></c>, and <c><![CDATA[jinterface]]></c> + libraries are now only guaranteed to be compatible with + other Erlang/OTP components from the same release. It is + possible to set each component in compatibility mode of + an earlier release, though. See the documentation for + respective component on how to set it in compatibility + mode. </p> + <p>*** POTENTIAL INCOMPATIBILITY ***</p> + <p>Own Id: OTP-4968 Aux Id: OTP-4196 </p> + </item> + </list> + </section> + </section> + + <section> + <title>Erl_interface 3.4.5</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>Corrections for mistakes done for patch erl_605/OTP-4874.</p> + <p>Own Id: OTP-4995 Aux Id: OTP-4874 </p> + </item> + </list> + </section> + </section> + + <section> + <title>Erl_interface 3.4.4</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>A small optimization in ei_rpc*() was added and a bug in + ei_decode_longlong() was corrected.</p> + <p>Own Id: OTP-4784</p> + </item> + </list> + </section> + </section> + + <section> + <title>Erl_interface 3.4.2</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>Strings longer than 65535 bytes were encoded wrong in + ei/erl_interface.</p> + <p>Own Id: OTP-4865 Aux Id: EABln07451 </p> + </item> + </list> + </section> + </section> + + <section> + <title>Erl_interface 3.4.1</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>erl_call -a parsed erlang terms incorrectly due to a bug + in ei_format, which is now corrected.</p> + <p>Own Id: OTP-4777 Aux Id: seq8099 </p> + </item> + </list> + </section> + </section> +</chapter> + diff --git a/lib/erl_interface/doc/src/notes_history.xml b/lib/erl_interface/doc/src/notes_history.xml new file mode 100644 index 0000000000..f484f3c04e --- /dev/null +++ b/lib/erl_interface/doc/src/notes_history.xml @@ -0,0 +1,367 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2006</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Erl_Interface Release Notes History</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + + <section> + <title>Erl_Interface 3.4</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p><c><![CDATA[erl_print_term()]]></c> and <c><![CDATA[erl_copy_term()]]></c> could not + previously handle uints. This bug has now been fixed.</p> + <p>Own Id: OTP-4061 Aux Id: seq7079</p> + </item> + <item> + <p><c><![CDATA[ei_x_format()]]></c> was not working correctly for floating + point arguments on some platforms. This is now corrected.</p> + <p>Own Id: OTP-4379</p> + </item> + <item> + <p><c><![CDATA[erl_compare_ext()]]></c> did not compare the node parts of + pids, ports, and references. This has now been fixed. + Comparison between two pids, ports, or references does now + conform to the Erlang specification.</p> + <p>Own Id: OTP-4512 Aux Id: OTP-4511</p> + </item> + </list> + </section> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>Erl_Interface and EI now supports 64 bit architectures.</p> + <p>Own Id: OTP-4772</p> + </item> + <item> + <p>There are new functions that support the GCC and Visual + C++ 64 bit extended integer types.</p> + <code type="none"><![CDATA[ +int ei_decode_longlong(const char *buf, int *index, EI_LONGLONG *p); +int ei_decode_ulonglong(const char *buf, int *index, EI_ULONGLONG *p); +int ei_encode_longlong(char *buf, int *index, EI_LONGLONG p); +int ei_encode_ulonglong(char *buf, int *index, EI_ULONGLONG p); +int ei_x_encode_longlong(ei_x_buff* x, EI_LONGLONG n); +int ei_x_encode_ulonglong(ei_x_buff* x, EI_ULONGLONG n); + ]]></code> + <p>Own Id: OTP-4772</p> + </item> + <item> + <p>If you compile the library from source you can use the ei + library together with GMP, the GNU multi precision + library, to convert integers larger than 64 bits from and + to the external format.</p> + <code type="none"><![CDATA[ +int ei_decode_bignum(const char *buf, int *index, mpz_t obj); +int ei_encode_bignum(char *buf, int *index, mpz_t obj); +int ei_x_encode_bignum(ei_x_buff *x, mpz_t obj); + ]]></code> + <p>Own Id: OTP-4772</p> + </item> + <item> + <p>Some general code improvements where done like correcting + buffer sizes, added more error checking etc.</p> + <p>Own Id: OTP-4772</p> + </item> + <item> + <p>In order to conform to the Erlang specification, + comparison between two pids was changed in the R9B + release. This change did however break a deadlock + prevention algorithm used by Mnesia during release + upgrade. Therefore, comparison between two pids has been + changed back so that R9B nodes are compatible with Erlang + nodes running pre-R9 releases.</p> + <p>Pre-R9 comparison between two pids which now is used + again: If t1 and t2 are both pids, t1 will precede t2 if + and only if either</p> + <list type="bulleted"> + <item>the node local id of t1 precedes the node local id + of t2, or</item> + <item>the node local ids of t1 and t2 are equal, and + node(t1) precedes node(t2), or</item> + <item>the node local ids of t1 and t2 are equal, and also + node(t1) and node(t2) are equal, and node(t1) was + created before node(t2).</item> + </list> + <p>The node local id consist of two integers; serial which + is most significant, and number.</p> + <p>The Erlang specification states: If t1 and t2 are both + refs, both PIDs, or both ports, then t1 precedes t2 if + and only if either</p> + <list type="bulleted"> + <item>node(t1) precedes node(t2), or</item> + <item>node(t1) equals node(t2) and t1 was created before + t2.</item> + </list> + <p>Note that comparisons between two refs, or two ports will + still conform to the Erlang specification.</p> + <p>*** POTENTIAL INCOMPATIBILITY ***</p> + <p>Own Id: OTP-4715 Aux Id: OTP-4511, OTP-4512</p> + </item> + </list> + </section> + </section> + + <section> + <title>ErlInterface 3.3</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>Erl_Interface has been rewritten extensively. The library + <c><![CDATA[ei]]></c> is now documented and supported. The old + <c><![CDATA[erl_interface]]></c> is considered obsolete, and provided + only for backward compatibility.</p> + </item> + <item> + <p>Erl_Interface is now thread-safe, and multiple C-nodes may + run from the same process.</p> + </item> + <item> + <p>New functions are added for connecting and accepting + connections from <c><![CDATA[ei]]></c>; these are documented in + <c><![CDATA[ei_connect]]></c>.</p> + </item> + <item> + <p>New functions are added for converting to and from Erlang + binary format; these are documented in <c><![CDATA[ei]]></c>.</p> + </item> + </list> + </section> + </section> + + <section> + <title>Erl_Interface 3.2.9</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>Changed back the return values from <c><![CDATA[erl_send()]]></c> and + <c><![CDATA[erl_reg_send()]]></c> to 1 (as they used to be). + Incompatible with plain R7, compatible with previous + versions.</p> + <p>*** INCOMPATIBILITY with R7B ***</p> + <p>Own Id: OTP-3772</p> + </item> + <item> + <p>A race-condition bug in the term allocation routines was + corrected.</p> + <p>Own Id: OTP-3809</p> + </item> + <item> + <p>Erl_Interface could not be linked with pthreads.</p> + <p>Own Id: OTP-3810 Aux Id: Seq 5032</p> + </item> + <item> + <p>The TCB of VxWorks processes no longer grows when + <c><![CDATA[erl_errno]]></c> is accessed. On Pthreads platforms + the use of <c><![CDATA[erl_errno]]></c> no longer crashes programs + using multithreading.</p> + <p>Own Id: OTP-3820</p> + </item> + <item> + <p>Name clashes between Erlang emulator and Erl_Interface + on VxWorks removed.</p> + <p>Own Id: OTP-3824</p> + </item> + </list> + </section> + </section> + + <section> + <title>Erl_Interface 3.2.3</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>Memory lossage affecting pids, ports and refs fixed.</p> + </item> + </list> + </section> + </section> + + <section> + <title>Erl_Interface 3.2.2</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>An error reporting facility <c><![CDATA[erl_errno]]></c> has been + introduced.</p> + <p>Own Id: OTP-3641</p> + </item> + <item> + <p>ETERMs are now shrunk to a more reasonable size.</p> + <p>Own Id: OTP-3648</p> + <p></p> + </item> + </list> + </section> + </section> + + <section> + <title>Erl_Interface 3.2.1</title> + + <section> + <title>Fixed Errors and Malfunctions</title> + <list type="bulleted"> + <item> + <p>Lists containing negative numbers were incorrectly + encoded by <c><![CDATA[erl_encode()]]></c>. This has been corrected.</p> + <p>Own Id: OTP-3535</p> + </item> + </list> + </section> + </section> + + <section> + <title>Erl_Interface 3.2</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>The reference type has been extended from 18 bits to + 82 bits. For compatibility with older nodes, an R6 node + can send a ref to an older node; if the older node sends + it back, it has lost all but its 18 least significant + bits, but still compares equal to the original ref. + The external format has been extended to represent the new + longer refs; that means for example that binaries with + refs, produced on an R6 node, cannot be converted to a + term on an older node. + In <c><![CDATA[erl_interface]]></c>, a function <c><![CDATA[erl_mk_long_ref]]></c> + has been added, and macros <c><![CDATA[ERL_REF_NUMBERS]]></c> and + <c><![CDATA[ERL_REF_LEN]]></c>.</p> + <p>*** POTENTIAL INCOMPATIBILITY ***</p> + <p>Own Id: OTP-3140 Aux Id: OTP-3139</p> + </item> + <item> + <p>The function <c><![CDATA[erl_receive_msg]]></c> has the problem that + a fixed buffer must be given - a larger message than + expected is simply discarded. A function + <c><![CDATA[erl_xreceive_msg]]></c> has been introduced, which + dynamically resizes the buffer given to it, if needed.</p> + <p>Own Id: OTP-3313 Aux Id: OTP-2927</p> + </item> + </list> + </section> + </section> + + <section> + <title>Erl_Interface 3.1.1</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p><c><![CDATA[#ifdef __cplusplus extern C {]]></c> is added to all the + <c><![CDATA[erl*.h]]></c> and <c><![CDATA[ei*.h]]></c> files in order to support + use from C++.</p> + <p>On Unix the object files are now produced with + the <c><![CDATA[-fPIC]]></c> option to make it possible to include + them in a shared library.</p> + <p>Own Id: OTP-3138 Aux Id: Seq 1722</p> + </item> + </list> + </section> + </section> + + <section> + <title>Erl_Interface 3.1</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>A buffer overflow in <c><![CDATA[erl_connect()]]></c> was causing + C-node crashes on Linux.</p> + <p>Own Id: OTP-2743</p> + </item> + <item> + <p>When decoding very long strings (more than 65535 + characters) the terminating 0 was left out.</p> + <p>Own Id: OTP-2744</p> + </item> + <item> + <p><c><![CDATA[erl_accept()]]></c> was not handshaking properly with + Erlang, causing incoming connection attempts to fail.</p> + <p>Own Id: OTP-2862</p> + </item> + <item> + <p>Very large negative numbers are no longer encoded + incorrectly.</p> + <p>Own Id: OTP-2897</p> + </item> + <item> + <p>Atoms could sometimes contain an unterminated string. + This is fixed.</p> + <p>Own Id: OTP-2956</p> + </item> + <item> + <p>Erl_Interface now uses the SENS resolver functions if + they are available at runtime. This primarily concerns + use on the VxWorks platform.</p> + <p>Own Id: OTP-3034 Aux Id: Seq 1559</p> + </item> + <item> + <p>The documentation for <c><![CDATA[erl_connect_init()]]></c> no longer + makes erroneous reference to the remote node.</p> + <p>Own Id: OTP-3102 Aux Id: Seq 1671</p> + </item> + </list> + </section> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>Erl_Interface has been moved out of the Erlang runtime + system (ERTS) and is now a separate application. This has + implications for all users of Erl_Interface, who will + need to make changes to the Makefiles used to build + applications based on Erl_Interface. In particular, + header and library files are no longer in + <c><![CDATA[$(OTPROOT)/usr/]]></c>. The <c><![CDATA[include]]></c> and <c><![CDATA[lib]]></c> + directories are now located in the directory + <c><![CDATA[$(OTPROOT)/lib/erl_interface-3.1]]></c> (i.e. + the directory name is now version specific).</p> + <p>Own Id: OTP-3082</p> + </item> + </list> + </section> + </section> +</chapter> + diff --git a/lib/erl_interface/doc/src/part.xml b/lib/erl_interface/doc/src/part.xml new file mode 100644 index 0000000000..e38b9164b8 --- /dev/null +++ b/lib/erl_interface/doc/src/part.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE part SYSTEM "part.dtd"> + +<part xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>2002</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>EI User's Guide</title> + <prepared>Gordon Beaton</prepared> + <docno></docno> + <date>1998-11-30</date> + <rev>1.2</rev> + <file>part.xml</file> + </header> + <xi:include href="ei_users_guide.xml"/> +</part> + diff --git a/lib/erl_interface/doc/src/part_erl_interface.xml b/lib/erl_interface/doc/src/part_erl_interface.xml new file mode 100644 index 0000000000..c69cc85c63 --- /dev/null +++ b/lib/erl_interface/doc/src/part_erl_interface.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE part SYSTEM "part.dtd"> + +<part xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Erl_Interface User's Guide</title> + <prepared>Gordon Beaton</prepared> + <docno></docno> + <date>1998-11-30</date> + <rev>1.2</rev> + <file>part_erl_interface.sgml</file> + </header> + <xi:include href="erl_interface.xml"/> +</part> + diff --git a/lib/erl_interface/doc/src/part_notes.xml b/lib/erl_interface/doc/src/part_notes.xml new file mode 100644 index 0000000000..14c1de1d6e --- /dev/null +++ b/lib/erl_interface/doc/src/part_notes.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE part SYSTEM "part.dtd"> + +<part xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>2004</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Erl_Interface Release Notes</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <description> + <p><em>Erl_Interface</em> is a C interface library for communication + with Erlang.</p> + <p>For information about older versions, see + <url href="part_notes_history_frame.html">Release Notes History</url>.</p> + </description> + <xi:include href="notes.xml"/> +</part> + diff --git a/lib/erl_interface/doc/src/part_notes_history.xml b/lib/erl_interface/doc/src/part_notes_history.xml new file mode 100644 index 0000000000..612b4a9e1e --- /dev/null +++ b/lib/erl_interface/doc/src/part_notes_history.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE part SYSTEM "part.dtd"> + +<part xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>2006</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Erl_Interface Release Notes History</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <description> + <p><em>Erl_Interface</em> is a C interface library for communication + with Erlang.</p> + </description> + <xi:include href="notes_history.xml"/> +</part> + diff --git a/lib/erl_interface/doc/src/ref_man.xml b/lib/erl_interface/doc/src/ref_man.xml new file mode 100644 index 0000000000..9ae4cf27f5 --- /dev/null +++ b/lib/erl_interface/doc/src/ref_man.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE application SYSTEM "application.dtd"> + +<application xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>1998</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + <title>Erl_Interface Command Reference</title> + <prepared>Gordon Beaton</prepared> + <docno></docno> + <date>1998-11.30</date> + <rev>1.2</rev> + <file>ref_man.xml</file> + </header> + <description> + <p>The <c>ei</c> and <c>erl_interface</c> are <c>C</c> interface libraries for + communication with <c>Erlang</c>.</p> + <note> + <p>By default, the <c>ei</c> and <c>erl_interface</c> libraries are only guaranteed + to be compatible with other Erlang/OTP components from the same + release as the libraries themself. See the documentation of the + <seealso marker="ei#ei_set_compat_rel">ei_set_compat_rel()</seealso> and + <seealso marker="erl_eterm#erl_set_compat_rel">erl_set_compat_rel()</seealso> + functions on how to communicate with Erlang/OTP components from earlier + releases.</p> + </note> + </description> + <xi:include href="ei.xml"/> + <xi:include href="ei_connect.xml"/> + <xi:include href="registry.xml"/> + <xi:include href="erl_connect.xml"/> + <xi:include href="erl_error.xml"/> + <xi:include href="erl_eterm.xml"/> + <xi:include href="erl_format.xml"/> + <xi:include href="erl_global.xml"/> + <xi:include href="erl_malloc.xml"/> + <xi:include href="erl_marshal.xml"/> + <xi:include href="erl_call.xml"/> +</application> + diff --git a/lib/erl_interface/doc/src/ref_man_ei.xml b/lib/erl_interface/doc/src/ref_man_ei.xml new file mode 100644 index 0000000000..ff161f9e7f --- /dev/null +++ b/lib/erl_interface/doc/src/ref_man_ei.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE application SYSTEM "application.dtd"> + +<application xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>2002</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>EI Library Reference</title> + <prepared>Gordon Beaton</prepared> + <docno></docno> + <date>1998-11-30</date> + <rev>1.2</rev> + <file>ref_man_ei.xml</file> + </header> + <description> + <p>The <c><![CDATA[ei]]></c> library is a <c><![CDATA[C]]></c> interface library for + communication with <c><![CDATA[Erlang]]></c>.</p> + <note> + <p>By default, the <c><![CDATA[ei]]></c> library is only guaranteed + to be compatible with other Erlang/OTP components from the same + release as the <c><![CDATA[ei]]></c> library itself. See the documentation of the + <seealso marker="ei#ei_set_compat_rel">ei_set_compat_rel()</seealso> + function on how to communicate with Erlang/OTP components from earlier + releases.</p> + </note> + </description> + <xi:include href="ei.xml"/> + <xi:include href="ei_connect.xml"/> + <xi:include href="registry.xml"/> +</application> + diff --git a/lib/erl_interface/doc/src/ref_man_erl_interface.xml b/lib/erl_interface/doc/src/ref_man_erl_interface.xml new file mode 100644 index 0000000000..7ffa0cfb23 --- /dev/null +++ b/lib/erl_interface/doc/src/ref_man_erl_interface.xml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE application SYSTEM "application.dtd"> + +<application xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Erl_Interface Library Reference</title> + <prepared>Gordon Beaton</prepared> + <docno></docno> + <date>1998-11-30</date> + <rev>1.2</rev> + <file>ref_man_erl_interface.xml</file> + </header> + <description> + <p>The <c>erl_interface</c> library is a <c>C</c> interface library + for communication with <c>Erlang</c>.</p> + <note> + <p>By default, the <c>erl_interface</c> library is only guaranteed + to be compatible with other Erlang/OTP components from the same + release as the <c>erl_interface</c> library. See the documentation + of the + <seealso marker="erl_eterm#erl_set_compat_rel">erl_set_compat_rel()</seealso> + function on how to communicate with Erlang/OTP components from earlier + releases.</p> + </note> + </description> + <xi:include href="erl_connect.xml"/> + <xi:include href="erl_error.xml"/> + <xi:include href="erl_eterm.xml"/> + <xi:include href="erl_format.xml"/> + <xi:include href="erl_global.xml"/> + <xi:include href="erl_malloc.xml"/> + <xi:include href="erl_marshal.xml"/> +</application> + diff --git a/lib/erl_interface/doc/src/registry.xml b/lib/erl_interface/doc/src/registry.xml new file mode 100644 index 0000000000..8aeb378d95 --- /dev/null +++ b/lib/erl_interface/doc/src/registry.xml @@ -0,0 +1,611 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE cref SYSTEM "cref.dtd"> + +<cref> + <header> + <copyright> + <year>1998</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>registry</title> + <prepared>Gordon Beaton</prepared> + <responsible>Gordon Beaton</responsible> + <docno></docno> + <approved>Gordon Beaton</approved> + <checked>Gordon Beaton</checked> + <date>980707</date> + <rev>A</rev> + <file>registry.sgml</file> + </header> + <lib>registry</lib> + <libsummary>Store and backup key-value pairs</libsummary> + <description> + <p>This module provides support for storing key-value + pairs in a table known as a registry, backing up registries to + Mnesia in an atomic manner, and later restoring the contents of a + registry from Mnesia.</p> + </description> + <funcs> + <func> + <name><ret>ei_reg *</ret><nametext>ei_reg_open(size)</nametext></name> + <fsummary>Create and open a registry</fsummary> + <type> + <v>int size;</v> + </type> + <desc> + <p>Open (create) a registry. The registry will be + initially empty. Use <c><![CDATA[ei_reg_close()]]></c> to close the registry + later. + </p> + <p><c><![CDATA[size]]></c> is the approximate number of objects you intend + to store in the registry. Since the registry uses a hash table + with collision chaining, there is no absolute upper limit on the + number of objects that can be stored in it. However for reasons + of efficiency, it is a good idea to choose a number that is + appropriate for your needs. It is possible to use + <c><![CDATA[ei_reg_resize()]]></c> to change the size later. Note that the + number you provide will be increased to the nearest larger prime + number. + </p> + <p>On success, an empty registry will be returned. On failure, NULL + will be returned.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_reg_resize(reg,newsize)</nametext></name> + <fsummary>Resize a registry</fsummary> + <type> + <v>ei_reg *reg;</v> + <v>int newsize;</v> + </type> + <desc> + <p>Change the size of a registry. + </p> + <p><c><![CDATA[newsize]]></c> is the new size to make the registry. The + number will be increased to the nearest larger prime number. + </p> + <p>On success, the registry will be resized, all contents + rehashed, and the function will return 0. On failure, the + registry will be left unchanged and the function will return -1.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_reg_close(reg)</nametext></name> + <fsummary>Close a registry </fsummary> + <type> + <v>ei_reg *reg;</v> + </type> + <desc> + <p>A registry that has previously been created with + <c><![CDATA[ei_reg_open()]]></c> is closed, and all the objects it contains + are freed. + </p> + <p><c><![CDATA[reg]]></c> is the registry to close. + </p> + <p>The function returns 0.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_reg_setival(reg,key,i)</nametext></name> + <fsummary>Assign an integer object</fsummary> + <type> + <v>ei_reg *reg;</v> + <v>const char *key;</v> + <v>int i;</v> + </type> + <desc> + <p>Create a key-value pair with the specified <c><![CDATA[key]]></c> and integer + value <c><![CDATA[i]]></c>. If an object already existed with the same + <c><![CDATA[key]]></c>, the new value replaces the old one. If the previous + value was a binary or string, it is freed with <c><![CDATA[free()]]></c>. + </p> + <p><c><![CDATA[reg]]></c> is the registry where the object should be placed. + </p> + <p><c><![CDATA[key]]></c> is the name of the object. + </p> + <p><c><![CDATA[i]]></c> is the integer value to assign. + </p> + <p>The function returns 0 on success, or -1 on failure.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_reg_setfval(reg,key,f)</nametext></name> + <fsummary>Assign a floating point object</fsummary> + <type> + <v>ei_reg *reg;</v> + <v>const char *key;</v> + <v>double f;</v> + </type> + <desc> + <p>Create a key-value pair with the specified <c><![CDATA[key]]></c> and + floating point value <c><![CDATA[f]]></c>. If an object already existed with + the same <c><![CDATA[key]]></c>, the new value replaces the old one. If the + previous value was a binary or string, it is freed with <c><![CDATA[free()]]></c>. + </p> + <p><c><![CDATA[reg]]></c> is the registry where the object should be placed. + </p> + <p><c><![CDATA[key]]></c> is the name of the object. + </p> + <p><c><![CDATA[f]]></c> is the floating point value to assign. + </p> + <p>The function returns 0 on success, or -1 on failure.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_reg_setsval(reg,key,s)</nametext></name> + <fsummary>Assign a string object</fsummary> + <type> + <v>ei_reg *reg;</v> + <v>const char *key;</v> + <v>const char *s;</v> + </type> + <desc> + <p>Create a key-value pair with the specified <c><![CDATA[key]]></c> whose + "value" is the specified string <c><![CDATA[s]]></c>. If an object already + existed with the same <c><![CDATA[key]]></c>, the new value replaces the old + one. If the previous value was a binary or string, it is freed + with <c><![CDATA[free()]]></c>. + </p> + <p><c><![CDATA[reg]]></c> is the registry where the object should be placed. + </p> + <p><c><![CDATA[key]]></c> is the name of the object. + </p> + <p><c><![CDATA[s]]></c> is the string to assign. The string itself + must have been created through a single call to <c><![CDATA[malloc()]]></c> or + similar function, so that the registry can later delete it if + necessary by calling <c><![CDATA[free()]]></c>. + </p> + <p>The function returns 0 on success, or -1 on failure.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_reg_setpval(reg,key,p,size)</nametext></name> + <fsummary>Assign a binary object</fsummary> + <type> + <v>ei_reg *reg;</v> + <v>const char *key;</v> + <v>const void *p;</v> + <v>int size;</v> + </type> + <desc> + <p>Create a key-value pair with the specified <c><![CDATA[key]]></c> whose + "value" is the binary object pointed to by <c><![CDATA[p]]></c>. If an + object already existed with the same <c><![CDATA[key]]></c>, the new value + replaces the old one. If the previous value was a binary or + string, it is freed with <c><![CDATA[free()]]></c>. + </p> + <p><c><![CDATA[reg]]></c> is the registry where the object should be placed. + </p> + <p><c><![CDATA[key]]></c> is the name of the object. + </p> + <p><c><![CDATA[p]]></c> is a pointer to the binary object. The object itself + must have been created through a single call to <c><![CDATA[malloc()]]></c> or + similar function, so that the registry can later delete it if + necessary by calling <c><![CDATA[free()]]></c>. + </p> + <p><c><![CDATA[size]]></c> is the length in bytes of the binary object. + </p> + <p>The function returns 0 on success, or -1 on failure.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_reg_setval(reg,key,flags,v,...)</nametext></name> + <fsummary>Assign a value to any object type</fsummary> + <type> + <v>ei_reg *reg;</v> + <v>const char *key;</v> + <v>int flags;</v> + <v>v (see below)</v> + </type> + <desc> + <p>Create a key-value pair with the specified <c><![CDATA[key]]></c> whose + value is specified by <c><![CDATA[v]]></c>. If an object already + existed with the same <c><![CDATA[key]]></c>, the new value replaces the old + one. If the previous value was a binary or string, it is freed + with <c><![CDATA[free()]]></c>. + </p> + <p><c><![CDATA[reg]]></c> is the registry where the object should be placed. + </p> + <p><c><![CDATA[key]]></c> is the name of the object. + </p> + <p><c><![CDATA[flags]]></c> indicates the type of the object specified by + <c><![CDATA[v]]></c>. Flags must be one of EI_INT, EI_FLT, EI_STR and + EI_BIN, indicating whether <c><![CDATA[v]]></c> is <c><![CDATA[int]]></c>, <c><![CDATA[double]]></c>, + <c><![CDATA[char*]]></c> or <c><![CDATA[void*]]></c>. If <c><![CDATA[flags]]></c> is EI_BIN, then a + fifth argument <c><![CDATA[size]]></c> is required, indicating the size + in bytes of the object pointed to by <c><![CDATA[v]]></c>. + </p> + <p>If you wish to store an arbitrary pointer in the registry, + specify a <c><![CDATA[size]]></c> of 0. In this case, the object itself will + not be transferred by an <c><![CDATA[ei_reg_dump()]]></c> operation, just + the pointer value. + </p> + <p>The function returns 0 on success, or -1 on failure.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_reg_getival(reg,key)</nametext></name> + <fsummary>Get an integer object</fsummary> + <type> + <v>ei_reg *reg;</v> + <v>const char *key;</v> + </type> + <desc> + <p>Get the value associated with <c><![CDATA[key]]></c> in the + registry. The value must be an integer. + </p> + <p><c><![CDATA[reg]]></c> is the registry where the object will be looked + up. + </p> + <p><c><![CDATA[key]]></c> is the name of the object to look up. + </p> + <p>On success, the function returns the value associated with <c><![CDATA[key]]></c>. + If the object was not found or it was not an integer + object, -1 is returned. To avoid problems with in-band error + reporting (i.e. if you cannot distinguish between -1 and a + valid result) use the more general function <c><![CDATA[ei_reg_getval()]]></c> + instead.</p> + </desc> + </func> + <func> + <name><ret>double</ret><nametext>ei_reg_getfval(reg,key)</nametext></name> + <fsummary>Get a floating point object</fsummary> + <type> + <v>ei_reg *reg;</v> + <v>const char *key;</v> + </type> + <desc> + <p>Get the value associated with <c><![CDATA[key]]></c> in the + registry. The value must be a floating point type. + </p> + <p><c><![CDATA[reg]]></c> is the registry where the object will be looked + up. + </p> + <p><c><![CDATA[key]]></c> is the name of the object to look up. + </p> + <p>On success, the function returns the value associated with <c><![CDATA[key]]></c>. + If the object was not found or it was not a floating point + object, -1.0 is returned. To avoid problems with in-band error + reporting (i.e. if you cannot distinguish between -1.0 and a + valid result) use the more general function <c><![CDATA[ei_reg_getval()]]></c> + instead.</p> + </desc> + </func> + <func> + <name><ret>const char *</ret><nametext>ei_reg_getsval(reg,key)</nametext></name> + <fsummary>Get a string object</fsummary> + <type> + <v>ei_reg *reg;</v> + <v>const char *key;</v> + </type> + <desc> + <p>Get the value associated with <c><![CDATA[key]]></c> in the + registry. The value must be a string. + </p> + <p><c><![CDATA[reg]]></c> is the registry where the object will be looked + up. + </p> + <p><c><![CDATA[key]]></c> is the name of the object to look up. + </p> + <p>On success, the function returns the value associated with + <c><![CDATA[key]]></c>. If the object was not found or it was not a string, + NULL is returned. To avoid problems with in-band error + reporting (i.e. if you cannot distinguish between NULL and a + valid result) use the more general function <c><![CDATA[ei_reg_getval()]]></c> + instead.</p> + </desc> + </func> + <func> + <name><ret>const void *</ret><nametext>ei_reg_getpval(reg,key,size)</nametext></name> + <fsummary>Get a binary object</fsummary> + <type> + <v>ei_reg *reg;</v> + <v>const char *key;</v> + <v>int size;</v> + </type> + <desc> + <p>Get the value associated with <c><![CDATA[key]]></c> in the + registry. The value must be a binary (pointer) type. + </p> + <p><c><![CDATA[reg]]></c> is the registry where the object will be looked + up. + </p> + <p><c><![CDATA[key]]></c> is the name of the object to look up. + </p> + <p><c><![CDATA[size]]></c> will be initialized to contain the length in + bytes of the object, if it is found. + </p> + <p>On success, the function returns the value associated with + <c><![CDATA[key]]></c> and indicates its length in <c><![CDATA[size]]></c>. + If the object was not found or it was not a binary object, + NULL is returned. To avoid problems with in-band error + reporting (i.e. if you cannot distinguish between NULL and a + valid result) use the more general function <c><![CDATA[ei_reg_getval()]]></c> + instead.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_reg_getval(reg,key,flags,v,...)</nametext></name> + <fsummary>Get any object</fsummary> + <type> + <v>ei_reg *reg;</v> + <v>const char *key;</v> + <v>int flags;</v> + <v>void *v (see below)</v> + </type> + <desc> + <p>This is a general function for retrieving any kind of + object from the registry. + </p> + <p><c><![CDATA[reg]]></c> is the registry where the object will be looked + up. + </p> + <p><c><![CDATA[key]]></c> is the name of the object to look up. + </p> + <p><c><![CDATA[flags]]></c> indicates the type of object that you are + looking for. If <c><![CDATA[flags]]></c> is 0, then any kind of object will + be returned. If <c><![CDATA[flags]]></c> is one of EI_INT, EI_FLT, EI_STR or + EI_BIN, then only values of that kind will be returned. The + buffer pointed to by <c><![CDATA[v]]></c> must be large enough to hold the return + data, i.e. it must be a pointer to one of <c><![CDATA[int]]></c>, + <c><![CDATA[double]]></c>, <c><![CDATA[char*]]></c> or <c><![CDATA[void*]]></c>, respectively. Also, + if <c><![CDATA[flags]]></c> is EI_BIN, then a fifth argument <c><![CDATA[int *size]]></c> is required, so that the size of the object can be + returned. + </p> + <p>If the function succeeds, <c><![CDATA[v]]></c> (and <c><![CDATA[size]]></c> if the + object is binary) will be initialized with the value associated + with <c><![CDATA[key]]></c>, and the function will return one of EI_INT, + EI_FLT, EI_STR or EI_BIN, indicating the type of object. On failure the + function will return -1 and the arguments will not be updated.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_reg_markdirty(reg,key)</nametext></name> + <fsummary>Mark an object as dirty </fsummary> + <type> + <v>ei_reg *reg;</v> + <v>const char *key;</v> + </type> + <desc> + <p>Mark a registry object as dirty. This will ensure that + it is included in the next backup to Mnesia. Normally this + operation will not be necessary since all of the normal registry + 'set' functions do this automatically. However if you have + retrieved the value of a string or binary object from the + registry and modified the contents, then the change will be + invisible to the registry and the object will be assumed to be + unmodified. This function allows you to make such modifications + and then let the registry know about them. + </p> + <p><c><![CDATA[reg]]></c> is the registry containing the object. + </p> + <p><c><![CDATA[key]]></c> is the name of the object to mark. + </p> + <p>The function returns 0 on success, or -1 on failure.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_reg_delete(reg,key)</nametext></name> + <fsummary>Delete an object from the registry</fsummary> + <type> + <v>ei_reg *reg;</v> + <v>const char *key;</v> + </type> + <desc> + <p>Delete an object from the registry. The object is not + actually removed from the registry, it is only marked for later + removal so that on subsequent backups to Mnesia, the + corresponding object can be removed from the Mnesia table as + well. If another object is later created with the same key, the + object will be reused. + </p> + <p>The object will be removed from the registry after a call to + <c><![CDATA[ei_reg_dump()]]></c> or <c><![CDATA[ei_reg_purge()]]></c>. + </p> + <p><c><![CDATA[reg]]></c> is the registry containing <c><![CDATA[key]]></c>. + </p> + <p><c><![CDATA[key]]></c> is the object to remove. + </p> + <p>If the object was found, the function returns 0 indicating + success. Otherwise the function returns -1.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_reg_stat(reg,key,obuf)</nametext></name> + <fsummary>Get object information</fsummary> + <type> + <v>ei_reg *reg;</v> + <v>const char *key;</v> + <v>struct ei_reg_stat *obuf;</v> + </type> + <desc> + <p>Return information about an object. + </p> + <p><c><![CDATA[reg]]></c> is the registry containing the object. + </p> + <p><c><![CDATA[key]]></c> is the name of the object. + </p> + <p><c><![CDATA[obuf]]></c> is a pointer to an <c><![CDATA[ei_reg_stat]]></c> structure, + defined below: + </p> + <code type="none"><![CDATA[ +struct ei_reg_stat { + int attr; + int size; +}; + ]]></code> + <p>In <c><![CDATA[attr]]></c> the object's attributes are stored as the logical + OR of its type (one of EI_INT, EI_FLT, EI_BIN and EI_STR), + whether it is marked for deletion (EI_DELET) and whether it has + been modified since the last backup to Mnesia (EI_DIRTY). + </p> + <p>The <c><![CDATA[size]]></c> field indicates the size in bytes required to store + EI_STR (including the terminating 0) and EI_BIN objects, or 0 + for EI_INT and EI_FLT. + </p> + <p>The function returns 0 and initializes <c><![CDATA[obuf]]></c> on + success, or returns -1 on failure.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_reg_tabstat(reg,obuf)</nametext></name> + <fsummary>Get registry information</fsummary> + <type> + <v>ei_reg *reg;</v> + <v>struct ei_reg_tabstat *obuf;</v> + </type> + <desc> + <p>Return information about a registry. Using information + returned by this function, you can see whether the size of the + registry is suitable for the amount of data it contains. + </p> + <p><c><![CDATA[reg]]></c> is the registry to return information about. + </p> + <p><c><![CDATA[obuf]]></c> is a pointer to an <c><![CDATA[ei_reg_tabstat]]></c> structure, + defined below: + </p> + <code type="none"><![CDATA[ +struct ei_reg_tabstat { + int size; + int nelem; + int npos; + int collisions; +}; + ]]></code> + <p>The <c><![CDATA[size]]></c> field indicates the number of hash positions + in the registry. This is the number you provided when you + created or last resized the registry, rounded up to the nearest + prime. + </p> + <p><c><![CDATA[nelem]]></c> indicates the number of elements stored in the + registry. It includes objects that are deleted but not purged. + </p> + <p><c><![CDATA[npos]]></c> indicates the number of unique positions that are + occupied in the registry. + </p> + <p><c><![CDATA[collisions]]></c> indicates how many elements are sharing + positions in the registry. + </p> + <p>On success, the function returns 0 and <c><![CDATA[obuf]]></c> is + initialized to contain table statistics. On failure, the function + returns -1.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_reg_dump(fd,reg,mntab,flags)</nametext></name> + <fsummary>Back up a registry to Mnesia</fsummary> + <type> + <v>int fd;</v> + <v>ei_reg *reg;</v> + <v>const char *mntab;</v> + <v>int flags;</v> + </type> + <desc> + <p>Dump the contents of a registry to a Mnesia table in an + atomic manner, i.e. either all data will be updated, or none of + it will. If any errors are encountered while backing up + the data, the entire operation is aborted. + </p> + <p><c><![CDATA[fd]]></c> is an open connection to Erlang. + Mnesia 3.0 or later must be running on the Erlang node. + </p> + <p><c><![CDATA[reg]]></c> is the registry to back up. + </p> + <p><c><![CDATA[mntab]]></c> is the name of the Mnesia table where the backed + up data should be placed. If the table does not exist, it will + be created automatically using configurable defaults. See your + Mnesia documentation for information about configuring this + behaviour. + </p> + <p>If <c><![CDATA[flags]]></c> is 0, the backup will include only those + objects which have been created, modified or deleted since the + last backup or restore (i.e. an incremental backup). After the + backup, any objects that were marked dirty are now clean, and any + objects that had been marked for deletion are deleted. + </p> + <p>Alternatively, setting flags to EI_FORCE will cause a full + backup to be done, and EI_NOPURGE will cause the deleted objects + to be left in the registry afterwards. These can be bitwise ORed + together if both behaviours are desired. If EI_NOPURGE was + specified, you can use <c><![CDATA[ei_reg_purge()]]></c> to explicitly remove + the deleted items from the registry later. + </p> + <p>The function returns 0 on success, or -1 on failure.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_reg_restore(fd,reg,mntab)</nametext></name> + <fsummary>Restore a registry from Mnesia</fsummary> + <type> + <v>int fd;</v> + <v>ei_reg *reg;</v> + <v>const char *mntab;</v> + </type> + <desc> + <p>The contents of a Mnesia table are read into the + registry. + </p> + <p><c><![CDATA[fd]]></c> is an open connection to Erlang. + Mnesia 3.0 or later must be running on the Erlang node. + </p> + <p><c><![CDATA[reg]]></c> is the registry where the data should be placed. + </p> + <p><c><![CDATA[mntab]]></c> is the name of the Mnesia table to read data + from. + </p> + <p>Note that only tables of a certain format can be + restored, i.e. those that have been created and backed up to + with <c><![CDATA[ei_reg_dump()]]></c>. If the registry was not empty before + the operation, then the contents of the table are added to the + contents of the registry. If the table contains objects with the + same keys as those already in the registry, the registry objects + will be overwritten with the new values. If the registry + contains objects that were not in the table, they will be + unchanged by this operation. + </p> + <p>After the restore operation, the entire contents of the + registry is marked as unmodified. Note that this includes any + objects that were modified before the restore and not + overwritten by the restore. + </p> + <p>The function returns 0 on success, or -1 on failure.</p> + </desc> + </func> + <func> + <name><ret>int</ret><nametext>ei_reg_purge(reg)</nametext></name> + <fsummary>Remove deleted objects</fsummary> + <type> + <v>ei_reg *reg;</v> + </type> + <desc> + <p>Remove all objects marked for deletion. When objects + are deleted with <c><![CDATA[ei_reg_delete()]]></c> they are not actually + removed from the registry, only marked for later removal. This + is so that on a subsequent backup to Mnesia, the + objects can also be removed from the Mnesia table. If you are + not backing up to Mnesia then you may wish to remove the objects + manually with this function. + </p> + <p><c><![CDATA[reg]]></c> is a registry containing objects marked for + deletion. + </p> + <p>The function returns 0 on success, or -1 on failure.</p> + </desc> + </func> + </funcs> +</cref> + diff --git a/lib/erl_interface/doc/src/warning.gif b/lib/erl_interface/doc/src/warning.gif Binary files differnew file mode 100644 index 0000000000..96af52360e --- /dev/null +++ b/lib/erl_interface/doc/src/warning.gif diff --git a/lib/erl_interface/include/ei.h b/lib/erl_interface/include/ei.h new file mode 100644 index 0000000000..01272244e1 --- /dev/null +++ b/lib/erl_interface/include/ei.h @@ -0,0 +1,785 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifndef EI_H +#define EI_H + +#define EI_HAVE_TIMEOUT 1 /* Flag to user code that we have them */ +#define USE_EI_UNDOCUMENTED /* Want declarations for undocumented */ + +/************************************************************************/ +/* This file defines the complete interface to ei */ +/************************************************************************/ + +/* -------------------------------------------------------------------- */ +/* Include types needed below */ +/* -------------------------------------------------------------------- */ + +#if defined(__WIN32__) +#include <winsock2.h> +#include <windows.h> +#include <winbase.h> +#endif + +#include <stdio.h> /* Need type FILE */ +#include <errno.h> /* Need EHOSTUNREACH, ENOMEM, ... */ + +#if !defined(__WIN32__) && !defined(VXWORKS) || (defined(VXWORKS) && defined(HAVE_SENS)) +# include <netdb.h> +#endif + + +/* -------------------------------------------------------------------- */ +/* Defines part of API */ +/* -------------------------------------------------------------------- */ + +/* + * Some error codes might be missing, so here's a backstop definitions + * of the ones we use with `erl_errno': + */ + +#ifndef EMSGSIZE /* Message too long */ +#define EMSGSIZE EIO +#endif + +#ifndef ETIMEDOUT /* Connection timed out */ +#define ETIMEDOUT EIO +#endif + +#ifndef EHOSTUNREACH /* No route to host */ +#define EHOSTUNREACH EIO +#endif + +/* FIXME just a few are documented, does it mean they can't be returned? */ + +#define ERL_ERROR -1 /* Error of some kind */ +#define ERL_NO_DAEMON -2 /* No contact with EPMD */ +#define ERL_NO_PORT -3 /* No port received from EPMD */ +#define ERL_CONNECT_FAIL -4 /* Connect to Erlang Node failed */ +#define ERL_TIMEOUT -5 /* A timeout has expired */ +#define ERL_NO_REMOTE -6 /* Cannot execute rsh */ + +#define ERL_TICK 0 +#define ERL_MSG 1 + +#define ERL_NO_TIMEOUT -1 + +/* these are the control message types */ +#define ERL_LINK 1 +#define ERL_SEND 2 +#define ERL_EXIT 3 +#define ERL_UNLINK 4 +#define ERL_NODE_LINK 5 +#define ERL_REG_SEND 6 +#define ERL_GROUP_LEADER 7 +#define ERL_EXIT2 8 +#define ERL_PASS_THROUGH 'p' + +/* new ones for tracing, from Kenneth */ +#define ERL_SEND_TT 12 +#define ERL_EXIT_TT 13 +#define ERL_REG_SEND_TT 16 +#define ERL_EXIT2_TT 18 + + +/* -------------------------------------------------------------------- */ +/* Defines used for ei_get_type_internal() output */ +/* -------------------------------------------------------------------- */ +/* + * these are the term type indicators used in + * the external (distribution) format + */ + +/* FIXME we don't want to export these..... */ + +#define ERL_SMALL_INTEGER_EXT 'a' +#define ERL_INTEGER_EXT 'b' +#define ERL_FLOAT_EXT 'c' +#define ERL_ATOM_EXT 'd' +#define ERL_REFERENCE_EXT 'e' +#define ERL_NEW_REFERENCE_EXT 'r' +#define ERL_PORT_EXT 'f' +#define ERL_PID_EXT 'g' +#define ERL_SMALL_TUPLE_EXT 'h' +#define ERL_LARGE_TUPLE_EXT 'i' +#define ERL_NIL_EXT 'j' +#define ERL_STRING_EXT 'k' +#define ERL_LIST_EXT 'l' +#define ERL_BINARY_EXT 'm' +#define ERL_SMALL_BIG_EXT 'n' +#define ERL_LARGE_BIG_EXT 'o' +#define ERL_NEW_FUN_EXT 'p' +#define ERL_FUN_EXT 'u' + +#define ERL_NEW_CACHE 'N' /* c nodes don't know these two */ +#define ERL_CACHED_ATOM 'C' + + +/* -------------------------------------------------------------------- */ +/* Define the erl_errno macro */ +/* -------------------------------------------------------------------- */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * GCC's attributes are too useful to not use. Other compilers + * just lose opportunities to optimize and warn. + */ +#if !defined(__GNUC__) || __GNUC__ < 2 +# define __attribute__(foo) /* nothing */ +#endif + +/* + * Define the 'erl_errno' facility. Unfortunately this lives on in + * the 'ei' interface as well.... :-( + */ + +#if defined(_REENTRANT) || defined(VXWORKS) || defined(__WIN32__) + +/* 'erl_errno' as a function return value */ +volatile int* __erl_errno_place(void) __attribute__ ((__const__)); + +#define erl_errno (*__erl_errno_place ()) + +#else /* !_REENTRANT && !VXWORKS && !__WIN32__ */ + +extern volatile int __erl_errno; + +#define erl_errno __erl_errno + +#endif /* !_REENTRANT && !VXWORKS && !__WIN32__ */ + + +/* -------------------------------------------------------------------- */ +/* Type definitions */ +/* -------------------------------------------------------------------- */ + +/* + * To avoid confusion about the MAXHOSTNAMELEN when compiling the + * library and when using the library we set a value that we use + */ + +#define EI_MAXHOSTNAMELEN 64 +#define EI_MAXALIVELEN 63 +#define EI_MAX_COOKIE_SIZE 512 +#define MAXATOMLEN 255 +#define MAXNODELEN EI_MAXALIVELEN+1+EI_MAXHOSTNAMELEN + +/* a pid */ +typedef struct { + char node[MAXATOMLEN+1]; + unsigned int num; + unsigned int serial; + unsigned int creation; +} erlang_pid; + +/* a port */ +typedef struct { + char node[MAXATOMLEN+1]; + unsigned int id; + unsigned int creation; +} erlang_port; + +/* a ref */ +typedef struct { + char node[MAXATOMLEN+1]; + int len; + unsigned int n[3]; + unsigned int creation; +} erlang_ref; + +/* a trace token */ +typedef struct { + long serial; + long prev; + erlang_pid from; + long label; + long flags; +} erlang_trace; + +/* a message */ +typedef struct { + long msgtype; + erlang_pid from; + erlang_pid to; + char toname[MAXATOMLEN+1]; + char cookie[MAXATOMLEN+1]; + erlang_trace token; +} erlang_msg; + +/* a fun */ +typedef struct { + long arity; + char module[MAXATOMLEN+1]; + char md5[16]; + long index; + long old_index; + long uniq; + long n_free_vars; + erlang_pid pid; + long free_var_len; + char* free_vars; +} erlang_fun; + +/* a big */ +typedef struct { + unsigned int arity; + int is_neg; + void *digits; +} erlang_big; + +typedef struct { + char ei_type; + int arity; + int size; + union { + long i_val; + double d_val; + char atom_name[MAXATOMLEN+1]; + erlang_pid pid; + erlang_port port; + erlang_ref ref; + } value; +} ei_term; + +/* XXX */ + +typedef struct { + char ipadr[4]; /* stored in network byte order */ + char nodename[MAXNODELEN+1]; +} ErlConnect; + +typedef struct ei_cnode_s { + char thishostname[EI_MAXHOSTNAMELEN+1]; + char thisnodename[MAXNODELEN+1]; + char thisalivename[EI_MAXALIVELEN+1]; +/* Currently this_ipaddr isn't used */ +/* struct in_addr this_ipaddr; */ + char ei_connect_cookie[EI_MAX_COOKIE_SIZE+1]; + short creation; + erlang_pid self; +} ei_cnode; + +typedef struct in_addr *Erl_IpAddr; + + +/* A dynamic version of ei XX */ + +typedef struct ei_x_buff_TAG { + char* buff; + int buffsz; + int index; +} ei_x_buff; + + +/* -------------------------------------------------------------------- */ +/* Function definitions (listed in same order as documentation) */ +/* -------------------------------------------------------------------- */ + +/* Handle the connection */ + +int ei_connect_init(ei_cnode* ec, const char* this_node_name, + const char *cookie, short creation); +int ei_connect_xinit (ei_cnode* ec, const char *thishostname, + const char *thisalivename, const char *thisnodename, + Erl_IpAddr thisipaddr, const char *cookie, + const short creation); + +int ei_connect(ei_cnode* ec, char *nodename); +int ei_connect_tmo(ei_cnode* ec, char *nodename, unsigned ms); +int ei_xconnect(ei_cnode* ec, Erl_IpAddr adr, char *alivename); +int ei_xconnect_tmo(ei_cnode* ec, Erl_IpAddr adr, char *alivename, unsigned ms); + +int ei_receive(int fd, unsigned char *bufp, int bufsize); +int ei_receive_tmo(int fd, unsigned char *bufp, int bufsize, unsigned ms); +int ei_receive_msg(int fd, erlang_msg* msg, ei_x_buff* x); +int ei_receive_msg_tmo(int fd, erlang_msg* msg, ei_x_buff* x, unsigned ms); +int ei_xreceive_msg(int fd, erlang_msg* msg, ei_x_buff* x); +int ei_xreceive_msg_tmo(int fd, erlang_msg* msg, ei_x_buff* x, unsigned ms); + +int ei_send(int fd, erlang_pid* to, char* buf, int len); +int ei_send_tmo(int fd, erlang_pid* to, char* buf, int len, unsigned ms); +int ei_reg_send(ei_cnode* ec, int fd, char *server_name, char* buf, int len); +int ei_reg_send_tmo(ei_cnode* ec, int fd, char *server_name, char* buf, int len, unsigned ms); + +int ei_rpc(ei_cnode* ec, int fd, char *mod, char *fun, + const char* inbuf, int inbuflen, ei_x_buff* x); +int ei_rpc_to(ei_cnode* ec, int fd, char *mod, char *fun, + const char* buf, int len); +int ei_rpc_from(ei_cnode* ec, int fd, int timeout, erlang_msg* msg, + ei_x_buff* x); + +int ei_publish(ei_cnode* ec, int port); +int ei_publish_tmo(ei_cnode* ec, int port, unsigned ms); +int ei_accept(ei_cnode* ec, int lfd, ErlConnect *conp); +int ei_accept_tmo(ei_cnode* ec, int lfd, ErlConnect *conp, unsigned ms); +int ei_unpublish(ei_cnode* ec); +int ei_unpublish_tmo(const char *alive, unsigned ms); + +const char *ei_thisnodename(const ei_cnode* ec); +const char *ei_thishostname(const ei_cnode* ec); +const char *ei_thisalivename(const ei_cnode* ec); + +erlang_pid *ei_self(ei_cnode* ec); + +void ei_set_compat_rel(unsigned rel); + +/* + * We have erl_gethost*() so we include ei versions as well. + */ + +#if defined(VXWORKS) + +extern int h_errno; + +/* + * We need these definitions - if the user has SENS then he gets them + * from netdb.h, otherwise we define them ourselves. + * + * If you are getting "multiple definition" errors here, + * make sure you have included <netdb.h> BEFORE "erl_interface.h" + * or define HAVE_SENS in your CFLAGS. + */ + +#if !defined(HAVE_SENS) && !defined(HOST_NOT_FOUND) /* just in case */ + +struct hostent { + char *h_name; /* official name of host */ + char **h_aliases; /* alias list */ + int h_addrtype; /* host address type */ + int h_length; /* length of address */ + char **h_addr_list; /* list of addresses from name server */ +#define h_addr h_addr_list[0] /* address, for backward compatiblity */ + unsigned int unused; /* SENS defines this as ttl */ +}; + +#define HOST_NOT_FOUND 1 /* Authoritative Answer Host not found */ +#define TRY_AGAIN 2 /* Non-Authoritive Host not found, or SERVERFAIL */ +#define NO_RECOVERY 3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */ +#define NO_DATA 4 /* Valid name, no data record of requested type */ +#define NO_ADDRESS NO_DATA /* no address, look for MX record */ + +#endif /* !HAVE_SENS && !HOST_NOT_FOUND */ +#endif /* VXWORKS */ + + +struct hostent *ei_gethostbyname(const char *name); +struct hostent *ei_gethostbyaddr(const char *addr, int len, int type); +struct hostent *ei_gethostbyname_r(const char *name, + struct hostent *hostp, + char *buffer, + int buflen, + int *h_errnop); +struct hostent *ei_gethostbyaddr_r(const char *addr, + int length, + int type, + struct hostent *hostp, + char *buffer, + int buflen, + int *h_errnop); + + +/* Encode/decode functions */ + +int ei_encode_version(char *buf, int *index); +int ei_x_encode_version(ei_x_buff* x); +int ei_encode_long(char *buf, int *index, long p); +int ei_x_encode_long(ei_x_buff* x, long n); +int ei_encode_ulong(char *buf, int *index, unsigned long p); +int ei_x_encode_ulong(ei_x_buff* x, unsigned long n); +int ei_encode_double(char *buf, int *index, double p); +int ei_x_encode_double(ei_x_buff* x, double dbl); +int ei_encode_boolean(char *buf, int *index, int p); +int ei_x_encode_boolean(ei_x_buff* x, int p); +int ei_encode_char(char *buf, int *index, char p); +int ei_x_encode_char(ei_x_buff* x, char p); +int ei_encode_string(char *buf, int *index, const char *p); +int ei_encode_string_len(char *buf, int *index, const char *p, int len); +int ei_x_encode_string(ei_x_buff* x, const char* s); +int ei_x_encode_string_len(ei_x_buff* x, const char* s, int len); +int ei_encode_atom(char *buf, int *index, const char *p); +int ei_encode_atom_len(char *buf, int *index, const char *p, int len); +int ei_x_encode_atom(ei_x_buff* x, const char* s); +int ei_x_encode_atom_len(ei_x_buff* x, const char* s, int len); +int ei_encode_binary(char *buf, int *index, const void *p, long len); +int ei_x_encode_binary(ei_x_buff* x, const void* s, int len); +int ei_encode_pid(char *buf, int *index, const erlang_pid *p); +int ei_x_encode_pid(ei_x_buff* x, const erlang_pid* pid); +int ei_encode_fun(char* buf, int* index, const erlang_fun* p); +int ei_x_encode_fun(ei_x_buff* x, const erlang_fun* fun); +int ei_encode_port(char *buf, int *index, const erlang_port *p); +int ei_x_encode_port(ei_x_buff* x, const erlang_port *p); +int ei_encode_ref(char *buf, int *index, const erlang_ref *p); +int ei_x_encode_ref(ei_x_buff* x, const erlang_ref *p); +int ei_encode_term(char *buf, int *index, void *t); /* ETERM* actually */ +int ei_x_encode_term(ei_x_buff* x, void* t); +int ei_encode_trace(char *buf, int *index, const erlang_trace *p); +int ei_x_encode_trace(ei_x_buff* x, const erlang_trace *p); +int ei_encode_tuple_header(char *buf, int *index, int arity); +int ei_x_encode_tuple_header(ei_x_buff* x, long n); +int ei_encode_list_header(char *buf, int *index, int arity); +int ei_x_encode_list_header(ei_x_buff* x, long n); +#define ei_encode_empty_list(buf,i) ei_encode_list_header(buf,i,0) +int ei_x_encode_empty_list(ei_x_buff* x); + +/* + * ei_get_type() returns the type and "size" of the item at + * buf[index]. For strings and atoms, size is the number of characters + * not including the terminating 0. For binaries, size is the number + * of bytes. For lists and tuples, size is the arity of the + * object. For other types, size is 0. In all cases, index is left + * unchanged. + */ + +int ei_get_type(const char *buf, const int *index, int *type, int *size); +int ei_get_type_internal(const char *buf, const int *index, int *type, + int *size); + +/* Step through buffer, decoding the given type into the buffer + * provided. On success, 0 is returned and index is updated to point + * to the start of the next item in the buffer. If the type of item at + * buf[index] is not the requested type, -1 is returned and index is + * not updated. The buffer provided by the caller must be sufficiently + * large to contain the decoded object. + */ +int ei_decode_version(const char *buf, int *index, int *version); +int ei_decode_long(const char *buf, int *index, long *p); +int ei_decode_ulong(const char *buf, int *index, unsigned long *p); +int ei_decode_double(const char *buf, int *index, double *p); +int ei_decode_boolean(const char *buf, int *index, int *p); +int ei_decode_char(const char *buf, int *index, char *p); +int ei_decode_string(const char *buf, int *index, char *p); +int ei_decode_atom(const char *buf, int *index, char *p); +int ei_decode_binary(const char *buf, int *index, void *p, long *len); +int ei_decode_fun(const char* buf, int* index, erlang_fun* p); +void free_fun(erlang_fun* f); +int ei_decode_pid(const char *buf, int *index, erlang_pid *p); +int ei_decode_port(const char *buf, int *index, erlang_port *p); +int ei_decode_ref(const char *buf, int *index, erlang_ref *p); +int ei_decode_term(const char *buf, int *index, void *t); /* ETERM** actually */ +int ei_decode_trace(const char *buf, int *index, erlang_trace *p); +int ei_decode_tuple_header(const char *buf, int *index, int *arity); +int ei_decode_list_header(const char *buf, int *index, int *arity); + +/* + * ei_decode_ei_term() returns 1 if term is decoded, 0 if term is OK, + * but not decoded here and -1 if something is wrong. ONLY changes + * index if term is decoded (return value 1)! + */ + +int ei_decode_ei_term(const char* buf, int* index, ei_term* term); + + +/* + * ei_print_term to print out a binary coded term + */ + +int ei_print_term(FILE *fp, const char* buf, int* index); +int ei_s_print_term(char** s, const char* buf, int* index); + +/* + * format to build binary format terms a bit like printf + */ + +int ei_x_format(ei_x_buff* x, const char* fmt, ...); +int ei_x_format_wo_ver(ei_x_buff* x, const char *fmt, ...); + +int ei_x_new(ei_x_buff* x); +int ei_x_new_with_version(ei_x_buff* x); +int ei_x_free(ei_x_buff* x); +int ei_x_append(ei_x_buff* x, const ei_x_buff* x2); +int ei_x_append_buf(ei_x_buff* x, const char* buf, int len); +int ei_skip_term(const char* buf, int* index); + +/*************************************************************************** + * + * Hash types needed by registry types + * + ***************************************************************************/ + +#define EI_SMALLKEY 32 + +typedef struct bucket_s { + int rawhash; + const char *key; + char keybuf[EI_SMALLKEY]; + const void *value; + struct bucket_s *next; +} ei_bucket; + +/* users of the package declare variables as pointers to this. */ +typedef struct { + ei_bucket **tab; + int (*hash)(const char *); /* hash function for this table */ + int size; /* size of table */ + int nelem; /* nr elements */ + int npos; /* nr occupied positions */ + ei_bucket *freelist; /* reuseable freed buckets */ +} ei_hash; + + +/*************************************************************************** + * + * Registry defines, types, functions + * + ***************************************************************************/ + +/* -------------------------------------------------------------------- */ +/* XXXXXXXXXXX */ +/* -------------------------------------------------------------------- */ + +/* registry object attributes */ +#define EI_DIRTY 0x01 /* dirty bit (object value differs from backup) */ +#define EI_DELET 0x02 /* object is deleted */ +#define EI_INT 0x10 /* object is an integer */ +#define EI_FLT 0x20 /* object is a float */ +#define EI_STR 0x40 /* object is a string */ +#define EI_BIN 0x80 /* object is a binary, i.e. pointer to arbitrary type */ + + +/* -------------------------------------------------------------------- */ +/* XXXXXXXXXXX */ +/* -------------------------------------------------------------------- */ + +typedef struct ei_reg_inode { + int attr; + int size; + union { + long i; + double f; + char *s; + void *p; + } val; + struct ei_reg_inode *next; +} ei_reg_obj; + +typedef struct { + ei_reg_obj *freelist; + ei_hash *tab; +} ei_reg; + +struct ei_reg_stat { + int attr; /* object attributes (see above) */ + int size; /* size in bytes (for STR and BIN) 0 for others */ +}; + +struct ei_reg_tabstat { + int size; /* size of table */ + int nelem; /* number of stored elements */ + int npos; /* number of occupied positions */ + int collisions; /* number of positions with more than one element */ +}; + + +/* -------------------------------------------------------------------- */ +/* XXXXXXXXXXX */ +/* -------------------------------------------------------------------- */ + +/* FIXME move comments to source */ + +/* open / close registry. On open, a descriptor is returned that must + * be specified in all subsequent calls to registry functions. You can + * open as many registries as you like. + */ +ei_reg *ei_reg_open(int size); +int ei_reg_resize(ei_reg *oldreg, int newsize); +int ei_reg_close(ei_reg *reg); + +/* set values... these routines assign values to keys. If the key + * exists, the previous value is discarded and the new one replaces + * it. + * + * BIN objects require an additional argument indicating the size in + * bytes of the stored object. This will be used when the object is + * backed up, since it will need to be copied at that time. Remember + * also that pointers are process-space specific and it is not + * meaningful to back them up for later recall. If you are storing + * binary objects for backup, make sure that they are self-contained + * (without references to other objects). + * + * On success the function returns 0, otherwise a value + * indicating the reason for failure will be returned. + */ +int ei_reg_setival(ei_reg *reg, const char *key, long i); +int ei_reg_setfval(ei_reg *reg, const char *key, double f); +int ei_reg_setsval(ei_reg *reg, const char *key, const char *s); +int ei_reg_setpval(ei_reg *reg, const char *key, const void *p, int size); + +/* general set function (specifiy type via flags) + * optional arguments are as for equivalent type-specific function, + * i.e.: + * ei_reg_setval(fd, path, EI_INT, int i); + * ei_reg_setval(fd, path, EI_FLT, float f); + * ei_reg_setval(fd, path, EI_STR, const char *s); + * ei_reg_setval(fd, path, EI_BIN, const void *p, int size); + */ +int ei_reg_setval(ei_reg *reg, const char *key, int flags, ...); + +/* get value of specific type object */ +/* warning: it may be difficult to detect errors when using these + * functions, since the error values are returned "in band" + */ +long ei_reg_getival(ei_reg *reg, const char *key); +double ei_reg_getfval(ei_reg *reg, const char *key); +const char *ei_reg_getsval(ei_reg *reg, const char *key); +const void *ei_reg_getpval(ei_reg *reg, const char *key, int *size); + +/* get value of any type object (must specify) + * Retrieve a value from an object. The type of value expected and a + * pointer to a large enough buffer must be provided. flags must be + * set to the appropriate type (see type constants above) and the + * object type must match. If (flags == 0) the pointer is *assumed* to + * be of the correct type for the object. In any case, the actual + * object type is always returned on success. + * + * The argument following flags must be one of int*, double*, const + * char** and const void**. + * + * for BIN objects an int* is needed to return the size of the object, i.e. + * int ei_reg_getval(ei_reg *reg, const char *path, int flags, void **p, int *size); + */ +int ei_reg_getval(ei_reg *reg, const char *key, int flags, ...); + +/* mark the object as dirty. Normally this operation will not be + * necessary, as it is done automatically by all of the above 'set' + * functions. However, if you modify the contents of an object pointed + * to by a STR or BIN object, then the registry will not be aware of + * the change. As a result, the object may be missed on a subsequent + * backup operation. Use this function to set the dirty bit on the + * object. + */ +int ei_reg_markdirty(ei_reg *reg, const char *key); + +/* remove objects. The value, if any, is discarded. For STR and BIN + * objects, the object itself is removed using free(). */ +int ei_reg_delete(ei_reg *reg, const char *key); + +/* get information about an object */ +int ei_reg_stat(ei_reg *reg, const char *key, struct ei_reg_stat *obuf); + +/* get information about table */ +int ei_reg_tabstat(ei_reg *reg, struct ei_reg_tabstat *obuf); + +/* dump to / restore from backup */ +/* fd is open descriptor to Erlang, mntab is Mnesia table name */ +/* flags here: */ +#define EI_FORCE 0x1 /* dump all records (not just dirty ones) */ +#define EI_NOPURGE 0x2 /* don't purge deleted records */ +int ei_reg_dump(int fd, ei_reg *reg, const char *mntab, int flags); +int ei_reg_restore(int fd, ei_reg *reg, const char *mntab); +int ei_reg_purge(ei_reg *reg); + + +/* -------------------------------------------------------------------- */ +/* Encoding/decoding bugnums to GNU MP format */ +/* -------------------------------------------------------------------- */ + +/* If the user included <gmp.h> we supply some more functions */ + +#if defined(__GNU_MP_VERSION) \ + && __GNU_MP_VERSION == 4 && __GNU_MP_VERSION_MINOR >= 1 + +int ei_decode_bignum(const char *buf, int *index, mpz_t obj); +int ei_encode_bignum(char *buf, int *index, mpz_t obj); +int ei_x_encode_bignum(ei_x_buff *x, mpz_t obj); + +#endif /* __GNU_MP_VERSION */ + +/* -------------------------------------------------------------------- */ +/* Function definitions not documented FIXME */ +/* -------------------------------------------------------------------- */ + +/* FIXME replace this primitive type size code */ + +#ifdef __WIN32__ +#define EI_LONGLONG __int64 +#define EI_ULONGLONG unsigned __int64 +#else +#ifndef VXWORKS +#define EI_LONGLONG long long +#define EI_ULONGLONG unsigned long long +#endif +#endif + +#ifndef VXWORKS +int ei_decode_longlong(const char *buf, int *index, EI_LONGLONG *p); +int ei_decode_ulonglong(const char *buf, int *index, EI_ULONGLONG *p); +int ei_encode_longlong(char *buf, int *index, EI_LONGLONG p); +int ei_encode_ulonglong(char *buf, int *index, EI_ULONGLONG p); +int ei_x_encode_longlong(ei_x_buff* x, EI_LONGLONG n); +int ei_x_encode_ulonglong(ei_x_buff* x, EI_ULONGLONG n); +#endif + +#ifdef USE_EI_UNDOCUMENTED + +/* + * Decode a list of integers into an integer array (i.e. even if it is + * encoded as a string). count gets number of items in array. + * See "decode_intlist.c". + */ + +int ei_decode_intlist(const char *buf, int *index, long *a, int *count); + +/* + * FIXME: used in IC, document? + * bufp = address of pointer to dynamically allocated buffer - may be reallocated by + * this function if it is too small for the message + * bufsz = in/out value: in=user buffer size, out=new buffer size + * msglen = nr bytes in received message + */ +int ei_receive_encoded(int fd, char **bufp, int *bufsz, erlang_msg *to, + int *msglen); +int ei_receive_encoded_tmo(int fd, char **bufp, int *bufsz, erlang_msg *to, + int *msglen, unsigned ms); +int ei_send_encoded(int fd, const erlang_pid *to, char *msg, int msglen); +int ei_send_encoded_tmo(int fd, const erlang_pid *to, char *msg, int msglen, + unsigned ms); +int ei_send_reg_encoded(int fd, const erlang_pid *from, const char *to, + char *msg, int msglen); +int ei_send_reg_encoded_tmo(int fd, const erlang_pid *from, const char *to, + char *msg, int msglen, unsigned ms); + +/* + * Bacward compatibility with old undocumented but used interface... + * FIXME use wrapper function instead?! + */ +#define ei_send_encoded_timeout(Fd,To,Msg,MsgLen,Ms) \ + ei_send_encoded_tmo((Fd),(To),(Msg),(MsgLen),(Ms)) +#define ei_send_reg_encoded_timeout(Fd,From,To,Msg,MsgLen,Ms) \ + ei_send_reg_encoded_tmo((Fd),(From),(To),(Msg),(MsgLen),(Ms)) + + +/* FIXME: is this really the best way to handle bignums? */ +int ei_encode_big(char *buf, int *index, erlang_big* big); +int ei_x_encode_big(ei_x_buff* x, erlang_big* big); +int ei_decode_big(const char *buf, int *index, erlang_big* p); +int ei_big_comp(erlang_big *x, erlang_big *y); +int ei_big_to_double(erlang_big *b, double *resp); +int ei_small_to_big(int s, erlang_big *b); +erlang_big *ei_alloc_big(unsigned int arity); +void ei_free_big(erlang_big *b); + +#endif /* USE_EI_UNDOCUMENTED */ + +#ifdef __cplusplus +} +#endif + +#endif /* EI_H */ diff --git a/lib/erl_interface/include/ei_connect.h b/lib/erl_interface/include/ei_connect.h new file mode 100644 index 0000000000..02880e197c --- /dev/null +++ b/lib/erl_interface/include/ei_connect.h @@ -0,0 +1,26 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2003-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifndef EI_CONNECT_H +#define EI_CONNECT_H + +/* Dummy for now.... */ + +#include "ei.h" + +#endif /* EI_CONNECT_H */ diff --git a/lib/erl_interface/include/eicode.h b/lib/erl_interface/include/eicode.h new file mode 100644 index 0000000000..c35489e890 --- /dev/null +++ b/lib/erl_interface/include/eicode.h @@ -0,0 +1,26 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2003-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifndef EICODE_H +#define EICODE_H + +/* Dummy for now.... */ + +#include "ei.h" + +#endif /* EICODE_H */ diff --git a/lib/erl_interface/include/erl_interface.h b/lib/erl_interface/include/erl_interface.h new file mode 100644 index 0000000000..1c4a94700d --- /dev/null +++ b/lib/erl_interface/include/erl_interface.h @@ -0,0 +1,449 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1996-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifndef _ERL_INTERFACE_H +#define _ERL_INTERFACE_H + +/************************************************************************/ +/* This file defines the complete interface to erl_interface */ +/* Note: the 'ei' interface is the prefered C API. */ +/************************************************************************/ + +/* FIXME only include if needed? */ + +#include "ei.h" /* ei is the base */ + +/* -------------------------------------------------------------------- */ +/* Public defines */ +/* -------------------------------------------------------------------- */ + +#define ERL_COMPOUND (1 << 7) + +#define ERL_UNDEF 0 +#define ERL_INTEGER 1 +#define ERL_U_INTEGER 2 /* unsigned int */ +#define ERL_ATOM 3 +#define ERL_PID 4 +#define ERL_PORT 5 +#define ERL_REF 6 +#define ERL_CONS (7 | ERL_COMPOUND) +#define ERL_LIST ERL_CONS +#define ERL_NIL 8 +#define ERL_EMPTY_LIST ERL_NIL +#define ERL_TUPLE (9 | ERL_COMPOUND) +#define ERL_BINARY 10 +#define ERL_FLOAT 11 +#define ERL_VARIABLE (12 | ERL_COMPOUND) /* used in patterns */ +#define ERL_SMALL_BIG 13 +#define ERL_U_SMALL_BIG 14 +#define ERL_FUNCTION (15 | ERL_COMPOUND) +#define ERL_BIG 16 +#define ERL_LONGLONG 17 +#define ERL_U_LONGLONG 18 + + +#define ERL_TYPE(x) (ERL_HEADER(x)->type) + +/* FIXME some macros left in erl_eterm.h should probably be documented */ + +#define ERL_IS_INTEGER(x) (ERL_TYPE(x) == ERL_INTEGER) +#define ERL_IS_UNSIGNED_INTEGER(x) (ERL_TYPE(x) == ERL_U_INTEGER) +#define ERL_IS_LONGLONG(x) (ERL_TYPE(x) == ERL_LONGLONG) +#define ERL_IS_UNSIGNED_LONGLONG(x) (ERL_TYPE(x) == ERL_U_LONGLONG) +#define ERL_IS_FLOAT(x) (ERL_TYPE(x) == ERL_FLOAT) +#define ERL_IS_ATOM(x) (ERL_TYPE(x) == ERL_ATOM) +#define ERL_IS_PID(x) (ERL_TYPE(x) == ERL_PID) +#define ERL_IS_PORT(x) (ERL_TYPE(x) == ERL_PORT) +#define ERL_IS_REF(x) (ERL_TYPE(x) == ERL_REF) +#define ERL_IS_TUPLE(x) (ERL_TYPE(x) == ERL_TUPLE) +#define ERL_IS_BINARY(x) (ERL_TYPE(x) == ERL_BINARY) +#define ERL_IS_NIL(x) (ERL_TYPE(x) == ERL_NIL) +#define ERL_IS_EMPTY_LIST(x) ERL_IS_NIL(x) +#define ERL_IS_CONS(x) (ERL_TYPE(x) == ERL_CONS) +#define ERL_IS_LIST(x) (ERL_IS_CONS(x) || ERL_IS_EMPTY_LIST(x)) + +/* + * Macros used for XXXX + */ + +#define ERL_HEADER(x) ((Erl_Header *)x) +#define ERL_COUNT(x) (ERL_HEADER(x)->count) + +/* + * Macros used for retrieving values from Erlang terms. + */ + +#define ERL_INT_VALUE(x) ((x)->uval.ival.i) +#define ERL_INT_UVALUE(x) ((x)->uval.uival.u) +#define ERL_LL_VALUE(x) ((x)->uval.llval.i) +#define ERL_LL_UVALUE(x) ((x)->uval.ullval.u) + +#define ERL_FLOAT_VALUE(x) ((x)->uval.fval.f) + +#define ERL_ATOM_PTR(x) ((x)->uval.aval.a) +#define ERL_ATOM_SIZE(x) ((x)->uval.aval.len) + +#define ERL_PID_NODE(x) ((x)->uval.pidval.node) +#define ERL_PID_NUMBER(x) ((x)->uval.pidval.number) +#define ERL_PID_SERIAL(x) ((x)->uval.pidval.serial) +#define ERL_PID_CREATION(x) ((x)->uval.pidval.creation) + +#define ERL_PORT_NODE(x) ((x)->uval.portval.node) +#define ERL_PORT_NUMBER(x) ((x)->uval.portval.number) +#define ERL_PORT_CREATION(x) ((x)->uval.portval.creation) + +#define ERL_REF_NODE(x) ((x)->uval.refval.node) +#define ERL_REF_NUMBER(x) ((x)->uval.refval.n[0]) +#define ERL_REF_NUMBERS(x) ((x)->uval.refval.n) +#define ERL_REF_LEN(x) ((x)->uval.refval.len) +#define ERL_REF_CREATION(x) ((x)->uval.refval.creation) + +#define ERL_TUPLE_SIZE(x) ((x)->uval.tval.size) + +/* NOTE!!! This is 0-based!! (first item is number 0) + * Note too that element/2 (in Erlang) and + * erl_element() are both 1-based. + */ +#define ERL_TUPLE_ELEMS(x) ((x)->uval.tval.elems) +#define ERL_TUPLE_ELEMENT(x, i) (ERL_TUPLE_ELEMS(x)[(i)]) + +#define ERL_BIN_SIZE(x) ((x)->uval.bval.size) +#define ERL_BIN_PTR(x) ((x)->uval.bval.b) + +#define ERL_CONS_HEAD(x) ((x)->uval.lval.head) +#define ERL_CONS_TAIL(x) ((x)->uval.lval.tail) + +#define ERL_VAR_LEN(x) ((x)->uval.vval.len) +#define ERL_VAR_NAME(x) ((x)->uval.vval.name) +#define ERL_VAR_VALUE(x) ((x)->uval.vval.v) + +#define ERL_CLOSURE_SIZE(x) ((x)->uval.funcval.size) +#define ERL_FUN_CREATOR(x) ((x)->uval.funcval.creator) +#define ERL_FUN_MODULE(x) ((x)->uval.funcval.module) +#define ERL_FUN_UNIQ(x) ((x)->uval.funcval.uniq) +#define ERL_FUN_INDEX(x) ((x)->uval.funcval.index) +#define ERL_FUN_ARITY(x) ((x)->uval.funcval.arity) +#define ERL_FUN_NEW_INDEX(x) ((x)->uval.funcval.new_index) +#define ERL_FUN_MD5(x) ((x)->uval.funcval.md5) +#define ERL_CLOSURE(x) ((x)->uval.funcval.closure) +#define ERL_CLOSURE_ELEMENT(x,i) (ERL_CLOSURE(x)[(i)]) + + +#ifdef __cplusplus +extern "C" { +#endif + +/* -------------------------------------------------------------------- */ +/* Type definitions of Erlang terms in C */ +/* -------------------------------------------------------------------- */ + +typedef struct { + unsigned int count:24; /* reference counter */ + unsigned int type:8; /* type of Erlang term */ +} Erl_Header; + +typedef struct { + Erl_Header h; + int i; +} Erl_Integer; + +typedef struct { + Erl_Header h; + unsigned int u; +} Erl_Uinteger; + +typedef struct { + Erl_Header h; + long long i; +} Erl_LLInteger; + +typedef struct { + Erl_Header h; + unsigned long long u; +} Erl_ULLInteger; + +typedef struct { + Erl_Header h; + double f; +} Erl_Float; + +typedef struct { + Erl_Header h; + int len; + char *a; +} Erl_Atom; + +typedef struct { + Erl_Header h; + char * node; + unsigned int number; + unsigned int serial; + unsigned char creation; +} Erl_Pid; + +typedef struct { + Erl_Header h; + char * node; + unsigned int number; + unsigned char creation; +} Erl_Port; + +typedef struct { + Erl_Header h; + char * node; + int len; + unsigned int n[3]; + unsigned char creation; +} Erl_Ref; + +typedef struct { + Erl_Header h; + int arity; + int is_neg; + unsigned short *digits; +} Erl_Big; + +struct _eterm; /* forward */ + +typedef struct { + Erl_Header h; + struct _eterm *head; + struct _eterm *tail; +} Erl_List; + +typedef struct { + Erl_Header h; +} Erl_EmptyList; + +typedef struct { + Erl_Header h; + int size; + struct _eterm **elems; +} Erl_Tuple; + +typedef struct { + Erl_Header h; + int size; + unsigned char *b; +} Erl_Binary; + +/* Variables may only exist in patterns. + * Note: identical variable names in a pattern + * denotes the same value. + */ +typedef struct { + Erl_Header h; + int len; + char *name; + struct _eterm *v; +} Erl_Variable; + + +typedef struct { + Erl_Header h; + int size; /* size of closure */ + int arity; /* arity for new (post R7) external funs */ + unsigned char md5[16]; /* md5 for new funs */ + int new_index; /* new funs */ + struct _eterm* creator; /* pid */ + struct _eterm* module; /* module */ + struct _eterm* index; + struct _eterm* uniq; + struct _eterm** closure; +} Erl_Function; + +typedef struct _eterm { + union { + Erl_Integer ival; + Erl_Uinteger uival; + Erl_LLInteger llval; + Erl_ULLInteger ullval; + Erl_Float fval; + Erl_Atom aval; + Erl_Pid pidval; + Erl_Port portval; + Erl_Ref refval; + Erl_List lval; + Erl_EmptyList nval; + Erl_Tuple tval; + Erl_Binary bval; + Erl_Variable vval; + Erl_Function funcval; + Erl_Big bigval; + } uval; +} ETERM; + + +#define MAXREGLEN 255 /* max length of registered (atom) name */ + +typedef struct { + int type; /* one of the message type constants in eiext.h */ + ETERM *msg; /* the actual message */ + ETERM *from; + ETERM *to; + char to_name[MAXREGLEN+1]; +} ErlMessage; + +typedef unsigned char Erl_Heap; + + +/* -------------------------------------------------------------------- */ +/* The functions */ +/* -------------------------------------------------------------------- */ + +void erl_init(void *x, long y); +void erl_set_compat_rel(unsigned); +int erl_connect_init(int, char*,short); +int erl_connect_xinit(char*,char*,char*,struct in_addr*,char*,short); +int erl_connect(char*); +int erl_xconnect(struct in_addr*,char *); +int erl_close_connection(int); +int erl_receive(int, unsigned char*, int); +int erl_receive_msg(int, unsigned char*, int, ErlMessage*); +int erl_xreceive_msg(int, unsigned char**, int*, ErlMessage*); +int erl_send(int, ETERM*, ETERM*); +int erl_reg_send(int, char*, ETERM*); +ETERM *erl_rpc(int,char*,char*,ETERM*); +int erl_rpc_to(int,char*,char*,ETERM*); +int erl_rpc_from(int,int,ErlMessage*); + +/* erl_publish returns open descriptor on success, or -1 */ +int erl_publish(int port); +int erl_accept(int,ErlConnect*); + +const char *erl_thiscookie(void); +const char *erl_thisnodename(void); +const char *erl_thishostname(void); +const char *erl_thisalivename(void); +short erl_thiscreation(void); + +/* returns 0 on success, -1 if node not known to epmd or epmd not reached */ +int erl_unpublish(const char *alive); + +/* Report generic error to stderr. */ +void erl_err_msg(const char * __template, ...) + __attribute__ ((__format__ (printf, 1, 2))); +/* Report generic error to stderr and die. */ +void erl_err_quit(const char * __template, ...) + __attribute__ ((__format__ (printf, 1, 2), __noreturn__)); +/* Report system/libc error to stderr. */ +void erl_err_ret(const char * __template, ...) + __attribute__ ((__format__ (printf, 1, 2))); +/* Report system/libc error to stderr and die. */ +void erl_err_sys(const char * __template, ...) + __attribute__ ((__format__ (printf, 1, 2), __noreturn__)); + +ETERM *erl_cons(ETERM*,ETERM*); +ETERM *erl_copy_term(const ETERM*); +ETERM *erl_element(int,const ETERM*); + +ETERM *erl_hd(const ETERM*); +ETERM* erl_iolist_to_binary(const ETERM* term); +char* erl_iolist_to_string(const ETERM* term); +int erl_iolist_length(const ETERM*); +int erl_length(const ETERM*); +ETERM *erl_mk_atom(const char*); +ETERM *erl_mk_binary(const char*,int); +ETERM *erl_mk_empty_list(void); +ETERM *erl_mk_estring(const char*, int); +ETERM *erl_mk_float(double); +ETERM *erl_mk_int(int); +ETERM *erl_mk_longlong(long long); +ETERM *erl_mk_list(ETERM**,int); +ETERM *erl_mk_pid(const char*,unsigned int,unsigned int,unsigned char); +ETERM *erl_mk_port(const char*,unsigned int,unsigned char); +ETERM *erl_mk_ref(const char*,unsigned int,unsigned char); +ETERM *erl_mk_long_ref(const char*,unsigned int,unsigned int, + unsigned int,unsigned char); +ETERM *erl_mk_string(const char*); +ETERM *erl_mk_tuple(ETERM**,int); +ETERM *erl_mk_uint(unsigned int); +ETERM *erl_mk_ulonglong(unsigned long long); +ETERM *erl_mk_var(const char*); +int erl_print_term(FILE*,const ETERM*); +/* int erl_sprint_term(char*,const ETERM*); */ +int erl_size(const ETERM*); +ETERM *erl_tl(const ETERM*); +ETERM *erl_var_content(const ETERM*, const char*); + +ETERM *erl_format(char*, ... ); +int erl_match(ETERM*, ETERM*); + +char **erl_global_names(int fd, int *count); +int erl_global_register(int fd, const char *name, ETERM *pid); +int erl_global_unregister(int fd, const char *name); +ETERM *erl_global_whereis(int fd, const char *name, char *node); + +void erl_init_malloc(Erl_Heap*,long); +ETERM *erl_alloc_eterm(unsigned char); +void erl_eterm_release(void); +void erl_eterm_statistics(unsigned long*,unsigned long*); +void erl_free_array(ETERM**,int); +void erl_free_term(ETERM*); +void erl_free_compound(ETERM*); +void *erl_malloc(long); +void erl_free(void*); + +int erl_compare_ext(unsigned char*, unsigned char*); +ETERM *erl_decode(unsigned char*); +ETERM *erl_decode_buf(unsigned char**); +int erl_encode(ETERM*,unsigned char*t); +int erl_encode_buf(ETERM*,unsigned char**); +int erl_ext_size(unsigned char*); +unsigned char erl_ext_type(unsigned char*); /* Note: returned 'char' before R9C */ +unsigned char *erl_peek_ext(unsigned char*,int); +int erl_term_len(ETERM*); + + +/* -------------------------------------------------------------------- */ +/* Wrappers around ei functions */ +/* -------------------------------------------------------------------- */ + +/* + * Undocumented before R9C, included for compatibility with old code + */ + +struct hostent *erl_gethostbyname(const char *name); +struct hostent *erl_gethostbyaddr(const char *addr, int len, int type); +struct hostent *erl_gethostbyname_r(const char *name, + struct hostent *hostp, + char *buffer, + int buflen, + int *h_errnop); +struct hostent *erl_gethostbyaddr_r(const char *addr, + int length, + int type, + struct hostent *hostp, + char *buffer, + int buflen, + int *h_errnop); + +/* + * Undocumented, included for compatibility with old code + */ + +void erl_init_resolve(void); +int erl_distversion(int fd); +int erl_epmd_connect(struct in_addr *inaddr); +int erl_epmd_port(struct in_addr *inaddr, const char *alive, int *dist); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/erl_interface/info b/lib/erl_interface/info new file mode 100644 index 0000000000..9612b0b6d4 --- /dev/null +++ b/lib/erl_interface/info @@ -0,0 +1,2 @@ +group: comm Interface and Communication Applications +short: Low level interface to C diff --git a/lib/erl_interface/priv/.gitignore b/lib/erl_interface/priv/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/erl_interface/priv/.gitignore 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; +} diff --git a/lib/erl_interface/vsn.mk b/lib/erl_interface/vsn.mk new file mode 100644 index 0000000000..c5f4c06037 --- /dev/null +++ b/lib/erl_interface/vsn.mk @@ -0,0 +1 @@ +EI_VSN = 3.6.4 |