diff options
author | Erlang/OTP <otp@erlang.org> | 2009-11-20 14:54:40 +0000 |
---|---|---|
committer | Erlang/OTP <otp@erlang.org> | 2009-11-20 14:54:40 +0000 |
commit | 84adefa331c4159d432d22840663c38f155cd4c1 (patch) | |
tree | bff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/erl_interface/src/misc | |
download | erlang-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz |
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/erl_interface/src/misc')
27 files changed, 3854 insertions, 0 deletions
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 */ |