aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl/c_src
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/ssl/c_src
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/ssl/c_src')
-rw-r--r--lib/ssl/c_src/Makefile26
-rw-r--r--lib/ssl/c_src/Makefile.dist33
-rw-r--r--lib/ssl/c_src/Makefile.in205
-rw-r--r--lib/ssl/c_src/Makefile.win32147
-rw-r--r--lib/ssl/c_src/Makefile.win32.dist45
-rw-r--r--lib/ssl/c_src/debuglog.c251
-rw-r--r--lib/ssl/c_src/debuglog.h50
-rw-r--r--lib/ssl/c_src/esock.c1904
-rw-r--r--lib/ssl/c_src/esock.h273
-rw-r--r--lib/ssl/c_src/esock_openssl.c1213
-rw-r--r--lib/ssl/c_src/esock_osio.c328
-rw-r--r--lib/ssl/c_src/esock_osio.h34
-rw-r--r--lib/ssl/c_src/esock_poll.c222
-rw-r--r--lib/ssl/c_src/esock_poll.h60
-rw-r--r--lib/ssl/c_src/esock_posix_str.c642
-rw-r--r--lib/ssl/c_src/esock_posix_str.h28
-rw-r--r--lib/ssl/c_src/esock_ssl.h110
-rw-r--r--lib/ssl/c_src/esock_utils.c150
-rw-r--r--lib/ssl/c_src/esock_utils.h32
-rw-r--r--lib/ssl/c_src/esock_winsock.h36
20 files changed, 5789 insertions, 0 deletions
diff --git a/lib/ssl/c_src/Makefile b/lib/ssl/c_src/Makefile
new file mode 100644
index 0000000000..52d9140153
--- /dev/null
+++ b/lib/ssl/c_src/Makefile
@@ -0,0 +1,26 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1999-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+
+#
+
+#
+# Invoke with GNU make or clearmake -C gnu.
+#
+
+include $(ERL_TOP)/make/run_make.mk
diff --git a/lib/ssl/c_src/Makefile.dist b/lib/ssl/c_src/Makefile.dist
new file mode 100644
index 0000000000..2468468921
--- /dev/null
+++ b/lib/ssl/c_src/Makefile.dist
@@ -0,0 +1,33 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1999-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+
+# Makefile for SSL on Unix
+#
+# Placed in obj directory.
+#
+CC = gcc
+
+BINDIR = %BINDIR%
+LIBS = %LIBS%
+SSL_LIBDIR = %SSL_LIBDIR%
+OBJS = %OBJS%
+
+$(BINDIR)/ssl_esock: $(OBJS)
+ $(CC) -L$(SSL_LIBDIR) -Wl,-R$(SSL_LIBDIR) -o $@ $^ \
+ $(LIBS) -lssl -lcrypto
diff --git a/lib/ssl/c_src/Makefile.in b/lib/ssl/c_src/Makefile.in
new file mode 100644
index 0000000000..bd1b2f9375
--- /dev/null
+++ b/lib/ssl/c_src/Makefile.in
@@ -0,0 +1,205 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1999-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+
+#
+# Makefile only for Unix and Win32/Cygwin.
+#
+
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+# ----------------------------------------------------
+# SSL locations and include options from configure
+# ----------------------------------------------------
+SSL_LIBDIR = @SSL_LIBDIR@
+SSL_INCLUDE = @SSL_INCLUDE@
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../vsn.mk
+VSN=$(SSL_VSN)
+
+# ----------------------------------------------------
+# Commands
+# ----------------------------------------------------
+CC = @CC@
+LD = @LD@
+SHELL = /bin/sh
+LIBS = @LIBS@
+PLAIN_CFLAGS = @CFLAGS@
+
+# ----------------------------------------------------
+# Includes and libs
+# ----------------------------------------------------
+
+ALL_CFLAGS = @WFLAGS@ @CFLAGS@ @DEFS@ $(TYPE_FLAGS)
+TARGET = @host@
+
+ifeq ($(TYPE),debug)
+TYPEMARKER = .debug
+TYPE_FLAGS = -g -DDEBUG @DEBUG_FLAGS@
+else
+TYPEMARKER =
+TYPE_FLAGS = -O2
+endif
+
+PRIVDIR = ../priv
+BINDIR = $(PRIVDIR)/bin/$(TARGET)
+OBJDIR = $(PRIVDIR)/obj/$(TARGET)
+
+# ----------------------------------------------------
+# File suffixes
+# ----------------------------------------------------
+exe = @EXEEXT@
+obj = .@OBJEXT@
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/ssl-$(VSN)
+
+# ----------------------------------------------------
+# Common Macros
+# ----------------------------------------------------
+OBJS = $(OBJDIR)/esock$(obj) \
+ $(OBJDIR)/debuglog$(obj) \
+ $(OBJDIR)/esock_poll$(obj) \
+ $(OBJDIR)/esock_osio$(obj) \
+ $(OBJDIR)/esock_utils$(obj) \
+ $(OBJDIR)/esock_posix_str$(obj) \
+ $(OBJDIR)/esock_openssl$(obj)
+
+PORT_PROGRAM = $(BINDIR)/ssl_esock$(exe)
+
+SKIP_BUILDING_BINARIES := false
+
+# Try to be BC for R10
+ifeq ($(findstring @SSL_,@SSL_DYNAMIC_ONLY@),@SSL_)
+DYNAMIC_CRYPTO_LIB=yes
+else
+DYNAMIC_CRYPTO_LIB=@SSL_DYNAMIC_ONLY@
+endif
+
+
+ifeq ($(DYNAMIC_CRYPTO_LIB),yes)
+
+ifneq ($(findstring win32,$(TARGET)),win32)
+SSL_MAKEFILE = $(OBJDIR)/Makefile
+else
+SSL_MAKEFILE =
+endif
+
+CC_R_FLAG=@CFLAG_RUNTIME_LIBRARY_PATH@
+ifeq ($(findstring @,$(CC_R_FLAG)),@)
+# Old erts configure used which hasn't replaced @CFLAG_RUNTIME_LIBRARY_PATH@;
+# we try our best here instead...
+
+ifeq ($(findstring darwin,$(TARGET)),darwin) # darwin: no flag
+CC_R_FLAG =
+else
+ifeq ($(findstring osf,$(TARGET)),osf) # osf1: -Wl,-rpath,
+CC_R_FLAG = -Wl,-rpath,
+else # Default: -Wl,-R
+CC_R_FLAG = -Wl,-R
+endif
+endif
+endif
+
+ifeq ($(strip $(CC_R_FLAG)),)
+CC_R_OPT =
+else
+CC_R_OPT = $(CC_R_FLAG)$(SSL_LIBDIR)
+endif
+
+SSL_LINK_LIB=-L$(SSL_LIBDIR) -lssl -lcrypto
+else
+# not dynamic crypto lib (default from R11B-5)
+NEED_KERBEROS=@SSL_LINK_WITH_KERBEROS@
+NEED_ZLIB=@SSL_LINK_WITH_ZLIB@
+SSL_MAKEFILE =
+CC_R_OPT =
+SSL_LINK_LIB = $(SSL_LIBDIR)/libssl.a $(SSL_LIBDIR)/libcrypto.a
+ifeq ($(NEED_KERBEROS),yes)
+SSL_LINK_LIB += @STATIC_KERBEROS_LIBS@
+endif
+ifeq ($(NEED_ZLIB),yes)
+SSL_LINK_LIB += @STATIC_ZLIB_LIBS@
+endif
+endif
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+debug opt: $(OBJDIR) $(BINDIR) $(OBJS) $(PORT_PROGRAM) $(SSL_MAKEFILE)
+
+$(OBJDIR):
+ -@mkdir -p $(OBJDIR)
+
+$(BINDIR):
+ -@mkdir -p $(BINDIR)
+
+$(OBJDIR)/esock_openssl$(obj): esock_openssl.c
+ $(CC) -c -o $@ $(ALL_CFLAGS) $(SSL_INCLUDE) $<
+
+$(OBJDIR)/%$(obj): %.c
+ $(CC) -c -o $@ $(ALL_CFLAGS) $<
+
+# Unix
+$(BINDIR)/ssl_esock: $(OBJS)
+ $(CC) $(CC_R_OPT) $(PLAIN_CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) $(SSL_LINK_LIB)
+
+# Win32/Cygwin
+$(BINDIR)/ssl_esock.exe: $(OBJS)
+ $(LD) -L$(SSL_LIBDIR) -o $@ $^ -lwsock32 -llibeay32 -lssleay32
+
+# Unix only, and only when linking statically
+$(SSL_MAKEFILE):
+ sed -e "s;%BINDIR%;../../bin/$(TARGET);" \
+ -e "s;%SSL_LIBDIR%;$(SSL_LIBDIR);" \
+ -e "s;%OBJS;$(OBJS);" \
+ -e "s;%LIBS%;$(LIBS);" ./Makefile.dist \
+ > $(OBJDIR)/Makefile
+
+
+clean:
+ rm -f $(PORT_PROGRAM) $(OBJS) core *~ $(SSL_MAKEFILE)
+
+docs:
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/priv/bin
+ $(INSTALL_PROGRAM) $(PORT_PROGRAM) $(RELSYSDIR)/priv/bin
+ifneq ($(SSL_MAKEFILE),)
+ $(INSTALL_DIR) $(RELSYSDIR)/priv/obj
+ $(INSTALL_DATA) $(OBJS) $(RELSYSDIR)/priv/obj
+ sed -e "s;%BINDIR%;../bin;" \
+ -e "s;%SSL_LIBDIR%;$(SSL_LIBDIR);" \
+ -e "s;%OBJS;$(OBJS);" \
+ -e "s;%LIBS%;$(LIBS);" ./Makefile.dist \
+ > $(RELSYSDIR)/priv/obj/Makefile
+endif
+
+release_docs_spec:
+
diff --git a/lib/ssl/c_src/Makefile.win32 b/lib/ssl/c_src/Makefile.win32
new file mode 100644
index 0000000000..668cd2a28d
--- /dev/null
+++ b/lib/ssl/c_src/Makefile.win32
@@ -0,0 +1,147 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1999-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+
+#
+# SSL - Makefile for Windows NT
+#
+# It is assumed that the following environment variables have been set:
+#
+# INCLUDE X:\MSDEV\INCLUDE
+# LIB X:\MSDEV\LIB
+#
+# so that standard include files, and the socket library can be found.
+#
+# When ssl_esock.exe is run, the PATH environment variable must contain
+# the name of a directory that contains ssleay32.dll and libeay32.dll,
+# and windows socket dll.
+#
+
+# Roots
+!ifndef OPENSSL_ROOT
+! error "Makefile.win32: ssl: OPENSSL_ROOT not set"
+!endif
+
+TARGET = win32
+
+BINDIR = ..\priv\bin\$(TARGET)
+OBJDIR = ..\priv\obj\$(TARGET)
+
+!if !exist($(BINDIR))
+! if [mkdir $(BINDIR)]
+! error "SSL: cannot create BINDIR"
+! endif
+!endif
+
+!if !exist($(OBJDIR))
+! if [mkdir $(OBJDIR)]
+! error "SSL: cannot create OBJDIR"
+! endif
+!endif
+
+# Includes
+#
+OPENSSL_INCLUDE = $(OPENSSL_ROOT)\inc32
+
+INCLUDES = /I. /I$(OPENSSL_INCLUDE)
+
+# Libraries
+#
+OPENSSL_LIBDIR = $(OPENSSL_ROOT)\out32dll
+OPENSSL_LIBS = \
+ $(OPENSSL_LIBDIR)\ssleay32.lib \
+ $(OPENSSL_LIBDIR)\libeay32.lib
+
+!ifdef ESOCK_WINSOCK2
+WINSOCK_LIB = ws2_32.lib
+DEFS = -DESOCK_WINSOCK2
+!else
+WINSOCK_LIB = wsock32.lib
+!endif
+
+# Compiler options
+#
+# NOTE: Size of fd_set is set in esock_winsock.h but can be overridden
+# with a -D option here.
+#
+OPTS = /MDd /G5 /Ox /O2 /Ob2 /Z7
+DEFS = -D__WIN32__ -DWIN32 $(DEFS)
+CFLAGS = $(INCLUDES) /nologo $(OPTS) $(DEFS)
+
+# Object files
+#
+SSL_BASE_OBJS = \
+ $(OBJDIR)\esock.obj \
+ $(OBJDIR)\debuglog.obj \
+ $(OBJDIR)\esock_poll$(obj) \
+ $(OBJDIR)\esock_osio.obj \
+ $(OBJDIR)\esock_utils.obj \
+ $(OBJDIR)\esock_posix_str.obj
+
+OPENSSL_OBJS = \
+ $(OBJDIR)\esock_openssl.obj
+
+#
+# Targets
+#
+
+all: $(SSL_BASE_OBJS) $(OPENSSL_OBJS) $(BINDIR)\ssl_esock.exe
+
+clean:
+ del $(BINDIR)\*.exe
+ del $(OBJDIR)\*.obj
+
+# Inference rule .c.obj:
+#
+{.}.c{$(OBJDIR)}.obj:
+ $(CC) $(CFLAGS) /c /Fo$@ $(*B).c
+
+# Binary
+#
+$(BINDIR)\ssl_esock.exe: $(SSL_BASE_OBJS) $(OPENSSL_OBJS)
+ $(CC) /nologo $(SSL_BASE_OBJS) $(OPENSSL_OBJS) $(OPENSSL_LIBS) \
+ $(WINSOCK_LIB) /Fe$(BINDIR)\ssl_esock.exe
+
+
+
+# Dependencies
+#
+$(OBJDIR)\esock.o: esock.h debuglog.h esock_ssl.h esock_osio.h \
+ esock_utils.h esock_winsock.h
+$(OBJDIR)\debuglog.o: debuglog.h esock_ssl.h esock_utils.h
+$(OBJDIR)\esock_osio.o: esock_osio.h esock.h debuglog.h esock_utils.h \
+ esock_winsock.h
+$(OBJDIR)\esock_utils.o: esock_utils.h
+$(OBJDIR)\esock_posix_str.o: esock_posix_str.h esock_winsock.h
+
+$(OBJDIR)\esock_openssl.o: esock.h esock_ssl.h debuglog.h esock_utils.h \
+ $(OPENSSL_INCLUDE)\crypto.h \
+ $(OPENSSL_INCLUDE)\ssl.h \
+ $(OPENSSL_INCLUDE)\err.h
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/ssl/c_src/Makefile.win32.dist b/lib/ssl/c_src/Makefile.win32.dist
new file mode 100644
index 0000000000..8510c44e08
--- /dev/null
+++ b/lib/ssl/c_src/Makefile.win32.dist
@@ -0,0 +1,45 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1999-2009. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+
+# Makefile.win32.dist for SSL
+#
+# To be placed in obj directory.
+#
+
+CC = cl
+
+BINDIR = %BINDIR%
+
+OPENSSL_LIBS = \
+ $(BINDIR)\ssleay32.lib \
+ $(BINDIR)\libeay32.lib
+
+WINSOCK_LIB = ws2_32.lib
+
+SSL_BASE_OBJS = esock.obj debuglog.obj esock_osio.obj esock_utils.obj \
+ esock_posix_str.obj
+
+OPENSSL_OBJS = esock_openssl.obj
+
+$(BINDIR)\ssl_esock.exe: $(SSL_BASE_OBJS) $(OPENSSL_OBJS)
+ $(CC) /nologo $(SSL_BASE_OBJS) $(OPENSSL_OBJS) $(OPENSSL_LIBS) \
+ $(WINSOCK_LIB) /Fe$(BINDIR)\ssl_esock.exe
+
+
+
diff --git a/lib/ssl/c_src/debuglog.c b/lib/ssl/c_src/debuglog.c
new file mode 100644
index 0000000000..e2e55df4b2
--- /dev/null
+++ b/lib/ssl/c_src/debuglog.c
@@ -0,0 +1,251 @@
+/*<copyright>
+ * <year>1999-2008</year>
+ * <holder>Ericsson AB, All Rights Reserved</holder>
+ *</copyright>
+ *<legalnotice>
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Initial Developer of the Original Code is Ericsson AB.
+ *</legalnotice>
+ */
+/*
+ * Purpose: Various routines for debug printouts and logs.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#include "debuglog.h"
+#include "esock_utils.h"
+
+#ifndef __WIN32__
+static char tr_format_buf[256];
+static char *tr_format(const char *format);
+static int vfprintclistf(FILE *fp, const char *format, va_list args);
+#endif
+
+int debug = 0;
+int debugmsg = 0;
+FILE *ssllogfp = NULL;
+FILE *__locallogfp = NULL;
+
+void open_ssllog(char *path)
+{
+ ssllogfp = openlog(path);
+}
+
+void close_ssllog(void)
+{
+ if (ssllogfp)
+ closelog(ssllogfp);
+}
+
+FILE *openlog(char *s)
+{
+ FILE *fp;
+ time_t t = time(NULL);
+
+ if ((fp = fopen(s, "a"))) {
+ setbuf(fp, NULL);
+ fprintf(fp, "===== Opened [%s] %s", s, ctime(&t));
+ }
+ return fp;
+}
+
+void closelog(FILE *fp)
+{
+ time_t t = time(NULL);
+
+ if (fp) {
+ fprintf(fp, "Closed %s", ctime(&t));
+ fclose(fp);
+ }
+}
+
+int __debugprintf(const char *format, ...)
+{
+ va_list args;
+ int ret;
+#ifndef __WIN32__
+ char *newformat;
+
+ va_start(args, format);
+ newformat = tr_format(format);
+ ret = vfprintf(stderr, newformat, args);
+ if (newformat != format && newformat != tr_format_buf)
+ esock_free(newformat);
+#else
+ va_start(args, format);
+ ret = vfprintf(stderr, format, args);
+#endif
+ va_end(args);
+ if (ssllogfp) {
+ va_start(args, format);
+ vfprintf(ssllogfp, format, args);
+ va_end(args);
+ }
+ return ret;
+}
+
+int __debugprintclistf(const char *format, ...)
+{
+ va_list args;
+ int ret;
+#ifndef __WIN32__
+ char *newformat;
+
+ va_start(args, format);
+ newformat = tr_format(format);
+ ret = vfprintclistf(stderr, newformat, args);
+ if (newformat != format && newformat != tr_format_buf)
+ esock_free(newformat);
+#else
+ va_start(args, format);
+ ret = vfprintclistf(stderr, format, args);
+#endif
+ if (ssllogfp)
+ vfprintclistf(ssllogfp, format, args);
+ va_end(args);
+ return ret;
+}
+
+int __debuglogf(const char *format, ...)
+{
+ va_list args;
+ int ret;
+
+ va_start(args, format);
+ ret = vfprintf(__locallogfp, format, args);
+ va_end(args);
+ return ret;
+}
+
+#ifndef __WIN32__
+
+/* Insert `\r' before each `\n' i format */
+static char *tr_format(const char *format)
+{
+ char *newformat, *s, *t;
+ int len;
+
+ len = strlen(format);
+ if ((newformat = (len > 127) ? esock_malloc(len) : tr_format_buf)) {
+ for (s = (char *)format, t = newformat; *s; *t++ = *s++)
+ if (*s == '\n')
+ *t++ = '\r';
+ *t = '\0';
+ } else
+ newformat = (char *)format;
+ return newformat;
+}
+
+#endif
+
+/* This function is for printing arrays of characters with formats
+ * %FPa or %FPb, where F and P are the ordinary specifiers for
+ * field width and precision, respectively.
+ *
+ * The conversion specifier `a' implies hex-string output, while
+ * the `b' specifier provides character output (for non-printable
+ * characters a `.' is written.
+ *
+ * The F specifier contains the width for each character. The
+ * P specifier tells how many characters to print.
+ *
+ * Example: Suppose we have a function myprintf(char *format, ...)
+ * that calls our vfprintclistf(), and that
+ *
+ * char buf[] = "h\r\n";
+ * len = 3;
+ *
+ * Then
+ *
+ * myprintf("%.2b", buf) prints "h."
+ * myprintf("%2.3b", buf) prints "h . . "
+ * myprintf("%3.*a", len, buf) prints "68 0d 0a"
+ *
+ */
+
+static int vfprintclistf(FILE *fp, const char *format, va_list args)
+{
+
+ int i, len, width, prec, written = 0;
+ char *s, *prevs, *fstart;
+ unsigned char *buf;
+
+ if (!format || !*format)
+ return 0;
+
+ /* %{[0-9]*|\*}{.{[0-9]*|\*}{a|b} */
+
+ prevs = (char *)format; /* format is const */
+ s = strchr(format, '%');
+ while (s && *s) {
+ if (s - prevs > 0)
+ written += fprintf(fp, "%.*s", s - prevs, prevs);
+ width = prec = 0;
+ fstart = s;
+ s++;
+ if (*s != '%') { /* otherwise it is not a format */
+ if (*s == '*') { /* width in arg */
+ s++;
+ width = va_arg(args, int);
+ } else if ((len = strspn(s, "0123456789"))) { /* const width */
+ width = atoi(s);
+ s += len;
+ } else
+ width = 0;
+ if (*s == '.') { /* precision specified */
+ s++;
+ if (*s == '*') { /* precision in arg */
+ s++;
+ prec = va_arg(args, int);
+ } else if ((len = strspn(s, "0123456789"))) { /* const prec */
+ prec = atoi(s);
+ s += len;
+ } else /* no precision value, defaults to zero */
+ prec = 0;
+ } else
+ prec = 0; /* no precision defaults to zero */
+ if (*s == 'a' || *s == 'b') { /* only valid specifiers */
+ buf = va_arg(args, unsigned char *);
+ if (*s == 'a') {
+ for (i = 0; i < prec; i++)
+ written += fprintf(fp, "%*.2x", width, buf[i]);
+ }else if (*s == 'b') {
+ for (i = 0; i < prec; i++) {
+ if (isprint(buf[i]))
+ written += fprintf(fp, "%*c", width, buf[i]);
+ else
+ written += fprintf(fp, "%*c", width, '.');
+ }
+ }
+ } else {
+ fprintf(stderr, "fprintclistf: format \"%s\" invalid.\n",
+ format);
+ va_end(args);
+ return written;
+ }
+ }
+ s++;
+ /* Now s points to the next character after the format */
+ prevs = s;
+ s = strchr(s, '%');
+ }
+ if (format + strlen(format) + 1 - prevs > 0)
+ written += fprintf(fp, "%s", prevs);
+ return written;
+}
+
diff --git a/lib/ssl/c_src/debuglog.h b/lib/ssl/c_src/debuglog.h
new file mode 100644
index 0000000000..5699e6b495
--- /dev/null
+++ b/lib/ssl/c_src/debuglog.h
@@ -0,0 +1,50 @@
+/*<copyright>
+ * <year>1998-2008</year>
+ * <holder>Ericsson AB, All Rights Reserved</holder>
+ *</copyright>
+ *<legalnotice>
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Initial Developer of the Original Code is Ericsson AB.
+ *</legalnotice>
+ */
+/*
+ * Purpose: Debug functions and macros.
+ *
+ */
+
+#ifndef __DEBUGLOG_H_
+#define __DEBUGLOG_H_
+
+#include <stdio.h>
+#include "esock_ssl.h"
+
+#define DEBUGF(x) if (debug) __debugprintf x;
+#define DEBUGMSGF(x) if (debugmsg) __debugprintclistf x;
+#define LOGF(fp, x) if (fp) { __locallogfp = fp; __debuglogf x; }
+#define SSLDEBUGF() if (debug) { esock_ssl_print_errors_fp(stderr); \
+ if (ssllogfp) esock_ssl_print_errors_fp(ssllogfp); }
+
+int debug;
+int debugmsg;
+FILE *ssllogfp;
+FILE *__locallogfp;
+
+void open_ssllog(char *path);
+void close_ssllog(void);
+FILE *openlog(char *);
+void closelog(FILE *);
+int __debugprintf(const char *, ...);
+int __debugprintclistf(const char *, ...);
+int __debuglogf(const char *, ...);
+
+#endif
diff --git a/lib/ssl/c_src/esock.c b/lib/ssl/c_src/esock.c
new file mode 100644
index 0000000000..78d08f7c29
--- /dev/null
+++ b/lib/ssl/c_src/esock.c
@@ -0,0 +1,1904 @@
+/*<copyright>
+ * <year>1999-2008</year>
+ * <holder>Ericsson AB, All Rights Reserved</holder>
+ *</copyright>
+ *<legalnotice>
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Initial Developer of the Original Code is Ericsson AB.
+ *</legalnotice>
+ */
+
+/*
+ * Purpose: Implementation of Secure Socket Layer (SSL).
+ *
+ * This is an "SSL proxy" for Erlang in the form of a port
+ * program.
+ *
+ * The implementation has borrowed somewhat from the original
+ * implementation of `socket' by Claes Wikstr�m, and the former
+ * implementation of `ssl_socket' by Helen Ariyan.
+ *
+ * All I/O is now non-blocking.
+ *
+ * When a connection (cp) is in the state JOINED we have the following
+ * picture:
+ *
+ * proxy->fd fd
+ * | |
+ * proxy->eof | --------> wq -----------> | bp
+ * | |
+ * Erlang | | SSL
+ * | |
+ * proxy->bp | <------ proxy->wq --------- | eof
+ * | |
+ *
+ * We read from Erlang (proxy->fd) and write to SSL (fd); and read from
+ * SSL (fd) and write to Erlang (proxy->fd).
+ *
+ * The variables bp (broken pipe) and eof (end of file) take the
+ * values 0 and 1.
+ *
+ * What has been read and cannot be immediately written is put in a
+ * write queue (wq). A wq is emptied before reads are continued, which
+ * means that at most one chunk that is read can be in a wq.
+ *
+ * The proxy-to-ssl part of a cp is valid iff
+ *
+ * !bp && (wq.len > 0 || !proxy->eof).
+ *
+ * The ssl-to-proxy part of a cp is valid iff
+ *
+ * !proxy->bp && (proxy->wq.len > 0 || !eof).
+ *
+ * The connection is valid if any of the above parts are valid, i.e.
+ * invalid if both parts are invalid.
+ *
+ * Every SELECT_TIMEOUT second we try to write to those file
+ * descriptors that have non-empty wq's (the only way to detect that a
+ * far end has gone away is to write to it).
+ *
+ * STATE TRANSITIONS
+ *
+ * Below (*) means that the corresponding file descriptor is published
+ * (i.e. kwown outside this port program) when the state is entered,
+ * and thus cannot be closed without synchronization with the
+ * ssl_server.
+ *
+ * Listen:
+ *
+ * STATE_NONE ---> (*) PASSIVE_LISTENING <---> ACTIVE_LISTENING
+ *
+ * Accept:
+ *
+ * STATE_NONE ---> SSL_ACCEPT ---> (*) CONNECTED ---> JOINED --->
+ * ---> SSL_SHUTDOWN ---> DEFUNCT
+ *
+ * Connect:
+ *
+ * STATE_NONE ---> (*) WAIT_CONNECT ---> SSL_CONNECT ---> CONNECTED --->
+ * ---> JOINED ---> SSL_SHUTDOWN ---> DEFUNCT
+ *
+ * In states where file descriptors has been published, and where
+ * something goes wrong, the state of the connection is set to
+ * DEFUNCT. A connection in such a state can only be closed by a CLOSE
+ * message from Erlang (a reception of such a message is registered in
+ * cp->closed). The possible states are: WAIT_CONNECT, SSL_CONNECT,
+ * CONNECTED, JOINED, and SSL_SHUTDOWN.
+ *
+ * A connection in state SSL_ACCEPT can be closed and removed without
+ * synchronization.
+ *
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#ifdef __WIN32__
+#include "esock_winsock.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#ifdef __WIN32__
+#include <process.h>
+#else
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <sys/time.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#endif
+
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xffffffff /* Should be in <netinet/in.h>. */
+#endif
+
+#include "esock.h"
+#include "debuglog.h"
+#include "esock_utils.h"
+#include "esock_ssl.h"
+#include "esock_osio.h"
+#include "esock_posix_str.h"
+#include "esock_poll.h"
+
+#define MAJOR_VERSION 2
+#define MINOR_VERSION 0
+#define MAXREPLYBUF 256
+#define RWBUFLEN (32*1024)
+#define IS_CLIENT 0
+#define IS_SERVER 1
+#define SELECT_TIMEOUT 2 /* seconds */
+
+#define psx_errstr() esock_posix_str(sock_errno())
+#define ssl_errstr() esock_ssl_errstr
+
+#define PROXY_TO_SSL_VALID(cp) (!(cp)->bp && \
+ ((cp)->wq.len > 0 || !(cp)->proxy->eof))
+
+#define SSL_TO_PROXY_VALID(cp) (!(cp)->proxy->bp && \
+ ((cp)->proxy->wq.len > 0 || !(cp)->eof))
+
+#define JOINED_STATE_INVALID(cp) (!(PROXY_TO_SSL_VALID(cp)) && \
+ !(SSL_TO_PROXY_VALID(cp)))
+static int loop(void);
+static int set_poll_conns(Connection *cp, EsockPoll *ep, int verbose);
+static Connection *next_polled_conn(Connection *cp, Connection **cpnext,
+ EsockPoll *ep, int set_wq_fds);
+
+static void leave_joined_state(Connection *cp);
+static void do_shutdown(Connection *cp);
+static void close_and_remove_connection(Connection *cp);
+static int reply(int cmd, char *fmt, ...);
+static int input(char *fmt, ...);
+static int put_pars(unsigned char *buf, char *fmt, va_list args);
+static int get_pars(unsigned char *buf, char *fmt, va_list args);
+static FD do_connect(char *lipstring, int lport, char *fipstring, int fport);
+static FD do_listen(char *ipstring, int lport, int backlog, int *aport);
+static FD do_accept(FD listensock, struct sockaddr *saddr, int *len);
+static void print_connections(void);
+static void dump_connections(void);
+static int check_num_sock_fds(FD fd);
+static void safe_close(FD fd);
+static Connection *new_connection(int state, FD fd);
+static Connection *get_connection(FD fd);
+static void remove_connection(Connection *conn);
+static Proxy *get_proxy_by_peerport(int port);
+static Proxy *new_proxy(FD fd);
+static void remove_proxy(Proxy *proxy);
+static void ensure_write_queue(WriteQueue *wq, int size);
+static void clean_up(void);
+
+static Connection *connections = NULL;
+static int num_sock_fds; /* On UNIX all file descriptors */
+static Proxy *proxies = NULL;
+static int proxy_listensock = INVALID_FD;
+static int proxy_listenport = 0;
+static int proxy_backlog = 128;
+static int proxysock_last_err = 0;
+static int proxysock_err_cnt = 0;
+static char rwbuf[RWBUFLEN];
+static unsigned char *ebuf = NULL; /* Set by read_ctrl() */
+
+static char *connstr[] = {
+ "STATE_NONE",
+ "ACTIVE_LISTENING",
+ "PASSIVE_LISTENING",
+ "CONNECTED",
+ "WAIT_CONNECT",
+ "SSL_CONNECT",
+ "SSL_ACCEPT",
+ "TRANSPORT_ACCEPT",
+ "JOINED",
+ "SSL_SHUTDOWN",
+ "DEFUNCT"
+};
+
+static char *originstr[] = {
+ "listen",
+ "accept",
+ "connect"
+};
+
+int main(int argc, char **argv)
+{
+ char *logfile = NULL;
+ int i;
+ esock_version *vsn;
+ char *ciphers;
+#ifdef __WIN32__
+ int pid;
+ WORD version;
+ WSADATA wsa_data;
+
+ set_binary_mode();
+ setvbuf(stderr, NULL, _IONBF, 0);
+ /* Two sockets for the stdin socket pipe (local thread). */
+ num_sock_fds = 2;
+#else
+ pid_t pid;
+ num_sock_fds = 3; /* 0, 1, 2 */
+#endif
+
+ pid = getpid();
+ i = 1;
+ while (i < argc) {
+ if (strcmp(argv[i], "-d") == 0) {
+ debug = 1;
+ i++;
+ } else if (strcmp(argv[i], "-dm") == 0) {
+ debugmsg = 1;
+ i++;
+ } else if (strcmp(argv[i], "-pp") == 0) {
+ i++;
+ proxy_listenport = atoi(argv[i]);
+ i++;
+ } else if (strcmp(argv[i], "-pb") == 0) {
+ i++;
+ proxy_backlog = atoi(argv[i]);
+ i++;
+ } else if (strcmp(argv[i], "-pv") == 0) {
+ i++;
+ protocol_version = atoi(argv[i]);
+ i++;
+ } else if (strcmp(argv[i], "-dd") == 0) {
+ i++;
+ logfile = esock_malloc(strlen(argv[i]) + 64);
+ sprintf(logfile, "%s/ssl_esock.%d.log", argv[i], (int)pid);
+ i++;
+ } else if (strcmp(argv[i], "-ersa") == 0) {
+ ephemeral_rsa = 1;
+ i++;
+ } else if (strcmp(argv[i], "-edh") == 0) {
+ ephemeral_dh = 1;
+ i++;
+ }
+ }
+ if (debug || debugmsg) {
+ DEBUGF(("Starting ssl_esock\n"));
+ if (logfile) {
+ open_ssllog(logfile);
+#ifndef __WIN32__
+ num_sock_fds++;
+#endif
+ }
+ atexit(close_ssllog);
+ DEBUGF(("pid = %d\n", getpid()));
+ }
+ if (esock_ssl_init() < 0) {
+ fprintf(stderr, "esock: Could not do esock_ssl_init\n");
+ exit(EXIT_FAILURE);
+ }
+
+ atexit(esock_ssl_finish);
+
+#ifdef __WIN32__
+ /* Start Windows' sockets */
+ version = MAKEWORD(MAJOR_VERSION, MINOR_VERSION);
+ if (WSAStartup(version, &wsa_data) != 0) {
+ fprintf(stderr, "esock: Could not start up Windows' sockets\n");
+ exit(EXIT_FAILURE);
+ }
+ atexit((void (*)(void))WSACleanup);
+ if (LOBYTE(wsa_data.wVersion) < MAJOR_VERSION ||
+ (LOBYTE(wsa_data.wVersion) == MAJOR_VERSION &&
+ HIBYTE(wsa_data.wVersion) < MINOR_VERSION)) {
+ fprintf(stderr, "esock: Windows socket version error. "
+ "Requested version:"
+ "%d.%d, version found: %d.%d\n", MAJOR_VERSION,
+ MINOR_VERSION, LOBYTE(wsa_data.wVersion),
+ HIBYTE(wsa_data.wVersion));
+ exit(EXIT_FAILURE);
+ }
+ DEBUGF(("Using Windows socket version: %d.%d\n",
+ LOBYTE(wsa_data.wVersion), HIBYTE(wsa_data.wVersion)));
+ DEBUGF(("Maximum number of sockets available: %d\n",
+ wsa_data.iMaxSockets));
+
+ if (esock_osio_init() < 0) {
+ fprintf(stderr, "esock: Could not init osio\n");
+ exit(EXIT_FAILURE);
+ }
+ atexit(esock_osio_finish);
+#endif
+
+ /* Create the local proxy listen socket and set it to non-blocking */
+ proxy_listensock = do_listen("127.0.0.1", proxy_listenport,
+ proxy_backlog, &proxy_listenport);
+ if (proxy_listensock == INVALID_FD) {
+ fprintf(stderr, "esock: Cannot create local listen socket\n");
+ exit(EXIT_FAILURE);
+ }
+ SET_NONBLOCKING(proxy_listensock);
+ DEBUGF(("Local proxy listen socket: fd = %d, port = %d\n",
+ proxy_listensock, proxy_listenport));
+
+ vsn = esock_ssl_version();
+ ciphers = esock_ssl_ciphers();
+
+ /* Report: port number of the local proxy listen socket, the native
+ * os pid, the compile and lib versions of the ssl library, and
+ * the list of available ciphers. */
+ reply(ESOCK_PROXY_PORT_REP, "24sss", proxy_listenport, (int)pid,
+ vsn->compile_version, vsn->lib_version, ciphers);
+
+ atexit(clean_up);
+
+ loop();
+
+ if (logfile)
+ esock_free(logfile);
+ exit(EXIT_SUCCESS);
+}
+
+
+/*
+ * Local functions
+ *
+ */
+
+static int loop(void)
+{
+ EsockPoll pollfd;
+ FD fd, msgsock, listensock, connectsock, proxysock;
+ int cc, wc, fport, lport, pport, length, backlog, intref, op;
+ int value;
+ char *lipstring, *fipstring;
+ char *flags;
+ char *protocol_vsn, *cipher;
+ unsigned char *cert, *bin;
+ int certlen, binlen;
+ struct sockaddr_in iserv_addr;
+ int sret = 1;
+ Connection *cp, *cpnext, *newcp;
+ Proxy *pp;
+ time_t last_time = 0, now = 0;
+ int set_wq_fds;
+
+ esock_poll_init(&pollfd);
+
+ while(1) {
+ esock_poll_zero(&pollfd);
+ esock_poll_fd_set_read(&pollfd, proxy_listensock);
+ esock_poll_fd_set_read(&pollfd, local_read_fd);
+
+ set_wq_fds = 0;
+
+ if (sret) /* sret == 1 the first time. */
+ DEBUGF(("==========LOOP=============\n"));
+
+ cc = set_poll_conns(connections, &pollfd, sret) + 1;
+
+ if (sret) {
+ print_connections();
+ DEBUGF(("Before poll/select: %d descriptor%s (total %d)\n",
+ cc, (cc == 1) ? "" : "s", num_sock_fds));
+ }
+
+ sret = esock_poll(&pollfd, SELECT_TIMEOUT);
+ if (sret < 0) {
+ DEBUGF(("select/poll error: %s\n", psx_errstr()));
+ continue;
+ }
+
+ time(&now);
+ if (now >= last_time + SELECT_TIMEOUT) {
+ set_wq_fds = 1;
+ last_time = now;
+ }
+ /*
+ * First accept as many connections as possible on the
+ * proxy listen socket. We record the peer port, which
+ * is later used as a reference for joining a proxy
+ * connection with a network connection.
+ */
+
+ if (esock_poll_fd_isset_read(&pollfd, proxy_listensock)) {
+ while (1) {
+ length = sizeof(iserv_addr);
+ proxysock = do_accept(proxy_listensock,
+ (struct sockaddr *)&iserv_addr,
+ (int*)&length);
+ if(proxysock == INVALID_FD) {
+ if (sock_errno() != ERRNO_BLOCK) {
+ /* We can here for example get the error
+ * EMFILE, i.e. no more file descriptors
+ * available, but we do not have any specific
+ * connection to report the error to. We
+ * increment the error counter and saves the
+ * last err.
+ */
+ proxysock_err_cnt++;
+ proxysock_last_err = sock_errno();
+ DEBUGF(("accept error (proxy_listensock): %s\n",
+ psx_errstr()));
+ }
+ break;
+ } else {
+ /* Get peer port number */
+/* length = sizeof(iserv_addr); */
+/* if (getpeername(proxysock, (struct sockaddr *)&iserv_addr, */
+/* &length) < 0) { */
+/* DEBUGF(("Can't get peername of proxy socket")); */
+/* safe_close(proxysock); */
+/* } else { */
+ /* Add to pending proxy connections */
+ SET_NONBLOCKING(proxysock);
+ pp = new_proxy(proxysock);
+ pp->peer_port = ntohs(iserv_addr.sin_port);
+ DEBUGF(("-----------------------------------\n"));
+ DEBUGF(("[PROXY_LISTEN_SOCK] conn accepted: "
+ "proxyfd = %d, "
+ "peer port = %d\n", proxysock, pp->peer_port));
+/* } */
+ }
+ }
+ }
+
+ /*
+ * Read control messages from Erlang
+ */
+ if (esock_poll_fd_isset_read(&pollfd, local_read_fd)) {
+ cc = read_ctrl(&ebuf);
+ if ( cc < 0 ) {
+ DEBUGF(("Read loop -1 or 0\n"));
+ return -1;
+ } else if (cc == 0) { /* not eof */
+ DEBUGF(("GOT empty string \n"));
+
+ } else {
+
+ switch((int)*ebuf) {
+
+ case ESOCK_SET_SEED_CMD:
+ /*
+ * ebuf = {cmd(1), binary(N) }
+ */
+ input("b", &binlen, &bin);
+ DEBUGF(("[SET_SEED_CMD]\n"));
+ esock_ssl_seed(bin, binlen);
+ /* no reply */
+ break;
+
+ case ESOCK_GETPEERNAME_CMD:
+ /*
+ * ebuf = {cmd(1), fd(4)}
+ */
+ input("4", &fd);
+ DEBUGF(("[GETPEERNAME_CMD] fd = %d\n", fd));
+ cp = get_connection(fd);
+ length = sizeof(iserv_addr);
+ if (!cp) {
+ sock_set_errno(ERRNO_NOTSOCK);
+ reply(ESOCK_GETPEERNAME_ERR, "4s", fd, psx_errstr());
+ } else if (getpeername(fd,
+ (struct sockaddr *) &iserv_addr,
+ &length) < 0) {
+ reply(ESOCK_GETPEERNAME_ERR, "4s", fd, psx_errstr());
+ } else {
+ /*
+ * reply = {cmd(1), fd(4), port(2),
+ * ipstring(N), 0(1)}
+ */
+ reply(ESOCK_GETPEERNAME_REP, "42s", fd,
+ ntohs(iserv_addr.sin_port),
+ inet_ntoa(iserv_addr.sin_addr));
+ }
+ break;
+
+ case ESOCK_GETSOCKNAME_CMD:
+ /*
+ * ebuf = {cmd(1), fd(4)}
+ */
+ input("4", &fd);
+ DEBUGF(("[GETSOCKNAME_CMD] fd = %d\n", fd));
+ cp = get_connection(fd);
+ length = sizeof(iserv_addr);
+ if (!cp) {
+ sock_set_errno(ERRNO_NOTSOCK);
+ reply(ESOCK_GETSOCKNAME_ERR, "4s", fd, psx_errstr());
+ } else if (getsockname(fd,
+ (struct sockaddr *)&iserv_addr,
+ &length) < 0) {
+ reply(ESOCK_GETSOCKNAME_ERR, "4s", fd, psx_errstr());
+ } else {
+ /*
+ * reply = {cmd(1), fd(4), port(2),
+ * ipstring(N), 0(1)}
+ */
+ reply(ESOCK_GETSOCKNAME_REP, "42s", fd,
+ ntohs(iserv_addr.sin_port),
+ inet_ntoa(iserv_addr.sin_addr));
+ }
+ break;
+
+ case ESOCK_GETCONNINFO_CMD:
+ /*
+ * ebuf = {cmd(1), fd(4)}
+ */
+ input("4", &fd);
+ DEBUGF(("[GETCONNINFO_CMD] fd = %d\n", fd));
+ cp = get_connection(fd);
+ if (!cp) {
+ sock_set_errno(ERRNO_NOTSOCK);
+ reply(ESOCK_GETCONNINFO_ERR, "4s", fd, psx_errstr());
+ } else {
+ if (esock_ssl_getprotocol_version(cp,
+ &protocol_vsn) < 0)
+ reply(ESOCK_GETCONNINFO_ERR, "4s", fd, psx_errstr());
+ else if (esock_ssl_getcipher(cp, &cipher) < 0)
+ reply(ESOCK_GETCONNINFO_ERR, "4s", fd, psx_errstr());
+ else
+ /*
+ * reply = {cmd(1), fd(4), protocol(N), 0(1),
+ * cipher(N), 0(1)}
+ */
+ reply(ESOCK_GETCONNINFO_REP, "4ss", fd,
+ protocol_vsn, cipher);
+ }
+ break;
+
+ case ESOCK_GETPEERCERT_CMD:
+ /*
+ * ebuf = {cmd(1), fd(4)}
+ */
+ input("4", &fd);
+ DEBUGF(("[GETPEERCERT_CMD] fd = %d\n", fd));
+ cp = get_connection(fd);
+ if (!cp) {
+ sock_set_errno(ERRNO_NOTSOCK);
+ reply(ESOCK_GETPEERCERT_ERR, "4s", fd, psx_errstr());
+ } else {
+ if ((certlen = esock_ssl_getpeercert(cp, &cert)) < 0)
+ reply(ESOCK_GETPEERCERT_ERR, "4s", fd, psx_errstr());
+ else {
+ /*
+ * reply = {cmd(1), fd(4), certlen(4), cert(N)}
+ */
+ reply(ESOCK_GETPEERCERT_REP, "4b", fd,
+ certlen, cert);
+ esock_free(cert);
+ }
+ }
+ break;
+
+ case ESOCK_CONNECT_CMD:
+ /*
+ * ebuf = {cmd(1), intref(4),
+ * lport(2), lipstring(N), 0(1), -- local
+ * fport(2), fipstring(N), 0(1), -- foreign
+ * flags(N), 0(1)}
+ */
+ input("42s2ss", &intref, &lport, &lipstring,
+ &fport, &fipstring, &flags);
+ DEBUGF(("[CONNECT_CMD] intref = %d, "
+ "lipstring = %s lport = %d, "
+ "fipstring = %s fport = %d, "
+ "flags = %s\n", intref, lipstring, lport,
+ fipstring, fport, flags));
+ connectsock = do_connect(lipstring, lport,
+ fipstring, fport);
+ if(connectsock == INVALID_FD) {
+ reply(ESOCK_CONNECT_SYNC_ERR, "4s", intref, psx_errstr());
+ break;
+ }
+ DEBUGF((" fd = %d\n", connectsock));
+ cp = new_connection(ESOCK_WAIT_CONNECT, connectsock);
+ cp->origin = ORIG_CONNECT;
+ length = strlen(flags);
+ cp->flags = esock_malloc(length + 1);
+ strcpy(cp->flags, flags);
+ DEBUGF(("-> WAIT_CONNECT fd = %d\n", connectsock));
+ /* Publish connectsock */
+ reply(ESOCK_CONNECT_WAIT_REP, "44", intref, connectsock);
+ break;
+
+ case ESOCK_TERMINATE_CMD:
+ /*
+ * ebuf = {cmd(1)}
+ */
+ exit(EXIT_SUCCESS);
+ break;
+
+ case ESOCK_CLOSE_CMD:
+ /*
+ * ebuf = {cmd(1), fd(4)}
+ */
+ input("4", &fd);
+ if ((cp = get_connection(fd))) {
+ DEBUGF(("%s[CLOSE_CMD]: fd = %d\n",
+ connstr[cp->state], fd));
+ if (cp->proxy)
+ cp->proxy->bp = 1;
+ switch (cp->state) {
+ case ESOCK_JOINED:
+ cp->close = 1;
+ if (JOINED_STATE_INVALID(cp))
+ leave_joined_state(cp);
+ break;
+ case ESOCK_SSL_SHUTDOWN:
+ cp->close = 1;
+ DEBUGF((" close flag set\n"));
+ break;
+ default:
+ DEBUGF(("-> (removal)\n"));
+ close_and_remove_connection(cp);
+ }
+ } else
+ DEBUGF(("[CLOSE_CMD]: ERROR: fd = %d not found\n", fd));
+ break;
+
+ case ESOCK_SET_SOCKOPT_CMD:
+ /*
+ * ebuf = {cmd(1), fd(4), op(1), on(1)}
+ */
+ input("411", &fd, &op, &value);
+ switch(op) {
+ case ESOCK_SET_TCP_NODELAY:
+ if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
+ (void *)&value, sizeof(value)) < 0) {
+ DEBUGF(("Error: setsockopt TCP_NODELAY\n"));
+ reply(ESOCK_IOCTL_ERR, "4s", fd, psx_errstr());
+ } else {
+ reply(ESOCK_IOCTL_OK, "4", fd);
+ }
+ break;
+ default:
+ DEBUGF(("Error: set_sock_opt - Not implemented\n"));
+ sock_set_errno(ERRNO_OPNOTSUPP);
+ reply(ESOCK_IOCTL_ERR, "4", fd, psx_errstr());
+ break;
+ }
+ break;
+
+ case ESOCK_LISTEN_CMD:
+ /*
+ * ebuf = {cmd(1), intref(4), lport(2), ipstring(N), 0(1),
+ * backlog(2), flags(N), 0(1)}
+ */
+ input("42s2s", &intref, &lport, &lipstring, &backlog,
+ &flags);
+ DEBUGF(("[LISTEN_CMD] intref = %d, port = %d, "
+ "ipstring = %s, backlog = %d, flags = %s\n",
+ intref, lport, lipstring, backlog, flags));
+
+ listensock = do_listen(lipstring, lport, backlog, &lport);
+ if(listensock == INVALID_FD) {
+ reply(ESOCK_LISTEN_SYNC_ERR, "4s", intref, psx_errstr());
+ break;
+ }
+ cp = new_connection(ESOCK_PASSIVE_LISTENING, listensock);
+ /* Flags may be an empty string */
+ length = strlen(flags);
+ cp->flags = esock_malloc(length + 1);
+ strcpy(cp->flags, flags);
+
+ cp->origin = ORIG_LISTEN;
+ if (esock_ssl_listen_init(cp) < 0) {
+ DEBUGF(("esock_ssl_listen_init() failed.\n"));
+ reply(ESOCK_LISTEN_SYNC_ERR, "4s", intref,
+ ssl_errstr());
+ close_and_remove_connection(cp);
+ break;
+ }
+ DEBUGF(("-> PASSIVE_LISTENING (fd = %d)\n", listensock));
+ /* Publish listensock */
+ reply(ESOCK_LISTEN_REP, "442", intref, listensock,
+ ntohs(iserv_addr.sin_port));
+ break;
+
+ case ESOCK_TRANSPORT_ACCEPT_CMD:
+ /*
+ * ebuf = { op(1), fd(4), flags(N), 0(1)}
+ */
+ input("4s", &fd, &flags);
+ DEBUGF(("[TRANSPORT_ACCEPT_CMD] listenfd = %d, flags = %s\n", fd,
+ flags));
+ cp = get_connection(fd);
+ if (cp) {
+ /* We store the flags in the listen socket's
+ * connection, and overwrite previous flags.
+ */
+ if ((length = strlen(flags)) > 0) {
+ if (cp->flags)
+ cp->flags = esock_realloc(cp->flags,
+ length + 1);
+ else
+ cp->flags = esock_malloc(length + 1);
+ strcpy(cp->flags, flags);
+ }
+ if (cp->flags && cp->flags[0] != '\0') {
+ cp->acceptors++;
+ cp->state = ESOCK_ACTIVE_LISTENING;
+ DEBUGF(("-> ACTIVE_LISTENING\n"));
+ break;
+ }
+ DEBUGF(("ERROR: flags empty\n"));
+ }
+ reply(ESOCK_TRANSPORT_ACCEPT_ERR, "4s", fd, "ebadf");
+ break;
+
+ case ESOCK_SSL_ACCEPT_CMD:
+ input("4s", &fd, &flags);
+ DEBUGF(("[SSL_ACCEPT_CMD] fd = %d, flags = %s\n", fd, flags));
+ cp = get_connection(fd);
+ if (cp)
+ cp->state = ESOCK_SSL_ACCEPT;
+ //reply(ESOCK_SSL_ACCEPT_REP, "4", fd);
+ break;
+
+ case ESOCK_NOACCEPT_CMD:
+ /*
+ * ebuf = {cmd(1), fd(4)}
+ */
+ input("4", &fd);
+ DEBUGF(("[NOACCEPT_CMD] listenfd = %d\n", fd));
+ cp = get_connection(fd);
+ if (cp && (--cp->acceptors <= 0)) {
+ cp->acceptors = 0;
+ cp->state = ESOCK_PASSIVE_LISTENING;
+ esock_poll_clear_event(&pollfd, fd);
+ DEBUGF(("-> PASSIVE_LISTENING\n"));
+ }
+ break;
+
+ case ESOCK_PROXY_JOIN_CMD:
+ /*
+ * ebuf = {cmd(1), fd(4), portnum(2)}
+ *
+ * fd - file descriptor of a connection in state
+ * CONNECTED
+ * portnum - port number of the Erlang proxy peer
+ */
+ input("42", &fd, &pport);
+ cp = get_connection(fd);
+ pp = get_proxy_by_peerport(pport);
+ if (cp && cp->state == ESOCK_CONNECTED && pp) {
+ DEBUGF(("CONNECTED[PROXY_JOIN_CMD] fd = %d "
+ "portnum = %d\n", fd, pport));
+ cp->proxy = pp;
+ pp->conn = cp;
+ reply(ESOCK_PROXY_JOIN_REP, "4", fd);
+ cp->state = ESOCK_JOINED;
+ DEBUGF(("-> JOINED\n"));
+ break;
+ }
+ if (!cp) {
+ DEBUGF(("[PROXY_JOIN_CMD] ERROR: No connection "
+ "having fd = %d\n", fd));
+ reply(ESOCK_PROXY_JOIN_ERR, "4s", fd, "ebadsocket");
+ } else if (cp->state != ESOCK_CONNECTED) {
+ DEBUGF(("%s[PROXY_JOIN_CMD] ERROR: Bad state: "
+ "fd = %d\n", connstr[cp->state], cp->fd));
+ reply(ESOCK_PROXY_JOIN_ERR, "4s", fd, "ebadstate");
+ } else {
+ DEBUGF(("ERROR: No proxy: fd = %d, pport = %d\n",
+ fd, pport));
+ if (proxysock_err_cnt > 0) {
+ proxysock_err_cnt--;
+ reply(ESOCK_PROXY_JOIN_ERR, "4s", fd,
+ esock_posix_str(proxysock_last_err));
+ } else {
+ reply(ESOCK_PROXY_JOIN_ERR, "4s", fd,
+ "enoproxysocket");
+ }
+ cp->state = ESOCK_DEFUNCT;
+ }
+ break;
+
+ case ESOCK_DUMP_STATE_CMD:
+ dump_connections();
+ break;
+
+ case ESOCK_SET_DEBUG_CMD:
+ /*
+ * ebuf = {cmd(1), debug(1)}
+ */
+ input("1", &debug);
+ break;
+
+ case ESOCK_SET_DEBUGMSG_CMD:
+ /*
+ * ebuf = {cmd(1), debugmsg(1)}
+ */
+ input("1", &debugmsg);
+ break;
+
+ default:
+ fprintf(stderr, "esock: default value in loop %c\n",
+ *ebuf);
+ exit(EXIT_FAILURE);
+ break;
+ }
+ }
+ }
+
+ /* Go through all connections that have their file descriptors
+ set. */
+
+ /* Note: We may remove the current connection (cp). Thus we
+ * must be careful not to read cp->next after cp has been
+ * removed. */
+ for (cp = next_polled_conn(connections, &cpnext, &pollfd, set_wq_fds);
+ cp != NULL;
+ cp = next_polled_conn(cpnext, &cpnext, &pollfd, set_wq_fds)
+ ) {
+
+ switch(cp->state) {
+
+ case ESOCK_PASSIVE_LISTENING:
+ DEBUGF(("-----------------------------------\n"));
+ fprintf(stderr, "esock: Got connect request while PASSIVE\n");
+ exit(EXIT_FAILURE);
+ break;
+
+ case ESOCK_ACTIVE_LISTENING:
+ /* new connect from network */
+ DEBUGF(("-----------------------------------\n"));
+ DEBUGF(("ACTIVE_LISTENING - trying to accept on %d\n",
+ cp->fd));
+ length = sizeof(iserv_addr);
+ msgsock = do_accept(cp->fd, (struct sockaddr*)&iserv_addr,
+ (int*)&length);
+ if(msgsock == INVALID_FD) {
+ DEBUGF(("accept error: %s\n", psx_errstr()));
+ reply(ESOCK_TRANSPORT_ACCEPT_ERR, "4s", cp->fd, psx_errstr());
+ break;
+ }
+ SET_NONBLOCKING(msgsock);
+ if (--cp->acceptors <= 0) {
+ cp->acceptors = 0;
+ cp->state = ESOCK_PASSIVE_LISTENING;
+ DEBUGF(("-> PASSIVE_LISTENING\n"));
+ }
+ DEBUGF(("server accepted connection on fd %d\n", msgsock));
+ newcp = new_connection(ESOCK_TRANSPORT_ACCEPT, msgsock);
+ newcp->origin = ORIG_ACCEPT;
+ reply(ESOCK_TRANSPORT_ACCEPT_REP, "44", cp->fd, msgsock);
+ newcp->listen_fd = cp->fd; /* Needed for ESOCK_ACCEPT_ERR */
+ length = strlen(cp->flags);
+ /* XXX new flags are not needed */
+ newcp->flags = esock_malloc(length + 1);
+ strcpy(newcp->flags, cp->flags); /* XXX Why? */
+ if (esock_ssl_accept_init(newcp, cp->opaque) < 0) {
+ cp->errstr = ssl_errstr();
+ break;
+ }
+ newcp->ssl_want = ESOCK_SSL_WANT_READ;
+ break;
+
+ case ESOCK_SSL_ACCEPT:
+ /* SSL accept handshake. msgsock is *not* published yet. */
+ msgsock = cp->fd;
+ DEBUGF(("-----------------------------------\n"));
+ DEBUGF(("SSL_ACCEPT fd = %d\n", msgsock));
+ if (cp->errstr != NULL) { /* this means we got an error in ssl_accept_init */
+ /* N.B.: The *listen fd* is reported. */
+ reply(ESOCK_SSL_ACCEPT_ERR, "4s", msgsock, cp->errstr);
+ close_and_remove_connection(cp);
+ break;
+ }
+ if (esock_ssl_accept(cp) < 0) {
+ if (sock_errno() != ERRNO_BLOCK) {
+ /* Handshake failed. */
+ reply(ESOCK_SSL_ACCEPT_ERR, "4s", msgsock,
+ ssl_errstr());
+ DEBUGF(("ERROR: handshake: %s\n", ssl_errstr()));
+ close_and_remove_connection(cp);
+ }
+ } else {
+ /* SSL handshake successful: publish */
+ reply(ESOCK_SSL_ACCEPT_REP, "4", msgsock);
+ DEBUGF(("-> CONNECTED\n"));
+ DEBUGF((" Session was %sreused.\n",
+ (esock_ssl_session_reused(cp)) ? "" : "NOT "));
+ cp->state = ESOCK_CONNECTED;
+ }
+ break;
+
+ case ESOCK_CONNECTED:
+ /* Should not happen. We do not read or write until
+ the connection is in state JOINED. */
+ DEBUGF(("-----------------------------------\n"));
+ DEBUGF(("CONNECTED: Error: should not happen. fd = %d\n",
+ cp->fd));
+ break;
+
+ case ESOCK_JOINED:
+ /*
+ * Reading from Proxy, writing to SSL
+ */
+ if (esock_poll_fd_isset_write(&pollfd, cp->fd)) {
+ /* If there is a write queue, write to ssl only */
+ if (cp->wq.len > 0) {
+ /* The write retry semantics of SSL_write in
+ * the OpenSSL package is strange. Partial
+ * writes never occur, only complete writes or
+ * failures. A failure, however, still
+ * consumes all data written, although not all
+ * encrypted data could be written to the
+ * underlying socket. To retry a write we have
+ * to provide the same buf and length as in
+ * the original call, in our case rwbuf and
+ * the original buffer length. Hence the
+ * strange memcpy(). Note that wq.offset will
+ * always be zero when we use OpenSSL.
+ */
+ DEBUGF(("-----------------------------------\n"));
+ DEBUGF(("JOINED: writing to ssl "
+ "fd = %d, from write queue only, wc = %d\n",
+ cp->fd, cp->wq.len - cp->wq.offset));
+ memcpy(rwbuf, cp->wq.buf, cp->wq.len - cp->wq.offset);
+
+ /* esock_ssl_write sets cp->eof, cp->bp when return
+ * value is zero */
+ wc = esock_ssl_write(cp, rwbuf,
+ cp->wq.len - cp->wq.offset);
+ if (wc < 0) {
+ if (sock_errno() != ERRNO_BLOCK) {
+ /* Assume broken SSL pipe */
+ DEBUGF(("broken SSL pipe\n"));
+ cp->bp = 1;
+ shutdown(cp->proxy->fd, SHUTDOWN_READ);
+ cp->proxy->eof = 1;
+ if (JOINED_STATE_INVALID(cp)) {
+ leave_joined_state(cp);
+ break;
+ }
+ }
+ } else if (wc == 0) {
+ /* SSL broken pipe */
+ DEBUGF(("broken SSL pipe\n"));
+ cp->bp = 1;
+ shutdown(cp->proxy->fd, SHUTDOWN_READ);
+ cp->proxy->eof = 1;
+ if (JOINED_STATE_INVALID(cp)) {
+ leave_joined_state(cp);
+ break;
+ }
+ } else {
+ cp->wq.offset += wc;
+ if (cp->wq.offset == cp->wq.len)
+ cp->wq.len = 0;
+ }
+ }
+ } else if (esock_poll_fd_isset_read(&pollfd, cp->proxy->fd)) {
+ /* Read from proxy and write to SSL */
+ DEBUGF(("-----------------------------------\n"));
+ DEBUGF(("JOINED: reading from proxy, "
+ "proxyfd = %d\n", cp->proxy->fd));
+ cc = sock_read(cp->proxy->fd, rwbuf, RWBUFLEN);
+ DEBUGF(("read from proxyfd = %d, cc = %d\n",
+ cp->proxy->fd, cc));
+ if (cc > 0) {
+ /* esock_ssl_write sets cp->eof, cp->bp when return
+ * value is zero */
+ wc = esock_ssl_write(cp, rwbuf, cc);
+ if (wc < 0) {
+ if (sock_errno() != ERRNO_BLOCK) {
+ /* Assume broken pipe */
+ DEBUGF(("broken SSL pipe\n"));
+ cp->bp = 1;
+ shutdown(cp->proxy->fd, SHUTDOWN_READ);
+ cp->proxy->eof = 1;
+ if (JOINED_STATE_INVALID(cp)) {
+ leave_joined_state(cp);
+ break;
+ }
+ } else {
+ /* add to write queue */
+ DEBUGF(("adding all to write queue "
+ "%d bytes\n", cc));
+ ensure_write_queue(&cp->wq, cc);
+ memcpy(cp->wq.buf, rwbuf, cc);
+ cp->wq.len = cc;
+ cp->wq.offset = 0;
+ }
+ } else if (wc == 0) {
+ /* Broken SSL pipe */
+ DEBUGF(("broken SSL pipe\n"));
+ cp->bp = 1;
+ shutdown(cp->proxy->fd, SHUTDOWN_READ);
+ cp->proxy->eof = 1;
+ if (JOINED_STATE_INVALID(cp)) {
+ leave_joined_state(cp);
+ break;
+ }
+ } else if (wc < cc) {
+ /* add remainder to write queue */
+ DEBUGF(("adding remainder to write queue "
+ "%d bytes\n", cc - wc));
+ ensure_write_queue(&cp->wq, cc - wc);
+ memcpy(cp->wq.buf, rwbuf + wc, cc - wc);
+ cp->wq.len = cc - wc;
+ cp->wq.offset = 0;
+ }
+ } else {
+ /* EOF proxy or error */
+ DEBUGF(("proxy eof or error %d\n", errno));
+ cp->proxy->eof = 1;
+ if (cp->wq.len == 0) {
+ esock_ssl_shutdown(cp);
+ cp->bp = 1;
+ }
+ if (JOINED_STATE_INVALID(cp)) {
+ leave_joined_state(cp);
+ break;
+ }
+ }
+ }
+ /*
+ * Reading from SSL, writing to proxy
+ */
+ if (esock_poll_fd_isset_write(&pollfd, cp->proxy->fd)) {
+ /* If there is a write queue, write to proxy only */
+ if (cp->proxy->wq.len > 0) {
+ DEBUGF(("-----------------------------------\n"));
+ DEBUGF(("JOINED: writing to proxyfd = %d, "
+ "from write queue only, wc = %d\n",
+ cp->proxy->fd, cp->proxy->wq.len -
+ cp->proxy->wq.offset));
+ wc = sock_write(cp->proxy->fd, cp->proxy->wq.buf +
+ cp->proxy->wq.offset,
+ cp->proxy->wq.len -
+ cp->proxy->wq.offset);
+ if (wc < 0) {
+ if (sock_errno() != ERRNO_BLOCK) {
+ /* Assume broken pipe */
+ DEBUGF(("broken proxy pipe\n"));
+ cp->proxy->bp = 1;
+ /* There is no SSL shutdown for read */
+ cp->eof = 1;
+ if (JOINED_STATE_INVALID(cp)) {
+ leave_joined_state(cp);
+ break;
+ }
+ }
+ } else {
+ cp->proxy->wq.offset += wc;
+ if (cp->proxy->wq.offset == cp->proxy->wq.len)
+ cp->proxy->wq.len = 0;
+ }
+ }
+ } else if (esock_poll_fd_isset_read(&pollfd, cp->fd)) {
+ /* Read from SSL and write to proxy */
+ DEBUGF(("-----------------------------------\n"));
+ DEBUGF(("JOINED: read from ssl fd = %d\n",
+ cp->fd));
+ cc = esock_ssl_read(cp, rwbuf, RWBUFLEN);
+ DEBUGF(("read from fd = %d, cc = %d\n", cp->fd, cc));
+ if (cc > 0) {
+ wc = sock_write(cp->proxy->fd, rwbuf, cc);
+ if (wc < 0) {
+ if (sock_errno() != ERRNO_BLOCK) {
+ DEBUGF(("broken proxy pipe\n"));
+ /* Assume broken pipe */
+ cp->proxy->bp = 1;
+ /* There is no SSL shutdown for read */
+ cp->eof = 1;
+ if (JOINED_STATE_INVALID(cp)) {
+ leave_joined_state(cp);
+ break;
+ }
+ } else {
+ /* add all to write queue */
+ DEBUGF(("adding to write queue %d bytes\n",
+ cc));
+ ensure_write_queue(&cp->proxy->wq, cc);
+ memcpy(cp->proxy->wq.buf, rwbuf, cc);
+ cp->proxy->wq.len = cc;
+ cp->proxy->wq.offset = 0;
+ }
+ } else if (wc < cc) {
+ /* add to write queue */
+ DEBUGF(("adding to write queue %d bytes\n",
+ cc - wc));
+ ensure_write_queue(&cp->proxy->wq, cc - wc);
+ memcpy(cp->proxy->wq.buf, rwbuf + wc, cc - wc);
+ cp->proxy->wq.len = cc - wc;
+ cp->proxy->wq.offset = 0;
+ }
+ } else if (cc == 0) {
+ /* SSL eof */
+ DEBUGF(("SSL eof\n"));
+ cp->eof = 1;
+ if (cp->proxy->wq.len == 0) {
+ shutdown(cp->proxy->fd, SHUTDOWN_WRITE);
+ cp->proxy->bp = 1;
+ }
+ if (JOINED_STATE_INVALID(cp)) {
+ leave_joined_state(cp);
+ break;
+ }
+ } else {
+ /* This may very well happen when reading from SSL. */
+ DEBUGF(("NOTE: readmask set, cc < 0, fd = %d, "
+ "is ok\n", cp->fd));
+ }
+ }
+ break;
+
+ case ESOCK_SSL_SHUTDOWN:
+ DEBUGF(("-----------------------------------\n"));
+ DEBUGF(("SSL_SHUTDOWN: fd = %d\n", cp->fd));
+ do_shutdown(cp);
+ break;
+
+ case ESOCK_DEFUNCT:
+ DEBUGF(("-----------------------------------\n"));
+ DEBUGF(("DEFUNCT: ERROR: should not happen. fd = %d\n",
+ cp->fd));
+ break;
+
+ case ESOCK_WAIT_CONNECT:
+ /* New connection shows up */
+ connectsock = cp->fd;/* Is published */
+ DEBUGF(("-----------------------------------\n"));
+ DEBUGF(("WAIT_CONNECT fd = %d\n", connectsock));
+
+ /* If the connection did succeed it's possible to
+ * fetch the peer name (UNIX); or failure shows in
+ * exceptmask (WIN32). Sorry for the mess below, but
+ * we have to have balanced paren's in #ifdefs in
+ * order not to confuse Emacs' indentation. */
+ length = sizeof(iserv_addr);
+ if (
+#ifdef __WIN32__
+ esock_poll_fd_isset_exception(&pollfd, connectsock)
+#else
+ getpeername(connectsock, (struct sockaddr *)&iserv_addr,
+ &length) < 0
+#endif
+ ) {
+ sock_set_errno(ERRNO_CONNREFUSED);
+ DEBUGF(("connect error: %s\n", psx_errstr()));
+ reply(ESOCK_CONNECT_ERR, "4s", connectsock, psx_errstr());
+ cp->state = ESOCK_DEFUNCT;
+ break;
+ }
+ if (esock_ssl_connect_init(cp) < 0) {
+ DEBUGF(("esock_ssl_connect_init() failed\n"));
+ reply(ESOCK_CONNECT_ERR, "4s", connectsock, ssl_errstr());
+ cp->state = ESOCK_DEFUNCT;
+ break;
+ }
+ DEBUGF(("-> SSL_CONNECT\n"));
+ cp->state = ESOCK_SSL_CONNECT;
+ cp->ssl_want = ESOCK_SSL_WANT_WRITE;
+ break;
+
+ case ESOCK_SSL_CONNECT:
+ /* SSL connect handshake. connectsock is published. */
+ connectsock = cp->fd;
+ DEBUGF(("-----------------------------------\n"));
+ DEBUGF(("SSL_CONNECT fd = %d\n", connectsock));
+ if (esock_ssl_connect(cp) < 0) {
+ if (sock_errno() != ERRNO_BLOCK) {
+ /* Handshake failed */
+ DEBUGF(("ERROR: handshake: %s\n", ssl_errstr()));
+ reply(ESOCK_CONNECT_ERR, "4s", connectsock,
+ ssl_errstr());
+ cp->state = ESOCK_DEFUNCT;
+ }
+ } else {
+ /* SSL connect handshake successful */
+ DEBUGF(("-> CONNECTED\n"));
+ reply(ESOCK_CONNECT_REP, "4", connectsock);
+ cp->state = ESOCK_CONNECTED;
+ }
+ break;
+
+ default:
+ DEBUGF(("ERROR: Connection in unknown state.\n"));
+ }
+ }
+ }
+}
+
+static int set_poll_conns(Connection *cp, EsockPoll *ep, int verbose)
+{
+ int i = 0;
+
+ if (verbose)
+ DEBUGF(("MASKS SET FOR FD: "));
+ while (cp) {
+ switch (cp->state) {
+ case ESOCK_ACTIVE_LISTENING:
+ if (verbose)
+ DEBUGF(("%d (read) ", cp->fd));
+ esock_poll_fd_set_read(ep, cp->fd);
+ break;
+ case ESOCK_WAIT_CONNECT:
+ if (verbose)
+ DEBUGF(("%d (write) ", cp->fd));
+ esock_poll_fd_set_write(ep, cp->fd);
+#ifdef __WIN32__
+ esock_poll_fd_set_exception(ep, cp->fd); /* Failure shows in exceptions */
+#endif
+ break;
+ case ESOCK_SSL_CONNECT:
+ case ESOCK_SSL_ACCEPT:
+ if (cp->ssl_want == ESOCK_SSL_WANT_READ) {
+ if (verbose)
+ DEBUGF(("%d (read) ", cp->fd));
+ esock_poll_fd_set_read(ep, cp->fd);
+ } else if (cp->ssl_want == ESOCK_SSL_WANT_WRITE) {
+ if (verbose)
+ DEBUGF(("%d (write) ", cp->fd));
+ esock_poll_fd_set_write(ep, cp->fd);
+ }
+ break;
+ case ESOCK_JOINED:
+ if (!cp->bp) {
+ if (cp->wq.len) {
+ if (verbose)
+ DEBUGF(("%d (write) ", cp->fd));
+ esock_poll_fd_set_write(ep, cp->fd);
+ } else if (!cp->proxy->eof) {
+ if (verbose)
+ DEBUGF(("%d (read) ", cp->proxy->fd));
+ esock_poll_fd_set_read(ep, cp->proxy->fd);
+ }
+ }
+ if (!cp->proxy->bp) {
+ if (cp->proxy->wq.len) {
+ if (verbose)
+ DEBUGF(("%d (write) ", cp->proxy->fd));
+ esock_poll_fd_set_write(ep, cp->proxy->fd);
+ } else if (!cp->eof) {
+ if (verbose)
+ DEBUGF(("%d (read) ", cp->fd));
+ esock_poll_fd_set_read(ep, cp->fd);
+ }
+ }
+ break;
+ case ESOCK_SSL_SHUTDOWN:
+ if (cp->ssl_want == ESOCK_SSL_WANT_READ) {
+ if (verbose)
+ DEBUGF(("%d (read) ", cp->fd));
+ esock_poll_fd_set_read(ep, cp->fd);
+ } else if (cp->ssl_want == ESOCK_SSL_WANT_WRITE) {
+ if (verbose)
+ DEBUGF(("%d (write) ", cp->fd));
+ esock_poll_fd_set_write(ep, cp->fd);
+ }
+ break;
+ default:
+ break;
+ }
+ i++;
+ cp = cp->next;
+ }
+ if (verbose)
+ DEBUGF(("\n"));
+ return i;
+}
+
+
+static Connection *next_polled_conn(Connection *cp, Connection **cpnext,
+ EsockPoll *ep, int set_wq_fds)
+{
+ while(cp) {
+ if (esock_poll_fd_isset_read(ep, cp->fd) ||
+ (cp->proxy && esock_poll_fd_isset_read(ep, cp->proxy->fd)) ||
+ (esock_poll_fd_isset_write(ep, cp->fd)) ||
+ (cp->proxy && esock_poll_fd_isset_write(ep, cp->proxy->fd))
+#ifdef __WIN32__
+ || esock_poll_fd_isset_exception(ep, cp->fd) /* Connect failure in WIN32 */
+#endif
+ || (set_wq_fds && (cp->wq.len ||
+ (cp->proxy && cp->proxy->wq.len)))
+ || cp->errstr != NULL) {
+ *cpnext = cp->next;
+ return cp;
+ }
+ cp = cp->next;
+ }
+ *cpnext = NULL;
+ return NULL;
+}
+
+static void leave_joined_state(Connection *cp)
+{
+ shutdown(cp->proxy->fd, SHUTDOWN_ALL);
+ if (((cp->bp || cp->eof) && cp->clean) ||
+ (!cp->bp && !cp->eof)) {
+ DEBUGF(("-> SSL_SHUTDOWN\n"));
+ cp->state = ESOCK_SSL_SHUTDOWN;
+ cp->ssl_want = ESOCK_SSL_WANT_WRITE;
+ do_shutdown(cp);
+ } else if (cp->close) {
+ DEBUGF(("-> (removal)\n"));
+ close_and_remove_connection(cp);
+ } else {
+ DEBUGF(("-> DEFUNCT\n"));
+ cp->state = ESOCK_DEFUNCT;
+ }
+}
+
+/* We are always in state SHUTDOWN here */
+static void do_shutdown(Connection *cp)
+{
+ int ret;
+
+ ret = esock_ssl_shutdown(cp);
+ if (ret < 0) {
+ if (sock_errno() == ERRNO_BLOCK) {
+ return;
+ } else {
+ /* Something is wrong -- close and remove or move to DEFUNCT */
+ DEBUGF(("Error in SSL shutdown\n"));
+ if (cp->close) {
+ DEBUGF(("-> (removal)\n"));
+ close_and_remove_connection(cp);
+ } else {
+ DEBUGF(("-> DEFUNCT\n"));
+ cp->state = ESOCK_DEFUNCT;
+ }
+ }
+ } else if (ret == 0) {
+ /* `close_notify' has been sent. Wait for reception of
+ same. */
+ return;
+ } else if (ret == 1) {
+ /* `close_notify' has been sent, and received. */
+ if (cp->close) {
+ DEBUGF(("-> (removal)\n"));
+ close_and_remove_connection(cp);
+ } else {
+ DEBUGF(("-> DEFUNCT\n"));
+ cp->state = ESOCK_DEFUNCT;
+ }
+ }
+}
+
+static void close_and_remove_connection(Connection *cp)
+{
+ safe_close(cp->fd);
+ remove_connection(cp);
+}
+
+static int reply(int cmd, char *fmt, ...)
+{
+ static unsigned char replybuf[MAXREPLYBUF];
+ unsigned char *buf = replybuf;
+ va_list args;
+ int len;
+
+ va_start(args, fmt);
+ len = put_pars(NULL, fmt, args);
+ va_end(args);
+ len++;
+ if (len > sizeof(replybuf))
+ buf = esock_malloc(len);
+
+ PUT_INT8(cmd, buf);
+ va_start(args, fmt);
+ (void) put_pars(buf + 1, fmt, args);
+ va_end(args);
+ write_ctrl(buf, len);
+ if (buf != replybuf)
+ esock_free(buf);
+ return len;
+}
+
+static int input(char *fmt, ...)
+{
+ va_list args;
+ int len;
+
+ va_start(args, fmt);
+ len = get_pars(ebuf + 1, fmt, args);
+ va_end(args);
+ return len + 1;
+}
+
+static int put_pars(unsigned char *buf, char *fmt, va_list args)
+{
+ char *s, *str, *bin;
+ int val, len, pos = 0;
+
+ s = fmt;
+ while (*s) {
+ switch (*s) {
+ case '1':
+ val = va_arg(args, int);
+ if (buf)
+ PUT_INT8(val, buf + pos);
+ pos++;
+ break;
+ case '2':
+ val = va_arg(args, int);
+ if (buf)
+ PUT_INT16(val, buf + pos);
+ pos += 2;
+ break;
+ case '4':
+ val = va_arg(args, int);
+ if (buf)
+ PUT_INT32(val, buf + pos);
+ pos += 4;
+ break;
+ case 's': /* string */
+ str = va_arg(args, char *);
+ if (buf)
+ strcpy((char *)(buf + pos), str);
+ pos += strlen(str) + 1;
+ break;
+ case 'b': /* binary */
+ len = va_arg(args, int);
+ if (buf)
+ PUT_INT32(len, buf + pos);
+ pos += 4;
+ bin = va_arg(args, char *);
+ if (buf)
+ memcpy(buf + pos, bin, len);
+ pos += len;
+ break;
+ default:
+ fprintf(stderr, "esock: Invalid format character: %c\n", *s);
+ exit(EXIT_FAILURE);
+ break;
+ }
+ s++;
+ }
+ return pos;
+}
+
+
+static int get_pars(unsigned char *buf, char *fmt, va_list args)
+{
+ int *ip;
+ char *s, **strp, **bin;
+ int pos = 0;
+
+ s = fmt;
+ while (*s) {
+ switch (*s) {
+ case '1':
+ ip = va_arg(args, int *);
+ *ip = GET_INT8(buf + pos);
+ pos++;
+ break;
+ case '2':
+ ip = va_arg(args, int *);
+ *ip = GET_INT16(buf + pos);
+ pos += 2;
+ break;
+ case '4':
+ ip = va_arg(args, int *);
+ *ip = GET_INT32(buf + pos);
+ pos += 4;
+ break;
+ case 's':
+ strp = va_arg(args, char **);
+ *strp = (char *)(buf + pos);
+ pos += strlen(*strp) + 1;
+ break;
+ case 'b':
+ ip = va_arg(args, int *);
+ *ip = GET_INT32(buf + pos);
+ pos += 4;
+ bin = va_arg(args, char **);
+ *bin = (char *)(buf + pos);
+ pos += *ip;
+ break;
+ default:
+ fprintf(stderr, "esock: Invalid format character: %c\n", *s);
+ exit(EXIT_FAILURE);
+ break;
+ }
+ s++;
+ }
+ return pos;
+}
+
+static FD do_connect(char *lipstring, int lport, char *fipstring, int fport)
+{
+ struct sockaddr_in sock_addr;
+ long inaddr;
+ FD fd;
+
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_FD) {
+ DEBUGF(("Error calling socket()\n"));
+ return fd;
+ }
+ if (check_num_sock_fds(fd) < 0)
+ return INVALID_FD;
+ DEBUGF((" fd = %d\n", fd));
+
+ /* local */
+ if ((inaddr = inet_addr(lipstring)) == INADDR_NONE) {
+ DEBUGF(("Error in inet_addr(): lipstring = %s\n", lipstring));
+ safe_close(fd);
+ sock_set_errno(ERRNO_ADDRNOTAVAIL);
+ return INVALID_FD;
+ }
+ memset(&sock_addr, 0, sizeof(sock_addr));
+ sock_addr.sin_family = AF_INET;
+ sock_addr.sin_addr.s_addr = inaddr;
+ sock_addr.sin_port = htons(lport);
+ if(bind(fd, (struct sockaddr*) &sock_addr, sizeof(sock_addr)) < 0) {
+ DEBUGF(("Error in bind()\n"));
+ safe_close(fd);
+ /* XXX Set error code for bind error */
+ return INVALID_FD;
+ }
+
+ /* foreign */
+ if ((inaddr = inet_addr(fipstring)) == INADDR_NONE) {
+ DEBUGF(("Error in inet_addr(): fipstring = %s\n", fipstring));
+ safe_close(fd);
+ sock_set_errno(ERRNO_ADDRNOTAVAIL);
+ return INVALID_FD;
+ }
+ memset(&sock_addr, 0, sizeof(sock_addr));
+ sock_addr.sin_family = AF_INET;
+ sock_addr.sin_addr.s_addr = inaddr;
+ sock_addr.sin_port = htons(fport);
+
+ SET_NONBLOCKING(fd);
+
+ if(connect(fd, (struct sockaddr*)&sock_addr, sizeof(sock_addr)) < 0) {
+ if (sock_errno() != ERRNO_PROGRESS && /* UNIX */
+ sock_errno() != ERRNO_BLOCK) { /* WIN32 */
+ DEBUGF(("Error in connect()\n"));
+ safe_close(fd);
+ return INVALID_FD;
+ }
+ }
+ return fd;
+}
+
+static FD do_listen(char *ipstring, int lport, int backlog, int *aport)
+{
+ static int one = 1; /* Type must be int, not long */
+ struct sockaddr_in sock_addr;
+ long inaddr;
+ int length;
+ FD fd;
+
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_FD) {
+ DEBUGF(("Error calling socket()\n"));
+ return fd;
+ }
+ if (check_num_sock_fds(fd) < 0)
+ return INVALID_FD;
+ DEBUGF((" fd = %d\n", fd));
+ if ((inaddr = inet_addr(ipstring)) == INADDR_NONE) {
+ DEBUGF(("Error in inet_addr(): ipstring = %s\n", ipstring));
+ safe_close(fd);
+ sock_set_errno(ERRNO_ADDRNOTAVAIL);
+ return INVALID_FD;
+ }
+ memset(&sock_addr, 0, sizeof(sock_addr));
+ sock_addr.sin_family = AF_INET;
+ sock_addr.sin_addr.s_addr = inaddr;
+ sock_addr.sin_port = htons(lport);
+
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one));
+
+ if(bind(fd, (struct sockaddr*) &sock_addr, sizeof(sock_addr)) < 0) {
+ DEBUGF(("Error in bind()\n"));
+ safe_close(fd);
+ return INVALID_FD;
+ }
+ if (listen(fd, backlog) < 0) {
+ DEBUGF(("Error in listen()\n"));
+ safe_close(fd);
+ return INVALID_FD;
+ }
+ /* find out assigned local port number */
+ length = sizeof(sock_addr);
+ if (getsockname(fd, (struct sockaddr *)&sock_addr, &length) < 0) {
+ DEBUGF(("Error in getsockname()\n"));
+ safe_close(fd);
+ return INVALID_FD;
+ }
+ if (aport)
+ *aport = ntohs(sock_addr.sin_port);
+ return fd;
+}
+
+static FD do_accept(FD listensock, struct sockaddr *saddr, int *len)
+{
+ FD fd;
+
+ if ((fd = accept(listensock, saddr, len)) == INVALID_FD) {
+ DEBUGF(("Error calling accept()\n"));
+ return fd;
+ }
+ if (check_num_sock_fds(fd) < 0)
+ return INVALID_FD;
+ return fd;
+}
+
+static Connection *new_connection(int state, FD fd)
+{
+ Connection *cp;
+
+ if (!(cp = esock_malloc(sizeof(Connection))))
+ return NULL;
+ cp->state = state;
+ cp->acceptors = 0;
+ cp->fd = fd;
+ cp->listen_fd = INVALID_FD;
+ cp->proxy = NULL;
+ cp->opaque = NULL;
+ cp->ssl_want = 0;
+ cp->eof = 0;
+ cp->bp = 0;
+ cp->clean = 0; /* XXX Used? */
+ cp->close = 0;
+ cp->origin = -1;
+ cp->flags = NULL;
+ cp->logfp = NULL;
+ cp->wq.size = 0;
+ cp->wq.buf = NULL;
+ cp->wq.len = 0;
+ cp->wq.offset = 0;
+ cp->next = connections;
+ cp->errstr = NULL;
+ connections = cp;
+ return cp;
+}
+
+
+static void print_connections(void)
+{
+ if (debug) {
+ Connection *cp = connections;
+ DEBUGF(("CONNECTIONS:\n"));
+ while (cp) {
+ if (cp->state == ESOCK_JOINED) {
+ DEBUGF((" - %s [%8p] (origin = %s)\n"
+ " (fd = %d, eof = %d, wq = %d, bp = %d)\n"
+ " (proxyfd = %d, eof = %d, wq = %d, bp = %d)\n",
+ connstr[cp->state], cp, originstr[cp->origin],
+ cp->fd, cp->eof, cp->wq.len, cp->bp,
+ cp->proxy->fd, cp->proxy->eof, cp->proxy->wq.len,
+ cp->proxy->bp));
+ } else if (cp->state == ESOCK_ACTIVE_LISTENING) {
+ DEBUGF((" - %s [%8p] (fd = %d, acceptors = %d)\n",
+ connstr[cp->state], cp, cp->fd, cp->acceptors));
+ } else {
+ DEBUGF((" - %s [%8p] (fd = %d)\n", connstr[cp->state], cp,
+ cp->fd));
+ }
+ cp= cp->next;
+ }
+ }
+}
+
+static void dump_connections(void)
+{
+ Connection *cp = connections;
+ Proxy *pp = proxies;
+ time_t t = time(NULL);
+ int length = 0;
+ struct sockaddr_in iserv_addr;
+
+ __debugprintf("CONNECTIONS %s", ctime(&t));
+ while (cp) {
+ if (cp->state == ESOCK_JOINED) {
+ __debugprintf(" - %s [%8p] (origin = %s)\n"
+ " (fd = %d, eof = %d, wq = %d, bp = %d), close = %d\n"
+ " (proxyfd = %d, eof = %d, wq = %d, bp = %d)\n",
+ connstr[cp->state], cp, originstr[cp->origin],
+ cp->fd, cp->eof, cp->wq.len, cp->bp, cp->close,
+ cp->proxy->fd, cp->proxy->eof, cp->proxy->wq.len,
+ cp->proxy->bp);
+ } else if (cp->state == ESOCK_ACTIVE_LISTENING) {
+ __debugprintf(" - %s [%8p] (fd = %d, acceptors = %d)\n",
+ connstr[cp->state], cp, cp->fd, cp->acceptors);
+ } else {
+ __debugprintf(" - %s [%8p] (fd = %d)\n", connstr[cp->state], cp,
+ cp->fd);
+ }
+ length = sizeof(iserv_addr);
+ if ((cp->state == ESOCK_ACTIVE_LISTENING) ||
+ (cp->state == ESOCK_PASSIVE_LISTENING)) {
+ getsockname(cp->fd, (struct sockaddr *) &iserv_addr, &length);
+ __debugprintf(" (ip = %s, port = %d)\n",
+ inet_ntoa(iserv_addr.sin_addr),
+ ntohs(iserv_addr.sin_port));
+ }
+ else {
+ getsockname(cp->fd, (struct sockaddr *) &iserv_addr, &length);
+ __debugprintf(" (local_ip = %s, local_port = %d)\n",
+ inet_ntoa(iserv_addr.sin_addr),
+ ntohs(iserv_addr.sin_port));
+ length = sizeof(iserv_addr);
+ getpeername(cp->fd, (struct sockaddr *) &iserv_addr, &length);
+ __debugprintf(" (remote_ip = %s, remote_port = %d)\n",
+ inet_ntoa(iserv_addr.sin_addr),
+ ntohs(iserv_addr.sin_port));
+ }
+ cp=cp->next;
+ }
+
+ __debugprintf("PROXIES\n");
+ while (pp) {
+ __debugprintf(" - fd = %d [%8p] (external_fd = %d, peer_port = %d,"
+ " eof = %d)\n", pp->fd, pp, pp->conn->fd, pp->peer_port,
+ pp->eof);
+
+ pp= pp->next;
+ }
+}
+
+static Connection *get_connection(FD fd)
+{
+ Connection *cp = connections;
+
+ while(cp) {
+ if(cp->fd == fd)
+ return cp;
+ cp = cp->next;
+ }
+ return NULL;
+}
+
+/*
+ * Remove a connection from the list of connection, close the proxy
+ * socket and free all resources. The main socket (fd) is *not*
+ * closed here, because the closing of that socket has to be synchronized
+ * with the Erlang process controlling this port program.
+ */
+static void remove_connection(Connection *conn)
+{
+ Connection **prev = &connections;
+ Connection *cp = connections;
+
+ while (cp) {
+ if(cp == conn) {
+ DEBUGF(("remove_connection: fd = %d\n", cp->fd));
+ esock_ssl_free(cp); /* frees cp->opaque only */
+ esock_free(cp->flags);
+ closelog(cp->logfp); /* XXX num_sock_fds */
+ esock_free(cp->wq.buf);
+ if (cp->proxy) {
+ safe_close(cp->proxy->fd);
+ remove_proxy(cp->proxy);
+ }
+ *prev = cp->next;
+ esock_free(cp);
+ return;
+ }
+ prev = &cp->next;
+ cp = cp->next;
+ }
+}
+
+static Proxy *get_proxy_by_peerport(int port)
+{
+ Proxy *p = proxies;
+
+ while(p) {
+ if (p->peer_port == port)
+ return p;
+ p = p->next;
+ }
+ return NULL;
+}
+
+static Proxy *new_proxy(FD fd)
+{
+ Proxy *p;
+
+ if (!(p = esock_malloc(sizeof(Proxy))))
+ return NULL;
+
+ p->fd = fd;
+ p->peer_port = -1;
+ p->eof = 0;
+ p->bp = 0;
+ p->conn = NULL;
+ p->wq.size = 0;
+ p->wq.buf = NULL;
+ p->wq.len = 0;
+ p->wq.offset = 0;
+ p->next = proxies;
+ proxies = p;
+ return p;
+}
+
+static void remove_proxy(Proxy *proxy)
+{
+ Proxy *p = proxies, **pp = &proxies;
+
+ while(p) {
+ if (p == proxy) {
+ DEBUGF(("remove_proxyfd = %d\n", p->fd));
+ esock_free(p->wq.buf);
+ *pp = p->next;
+ esock_free(p);
+ return;
+ }
+ pp = &p->next;
+ p = p->next;
+ }
+}
+
+static int check_num_sock_fds(FD fd)
+{
+ num_sock_fds++; /* fd is valid */
+#ifdef USE_SELECT
+ if (num_sock_fds > FD_SETSIZE) {
+ num_sock_fds--;
+ sock_set_errno(ERRNO_MFILE);
+ safe_close(fd);
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+static void safe_close(FD fd)
+{
+ int err;
+
+ err = sock_errno();
+ DEBUGF(("safe_close fd = %d\n", fd));
+ if (sock_close(fd) < 0) {
+ DEBUGF(("safe_close failed\n"));
+ } else {
+ num_sock_fds--;
+ }
+ sock_set_errno(err);
+}
+
+static void clean_up(void)
+{
+ Connection *cp, *cpnext;
+ Proxy *pp, *ppnext;
+
+ cp = connections;
+ while (cp) {
+ safe_close(cp->fd);
+ cpnext = cp->next;
+ remove_connection(cp);
+ cp = cpnext;
+ }
+
+ pp = proxies;
+ while (pp) {
+ safe_close(pp->fd);
+ ppnext = pp->next;
+ remove_proxy(pp);
+ pp = ppnext;
+ }
+}
+
+static void ensure_write_queue(WriteQueue *wq, int size)
+{
+ if (wq->size < size) {
+ wq->buf = esock_realloc(wq->buf, size);
+ wq->size = size;
+ }
+}
+
+
+
+
+
+
+
diff --git a/lib/ssl/c_src/esock.h b/lib/ssl/c_src/esock.h
new file mode 100644
index 0000000000..16c9faa530
--- /dev/null
+++ b/lib/ssl/c_src/esock.h
@@ -0,0 +1,273 @@
+/*<copyright>
+ * <year>1999-2008</year>
+ * <holder>Ericsson AB, All Rights Reserved</holder>
+ *</copyright>
+ *<legalnotice>
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Initial Developer of the Original Code is Ericsson AB.
+ *</legalnotice>
+ */
+/*
+ * Purpose: Implementation of Secure Socket Layer (SSL).
+ *
+ */
+
+#ifndef ESOCK_H
+#define ESOCK_H
+
+#ifdef __WIN32__
+#include "esock_winsock.h"
+#endif
+#include <stdio.h>
+
+#ifdef __WIN32__
+#define INVALID_FD INVALID_SOCKET
+
+#define sock_read(fd, buf, len) recv((fd), (buf), (len), 0)
+#define sock_write(fd, buf, len) send((fd), (buf), (len), 0)
+#define sock_close(fd) closesocket(fd)
+#define sock_errno() WSAGetLastError()
+#define sock_set_errno(err) WSASetLastError(err)
+
+#define ERRNO_NONE 0
+#define ERRNO_BLOCK WSAEWOULDBLOCK
+#define ERRNO_CONNREFUSED WSAECONNREFUSED
+#define ERRNO_PROGRESS WSAEINPROGRESS
+#define ERRNO_PROTONOSUPPORT WSAEPROTONOSUPPORT
+#define ERRNO_INVAL WSAEINVAL
+#define ERRNO_ADDRNOTAVAIL WSAEADDRNOTAVAIL
+#define ERRNO_NOTSOCK WSAENOTSOCK
+#define ERRNO_OPNOTSUPP WSAEOPNOTSUPP
+#define ERRNO_MFILE WSAEMFILE
+#define SET_BLOCKING(fd) do { \
+ unsigned long zeroval = 0; \
+ ioctlsocket((fd), FIONBIO, &zeroval); \
+ } while (0)
+#define SET_NONBLOCKING(fd) do { \
+ unsigned long oneval = 1; \
+ ioctlsocket((fd), FIONBIO, &oneval); \
+ } while (0)
+#else
+#define INVALID_FD (-1)
+
+#define sock_read(fd, buf, len) read((fd), (buf), (len))
+#define sock_write(fd, buf, len) write((fd), (buf), (len))
+#define sock_close(fd) close(fd)
+#define sock_errno() errno
+#define sock_set_errno(err) do {errno = (err);} while(0)
+
+#define ERRNO_NONE 0
+#define ERRNO_BLOCK EAGAIN
+#define ERRNO_CONNREFUSED ECONNREFUSED
+#define ERRNO_PROGRESS EINPROGRESS
+#define ERRNO_PROTONOSUPPORT EPROTONOSUPPORT
+#define ERRNO_INVAL EINVAL
+#define ERRNO_ADDRNOTAVAIL EADDRNOTAVAIL
+#define ERRNO_NOTSOCK ENOTSOCK
+#define ERRNO_OPNOTSUPP EOPNOTSUPP
+#define ERRNO_MFILE EMFILE
+#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)
+#endif
+
+#define GET_INT8(s) ((s)[0])
+#define GET_INT16(s) (((s)[0] << 8) | (s)[1])
+#define GET_INT32(s) (((s)[0] << 24) | ((s)[1] << 16) | \
+ ((s)[2] << 8) | (s)[3])
+
+#define PUT_INT8(x, s) do { (s)[0] = x; } while(0)
+#define PUT_INT16(x, s) do { (s)[0] = ((x) >> 8) & 0xff; \
+ (s)[1] = ((x) & 0xff); } while(0)
+#define PUT_INT32(x, s) do { (s)[0] = ((x) >> 24) & 0xff; \
+ (s)[1] = ((x) >> 16) & 0xff; \
+ (s)[2] = ((x) >> 8) & 0xff; \
+ (s)[3] = (x) & 0xff; } while(0)
+
+/* type for Connections */
+#define ESOCK_STATE_NONE 0
+#define ESOCK_ACTIVE_LISTENING 1
+#define ESOCK_PASSIVE_LISTENING 2
+#define ESOCK_CONNECTED 3
+#define ESOCK_WAIT_CONNECT 4
+#define ESOCK_SSL_CONNECT 5
+#define ESOCK_SSL_ACCEPT 6
+#define ESOCK_TRANSPORT_ACCEPT 7
+#define ESOCK_JOINED 8
+#define ESOCK_SSL_SHUTDOWN 9
+#define ESOCK_DEFUNCT 10
+
+#ifdef __WIN32__
+ typedef SOCKET FD;
+#else
+ typedef int FD;
+#endif
+
+/* For the shutdown(fd, how) call */
+#ifdef __WIN32__
+#define SHUTDOWN_READ SD_RECEIVE
+#define SHUTDOWN_WRITE SD_SEND
+#define SHUTDOWN_ALL SD_BOTH
+#else
+#define SHUTDOWN_READ 0
+#define SHUTDOWN_WRITE 1
+#define SHUTDOWN_ALL 2
+#endif
+
+#define ORIG_LISTEN 0
+#define ORIG_ACCEPT 1
+#define ORIG_CONNECT 2
+
+typedef struct {
+ int size; /* Total size of buf */
+ unsigned char *buf;
+ int len; /* Current number of bytes in buf */
+ int offset; /* Bytes already written */
+} WriteQueue;
+
+typedef struct _proxy Proxy;
+
+typedef struct Connection {
+ FD fd;
+ FD listen_fd; /* Needed for async listen error */
+ unsigned char state;
+ int acceptors; /* Count acceptors for listen socket */
+ Proxy *proxy;
+ void *opaque; /* Any suitable ssl structure */
+ int ssl_want; /* read/write flags */
+ int eof; /* end of file (read) */
+ int bp; /* broken pipe (write) */
+ int clean; /* Clean SSL shutdown initiated */
+ int close; /* Close if set */
+ int origin; /* listen, accept or connect */
+ int encrypted; /* 1 = SSL encrypted, 0 = normal, unencrypted tcp */
+ char *flags; /* ssl parameters */
+ FILE *logfp; /* connection log file (not used) */
+ WriteQueue wq;
+ struct Connection* next;
+ const char* errstr; /* only used to report errors from ssl_accept_init in SSL_ACCEPT */
+} Connection;
+
+struct _proxy {
+ FD fd;
+ int peer_port;
+ int eof; /* end of file (read) */
+ int bp; /* broken pipe (write) */
+ Connection *conn;
+ WriteQueue wq;
+ Proxy *next;
+};
+
+/* Commands, replies, and error responses */
+
+#define ESOCK_CONNECT_CMD 1
+#define ESOCK_CONNECT_WAIT_REP 2
+#define ESOCK_CONNECT_REP 3
+#define ESOCK_CONNECT_ERR 4
+
+#define ESOCK_TERMINATE_CMD 5
+#define ESOCK_CLOSE_CMD 6
+
+#define ESOCK_LISTEN_CMD 7
+#define ESOCK_LISTEN_REP 8
+#define ESOCK_LISTEN_ERR 9
+
+#define ESOCK_TRANSPORT_ACCEPT_CMD 10
+#define ESOCK_NOACCEPT_CMD 11
+#define ESOCK_TRANSPORT_ACCEPT_REP 12
+#define ESOCK_TRANSPORT_ACCEPT_ERR 13
+
+#define ESOCK_FROMNET_CLOSE_REP 14
+
+#define ESOCK_CONNECT_SYNC_ERR 15
+#define ESOCK_LISTEN_SYNC_ERR 16
+
+#define ESOCK_PROXY_PORT_REP 23
+#define ESOCK_PROXY_JOIN_CMD 24
+#define ESOCK_PROXY_JOIN_REP 25
+#define ESOCK_PROXY_JOIN_ERR 26
+
+#define ESOCK_SET_SOCKOPT_CMD 27
+#define ESOCK_IOCTL_OK 28
+#define ESOCK_IOCTL_ERR 29
+
+#define ESOCK_GETPEERNAME_CMD 30
+#define ESOCK_GETPEERNAME_REP 31
+#define ESOCK_GETPEERNAME_ERR 32
+
+#define ESOCK_GETSOCKNAME_CMD 33
+#define ESOCK_GETSOCKNAME_REP 34
+#define ESOCK_GETSOCKNAME_ERR 35
+
+#define ESOCK_GETPEERCERT_CMD 36
+#define ESOCK_GETPEERCERT_REP 37
+#define ESOCK_GETPEERCERT_ERR 38
+
+#define ESOCK_GETVERSION_CMD 39
+#define ESOCK_GETVERSION_REP 40
+
+#define ESOCK_SET_SEED_CMD 41
+
+#define ESOCK_GETCONNINFO_CMD 42
+#define ESOCK_GETCONNINFO_REP 43
+#define ESOCK_GETCONNINFO_ERR 44
+
+#define ESOCK_SSL_ACCEPT_CMD 45
+#define ESOCK_SSL_ACCEPT_REP 46
+#define ESOCK_SSL_ACCEPT_ERR 47
+
+#define ESOCK_DUMP_STATE_CMD 48
+#define ESOCK_SET_DEBUG_CMD 49
+#define ESOCK_SET_DEBUGMSG_CMD 50
+
+
+/* Option codes for ESOCK_SET_SOCKOPT_CMD */
+#define ESOCK_SET_TCP_NODELAY 1
+
+/* SSL want to read or write */
+#define ESOCK_SSL_WANT_READ 1
+#define ESOCK_SSL_WANT_WRITE 2
+
+/* Protocol version according to ssl_server */
+#define ESOCK_SSLv2 1
+#define ESOCK_SSLv3 2
+#define ESOCK_TLSv1 4
+
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/ssl/c_src/esock_openssl.c b/lib/ssl/c_src/esock_openssl.c
new file mode 100644
index 0000000000..2621c9934e
--- /dev/null
+++ b/lib/ssl/c_src/esock_openssl.c
@@ -0,0 +1,1213 @@
+/*<copyright>
+ * <year>1999-2008</year>
+ * <holder>Ericsson AB, All Rights Reserved</holder>
+ *</copyright>
+ *<legalnotice>
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Initial Developer of the Original Code is Ericsson AB.
+ *</legalnotice>
+ */
+/*
+ * Purpose: Adaptions for the OpenSSL package.
+ *
+ * This file implements the functions defined in esock_ssl.h for
+ * the OpenSSL package.
+ *
+ * The following holds true for non-blockling I/O:
+ *
+ * Function Return values
+ * -------- -------------
+ * SSL_accept() success: 1, failure: =<0
+ * SSL_connect() success: 1, failure: =<0
+ * SSL_read() success: >0, eof: 0, failure: <0
+ * SSL_write() success: > 0, failure: =<0
+ * SSL_shutdown() success: 1, not finished: 0
+ *
+ * If the return value of any of the above functions is `ret' and the
+ * ssl connection is `ssl', the call
+ *
+ * ssl_error = SSL_get_error(ssl, ret);
+ *
+ * returns one of the following eight values:
+ *
+ * SSL_ERROR_NONE ret > 0
+ * SSL_ERROR_ZERO_RETURN ret = 0
+ * SSL_ERROR_WANT_READ ret < 0 and ssl wants to read
+ * SSL_ERROR_WANT_WRITE ret < 0 and ssl wants to write
+ * SSL_ERROR_SYSCALL ret < 0 or ret = 0
+ * SSL_ERROR_SSL if there was an ssl internal error
+ * SSL_ERROR_WANT_X509_LOOKUP ret < 0 and ssl wants x509 lookup
+ * SSL_ERROR_WANT_CONNECT ret < 0 and ssl wants connect
+ *
+ * It is the case that SSL_read() sometimes returns -1, even when the
+ * underlying file descriptor is ready for reading.
+ *
+ * Also, sometimes we may have SSL_ERROR_SSL in SSL_accept() and SSL_connect()
+ * when a retry should be done.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#ifndef __WIN32__
+# include <fcntl.h>
+# include <unistd.h>
+#endif
+
+#include "esock.h"
+#include "esock_ssl.h"
+#include "debuglog.h"
+#include "esock_utils.h"
+#include "esock_posix_str.h"
+
+#include <openssl/crypto.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+
+int ephemeral_rsa = 0;
+int ephemeral_dh = 0; /* XXX Not used yet */
+int protocol_version = 0;
+
+char *esock_ssl_errstr = "";
+
+#define FLAGSBUFSIZE 512
+#define X509BUFSIZE 256
+#define DEFAULT_VERIFY_DEPTH 1
+
+#define SET_WANT(cp, ssl_error) \
+ switch((ssl_error)) { \
+ case SSL_ERROR_WANT_READ: \
+ (cp)->ssl_want = ESOCK_SSL_WANT_READ; \
+ break; \
+ case SSL_ERROR_WANT_WRITE: \
+ (cp)->ssl_want = ESOCK_SSL_WANT_WRITE; \
+ break; \
+ default: \
+ (cp)->ssl_want = 0; \
+ break; \
+ }
+
+#define RESET_ERRSTR() \
+ esock_ssl_errstr = "";
+
+#define MAYBE_SET_ERRSTR(s) \
+ if (!esock_ssl_errstr[0]) \
+ esock_ssl_errstr = (s);
+
+typedef struct {
+ int code;
+ char *text;
+} err_entry;
+
+typedef struct {
+ SSL_CTX *ctx;
+ char *passwd;
+ int verify_depth;
+} callback_data;
+
+static char *ssl_error_str(int error);
+static void end_ssl_call(int ret, Connection *cp, int ssl_error);
+static void check_shutdown(Connection *cp);
+static int set_ssl_parameters(Connection *cp, SSL_CTX *ctx);
+static int verify_callback(int ok, X509_STORE_CTX *ctx);
+static int passwd_callback(char *buf, int num, int rwflag, void *userdata);
+static void info_callback(const SSL *ssl, int where, int ret);
+static void callback_data_free(void *parent, void *ptr,
+ CRYPTO_EX_DATA *ad,
+ int idx, long arg1, void *argp);
+static RSA *tmp_rsa_callback(SSL *ssl, int is_export, int keylen);
+static void restrict_protocols(SSL_CTX *ctx);
+
+static err_entry errs[] = {
+ {SSL_ERROR_NONE, "SSL_ERROR_NONE"},
+ {SSL_ERROR_ZERO_RETURN, "SSL_ERROR_ZERO_RETURN"},
+ {SSL_ERROR_WANT_READ, "SSL_ERROR_WANT_READ"},
+ {SSL_ERROR_WANT_WRITE, "SSL_ERROR_WANT_WRITE"},
+ {SSL_ERROR_SYSCALL, "SSL_ERROR_SYSCALL"},
+ {SSL_ERROR_SSL, "SSL_ERROR_SSL"},
+ {SSL_ERROR_WANT_X509_LOOKUP, "SSL_ERROR_WANT_X509_LOOKUP"},
+ {SSL_ERROR_WANT_CONNECT, "SSL_ERROR_WANT_CONNECT"}
+};
+
+static SSL_METHOD *method; /* for listen and connect init */
+static char x509_buf[X509BUFSIZE]; /* for verify_callback */
+static int callback_data_index = -1; /* for ctx ex_data */
+static unsigned char randvec[1024]; /* XXX */
+
+#if defined(__WIN32__) || OPEN_MAX > 256
+# define FOPEN_WORKAROUND(var, expr) var = (expr)
+# define VOID_FOPEN_WORKAROUND(expr) expr
+#else
+/*
+ * This is an ugly workaround. On Solaris, fopen() will return NULL if
+ * it gets a file descriptor > 255. To avoid that, we'll make sure that
+ * there is always one low-numbered file descriptor available when
+ * fopen() is called.
+ */
+static int reserved_fd; /* Reserve a low-numbered file descriptor */
+# define USE_FOPEN_WORKAROUND 1
+
+# define FOPEN_WORKAROUND(var, expr) \
+do { \
+ close(reserved_fd); \
+ var = (expr); \
+ reserved_fd = open("/dev/null", O_RDONLY); \
+} while (0)
+
+# define VOID_FOPEN_WORKAROUND(expr) \
+do { \
+ close(reserved_fd); \
+ expr; \
+ reserved_fd = open("/dev/null", O_RDONLY); \
+} while (0)
+#endif
+
+esock_version *esock_ssl_version(void)
+{
+ static esock_version vsn;
+
+ vsn.compile_version = OPENSSL_VERSION_TEXT;
+ vsn.lib_version = SSLeay_version(SSLEAY_VERSION);
+ return &vsn;
+}
+
+char *esock_ssl_ciphers(void)
+{
+ SSL_CTX *ctx;
+ SSL *ssl;
+ char *ciphers;
+ const char *cp;
+ int i = 0, used = 0, len, incr = 1024;
+
+ if (!(ctx = SSL_CTX_new(method)))
+ return NULL;
+ restrict_protocols(ctx);
+ if (!(ssl = SSL_new(ctx))) {
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+
+ ciphers = esock_malloc(incr);
+ len = incr;
+ *ciphers = '\0';
+
+ while (1) {
+ if (!(cp = SSL_get_cipher_list(ssl, i)))
+ break;
+ if (i > 0) {
+ if (used == len) {
+ len += incr;
+ ciphers = esock_realloc(ciphers, len);
+ }
+ strcat(ciphers, ":");
+ used++;
+ }
+ if (strlen(cp) + used >= len) {
+ len += incr;
+ ciphers = esock_realloc(ciphers, len);
+ }
+ strcat(ciphers, cp);
+ used += strlen(cp);
+ i++;
+ }
+ SSL_free(ssl);
+ SSL_CTX_free(ctx);
+ return ciphers;
+}
+
+void esock_ssl_seed(void *buf, int len)
+{
+ RAND_seed(buf, len);
+
+ /* XXX Maybe we should call RAND_status() and check if we have got
+ * enough randomness.
+ */
+}
+
+int esock_ssl_init(void)
+{
+ method = SSLv23_method(); /* SSLv2, SSLv3 and TLSv1, may be restricted
+ in listen and connect */
+ SSL_load_error_strings();
+ SSL_library_init();
+ esock_ssl_seed(randvec, sizeof(randvec));
+ callback_data_index = SSL_CTX_get_ex_new_index(0, "callback_data",
+ NULL, NULL,
+ callback_data_free);
+#ifdef USE_FOPEN_WORKAROUND
+ reserved_fd = open("/dev/null", O_RDONLY);
+ DEBUGF(("init: reserved_fd=%d\r\n", reserved_fd));
+#endif
+ return 0;
+}
+
+
+void esock_ssl_finish(void)
+{
+ /* Nothing */
+}
+
+
+void esock_ssl_free(Connection *cp)
+{
+ SSL *ssl = cp->opaque;
+ SSL_CTX *ctx;
+
+ if (ssl) {
+ ctx = SSL_get_SSL_CTX(ssl);
+ SSL_free(ssl);
+ if (cp->origin != ORIG_ACCEPT)
+ SSL_CTX_free(ctx);
+ cp->opaque = NULL;
+ }
+}
+
+
+/*
+ * Print SSL specific errors.
+ */
+void esock_ssl_print_errors_fp(FILE *fp)
+{
+ ERR_print_errors_fp(fp);
+}
+
+
+int esock_ssl_accept_init(Connection *cp, void *listenssl)
+{
+ SSL_CTX *listenctx;
+ SSL *ssl;
+
+ RESET_ERRSTR();
+ MAYBE_SET_ERRSTR("esslacceptinit");
+
+ if(!listenssl) {
+ DEBUGF(("esock_ssl_accept_init: listenssl null\n"));
+ return -1;
+ }
+ if (!(listenctx = SSL_get_SSL_CTX(listenssl))) {
+ DEBUGF(("esock_ssl_accept_init: SSL_get_SSL_CTX\n"));
+ return -1;
+ }
+ if (!(ssl = cp->opaque = SSL_new(listenctx))) {
+ DEBUGF(("esock_ssl_accept_init: SSL_new(listenctx)\n"));
+ return -1;
+ }
+ SSL_set_fd(ssl, cp->fd);
+ return 0;
+
+}
+
+
+int esock_ssl_connect_init(Connection *cp)
+{
+ SSL_CTX *ctx;
+ SSL *ssl;
+
+ RESET_ERRSTR();
+ MAYBE_SET_ERRSTR("esslconnectinit");
+
+ if (!(ctx = SSL_CTX_new(method)))
+ return -1;
+ if (set_ssl_parameters(cp, ctx) < 0) {
+ SSL_CTX_free(ctx);
+ return -1;
+ }
+ restrict_protocols(ctx);
+ if (!(ssl = cp->opaque = SSL_new(ctx))) {
+ SSL_CTX_free(ctx);
+ return -1;
+ }
+ SSL_set_fd(ssl, cp->fd);
+ return 0;
+}
+
+
+int esock_ssl_listen_init(Connection *cp)
+{
+ SSL_CTX *ctx;
+ SSL *ssl;
+
+ RESET_ERRSTR();
+ MAYBE_SET_ERRSTR("essllisteninit");
+
+ if (!(ctx = SSL_CTX_new(method)))
+ return -1;
+ if (set_ssl_parameters(cp, ctx) < 0) {
+ SSL_CTX_free(ctx);
+ return -1;
+ }
+ restrict_protocols(ctx);
+
+ /* The allocation of ctx is for setting ssl parameters, so that
+ * accepts can inherit them. We allocate ssl to be able to
+ * refer to it via cp->opaque, but will not be used otherwise.
+ */
+ if (!(ssl = cp->opaque = SSL_new(ctx))) {
+ SSL_CTX_free(ctx);
+ return -1;
+ }
+ /* Set callback for temporary ephemeral RSA key generation.
+ * Note: for servers only. */
+ SSL_CTX_set_tmp_rsa_callback(ctx, tmp_rsa_callback);
+ return 0;
+}
+
+/*
+ * esock_ssl_accept(Connection *cp)
+ *
+ */
+int esock_ssl_accept(Connection *cp)
+{
+ int ret, ssl_error;
+ SSL *ssl = cp->opaque;
+
+ RESET_ERRSTR();
+
+ DEBUGF(("esock_ssl_accept: calling SSL_accept fd = %d\n"
+ " state before: %s\n", cp->fd, SSL_state_string(ssl)));
+ ret = SSL_accept(ssl);
+ DEBUGF((" sock_errno %d errno %d \n", sock_errno(), errno));
+ ssl_error = SSL_get_error(ssl, ret);
+ DEBUGF((" SSL_accept = %d\n"
+ " ssl_error: %s\n"
+ " state after: %s\n",
+ ret, ssl_error_str(ssl_error), SSL_state_string(ssl)));
+ DEBUGF((" ret %d os error %s\n", ret, strerror(errno)));
+ if (ret > 0)
+ return ret;
+ else if (ret == 0) {
+ const char* f; int l; unsigned int e;
+ while ((e = ERR_get_error_line(&f, &l))) {
+ DEBUGF((" error %s:%d %s\n", f, l, ssl_error_str(e)));
+ }
+ /* permanent accept error */
+ sock_set_errno(ERRNO_NONE);
+ MAYBE_SET_ERRSTR("esslaccept");
+ return -1;
+ }
+ end_ssl_call(ret, cp, ssl_error);
+ return ret;
+}
+
+/*
+ * esock_ssl_connect(Connection *cp)
+ *
+ */
+int esock_ssl_connect(Connection *cp)
+{
+ int ret, ssl_error;
+ SSL *ssl = cp->opaque;
+
+ RESET_ERRSTR();
+
+ DEBUGF(("esock_ssl_connect: calling SSL_connect fd = %d\n"
+ " state before: %s\n", cp->fd, SSL_state_string(ssl)));
+ ret = SSL_connect(ssl);
+ ssl_error = SSL_get_error(ssl, ret);
+ DEBUGF((" SSL_connect() = %d\n"
+ " ssl_error: %s\n"
+ " state after: %s\n",
+ ret, ssl_error_str(ssl_error), SSL_state_string(ssl)));
+ if (ret > 0)
+ return ret;
+ else if (ret == 0) {
+ /* permanent connect error */
+ sock_set_errno(ERRNO_NONE);
+ MAYBE_SET_ERRSTR("esslconnect");
+ return -1;
+ }
+ end_ssl_call(ret, cp, ssl_error);
+ return ret;
+}
+
+
+int esock_ssl_session_reused(Connection *cp)
+{
+ SSL *ssl = cp->opaque;
+
+ return SSL_session_reused(ssl);
+}
+
+
+/* esock_ssl_read(Connection *cp, char *buf, int len)
+ *
+ * Read at most `len' chars into `buf'. Returns number of chars
+ * read ( > 0), or 0 at EOF, or -1 on error. Sets cp->eof, cp->bp if
+ * appropriate.
+ */
+
+int esock_ssl_read(Connection *cp, char *buf, int len)
+{
+ int ret, ssl_error;
+ SSL *ssl = cp->opaque;
+
+ RESET_ERRSTR();
+ DEBUGF(("esock_ssl_read: calling SSL_read fd = %d\n"
+ " state before: %s\n", cp->fd, SSL_state_string(ssl)));
+
+ ret = SSL_read(ssl, buf, len);
+ ssl_error = SSL_get_error(ssl, ret);
+
+ DEBUGF((" SSL_read = %d\n"
+ " ssl_error: %s\n"
+ " state after: %s\n",
+ ret, ssl_error_str(ssl_error), SSL_state_string(ssl)));
+
+ if (ssl_error == SSL_ERROR_NONE) {
+ DEBUGMSGF(("message (hex) : [%3.*a]\n", ret, buf));
+ DEBUGMSGF(("message (char): [%3.*b]\n", ret, buf));
+ }
+ if (ret > 0)
+ return ret;
+ if (ret == 0) {
+ check_shutdown(cp);
+ return ret;
+ }
+ end_ssl_call(ret, cp, ssl_error);
+ return ret;
+}
+
+/*
+ * esock_ssl_write(Connection *cp, char *buf, int len)
+ *
+ * Writes at most `len' chars from `buf'. Returns number of chars
+ * written, or -1 on error.
+ */
+int esock_ssl_write(Connection *cp, char *buf, int len)
+{
+ int ret, ssl_error;
+ SSL *ssl = cp->opaque;
+
+ RESET_ERRSTR();
+ DEBUGF(("esock_ssl_write: calling SSL_write fd = %d\n"
+ " state before: %s\n", cp->fd, SSL_state_string(ssl)));
+ ret = SSL_write(ssl, buf, len);
+ ssl_error = SSL_get_error(ssl, ret);
+ DEBUGF((" SSL_write = %d\n"
+ " ssl_error: %s\n"
+ " state after: %s\n",
+ ret, ssl_error_str(ssl_error), SSL_state_string(ssl)));
+ if (ssl_error == SSL_ERROR_NONE) {
+ DEBUGMSGF(("message (hex) : [%3.*a]\n", ret, buf));
+ DEBUGMSGF(("message (char): [%3.*b]\n", ret, buf));
+ }
+ if (ret > 0)
+ return ret;
+ if (ret == 0) {
+ check_shutdown(cp);
+ return ret;
+ }
+ end_ssl_call(ret, cp, ssl_error);
+ return ret;
+}
+
+
+int esock_ssl_shutdown(Connection *cp)
+{
+ int ret, ssl_error;
+ SSL *ssl = cp->opaque;
+
+ RESET_ERRSTR();
+ DEBUGF(("esock_ssl_shutdown: calling SSL_shutdown fd = %d\n"
+ " state before: %s\n", cp->fd, SSL_state_string(ssl)));
+ ret = SSL_shutdown(ssl);
+ ssl_error = SSL_get_error(ssl, ret);
+ DEBUGF((" SSL_shutdown = %d\n"
+ " ssl_error: %s\n"
+ " state after: %s\n",
+ ret, ssl_error_str(ssl_error), SSL_state_string(ssl)));
+ if (ret >= 0) {
+ check_shutdown(cp);
+ return ret;
+ }
+ end_ssl_call(ret, cp, ssl_error);
+ return ret;
+}
+
+
+/* Returns total number of bytes in DER encoded cert pointed to by
+ * *buf, which is allocated by this function, unless return < 0.
+ * XXX X509_free ??
+ */
+int esock_ssl_getpeercert(Connection *cp, unsigned char **buf)
+{
+ int len;
+ SSL *ssl = cp->opaque;
+ X509 *x509;
+ unsigned char *tmp;
+
+ RESET_ERRSTR();
+ if((x509 = SSL_get_peer_certificate(ssl)) == NULL) {
+ MAYBE_SET_ERRSTR("enopeercert"); /* XXX doc */
+ return -1;
+ }
+
+ if ((len = i2d_X509(x509, NULL)) <= 0) {
+ MAYBE_SET_ERRSTR("epeercert");
+ return -1;
+ }
+
+ tmp = *buf = esock_malloc(len);
+
+ /* We must use a temporary value here, since i2d_X509(X509 *x,
+ * unsigned char **out) increments *out.
+ */
+ if (i2d_X509(x509, &tmp) < 0) {
+ esock_free(tmp);
+ MAYBE_SET_ERRSTR("epeercert");
+ return -1;
+ }
+ return len;
+}
+
+/* Returns total number of bytes in chain of certs. Each cert begins
+ * with a 4-bytes length. The last cert is ended with 4-bytes of
+ * zeros. The result is returned in *buf, which is allocated unless
+ * the return value is < 0.
+ * XXX X509_free ? sk_X509_free ?
+ * XXX X509_free is reference counting.
+ */
+int esock_ssl_getpeercertchain(Connection *cp, unsigned char **buf)
+{
+ SSL *ssl = cp->opaque;
+ STACK_OF(X509) *x509_stack;
+ X509 *x509;
+ int num, i, totlen, pos, *der_len;
+ unsigned char *vbuf;
+
+ RESET_ERRSTR();
+ if((x509_stack = SSL_get_peer_cert_chain(ssl)) == NULL) {
+ MAYBE_SET_ERRSTR("enopeercertchain"); /* XXX doc */
+ return -1;
+ }
+
+ num = sk_X509_num(x509_stack);
+ der_len = esock_malloc(num * sizeof(int));
+ totlen = 0;
+
+ for (i = 0; i < num; i++) {
+ x509 = sk_X509_value(x509_stack, i);
+ totlen += 4;
+ if ((der_len[i] = i2d_X509(x509, NULL)) < 0) {
+ MAYBE_SET_ERRSTR("epeercertchain");
+ esock_free(der_len);
+ return -1;
+ }
+ totlen += der_len[i];
+ }
+ totlen += 4;
+
+ vbuf = *buf = esock_malloc(totlen);
+ pos = 0;
+
+ for (i = 0; i < num; i++) {
+ x509 = sk_X509_value(x509_stack, i);
+ PUT_INT32(der_len[i], vbuf);
+ vbuf += 4;
+ /* Note: i2d_X509 increments vbuf */
+ if (i2d_X509(x509, &vbuf) < 0) {
+ MAYBE_SET_ERRSTR("epeercertchain");
+ esock_free(*buf);
+ esock_free(der_len);
+ return -1;
+ }
+ }
+ esock_free(der_len);
+ return totlen;
+}
+
+
+int esock_ssl_getprotocol_version(Connection *cp, char **buf)
+{
+ SSL *ssl = cp->opaque;
+
+ RESET_ERRSTR();
+ if (!ssl) {
+ MAYBE_SET_ERRSTR("enoent");
+ return -1;
+ }
+ *buf = (char *) SSL_get_version(ssl);
+
+ return 0;
+}
+
+
+int esock_ssl_getcipher(Connection *cp, char **buf)
+{
+ SSL *ssl = cp->opaque;
+
+ RESET_ERRSTR();
+ if (!ssl) {
+ MAYBE_SET_ERRSTR("enoent");
+ return -1;
+ }
+ *buf = (char *) SSL_get_cipher(ssl);
+
+ return 0;
+}
+
+/* Local functions */
+
+static char *ssl_error_str(int ssl_error)
+{
+ int i;
+ static char buf[128];
+
+ for (i = 0; i < sizeof(errs)/sizeof(err_entry); i ++) {
+ if (ssl_error == errs[i].code)
+ return errs[i].text;
+ }
+ sprintf(buf, "esock_openssl: SSL_error unknown: %d", ssl_error);
+ return buf;
+}
+
+void end_ssl_call(int ret, Connection *cp, int ssl_error)
+{
+ SET_WANT(cp, ssl_error);
+ switch (ssl_error) {
+ case SSL_ERROR_SYSCALL:
+ /* Typically sock_errno() is equal to ERRNO_BLOCK */
+ MAYBE_SET_ERRSTR(esock_posix_str(sock_errno()));
+ break;
+ case SSL_ERROR_SSL:
+ sock_set_errno(ERRNO_NONE);
+ MAYBE_SET_ERRSTR("esslerrssl");
+ break;
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ SSLDEBUGF();
+ sock_set_errno(ERRNO_NONE);
+ MAYBE_SET_ERRSTR("ex509lookup");
+ break;
+ case SSL_ERROR_WANT_CONNECT:
+ SSLDEBUGF();
+ sock_set_errno(ERRNO_NONE);
+ MAYBE_SET_ERRSTR("ewantconnect");
+ break;
+ default:
+ break;
+ }
+}
+
+void check_shutdown(Connection *cp)
+{
+ int sd_mode;
+ SSL *ssl = cp->opaque;
+
+ sd_mode = SSL_get_shutdown(ssl);
+ if (sd_mode & SSL_RECEIVED_SHUTDOWN)
+ cp->eof = 1;
+ if (sd_mode & SSL_SENT_SHUTDOWN) {
+ DEBUGF(("check_shutdown SSL_SENT_SHUTDOWN\n"));
+ cp->bp = 1;
+ }
+}
+
+/*
+ * set_ssl_parameters
+ *
+ * Set ssl parameters from connection structure. Only called for
+ * listen and connect.
+ *
+ * Note: The -cacertdir option is not documented.
+ */
+static int set_ssl_parameters(Connection *cp, SSL_CTX *ctx)
+{
+ char *cacertfile = NULL, *cacertdir = NULL, *certfile = NULL;
+ char *keyfile = NULL, *ciphers = NULL, *password = NULL;
+ int verify = 0, verify_depth = DEFAULT_VERIFY_DEPTH, verify_mode;
+ int i, argc;
+ char **argv;
+ callback_data *cb_data;
+
+ RESET_ERRSTR();
+
+ argc = esock_build_argv(cp->flags, &argv);
+
+ DEBUGF(("Argv:\n"));
+ for (i = 0; i < argc; i++) {
+ DEBUGF(("%d: %s\n", i, argv[i]));
+ }
+
+ for (i = 0; i < argc; i++) {
+ if (strcmp(argv[i], "-verify") == 0) {
+ verify = atoi(argv[++i]);
+ } else if (strcmp(argv[i], "-depth") == 0) {
+ verify_depth = atoi(argv[++i]);
+ } else if (strcmp(argv[i], "-log") == 0) {
+ /* XXX ignored: logging per connection not supported */
+ i++;
+ } else if (strcmp(argv[i], "-certfile") == 0) {
+ certfile = argv[++i];
+ } else if (strcmp(argv[i], "-keyfile") == 0) {
+ keyfile = argv[++i];
+ } else if (strcmp(argv[i], "-password") == 0) {
+ password = argv[++i];
+ } else if (strcmp(argv[i], "-cacertfile") == 0) {
+ cacertfile = argv[++i];
+ } else if (strcmp(argv[i], "-cacertdir") == 0) {
+ cacertdir = argv[++i];
+ } else if (strcmp(argv[i], "-d") == 0) {
+ /* XXX ignored: debug per connection not supported */
+ i++;
+ } else if (strcmp(argv[i], "-ciphers") == 0) {
+ ciphers = argv[++i];
+ } else {
+ /* XXX Error: now ignored */
+ }
+ }
+ DEBUGF(("set_ssl_parameters: all arguments read\n"));
+
+ if (cp->origin == ORIG_LISTEN && !certfile) {
+ DEBUGF(("ERROR: Server must have certificate\n"));
+ MAYBE_SET_ERRSTR("enoservercert");
+ goto err_end;
+ }
+
+ /* Define callback data */
+ /* XXX Check for NULL */
+ cb_data = esock_malloc(sizeof(callback_data));
+ cb_data->ctx = ctx;
+ if (password) {
+ cb_data->passwd = esock_malloc(strlen(password) + 1);
+ strcpy(cb_data->passwd, password);
+ } else
+ cb_data->passwd = NULL;
+ cb_data->verify_depth = verify_depth;
+ SSL_CTX_set_ex_data(ctx, callback_data_index, cb_data);
+
+ /* password callback */
+ SSL_CTX_set_default_passwd_cb(ctx, passwd_callback);
+ SSL_CTX_set_default_passwd_cb_userdata(ctx, cb_data);
+
+ /* Set location for "trusted" certificates */
+ if (cacertfile || cacertdir) {
+ int res;
+ DEBUGF(("set_ssl_parameters: SSL_CTX_load_verify_locations\n"));
+ FOPEN_WORKAROUND(res, SSL_CTX_load_verify_locations(ctx, cacertfile,
+ cacertdir));
+ if (!res) {
+ DEBUGF(("ERROR: Cannot load verify locations\n"));
+ MAYBE_SET_ERRSTR("ecacertfile");
+ goto err_end;
+ }
+ } else {
+ int res;
+ DEBUGF(("set_ssl_parameters: SSL_CTX_set_default_verify_paths\n"));
+ FOPEN_WORKAROUND(res, SSL_CTX_set_default_verify_paths(ctx));
+ if (!res) {
+ DEBUGF(("ERROR: Cannot set default verify paths\n"));
+ MAYBE_SET_ERRSTR("ecacertfile");
+ goto err_end;
+ }
+ }
+
+ /* For a server the following sets the list of CA distinguished
+ * names that it sends to its client when it requests the
+ * certificate from the client.
+ * XXX The names of certs in cacertdir ignored.
+ */
+ if (cp->origin == ORIG_LISTEN && cacertfile) {
+ DEBUGF(("set_ssl_parameters: SSL_CTX_set_client_CA_list\n"));
+ VOID_FOPEN_WORKAROUND(SSL_CTX_set_client_CA_list(ctx,
+ SSL_load_client_CA_file(cacertfile)));
+ if (!SSL_CTX_get_client_CA_list(ctx)) {
+ DEBUGF(("ERROR: Cannot set client CA list\n"));
+ MAYBE_SET_ERRSTR("ecacertfile");
+ goto err_end;
+ }
+ }
+
+ /* Use certificate file if key file has not been set. */
+ if (!keyfile)
+ keyfile = certfile;
+
+ if (certfile) {
+ int res;
+ DEBUGF(("set_ssl_parameters: SSL_CTX_use_certificate_file\n"));
+ FOPEN_WORKAROUND(res, SSL_CTX_use_certificate_file(ctx, certfile,
+ SSL_FILETYPE_PEM));
+ if (res <= 0) {
+ DEBUGF(("ERROR: Cannot set certificate file\n"));
+ MAYBE_SET_ERRSTR("ecertfile");
+ goto err_end;
+ }
+ }
+ if (keyfile) {
+ int res;
+ DEBUGF(("set_ssl_parameters: SSL_CTX_use_PrivateKey_file\n"));
+ FOPEN_WORKAROUND(res, SSL_CTX_use_PrivateKey_file(ctx, keyfile,
+ SSL_FILETYPE_PEM));
+ if (res <= 0) {
+ DEBUGF(("ERROR: Cannot set private key file\n"));
+ MAYBE_SET_ERRSTR("ekeyfile");
+ goto err_end;
+ }
+ }
+ if(certfile && keyfile) {
+ DEBUGF(("set_ssl_parameters: SSL_CTX_check_private_key\n"));
+ if (!SSL_CTX_check_private_key(ctx)) {
+ DEBUGF(("ERROR: Private key does not match the certificate\n"));
+ MAYBE_SET_ERRSTR("ekeymismatch");
+ goto err_end;
+ }
+ }
+
+ /* Ciphers */
+ if (ciphers) {
+ DEBUGF(("set_ssl_parameters: SSL_CTX_set_cipher_list\n"));
+ if (!SSL_CTX_set_cipher_list(ctx, ciphers)) {
+ DEBUGF(("ERROR: Cannot set cipher list\n"));
+ MAYBE_SET_ERRSTR("ecipher");
+ goto err_end;
+ }
+ }
+
+ /* Verify depth */
+ DEBUGF(("set_ssl_parameters: SSL_CTX_set_verify_depth (depth = %d)\n",
+ verify_depth));
+ SSL_CTX_set_verify_depth(ctx, verify_depth);
+
+ /* Verify mode and callback */
+ /* XXX Why precisely these modes? */
+ switch (verify) {
+ case 0:
+ verify_mode = SSL_VERIFY_NONE;
+ break;
+ case 1:
+ verify_mode = SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE;
+ break;
+ case 2:
+ verify_mode = SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE|
+ SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+ break;
+ default:
+ verify_mode = SSL_VERIFY_NONE;
+ }
+ DEBUGF(("set_ssl_parameters: SSL_CTX_set_verify (verify = %d)\n",
+ verify));
+ SSL_CTX_set_verify(ctx, verify_mode, verify_callback);
+
+ /* Session id context. Should be an option really. */
+ if (cp->origin == ORIG_LISTEN) {
+ unsigned char *sid = "Erlang/OTP/ssl";
+ SSL_CTX_set_session_id_context(ctx, sid, strlen(sid));
+ }
+
+ /* info callback */
+ if (debug)
+ SSL_CTX_set_info_callback(ctx, info_callback);
+
+ DEBUGF(("set_ssl_parameters: done\n"));
+ /* Free arg list */
+ for (i = 0; argv[i]; i++)
+ esock_free(argv[i]);
+ esock_free(argv);
+ return 0;
+
+ err_end:
+ DEBUGF(("set_ssl_parameters: error\n"));
+ /* Free arg list */
+ for (i = 0; argv[i]; i++)
+ esock_free(argv[i]);
+ esock_free(argv);
+ return -1;
+}
+
+/* Call back functions */
+
+static int verify_callback(int ok, X509_STORE_CTX *x509_ctx)
+{
+ X509 *cert;
+ int cert_err, depth;
+ SSL *ssl;
+ SSL_CTX *ctx;
+ callback_data *cb_data;
+
+ cert = X509_STORE_CTX_get_current_cert(x509_ctx);
+ cert_err = X509_STORE_CTX_get_error(x509_ctx);
+ depth = X509_STORE_CTX_get_error_depth(x509_ctx);
+
+ ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
+ SSL_get_ex_data_X509_STORE_CTX_idx());
+ ctx = SSL_get_SSL_CTX(ssl);
+ cb_data = SSL_CTX_get_ex_data(ctx, callback_data_index);
+
+ X509_NAME_oneline(X509_get_subject_name(cert), x509_buf, sizeof(x509_buf));
+ DEBUGF((" +vfy: depth = %d\n", depth));
+ DEBUGF((" subject = %s\n", x509_buf));
+ X509_NAME_oneline(X509_get_issuer_name(cert), x509_buf, sizeof(x509_buf));
+ DEBUGF((" issuer = %s\n", x509_buf));
+
+ if (!ok) {
+ DEBUGF((" +vfy: error = %d [%s]\n", cert_err,
+ X509_verify_cert_error_string(cert_err)));
+ if (depth >= cb_data->verify_depth)
+ ok = 1;
+ }
+
+ switch (cert_err) {
+ case X509_V_OK:
+ case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+ ok = 1;
+ break;
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+ MAYBE_SET_ERRSTR("enoissuercert");
+ break;
+ case X509_V_ERR_CERT_HAS_EXPIRED:
+ MAYBE_SET_ERRSTR("epeercertexpired");
+ break;
+ case X509_V_ERR_CERT_NOT_YET_VALID:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+ MAYBE_SET_ERRSTR("epeercertinvalid");
+ break;
+ case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+ MAYBE_SET_ERRSTR("eselfsignedcert");
+ break;
+ case X509_V_ERR_CERT_CHAIN_TOO_LONG:
+ MAYBE_SET_ERRSTR("echaintoolong");
+ break;
+ default:
+ MAYBE_SET_ERRSTR("epeercert");
+ break;
+ }
+ DEBUGF((" +vfy: return = %d\n",ok));
+ return ok;
+}
+
+static int passwd_callback(char *buf, int num, int rwflag, void *userdata)
+{
+ callback_data *cb_data = userdata;
+ int len;
+
+ if (cb_data && cb_data->passwd) {
+ DEBUGF((" +passwd: %s\n", cb_data->passwd));
+ strncpy(buf, cb_data->passwd, num);
+ len = strlen(cb_data->passwd);
+ return len;
+ }
+ DEBUGF((" +passwd: ERROR: No password set.\n"));
+ return 0;
+}
+
+static void info_callback(const SSL *ssl, int where, int ret)
+{
+ char *str;
+
+ if (where & SSL_CB_LOOP) {
+ DEBUGF((" info: %s\n",SSL_state_string_long(ssl)));
+ } else if (where & SSL_CB_ALERT) {
+ str = (where & SSL_CB_READ) ? "read" : "write";
+ DEBUGF((" info: SSL3 alert %s:%s:%s\n", str,
+ SSL_alert_type_string_long(ret),
+ SSL_alert_desc_string_long(ret)));
+ } else if (where & SSL_CB_EXIT) {
+ if (ret == 0) {
+ DEBUGF((" info: failed in %s\n", SSL_state_string_long(ssl)));
+ } else if (ret < 0) {
+ DEBUGF((" info: error in %s\n", SSL_state_string_long(ssl)));
+ }
+ }
+}
+
+/* This function is called whenever a SSL_CTX *ctx structure is
+ * freed.
+*/
+static void callback_data_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad,
+ int idx, long arg1, void *argp)
+{
+ callback_data *cb_data = ptr;
+
+ if (cb_data) {
+ if (cb_data->passwd)
+ esock_free(cb_data->passwd);
+ esock_free(cb_data);
+ }
+}
+
+static RSA *tmp_rsa_callback(SSL *ssl, int is_export, int keylen)
+{
+ static RSA *rsa512 = NULL;
+ static RSA *rsa1024 = NULL;
+
+ switch (keylen) {
+ case 512:
+ if (!rsa512)
+ rsa512 = RSA_generate_key(keylen, RSA_F4, NULL, NULL);
+ return rsa512;
+ break;
+ case 1024:
+ if (!rsa1024)
+ rsa1024 = RSA_generate_key(keylen, RSA_F4, NULL, NULL);
+ return rsa1024;
+ break;
+ default:
+ if (rsa1024)
+ return rsa1024;
+ if (rsa512)
+ return rsa512;
+ rsa512 = RSA_generate_key(keylen, RSA_F4, NULL, NULL);
+ return rsa512;
+ }
+}
+
+/* Restrict protocols (SSLv2, SSLv3, TLSv1) */
+static void restrict_protocols(SSL_CTX *ctx)
+{
+ long options = 0;
+
+ if (protocol_version) {
+ if ((protocol_version & ESOCK_SSLv2) == 0)
+ options |= SSL_OP_NO_SSLv2;
+ if ((protocol_version & ESOCK_SSLv3) == 0)
+ options |= SSL_OP_NO_SSLv3;
+ if ((protocol_version & ESOCK_TLSv1) == 0)
+ options |= SSL_OP_NO_TLSv1;
+ SSL_CTX_set_options(ctx, options);
+ }
+}
+
+
+static unsigned char randvec [] = {
+ 181, 177, 237, 240, 107, 24, 43, 148,
+ 105, 4, 248, 13, 199, 255, 23, 58,
+ 71, 181, 57, 151, 156, 25, 165, 7,
+ 73, 80, 80, 231, 70, 110, 96, 162,
+ 24, 205, 178, 178, 67, 122, 210, 180,
+ 92, 6, 156, 182, 84, 159, 85, 6,
+ 175, 66, 165, 167, 137, 34, 179, 237,
+ 77, 90, 87, 185, 21, 106, 92, 115,
+ 137, 65, 233, 42, 164, 153, 208, 133,
+ 160, 172, 129, 202, 46, 220, 98, 66,
+ 115, 66, 46, 28, 226, 200, 140, 145,
+ 207, 194, 58, 71, 56, 203, 113, 34,
+ 221, 116, 63, 114, 188, 210, 45, 238,
+ 200, 123, 35, 150, 2, 78, 160, 22,
+ 226, 167, 162, 10, 182, 75, 109, 97,
+ 86, 252, 93, 125, 117, 214, 220, 37,
+ 105, 160, 56, 158, 97, 57, 22, 14,
+ 73, 169, 111, 190, 222, 176, 14, 82,
+ 111, 42, 87, 90, 136, 236, 22, 209,
+ 156, 207, 40, 251, 88, 141, 51, 211,
+ 31, 158, 153, 91, 119, 83, 255, 60,
+ 55, 94, 5, 115, 119, 210, 224, 185,
+ 163, 163, 5, 3, 197, 106, 110, 206,
+ 109, 132, 50, 190, 177, 133, 175, 129,
+ 225, 161, 156, 244, 77, 150, 99, 38,
+ 17, 111, 46, 230, 152, 64, 50, 164,
+ 19, 78, 3, 164, 169, 175, 104, 97,
+ 103, 158, 91, 168, 186, 191, 73, 88,
+ 118, 112, 41, 188, 219, 0, 198, 209,
+ 206, 7, 5, 169, 127, 180, 80, 74,
+ 124, 4, 4, 108, 197, 67, 204, 29,
+ 101, 95, 174, 147, 64, 163, 89, 160,
+ 10, 5, 56, 134, 209, 69, 209, 55,
+ 214, 136, 45, 212, 113, 85, 159, 133,
+ 141, 249, 75, 40, 175, 91, 142, 13,
+ 179, 179, 51, 0, 136, 63, 148, 175,
+ 103, 162, 8, 214, 4, 24, 59, 71,
+ 9, 185, 48, 127, 159, 165, 8, 8,
+ 135, 151, 92, 214, 132, 151, 204, 169,
+ 24, 112, 229, 59, 236, 81, 238, 64,
+ 150, 196, 97, 213, 140, 159, 20, 24,
+ 79, 210, 191, 53, 130, 33, 157, 87,
+ 16, 180, 175, 217, 56, 123, 115, 196,
+ 130, 6, 155, 37, 220, 80, 232, 129,
+ 240, 57, 199, 249, 196, 152, 28, 111,
+ 124, 192, 59, 46, 29, 21, 178, 51,
+ 156, 17, 248, 61, 254, 80, 201, 131,
+ 203, 59, 227, 191, 71, 121, 134, 181,
+ 55, 79, 130, 225, 246, 36, 179, 224,
+ 189, 243, 200, 75, 73, 41, 251, 41,
+ 71, 251, 78, 146, 99, 101, 104, 69,
+ 18, 122, 65, 24, 232, 84, 246, 242,
+ 209, 18, 241, 114, 3, 65, 177, 99,
+ 49, 99, 215, 59, 9, 175, 195, 11,
+ 25, 46, 43, 120, 109, 179, 159, 250,
+ 239, 246, 135, 78, 2, 238, 214, 237,
+ 64, 170, 50, 44, 68, 67, 111, 232,
+ 225, 230, 224, 124, 76, 32, 52, 158,
+ 151, 54, 184, 135, 122, 66, 211, 215,
+ 121, 90, 124, 158, 55, 73, 116, 137,
+ 240, 15, 38, 31, 183, 86, 93, 49,
+ 148, 184, 125, 250, 155, 216, 84, 246,
+ 27, 172, 141, 54, 80, 158, 227, 254,
+ 189, 164, 238, 229, 68, 26, 231, 11,
+ 198, 222, 15, 141, 98, 8, 124, 219,
+ 60, 125, 170, 213, 114, 24, 189, 65,
+ 80, 186, 71, 126, 223, 153, 20, 141,
+ 110, 73, 173, 218, 214, 63, 205, 177,
+ 132, 115, 184, 28, 122, 232, 210, 72,
+ 237, 41, 93, 17, 152, 95, 242, 138,
+ 79, 98, 47, 197, 36, 17, 137, 230,
+ 15, 73, 193, 1, 181, 123, 0, 186,
+ 185, 135, 142, 200, 139, 78, 57, 145,
+ 191, 32, 98, 250, 113, 188, 71, 32,
+ 205, 81, 219, 99, 60, 87, 42, 95,
+ 249, 252, 121, 125, 246, 230, 74, 162,
+ 73, 59, 179, 142, 178, 47, 163, 161,
+ 236, 14, 123, 219, 18, 6, 102, 140,
+ 215, 210, 76, 9, 119, 147, 252, 63,
+ 13, 51, 161, 172, 180, 116, 212, 129,
+ 116, 237, 38, 64, 213, 222, 35, 14,
+ 183, 237, 78, 204, 250, 250, 5, 41,
+ 142, 5, 207, 154, 65, 183, 108, 82,
+ 1, 43, 149, 233, 89, 195, 25, 233,
+ 4, 34, 19, 122, 16, 58, 121, 5,
+ 118, 168, 22, 213, 49, 226, 163, 169,
+ 21, 78, 179, 232, 125, 216, 198, 147,
+ 245, 196, 199, 138, 185, 167, 179, 82,
+ 175, 53, 6, 162, 5, 141, 180, 212,
+ 95, 201, 234, 169, 111, 175, 138, 197,
+ 177, 246, 154, 41, 185, 201, 134, 187,
+ 88, 99, 231, 23, 190, 36, 72, 174,
+ 244, 185, 205, 50, 230, 226, 210, 119,
+ 175, 107, 109, 244, 12, 122, 84, 51,
+ 146, 95, 68, 74, 76, 212, 221, 103,
+ 244, 71, 63, 133, 149, 233, 48, 3,
+ 176, 168, 6, 98, 88, 226, 120, 190,
+ 205, 249, 38, 157, 205, 148, 250, 203,
+ 147, 62, 195, 229, 219, 109, 177, 119,
+ 120, 43, 165, 99, 253, 210, 180, 32,
+ 227, 180, 174, 64, 156, 139, 251, 53,
+ 205, 132, 210, 208, 3, 199, 115, 64,
+ 59, 27, 249, 164, 224, 191, 124, 241,
+ 142, 10, 19, 120, 227, 46, 174, 231,
+ 48, 65, 41, 56, 51, 38, 185, 95,
+ 250, 182, 100, 40, 196, 124, 173, 119,
+ 162, 148, 170, 34, 51, 68, 175, 60,
+ 242, 201, 225, 34, 146, 157, 159, 0,
+ 144, 148, 82, 72, 149, 53, 201, 10,
+ 248, 206, 154, 126, 33, 153, 56, 48,
+ 5, 90, 194, 22, 251, 173, 211, 202,
+ 203, 253, 112, 147, 188, 200, 142, 206,
+ 206, 175, 233, 76, 93, 104, 125, 41,
+ 64, 145, 202, 53, 130, 251, 23, 90,
+ 28, 199, 13, 128, 185, 154, 53, 194,
+ 195, 55, 80, 56, 151, 216, 195, 138,
+ 7, 170, 143, 236, 74, 141, 229, 174,
+ 32, 165, 131, 68, 174, 104, 35, 143,
+ 183, 41, 80, 191, 120, 79, 166, 240,
+ 123, 55, 60, 2, 128, 56, 4, 199,
+ 122, 85, 90, 76, 246, 29, 13, 6,
+ 126, 229, 14, 203, 244, 73, 121, 42,
+ 169, 35, 44, 202, 18, 69, 153, 120,
+ 141, 77, 124, 191, 215, 18, 115, 187,
+ 108, 246, 135, 151, 225, 192, 50, 89,
+ 128, 45, 39, 253, 149, 234, 203, 84,
+ 51, 174, 15, 237, 17, 57, 76, 81,
+ 39, 107, 40, 36, 22, 52, 92, 39};
diff --git a/lib/ssl/c_src/esock_osio.c b/lib/ssl/c_src/esock_osio.c
new file mode 100644
index 0000000000..41c5271c16
--- /dev/null
+++ b/lib/ssl/c_src/esock_osio.c
@@ -0,0 +1,328 @@
+/*<copyright>
+ * <year>1999-2008</year>
+ * <holder>Ericsson AB, All Rights Reserved</holder>
+ *</copyright>
+ *<legalnotice>
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Initial Developer of the Original Code is Ericsson AB.
+ *</legalnotice>
+ */
+/*
+ * Purpose: Std filedescriptors, break handler
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef __WIN32__
+#include "esock_winsock.h"
+#include <process.h>
+#include <io.h>
+#include <fcntl.h>
+#else
+#include <unistd.h>
+#include <signal.h>
+#endif
+
+#include "esock.h"
+#include "debuglog.h"
+#include "esock_utils.h"
+#include "esock_osio.h"
+
+#ifdef __WIN32__
+#define write _write
+#define read _read
+#define LOCALHOSTADDR "127.0.0.1"
+#define LOCBUFSIZE 1024
+#endif
+
+#define PACKET_SIZE 4
+#define EBUFSIZE 256
+
+FD local_read_fd = 0;
+
+static int inc_rbuf(int size);
+static void free_rbuf(void);
+static int read_fill(unsigned char *buf, int len);
+#ifdef __WIN32__
+static int create_local_thread(void);
+static DWORD WINAPI local_thread(LPVOID lpvParam);
+static BOOL WINAPI signal_handler(DWORD ctrl);
+#endif
+
+static unsigned char *rbuf = NULL;
+static int rbuf_malloced = 0;
+#ifdef __WIN32__
+static unsigned long one = 1, zero = 0;
+static int local_portno;
+static char *local_buf;
+#endif
+
+int set_break_handler(void)
+{
+#ifndef __WIN32__
+ struct sigaction act;
+
+ /* Ignore SIGPIPE signal */
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+ act.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &act, NULL);
+ return 0;
+#else
+ SetConsoleCtrlHandler(signal_handler, TRUE);
+ return 0;
+#endif
+}
+
+
+#ifdef __WIN32__
+
+int set_binary_mode(void)
+{
+ _setmode(0, _O_BINARY);
+ _setmode(1, _O_BINARY);
+ return 0;
+}
+
+int esock_osio_init(void)
+{
+ return create_local_thread();
+}
+
+void esock_osio_finish(void)
+{
+ sock_close(local_read_fd);
+}
+
+#endif
+
+int read_ctrl(unsigned char **ebufp)
+{
+ int tbh, cc;
+ unsigned char *mbuf;
+
+ if (inc_rbuf(EBUFSIZE) < 0) {
+ fprintf(stderr, "read_ctrl: cannot alloc rbuf\n");
+ return -1;
+ }
+ cc = read_fill(rbuf, PACKET_SIZE);
+ if (cc < 0) {
+ free_rbuf();
+ return -1;
+ }
+ if (cc == 0) {
+ free_rbuf();
+ return -1; /* XXX 0 ?? */
+ }
+ tbh = GET_INT32(rbuf);
+
+ if (tbh > rbuf_malloced - 4) {
+ if (inc_rbuf(tbh + 4) < 0)
+ return -1;
+ }
+
+ mbuf = rbuf + PACKET_SIZE;
+ cc = read_fill(mbuf, tbh);
+ DEBUGF(("-----------------------------------\n"));
+ DEBUGF(("read_ctrl: cc = %d\n", cc));
+ if(cc > 0) {
+ DEBUGMSGF(("message (hex) : [%3.*a]\n", cc, mbuf));
+ DEBUGMSGF(("message (char): [%3.*b]\n", cc, mbuf));
+ }
+ *ebufp = mbuf;
+ return cc;
+}
+
+int write_ctrl(unsigned char *buf, int len)
+{
+ unsigned char lb[4];
+
+ PUT_INT32(len, lb);
+ DEBUGF(("write_ctrl: len = %d\n", len));
+ DEBUGMSGF(("message (hex) : [%3.*a] [%3.*a]\n", PACKET_SIZE, lb,
+ len, buf));
+ DEBUGMSGF(("message (char): [%3.*b] [%3.*b]\n", PACKET_SIZE, lb,
+ len, buf));
+
+ if (write(1, lb, PACKET_SIZE) != PACKET_SIZE) { /* XXX */
+ fprintf(stderr, "write_ctrl: Bad write \n");
+ return -1;
+ }
+ if (write(1, buf, len) != len) { /* XXX */
+ fprintf(stderr, "write_ctrl: Bad write \n");
+ return -1;
+ }
+ return len;
+}
+
+
+/*
+ * Local functions
+ *
+ */
+
+static int inc_rbuf(int size)
+{
+ unsigned char *nbuf;
+
+ if (rbuf_malloced >= size)
+ return 0;
+ if (rbuf != NULL)
+ nbuf = esock_realloc(rbuf, size);
+ else
+ nbuf = esock_malloc(size);
+ if(nbuf != NULL) {
+ rbuf = nbuf;
+ rbuf_malloced = size;
+ return 0;
+ }
+ return -1;
+}
+
+static void free_rbuf(void)
+{
+ if (rbuf != NULL) {
+ esock_free(rbuf);
+ rbuf = NULL;
+ rbuf_malloced = 0;
+ }
+}
+
+/* Fill buffer, return buffer length, 0 for EOF, < 0 for error. */
+
+static int read_fill(unsigned char *buf, int len)
+{
+ int i, got = 0;
+
+ do {
+ if ((i = sock_read(local_read_fd, buf+got, len-got)) <= 0)
+ return i;
+ got += i;
+ } while (got < len);
+ return len;
+}
+
+
+#ifdef __WIN32__
+
+/*
+ * This routine creates a local thread, which reads from standard input
+ * and writes to a socket.
+ */
+
+static int create_local_thread(void)
+{
+ struct sockaddr_in iserv_addr;
+ SOCKET tmpsock;
+ int length;
+ unsigned threadaddr;
+
+ local_buf = esock_malloc(LOCBUFSIZE);
+ if ((tmpsock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
+ fprintf(stderr, "create_local_thread could not create socket.\n");
+ return -1;
+ }
+ memset(&iserv_addr, 0, sizeof(iserv_addr));
+ iserv_addr.sin_family = AF_INET;
+ iserv_addr.sin_addr.s_addr = inet_addr(LOCALHOSTADDR);
+ iserv_addr.sin_port = htons(0); /* Have any port */
+
+ if (bind(tmpsock, (struct sockaddr *) &iserv_addr,
+ sizeof(iserv_addr)) < 0) {
+ fprintf(stderr, "create_local_thread could not bind.\n");
+ closesocket(tmpsock);
+ return -1;
+ }
+ listen(tmpsock, 1);
+ length = sizeof(iserv_addr);
+ if (getsockname(tmpsock, (struct sockaddr *) &iserv_addr, &length) < 0) {
+ fprintf(stderr, "create_local_thread could not getsockname.\n");
+ closesocket(tmpsock);
+ return -1;
+ }
+ local_portno = ntohs(iserv_addr.sin_port);
+
+ if (_beginthreadex(NULL, 0, local_thread, NULL, 0, &threadaddr) == 0) {
+ fprintf(stderr, "create_local_thread could not _beginthreadex().\n");
+ closesocket(tmpsock);
+ return -1;
+ }
+ local_read_fd = accept(tmpsock, (struct sockaddr *) NULL, (int *) NULL);
+ if (local_read_fd == INVALID_FD) {
+ fprintf(stderr, "create_local_thread could not accept.\n");
+ closesocket(tmpsock);
+ return -1;
+ }
+ closesocket(tmpsock);
+ return 0;
+}
+
+static DWORD WINAPI local_thread(LPVOID lpvParam)
+{
+ SOCKET sock;
+ struct hostent *host;
+ char hostname[64];
+ struct sockaddr_in iserv_addr;
+ unsigned long addr;
+ int len;
+ HANDLE thread;
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ memset(&iserv_addr, 0, sizeof(struct sockaddr_in));
+ iserv_addr.sin_family = AF_INET;
+ iserv_addr.sin_addr.s_addr = inet_addr(LOCALHOSTADDR);
+ iserv_addr.sin_port = htons(local_portno);
+ if(connect(sock, (struct sockaddr*)&iserv_addr, sizeof iserv_addr) ==
+ SOCKET_ERROR) {
+ fprintf(stderr, "local_thread thread could not connect\n");
+ closesocket(sock);
+ return 0;
+ }
+ setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
+
+ /* read from 0 and write to sock */
+ while (1) {
+ if ((len = read(0, local_buf, LOCBUFSIZE)) <= 0) {
+ closesocket(sock);
+ close(0);
+ return 0;
+ }
+ if (send(sock, local_buf, len, 0) != len ) {
+ closesocket(sock);
+ close(0);
+ return 0;
+ }
+ }
+ return 0;
+}
+
+/* Signal handler */
+
+static BOOL WINAPI signal_handler(DWORD ctrl)
+{
+ switch (ctrl) {
+ case CTRL_C_EVENT:
+ case CTRL_BREAK_EVENT:
+ break;
+ case CTRL_LOGOFF_EVENT:
+ if (!getenv("ERLSRV_SERVICE_NAME"))
+ return FALSE;
+ break;
+ default:
+ exit(1);
+ }
+ return TRUE;
+}
+
+#endif
diff --git a/lib/ssl/c_src/esock_osio.h b/lib/ssl/c_src/esock_osio.h
new file mode 100644
index 0000000000..8742c3b05b
--- /dev/null
+++ b/lib/ssl/c_src/esock_osio.h
@@ -0,0 +1,34 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1999-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, 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 ESOCK_OSIO_H
+#define ESOCK_OSIO_H
+
+extern FD local_read_fd;
+
+#ifdef __WIN32__
+int set_binary_mode(void);
+int esock_osio_init(void);
+void esock_osio_finish(void);
+#endif
+int set_break_handler(void);
+int read_ctrl(unsigned char **ebufp);
+int write_ctrl(unsigned char *buf, int len);
+
+#endif
diff --git a/lib/ssl/c_src/esock_poll.c b/lib/ssl/c_src/esock_poll.c
new file mode 100644
index 0000000000..e982eba881
--- /dev/null
+++ b/lib/ssl/c_src/esock_poll.c
@@ -0,0 +1,222 @@
+/*<copyright>
+ * <year>2005-2008</year>
+ * <holder>Ericsson AB, All Rights Reserved</holder>
+ *</copyright>
+ *<legalnotice>
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Initial Developer of the Original Code is Ericsson AB.
+ *</legalnotice>
+ */
+
+/*
+ * Purpose: Hide poll() and select() behind an API so that we
+ * can use either one.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#ifdef __WIN32__
+#include "esock_winsock.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#ifdef __WIN32__
+#include <process.h>
+#else
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <sys/time.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#endif
+
+#include "esock.h"
+#include "esock_ssl.h"
+#include "esock_utils.h"
+#include "esock_poll.h"
+#include "debuglog.h"
+
+#if !defined(USE_SELECT)
+
+/* At least on FreeBSD, we need POLLRDNORM for normal files, not POLLIN. */
+/* Whether this is a bug in FreeBSD, I don't know. */
+#ifdef POLLRDNORM
+#define POLL_INPUT (POLLIN | POLLRDNORM)
+#else
+#define POLL_INPUT POLLIN
+#endif
+
+static void poll_fd_set(EsockPoll *ep, FD fd, short events)
+{
+ int i, j;
+ int prev_num_fds = ep->num_fds;
+
+ if (ep->num_fds <= fd) {
+ ep->num_fds = fd + 64;
+ ep->fd_to_poll = (int *) esock_realloc(ep->fd_to_poll,
+ ep->num_fds*sizeof(int));
+ for (j = prev_num_fds; j < ep->num_fds; j++)
+ ep->fd_to_poll[j] = -1;
+ }
+ i = ep->fd_to_poll[fd];
+ if (i > 0 && i < ep->active && ep->fds[i].fd == fd) {
+ /* Already present in poll array */
+ ep->fds[i].events |= events;
+ } else {
+ /* Append to poll array */
+ if (ep->active >= ep->allocated) {
+ ep->allocated *= 2;
+ ep->fds = (struct pollfd *)
+ esock_realloc(ep->fds, ep->allocated*sizeof(struct pollfd));
+ }
+ ep->fd_to_poll[fd] = ep->active;
+ ep->fds[ep->active].fd = fd;
+ ep->fds[ep->active].events = events;
+ ep->fds[ep->active].revents = 0;
+ ep->active++;
+ }
+}
+
+static int poll_is_set(EsockPoll *ep, FD fd, short mask)
+{
+ if (fd >= ep->num_fds) {
+ return 0;
+ } else {
+ int i = ep->fd_to_poll[fd];
+ return 0 <= i && i < ep->active && ep->fds[i].fd == fd &&
+ (ep->fds[i].revents & mask) != 0;
+ }
+}
+
+#endif
+
+void esock_poll_init(EsockPoll *ep)
+{
+#ifdef USE_SELECT
+ /* Nothing to do here */
+#else
+ ep->allocated = 2;
+ ep->fds = (struct pollfd *) esock_malloc(ep->allocated*sizeof(struct pollfd));
+ ep->num_fds = 1;
+ ep->fd_to_poll = esock_malloc(ep->num_fds*sizeof(int));
+#endif
+}
+
+void esock_poll_zero(EsockPoll *ep)
+{
+#ifdef USE_SELECT
+ FD_ZERO(&ep->readmask);
+ FD_ZERO(&ep->writemask);
+ FD_ZERO(&ep->exceptmask);
+#else
+ int i;
+
+ for (i = 0; i < ep->num_fds; i++)
+ ep->fd_to_poll[i] = -1;
+ ep->active = 0;
+#endif
+}
+
+void esock_poll_fd_set_read(EsockPoll *ep, FD fd)
+{
+#ifdef USE_SELECT
+ FD_SET(fd, &ep->readmask);
+#else
+ poll_fd_set(ep, fd, POLL_INPUT);
+#endif
+}
+
+void esock_poll_fd_set_write(EsockPoll *ep, FD fd)
+{
+#ifdef USE_SELECT
+ FD_SET(fd, &ep->writemask);
+#else
+ poll_fd_set(ep, fd, POLLOUT);
+#endif
+}
+
+int esock_poll_fd_isset_read(EsockPoll *ep, FD fd)
+{
+#ifdef USE_SELECT
+ return FD_ISSET(fd, &ep->readmask);
+#else
+ return poll_is_set(ep, fd, (POLL_INPUT|POLLHUP|POLLERR|POLLNVAL));
+#endif
+}
+
+int esock_poll_fd_isset_write(EsockPoll *ep, FD fd)
+{
+#ifdef USE_SELECT
+ return FD_ISSET(fd, &ep->writemask);
+#else
+ return poll_is_set(ep, fd, (POLLOUT|POLLHUP|POLLERR|POLLNVAL));
+#endif
+}
+
+#ifdef __WIN32__
+void esock_poll_fd_set_exception(EsockPoll *ep, FD fd)
+{
+ FD_SET(fd, &ep->exceptmask);
+}
+
+int esock_poll_fd_isset_exception(EsockPoll *ep, FD fd)
+{
+ return FD_ISSET(fd, &ep->exceptmask);
+}
+#endif
+
+int esock_poll(EsockPoll *ep, int seconds)
+{
+ int sret;
+
+#ifdef USE_SELECT
+ struct timeval tv;
+
+ tv.tv_sec = seconds;
+ tv.tv_usec = 0;
+ sret = select(FD_SETSIZE, &ep->readmask, &ep->writemask, &ep->exceptmask, &tv);
+ if (sret == 0) {
+ FD_ZERO(&ep->readmask);
+ FD_ZERO(&ep->writemask);
+ FD_ZERO(&ep->exceptmask);
+ }
+#else
+ sret = poll(ep->fds, ep->active, 1000*seconds);
+#endif
+ return sret;
+}
+
+void esock_poll_clear_event(EsockPoll* ep, FD fd)
+{
+#ifdef USE_SELECT
+ FD_CLR(fd, &ep->readmask);
+ FD_CLR(fd, &ep->writemask);
+ FD_CLR(fd, &ep->exceptmask);
+#else
+ int i = ep->fd_to_poll[fd];
+ if (i > 0 && ep->fds[i].fd == fd)
+ ep->fds[i].revents = 0;
+#endif
+}
diff --git a/lib/ssl/c_src/esock_poll.h b/lib/ssl/c_src/esock_poll.h
new file mode 100644
index 0000000000..639976dfa9
--- /dev/null
+++ b/lib/ssl/c_src/esock_poll.h
@@ -0,0 +1,60 @@
+/*<copyright>
+ * <year>2005-2008</year>
+ * <holder>Ericsson AB, All Rights Reserved</holder>
+ *</copyright>
+ *<legalnotice>
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Initial Developer of the Original Code is Ericsson AB.
+ *</legalnotice>
+ */
+#ifndef ESOCK_POLL_SELECT_H
+#define ESOCK_POLL_SELECT_H
+
+#if !defined(USE_SELECT)
+#include <poll.h>
+#endif
+
+typedef struct esock_poll {
+#ifdef USE_SELECT
+ fd_set readmask;
+ fd_set writemask;
+ fd_set exceptmask;
+#else
+ int* fd_to_poll; /* Map from fd to index into poll
+ * descriptor array.
+ */
+ int num_fds; /* Number of entries in fd_to_poll. */
+ struct pollfd* fds; /* Array of poll descriptors. */
+ int allocated; /* Allocated number of fds. */
+ int active; /* Active number of fds */
+#endif
+} EsockPoll;
+
+void esock_poll_init(EsockPoll *ep);
+void esock_poll_zero(EsockPoll *ep);
+
+void esock_poll_fd_set_read(EsockPoll *ep, FD fd);
+void esock_poll_fd_set_write(EsockPoll *ep, FD fd);
+
+void esock_poll_clear_event(EsockPoll *ep, FD fd);
+
+int esock_poll_fd_isset_read(EsockPoll *ep, FD fd);
+int esock_poll_fd_isset_write(EsockPoll *ep, FD fd);
+
+#ifdef __WIN32__
+void esock_poll_fd_set_exception(EsockPoll *ep, FD fd);
+int esock_poll_fd_isset_exception(EsockPoll *ep, FD fd);
+#endif
+
+int esock_poll(EsockPoll *ep, int seconds);
+#endif
diff --git a/lib/ssl/c_src/esock_posix_str.c b/lib/ssl/c_src/esock_posix_str.c
new file mode 100644
index 0000000000..31062baaaf
--- /dev/null
+++ b/lib/ssl/c_src/esock_posix_str.c
@@ -0,0 +1,642 @@
+/*
+ * %ExternalCopyright%
+ */
+
+/*
+ * Original: tclPosixStr.c --
+ *
+ * This file contains procedures that generate strings
+ * corresponding to various POSIX-related codes, such
+ * as errno and signals.
+ *
+ * Copyright (c) 1991-1994 The Regents of the University of California.
+ * Copyright (c) 1994-1996 Sun Microsystems, Inc.
+ *
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ *
+ * SCCS: @(#) tclPosixStr.c 1.32 96/10/10 10:09:42
+ */
+
+/* Copy of erl_posix_str.c */
+
+#ifdef __WIN32__
+#include "esock_winsock.h"
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include "esock_posix_str.h"
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * esock_posix_str --
+ *
+ * Return a textual identifier for the given errno value.
+ *
+ * Results:
+ * This procedure returns a machine-readable textual identifier
+ * that corresponds to the current errno value (e.g. "eperm").
+ * The identifier is the same as the #define name in errno.h,
+ * except that it is in lowercase.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static char errstrbuf[32];
+
+char *esock_posix_str(int error)
+{
+ switch (error) {
+#ifdef E2BIG
+ case E2BIG: return "e2big";
+#endif
+#ifdef EACCES
+ case EACCES: return "eacces";
+#endif
+#ifdef EADDRINUSE
+ case EADDRINUSE: return "eaddrinuse";
+#endif
+#ifdef EADDRNOTAVAIL
+ case EADDRNOTAVAIL: return "eaddrnotavail";
+#endif
+#ifdef EADV
+ case EADV: return "eadv";
+#endif
+#ifdef EAFNOSUPPORT
+ case EAFNOSUPPORT: return "eafnosupport";
+#endif
+#ifdef EAGAIN
+ case EAGAIN: return "eagain";
+#endif
+#ifdef EALIGN
+ case EALIGN: return "ealign";
+#endif
+#if defined(EALREADY) && (!defined(EBUSY) || (EALREADY != EBUSY ))
+ case EALREADY: return "ealready";
+#endif
+#ifdef EBADE
+ case EBADE: return "ebade";
+#endif
+#ifdef EBADF
+ case EBADF: return "ebadf";
+#endif
+#ifdef EBADFD
+ case EBADFD: return "ebadfd";
+#endif
+#ifdef EBADMSG
+ case EBADMSG: return "ebadmsg";
+#endif
+#ifdef EBADR
+ case EBADR: return "ebadr";
+#endif
+#ifdef EBADRPC
+ case EBADRPC: return "ebadrpc";
+#endif
+#ifdef EBADRQC
+ case EBADRQC: return "ebadrqc";
+#endif
+#ifdef EBADSLT
+ case EBADSLT: return "ebadslt";
+#endif
+#ifdef EBFONT
+ case EBFONT: return "ebfont";
+#endif
+#ifdef EBUSY
+ case EBUSY: return "ebusy";
+#endif
+#ifdef ECHILD
+ case ECHILD: return "echild";
+#endif
+#ifdef ECHRNG
+ case ECHRNG: return "echrng";
+#endif
+#ifdef ECOMM
+ case ECOMM: return "ecomm";
+#endif
+#ifdef ECONNABORTED
+ case ECONNABORTED: return "econnaborted";
+#endif
+#ifdef ECONNREFUSED
+ case ECONNREFUSED: return "econnrefused";
+#endif
+#ifdef ECONNRESET
+ case ECONNRESET: return "econnreset";
+#endif
+#if defined(EDEADLK) && (!defined(EWOULDBLOCK) || (EDEADLK != EWOULDBLOCK))
+ case EDEADLK: return "edeadlk";
+#endif
+#if defined(EDEADLOCK) && (!defined(EDEADLK) || (EDEADLOCK != EDEADLK))
+ case EDEADLOCK: return "edeadlock";
+#endif
+#ifdef EDESTADDRREQ
+ case EDESTADDRREQ: return "edestaddrreq";
+#endif
+#ifdef EDIRTY
+ case EDIRTY: return "edirty";
+#endif
+#ifdef EDOM
+ case EDOM: return "edom";
+#endif
+#ifdef EDOTDOT
+ case EDOTDOT: return "edotdot";
+#endif
+#ifdef EDQUOT
+ case EDQUOT: return "edquot";
+#endif
+#ifdef EDUPPKG
+ case EDUPPKG: return "eduppkg";
+#endif
+#ifdef EEXIST
+ case EEXIST: return "eexist";
+#endif
+#ifdef EFAULT
+ case EFAULT: return "efault";
+#endif
+#ifdef EFBIG
+ case EFBIG: return "efbig";
+#endif
+#ifdef EHOSTDOWN
+ case EHOSTDOWN: return "ehostdown";
+#endif
+#ifdef EHOSTUNREACH
+ case EHOSTUNREACH: return "ehostunreach";
+#endif
+#if defined(EIDRM) && (!defined(EINPROGRESS) || (EIDRM != EINPROGRESS))
+ case EIDRM: return "eidrm";
+#endif
+#ifdef EINIT
+ case EINIT: return "einit";
+#endif
+#ifdef EINPROGRESS
+ case EINPROGRESS: return "einprogress";
+#endif
+#ifdef EINTR
+ case EINTR: return "eintr";
+#endif
+#ifdef EINVAL
+ case EINVAL: return "einval";
+#endif
+#ifdef EIO
+ case EIO: return "eio";
+#endif
+#ifdef EISCONN
+ case EISCONN: return "eisconn";
+#endif
+#ifdef EISDIR
+ case EISDIR: return "eisdir";
+#endif
+#ifdef EISNAME
+ case EISNAM: return "eisnam";
+#endif
+#ifdef ELBIN
+ case ELBIN: return "elbin";
+#endif
+#ifdef EL2HLT
+ case EL2HLT: return "el2hlt";
+#endif
+#ifdef EL2NSYNC
+ case EL2NSYNC: return "el2nsync";
+#endif
+#ifdef EL3HLT
+ case EL3HLT: return "el3hlt";
+#endif
+#ifdef EL3RST
+ case EL3RST: return "el3rst";
+#endif
+#ifdef ELIBACC
+ case ELIBACC: return "elibacc";
+#endif
+#ifdef ELIBBAD
+ case ELIBBAD: return "elibbad";
+#endif
+#ifdef ELIBEXEC
+ case ELIBEXEC: return "elibexec";
+#endif
+#ifdef ELIBMAX
+ case ELIBMAX: return "elibmax";
+#endif
+#ifdef ELIBSCN
+ case ELIBSCN: return "elibscn";
+#endif
+#ifdef ELNRNG
+ case ELNRNG: return "elnrng";
+#endif
+#if defined(ELOOP) && (!defined(ENOENT) || (ELOOP != ENOENT))
+ case ELOOP: return "eloop";
+#endif
+#ifdef EMFILE
+ case EMFILE: return "emfile";
+#endif
+#ifdef EMLINK
+ case EMLINK: return "emlink";
+#endif
+#ifdef EMSGSIZE
+ case EMSGSIZE: return "emsgsize";
+#endif
+#ifdef EMULTIHOP
+ case EMULTIHOP: return "emultihop";
+#endif
+#ifdef ENAMETOOLONG
+ case ENAMETOOLONG: return "enametoolong";
+#endif
+#ifdef ENAVAIL
+ case ENAVAIL: return "enavail";
+#endif
+#ifdef ENET
+ case ENET: return "enet";
+#endif
+#ifdef ENETDOWN
+ case ENETDOWN: return "enetdown";
+#endif
+#ifdef ENETRESET
+ case ENETRESET: return "enetreset";
+#endif
+#ifdef ENETUNREACH
+ case ENETUNREACH: return "enetunreach";
+#endif
+#ifdef ENFILE
+ case ENFILE: return "enfile";
+#endif
+#ifdef ENOANO
+ case ENOANO: return "enoano";
+#endif
+#if defined(ENOBUFS) && (!defined(ENOSR) || (ENOBUFS != ENOSR))
+ case ENOBUFS: return "enobufs";
+#endif
+#ifdef ENOCSI
+ case ENOCSI: return "enocsi";
+#endif
+#if defined(ENODATA) && (!defined(ECONNREFUSED) || (ENODATA != ECONNREFUSED))
+ case ENODATA: return "enodata";
+#endif
+#ifdef ENODEV
+ case ENODEV: return "enodev";
+#endif
+#ifdef ENOENT
+ case ENOENT: return "enoent";
+#endif
+#ifdef ENOEXEC
+ case ENOEXEC: return "enoexec";
+#endif
+#ifdef ENOLCK
+ case ENOLCK: return "enolck";
+#endif
+#ifdef ENOLINK
+ case ENOLINK: return "enolink";
+#endif
+#ifdef ENOMEM
+ case ENOMEM: return "enomem";
+#endif
+#ifdef ENOMSG
+ case ENOMSG: return "enomsg";
+#endif
+#ifdef ENONET
+ case ENONET: return "enonet";
+#endif
+#ifdef ENOPKG
+ case ENOPKG: return "enopkg";
+#endif
+#ifdef ENOPROTOOPT
+ case ENOPROTOOPT: return "enoprotoopt";
+#endif
+#ifdef ENOSPC
+ case ENOSPC: return "enospc";
+#endif
+#if defined(ENOSR) && (!defined(ENAMETOOLONG) || (ENAMETOOLONG != ENOSR))
+ case ENOSR: return "enosr";
+#endif
+#if defined(ENOSTR) && (!defined(ENOTTY) || (ENOTTY != ENOSTR))
+ case ENOSTR: return "enostr";
+#endif
+#ifdef ENOSYM
+ case ENOSYM: return "enosym";
+#endif
+#ifdef ENOSYS
+ case ENOSYS: return "enosys";
+#endif
+#ifdef ENOTBLK
+ case ENOTBLK: return "enotblk";
+#endif
+#ifdef ENOTCONN
+ case ENOTCONN: return "enotconn";
+#endif
+#ifdef ENOTDIR
+ case ENOTDIR: return "enotdir";
+#endif
+#if defined(ENOTEMPTY) && (!defined(EEXIST) || (ENOTEMPTY != EEXIST))
+ case ENOTEMPTY: return "enotempty";
+#endif
+#ifdef ENOTNAM
+ case ENOTNAM: return "enotnam";
+#endif
+#ifdef ENOTSOCK
+ case ENOTSOCK: return "enotsock";
+#endif
+#ifdef ENOTSUP
+ case ENOTSUP: return "enotsup";
+#endif
+#ifdef ENOTTY
+ case ENOTTY: return "enotty";
+#endif
+#ifdef ENOTUNIQ
+ case ENOTUNIQ: return "enotuniq";
+#endif
+#ifdef ENXIO
+ case ENXIO: return "enxio";
+#endif
+#if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || EOPNOTSUPP != ENOTSUP)
+ case EOPNOTSUPP: return "eopnotsupp";
+#endif
+#ifdef EPERM
+ case EPERM: return "eperm";
+#endif
+#if defined(EPFNOSUPPORT) && (!defined(ENOLCK) || (ENOLCK != EPFNOSUPPORT))
+ case EPFNOSUPPORT: return "epfnosupport";
+#endif
+#ifdef EPIPE
+ case EPIPE: return "epipe";
+#endif
+#ifdef EPROCLIM
+ case EPROCLIM: return "eproclim";
+#endif
+#ifdef EPROCUNAVAIL
+ case EPROCUNAVAIL: return "eprocunavail";
+#endif
+#ifdef EPROGMISMATCH
+ case EPROGMISMATCH: return "eprogmismatch";
+#endif
+#ifdef EPROGUNAVAIL
+ case EPROGUNAVAIL: return "eprogunavail";
+#endif
+#ifdef EPROTO
+ case EPROTO: return "eproto";
+#endif
+#ifdef EPROTONOSUPPORT
+ case EPROTONOSUPPORT: return "eprotonosupport";
+#endif
+#ifdef EPROTOTYPE
+ case EPROTOTYPE: return "eprototype";
+#endif
+#ifdef ERANGE
+ case ERANGE: return "erange";
+#endif
+#if defined(EREFUSED) && (!defined(ECONNREFUSED) || (EREFUSED != ECONNREFUSED))
+ case EREFUSED: return "erefused";
+#endif
+#ifdef EREMCHG
+ case EREMCHG: return "eremchg";
+#endif
+#ifdef EREMDEV
+ case EREMDEV: return "eremdev";
+#endif
+#ifdef EREMOTE
+ case EREMOTE: return "eremote";
+#endif
+#ifdef EREMOTEIO
+ case EREMOTEIO: return "eremoteio";
+#endif
+#ifdef EREMOTERELEASE
+ case EREMOTERELEASE: return "eremoterelease";
+#endif
+#ifdef EROFS
+ case EROFS: return "erofs";
+#endif
+#ifdef ERPCMISMATCH
+ case ERPCMISMATCH: return "erpcmismatch";
+#endif
+#ifdef ERREMOTE
+ case ERREMOTE: return "erremote";
+#endif
+#ifdef ESHUTDOWN
+ case ESHUTDOWN: return "eshutdown";
+#endif
+#ifdef ESOCKTNOSUPPORT
+ case ESOCKTNOSUPPORT: return "esocktnosupport";
+#endif
+#ifdef ESPIPE
+ case ESPIPE: return "espipe";
+#endif
+#ifdef ESRCH
+ case ESRCH: return "esrch";
+#endif
+#ifdef ESRMNT
+ case ESRMNT: return "esrmnt";
+#endif
+#ifdef ESTALE
+ case ESTALE: return "estale";
+#endif
+#ifdef ESUCCESS
+ case ESUCCESS: return "esuccess";
+#endif
+#if defined(ETIME) && (!defined(ELOOP) || (ETIME != ELOOP))
+ case ETIME: return "etime";
+#endif
+#if defined(ETIMEDOUT) && (!defined(ENOSTR) || (ETIMEDOUT != ENOSTR))
+ case ETIMEDOUT: return "etimedout";
+#endif
+#ifdef ETOOMANYREFS
+ case ETOOMANYREFS: return "etoomanyrefs";
+#endif
+#ifdef ETXTBSY
+ case ETXTBSY: return "etxtbsy";
+#endif
+#ifdef EUCLEAN
+ case EUCLEAN: return "euclean";
+#endif
+#ifdef EUNATCH
+ case EUNATCH: return "eunatch";
+#endif
+#ifdef EUSERS
+ case EUSERS: return "eusers";
+#endif
+#ifdef EVERSION
+ case EVERSION: return "eversion";
+#endif
+#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
+ case EWOULDBLOCK: return "ewouldblock";
+#endif
+#ifdef EXDEV
+ case EXDEV: return "exdev";
+#endif
+#ifdef EXFULL
+ case EXFULL: return "exfull";
+#endif
+#ifdef WSAEINTR
+ case WSAEINTR: return "eintr";
+#endif
+#ifdef WSAEBADF
+ case WSAEBADF: return "ebadf";
+#endif
+#ifdef WSAEACCES
+ case WSAEACCES: return "eacces";
+#endif
+#ifdef WSAEFAULT
+ case WSAEFAULT: return "efault";
+#endif
+#ifdef WSAEINVAL
+ case WSAEINVAL: return "einval";
+#endif
+#ifdef WSAEMFILE
+ case WSAEMFILE: return "emfile";
+#endif
+#ifdef WSAEWOULDBLOCK
+ case WSAEWOULDBLOCK: return "ewouldblock";
+#endif
+#ifdef WSAEINPROGRESS
+ case WSAEINPROGRESS: return "einprogress";
+#endif
+#ifdef WSAEALREADY
+ case WSAEALREADY: return "ealready";
+#endif
+#ifdef WSAENOTSOCK
+ case WSAENOTSOCK: return "enotsock";
+#endif
+#ifdef WSAEDESTADDRREQ
+ case WSAEDESTADDRREQ: return "edestaddrreq";
+#endif
+#ifdef WSAEMSGSIZE
+ case WSAEMSGSIZE: return "emsgsize";
+#endif
+#ifdef WSAEPROTOTYPE
+ case WSAEPROTOTYPE: return "eprototype";
+#endif
+#ifdef WSAENOPROTOOPT
+ case WSAENOPROTOOPT: return "enoprotoopt";
+#endif
+#ifdef WSAEPROTONOSUPPORT
+ case WSAEPROTONOSUPPORT: return "eprotonosupport";
+#endif
+#ifdef WSAESOCKTNOSUPPORT
+ case WSAESOCKTNOSUPPORT: return "esocktnosupport";
+#endif
+#ifdef WSAEOPNOTSUPP
+ case WSAEOPNOTSUPP: return "eopnotsupp";
+#endif
+#ifdef WSAEPFNOSUPPORT
+ case WSAEPFNOSUPPORT: return "epfnosupport";
+#endif
+#ifdef WSAEAFNOSUPPORT
+ case WSAEAFNOSUPPORT: return "eafnosupport";
+#endif
+#ifdef WSAEADDRINUSE
+ case WSAEADDRINUSE: return "eaddrinuse";
+#endif
+#ifdef WSAEADDRNOTAVAIL
+ case WSAEADDRNOTAVAIL: return "eaddrnotavail";
+#endif
+#ifdef WSAENETDOWN
+ case WSAENETDOWN: return "enetdown";
+#endif
+#ifdef WSAENETUNREACH
+ case WSAENETUNREACH: return "enetunreach";
+#endif
+#ifdef WSAENETRESET
+ case WSAENETRESET: return "enetreset";
+#endif
+#ifdef WSAECONNABORTED
+ case WSAECONNABORTED: return "econnaborted";
+#endif
+#ifdef WSAECONNRESET
+ case WSAECONNRESET: return "econnreset";
+#endif
+#ifdef WSAENOBUFS
+ case WSAENOBUFS: return "enobufs";
+#endif
+#ifdef WSAEISCONN
+ case WSAEISCONN: return "eisconn";
+#endif
+#ifdef WSAENOTCONN
+ case WSAENOTCONN: return "enotconn";
+#endif
+#ifdef WSAESHUTDOWN
+ case WSAESHUTDOWN: return "eshutdown";
+#endif
+#ifdef WSAETOOMANYREFS
+ case WSAETOOMANYREFS: return "etoomanyrefs";
+#endif
+#ifdef WSAETIMEDOUT
+ case WSAETIMEDOUT: return "etimedout";
+#endif
+#ifdef WSAECONNREFUSED
+ case WSAECONNREFUSED: return "econnrefused";
+#endif
+#ifdef WSAELOOP
+ case WSAELOOP: return "eloop";
+#endif
+#ifdef WSAENAMETOOLONG
+ case WSAENAMETOOLONG: return "enametoolong";
+#endif
+#ifdef WSAEHOSTDOWN
+ case WSAEHOSTDOWN: return "ehostdown";
+#endif
+#ifdef WSAEHOSTUNREACH
+ case WSAEHOSTUNREACH: return "ehostunreach";
+#endif
+#ifdef WSAENOTEMPTY
+ case WSAENOTEMPTY: return "enotempty";
+#endif
+#ifdef WSAEPROCLIM
+ case WSAEPROCLIM: return "eproclim";
+#endif
+#ifdef WSAEUSERS
+ case WSAEUSERS: return "eusers";
+#endif
+#ifdef WSAEDQUOT
+ case WSAEDQUOT: return "edquot";
+#endif
+#ifdef WSAESTALE
+ case WSAESTALE: return "estale";
+#endif
+#ifdef WSAEREMOTE
+ case WSAEREMOTE: return "eremote";
+#endif
+#ifdef WSASYSNOTREADY
+ case WSASYSNOTREADY: return "sysnotready";
+#endif
+#ifdef WSAVERNOTSUPPORTED
+ case WSAVERNOTSUPPORTED: return "vernotsupported";
+#endif
+#ifdef WSANOTINITIALISED
+ case WSANOTINITIALISED: return "notinitialised";
+#endif
+#ifdef WSAEDISCON
+ case WSAEDISCON: return "ediscon";
+#endif
+#ifdef WSAENOMORE
+ case WSAENOMORE: return "enomore";
+#endif
+#ifdef WSAECANCELLED
+ case WSAECANCELLED: return "ecancelled";
+#endif
+#ifdef WSAEINVALIDPROCTABLE
+ case WSAEINVALIDPROCTABLE: return "einvalidproctable";
+#endif
+#ifdef WSAEINVALIDPROVIDER
+ case WSAEINVALIDPROVIDER: return "einvalidprovider";
+#endif
+#ifdef WSAEPROVIDERFAILEDINIT
+ case WSAEPROVIDERFAILEDINIT: return "eproviderfailedinit";
+#endif
+#ifdef WSASYSCALLFAILURE
+ case WSASYSCALLFAILURE: return "syscallfailure";
+#endif
+#ifdef WSASERVICE_NOT_FOUND
+ case WSASERVICE_NOT_FOUND: return "service_not_found";
+#endif
+#ifdef WSATYPE_NOT_FOUND
+ case WSATYPE_NOT_FOUND: return "type_not_found";
+#endif
+#ifdef WSA_E_NO_MORE
+ case WSA_E_NO_MORE: return "e_no_more";
+#endif
+#ifdef WSA_E_CANCELLED
+ case WSA_E_CANCELLED: return "e_cancelled";
+#endif
+ default:
+ sprintf(errstrbuf, "unknown:%d", error);
+ return errstrbuf;
+ }
+}
+
diff --git a/lib/ssl/c_src/esock_posix_str.h b/lib/ssl/c_src/esock_posix_str.h
new file mode 100644
index 0000000000..53916c888a
--- /dev/null
+++ b/lib/ssl/c_src/esock_posix_str.h
@@ -0,0 +1,28 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1999-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/* esock_posix_str.h */
+
+#ifndef ESOCK_POSIX_STR_H
+#define ESOCK_POSIX_STR_H
+
+char *esock_posix_str(int error);
+
+#endif
+
diff --git a/lib/ssl/c_src/esock_ssl.h b/lib/ssl/c_src/esock_ssl.h
new file mode 100644
index 0000000000..535e9a6491
--- /dev/null
+++ b/lib/ssl/c_src/esock_ssl.h
@@ -0,0 +1,110 @@
+/*<copyright>
+ * <year>1999-2008</year>
+ * <holder>Ericsson AB, All Rights Reserved</holder>
+ *</copyright>
+ *<legalnotice>
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Initial Developer of the Original Code is Ericsson AB.
+ *</legalnotice>
+ */
+/*
+ * Purpose: Header file for adaptions to various SSL packages.
+ */
+
+#ifndef ESOCK_SSL_H
+#define ESOCK_SSL_H
+
+#include <sys/types.h>
+#include <stdio.h>
+#include "esock.h"
+
+typedef struct {
+ const char *compile_version;/* version of OpenSSL when compiling esock */
+ const char *lib_version; /* version of OpenSSL in library */
+} esock_version;
+
+/* Variables to be set by certain functions (see below) */
+char *esock_ssl_errstr;
+
+/* Ephemeral RSA and DH */
+int ephemeral_rsa, ephemeral_dh;
+
+/* Protocol version (sslv2, sslv3, tlsv1) */
+int protocol_version;
+
+/* version info */
+esock_version *esock_ssl_version(void);
+
+/* ciphers info */
+char *esock_ssl_ciphers(void);
+
+/* seeding */
+void esock_ssl_seed(void *buf, int len);
+
+/* Initialization and finalization of SSL */
+
+int esock_ssl_init(void);
+void esock_ssl_finish(void);
+
+/* Freeing of SSL resources for a connection */
+
+void esock_ssl_free(Connection *cp);
+
+/* Print error diagnostics to a file pointer */
+
+void esock_ssl_print_errors_fp(FILE *fp);
+
+/* All functions below have to return >= 0 on success, and < 0 on
+ * failure.
+ *
+ * If the return indicates a failure (return value < 0) and the failure
+ * is temporary the error context (sock_errno()/sock_set_errno()) must
+ * be set to ERRNO_BLOCK.
+ *
+ * If the failure is permanent, the error context must be set to something
+ * else than ERRNO_BLOCK, and `esock_ssl_errstr' must be set to point to
+ * short diagnostic string describing the error.
+ */
+
+int esock_ssl_accept_init(Connection *cp, void *listenssl);
+int esock_ssl_connect_init(Connection *cp);
+int esock_ssl_listen_init(Connection *cp);
+
+/* All functions below may involve non-blocking I/O with a temporary
+ * failure. Hence they have to have the error context set to
+ * ERRNO_BLOCK, or else have esock_ssl_errstr set to point to a
+ * diagnostic string, in case the return value is < 0. If the return
+ * value is 0, cp->eof and cp->bp are set, if appropritate.
+ */
+
+int esock_ssl_accept(Connection *cp);
+int esock_ssl_connect(Connection *cp);
+
+int esock_ssl_read(Connection *cp, char *buf, int len);
+int esock_ssl_write(Connection *cp, char *buf, int len);
+
+int esock_ssl_shutdown(Connection *cp);
+
+/* Peer certificate */
+
+int esock_ssl_getpeercert(Connection *cp, unsigned char **buf);
+int esock_ssl_getpeercertchain(Connection *cp, unsigned char **buf);
+
+/* Sessions */
+int esock_ssl_session_reused(Connection *cp);
+
+/* Protocol version and cipher of established connection */
+int esock_ssl_getprotocol_version(Connection *cp, char **buf);
+int esock_ssl_getcipher(Connection *cp, char **buf);
+
+#endif
diff --git a/lib/ssl/c_src/esock_utils.c b/lib/ssl/c_src/esock_utils.c
new file mode 100644
index 0000000000..0098a4f5f6
--- /dev/null
+++ b/lib/ssl/c_src/esock_utils.c
@@ -0,0 +1,150 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1999-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/*
+ * Purpose: Safe memory allocation and other utilities.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "esock_utils.h"
+
+static char *strtok_quote(char *s1, const char *s2);
+
+
+void *esock_malloc(size_t size)
+{
+ void *p;
+
+ p = malloc(size);
+ if (!p) {
+ fprintf(stderr, "esock_malloc: cannot alloc %d bytes\n", size);
+ exit(EXIT_FAILURE);
+ }
+ return p;
+}
+
+void *esock_realloc(void *p, size_t size)
+{
+ void *np;
+
+ np = realloc(p, size);
+ if (!np) {
+ fprintf(stderr, "esock_realloc: cannot realloc %d bytes\n", size);
+ exit(EXIT_FAILURE);
+ }
+ return np;
+}
+
+void esock_free(void *p)
+{
+ free(p);
+}
+
+/* Builds an argv array from cmd. Spaces and tabs within double quotes
+ * are not considered delimiters. Double quotes are removed.
+ *
+ * The return value is argc, and the pointer to char ** is set. argc
+ * is non-negative, argv[0], ..., argv[argc - 1] are pointers to
+ * strings, and argv[argc] == NULL. All argv[0], ..., argv[argc - 1]
+ * must be freed by the user, and also the argv pointer itself.
+ *
+ * Example: cmd = abc"/program files/"olle nisse, results in
+ * argv[0] = abc/program files/olle, argv[1] = nisse, argc = 2.
+ *
+ */
+int esock_build_argv(char *cmd, char ***argvp)
+{
+ int argvsize = 10, argc = 0;
+ char *args, *tokp, *argp;
+ char **argv;
+
+ argv = esock_malloc(argvsize * sizeof(char *));
+ args = esock_malloc(strlen(cmd) + 1);
+ strcpy(args, cmd);
+ tokp = strtok_quote(args, " \t");
+ while (tokp != NULL) {
+ if (argc + 1 >= argvsize) {
+ argvsize += 10;
+ argv = esock_realloc(argv, argvsize * sizeof(char *));
+ }
+ argp = esock_malloc(strlen(tokp) + 1);
+ strcpy(argp, tokp);
+ argv[argc++] = argp;
+ tokp = strtok_quote(NULL, " \t");
+ }
+ esock_free(args);
+ argv[argc] = NULL;
+ *argvp = argv;
+ return argc;
+}
+
+/* strtok_quote
+ * Works as strtok, but characters within pairs of double quotes are not
+ * considered as delimiters. Quotes are removed.
+ */
+static char *strtok_quote(char *s1, const char *s2)
+{
+ static char *last;
+ char *s, *t, *u;
+
+ s = (s1) ? s1 : last;
+ if (!s)
+ return last = NULL;
+
+ while (*s != '"' && *s != '\0' && strchr(s2, *s))
+ s++;
+ t = s;
+
+ while (1) {
+ if (*t == '"') {
+ t++;
+ while (*t != '"' && *t != '\0')
+ t++;
+ if (*t == '\0') {
+ last = NULL;
+ goto end;
+ }
+ t++;
+ }
+ while(*t != '"' && *t != '\0' && !strchr(s2, *t))
+ t++;
+ if (*t == '\0') {
+ last = NULL;
+ goto end;
+ } else if (*t != '"') {
+ *t = '\0';
+ last = t + 1;
+ goto end;
+ }
+ }
+end:
+ /* Remove quotes */
+ u = t = s;
+ while (*u) {
+ if (*u == '"')
+ u++;
+ else
+ *t++ = *u++;
+ }
+ *t = '\0';
+ return s;
+}
+
diff --git a/lib/ssl/c_src/esock_utils.h b/lib/ssl/c_src/esock_utils.h
new file mode 100644
index 0000000000..99ed6c23e3
--- /dev/null
+++ b/lib/ssl/c_src/esock_utils.h
@@ -0,0 +1,32 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1999-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, 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 ESOCK_UTILS_H
+#define ESOCK_UTILS_H
+
+#include <stdlib.h>
+
+void *esock_malloc(size_t size);
+void *esock_realloc(void *p, size_t size);
+void esock_free(void *p);
+int esock_build_argv(char *cmd, char ***argvp);
+
+#endif
+
+
diff --git a/lib/ssl/c_src/esock_winsock.h b/lib/ssl/c_src/esock_winsock.h
new file mode 100644
index 0000000000..069782a18d
--- /dev/null
+++ b/lib/ssl/c_src/esock_winsock.h
@@ -0,0 +1,36 @@
+/*<copyright>
+ * <year>2003-2008</year>
+ * <holder>Ericsson AB, All Rights Reserved</holder>
+ *</copyright>
+ *<legalnotice>
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Initial Developer of the Original Code is Ericsson AB.
+ *</legalnotice>
+ */
+/*
+ * Purpose: Control winsock version and setting of FD_SETSIZE.
+ *
+ */
+
+/* Maybe set FD_SETSIZE */
+
+#ifdef ESOCK_WINSOCK2
+#include <winsock2.h>
+#else
+#include <winsock.h>
+/* These are defined in winsock2.h but not in winsock.h */
+#define SD_RECEIVE 0x00
+#define SD_SEND 0x01
+#define SD_BOTH 0x02
+#endif
+