aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/drivers/common
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/drivers/common')
-rw-r--r--erts/emulator/drivers/common/efile_drv.c16
-rw-r--r--erts/emulator/drivers/common/gzio.c2
-rw-r--r--erts/emulator/drivers/common/inet_drv.c248
-rw-r--r--erts/emulator/drivers/common/zlib_drv.c736
4 files changed, 198 insertions, 804 deletions
diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c
index 3adb8db661..3a7b3bb50c 100644
--- a/erts/emulator/drivers/common/efile_drv.c
+++ b/erts/emulator/drivers/common/efile_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2016. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2017. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -742,7 +742,8 @@ file_init(void)
efile_init();
#ifdef USE_VM_PROBES
- erts_mtx_init(&dt_driver_mutex, "efile_drv dtrace mutex");
+ erts_mtx_init(&dt_driver_mutex, "efile_drv dtrace mutex", NIL,
+ ERTS_LOCK_FLAGS_PROPERTY_STATIC | ERTS_LOCK_FLAGS_CATEGORY_IO);
pthread_key_create(&dt_driver_key, NULL);
#endif /* USE_VM_PROBES */
@@ -1937,7 +1938,8 @@ static void free_sendfile(void *data) {
MUTEX_LOCK(d->c.sendfile.q_mtx);
driver_deq(d->c.sendfile.port,1);
MUTEX_UNLOCK(d->c.sendfile.q_mtx);
- driver_select(d->c.sendfile.port, (ErlDrvEvent)(long)d->c.sendfile.out_fd, ERL_DRV_USE_NO_CALLBACK|ERL_DRV_WRITE, 0);
+ driver_select(d->c.sendfile.port, (ErlDrvEvent)(long)d->c.sendfile.out_fd,
+ ERL_DRV_USE_NO_CALLBACK|ERL_DRV_WRITE, 0);
}
EF_FREE(data);
}
@@ -2330,9 +2332,9 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data)
free_read(data);
break;
case FILE_READ_LINE:
- /* The read_line stucture differs from the read structure.
- The data->read_offset and d->c.read_line.read_offset are copies, as are
- data->read_size and d->c.read_line.read_size
+ /* The read_line structure differs from the read structure.
+ The data->read_offset and d->c.read_line.read_offset are copies, as are
+ data->read_size and d->c.read_line.read_size
The read_line function does not kniow in advance how large the binary has to be,
why new allocation (but not reallocation of the old binary, for obvious reasons)
may happen in the worker thread. */
@@ -2555,7 +2557,7 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data)
desc->sendfile_state = sending;
desc->d = d;
driver_select(desc->port, (ErlDrvEvent)(long)d->c.sendfile.out_fd,
- ERL_DRV_USE_NO_CALLBACK|ERL_DRV_WRITE, 1);
+ ERL_DRV_USE|ERL_DRV_WRITE, 1);
}
break;
#endif
diff --git a/erts/emulator/drivers/common/gzio.c b/erts/emulator/drivers/common/gzio.c
index 1ef1602ec9..f60c781894 100644
--- a/erts/emulator/drivers/common/gzio.c
+++ b/erts/emulator/drivers/common/gzio.c
@@ -308,7 +308,7 @@ ErtsGzFile erts_gzopen (path, mode)
/* ===========================================================================
Read a byte from a gz_stream; update next_in and avail_in. Return EOF
for end of file.
- IN assertion: the stream s has been sucessfully opened for reading.
+ IN assertion: the stream s has been successfully opened for reading.
*/
local int get_byte(s)
gz_stream *s;
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index ebd13e6f05..f6de343f72 100644
--- a/erts/emulator/drivers/common/inet_drv.c
+++ b/erts/emulator/drivers/common/inet_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2016. All Rights Reserved.
+ * Copyright Ericsson AB 1997-2017. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -591,7 +591,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
(((unsigned char*) (s))[1] << 8) | \
(((unsigned char*) (s))[0]))
-#ifdef HAVE_SYS_UN_H
+#if defined(HAVE_SYS_UN_H) || defined(SO_BINDTODEVICE)
/* strnlen doesn't exist everywhere */
static size_t my_strnlen(const char *s, size_t maxlen)
@@ -602,14 +602,6 @@ static size_t my_strnlen(const char *s, size_t maxlen)
return i;
}
-/* Check that some character in the buffer != '\0' */
-static int is_nonzero(const char *s, size_t n)
-{
- size_t i;
- for (i = 0; i < n; i++) if (s[i] != '\0') return !0;
- return 0;
-}
-
#endif
#ifdef VALGRIND
@@ -728,7 +720,7 @@ static int is_nonzero(const char *s, size_t n)
#define TCP_ADDF_PENDING_SHUTDOWN \
(TCP_ADDF_PENDING_SHUT_WR | TCP_ADDF_PENDING_SHUT_RDWR)
#define TCP_ADDF_SHOW_ECONNRESET 64 /* Tell user about incoming RST */
-#define TCP_ADDF_DELAYED_ECONNRESET 128 /* An ECONNRESET error occured on send or shutdown */
+#define TCP_ADDF_DELAYED_ECONNRESET 128 /* An ECONNRESET error occurred on send or shutdown */
#define TCP_ADDF_SHUTDOWN_WR_DONE 256 /* A shutdown(sock, SHUT_WR) or SHUT_RDWR was made */
#define TCP_ADDF_LINGER_ZERO 512 /* Discard driver queue on port close */
@@ -778,6 +770,7 @@ static int is_nonzero(const char *s, size_t n)
#define INET_LOPT_TCP_SHOW_ECONNRESET 39 /* tell user about incoming RST */
#define INET_LOPT_LINE_DELIM 40 /* Line delimiting char */
#define INET_OPT_TCLASS 41 /* IPv6 transport class */
+#define INET_OPT_BIND_TO_DEVICE 42 /* get/set network device the socket is bound to */
/* SCTP options: a separate range, from 100: */
#define SCTP_OPT_RTOINFO 100
#define SCTP_OPT_ASSOCINFO 101
@@ -1025,6 +1018,7 @@ typedef struct {
inet_async_op* oph; /* queue head or NULL */
inet_async_op* opt; /* queue tail or NULL */
inet_async_op op_queue[INET_MAX_ASYNC]; /* call queue */
+ int op_ref; /* queue reference generator */
int active; /* 0 = passive, 1 = active, 2 = active once */
Sint16 active_count; /* counter for {active,N} */
@@ -1256,6 +1250,8 @@ static int tcp_shutdown_error(tcp_descriptor* desc, int err);
static int tcp_inet_output(tcp_descriptor* desc, HANDLE event);
static int tcp_inet_input(tcp_descriptor* desc, HANDLE event);
+static void tcp_desc_close(tcp_descriptor*);
+
#ifdef HAVE_UDP
typedef struct {
inet_descriptor inet; /* common data structure (DON'T MOVE) */
@@ -1273,8 +1269,7 @@ static int packet_inet_output(udp_descriptor* udesc, HANDLE event);
/* convert descriptor pointer to inet_descriptor pointer */
#define INETP(d) (&(d)->inet)
-static int async_ref = 0; /* async reference id generator */
-#define NEW_ASYNC_ID() ((async_ref++) & 0xffff)
+#define NEW_ASYNC_ID(desc) ((desc)->op_ref++ & 0xffff)
/* check for transition from active to passive */
#define INET_CHECK_ACTIVE_TO_PASSIVE(inet) \
@@ -1334,6 +1329,7 @@ static ErlDrvTermData am_tos;
static ErlDrvTermData am_tclass;
static ErlDrvTermData am_ipv6_v6only;
static ErlDrvTermData am_netns;
+static ErlDrvTermData am_bind_to_device;
#endif
static char str_eafnosupport[] = "eafnosupport";
@@ -1925,7 +1921,7 @@ static void enq_multi_op(tcp_descriptor *desc, char *buf, int req,
ErlDrvTermData caller, MultiTimerData *timeout,
ErlDrvMonitor *monitorp)
{
- int id = NEW_ASYNC_ID();
+ int id = NEW_ASYNC_ID(INETP(desc));
enq_old_multi_op(desc,id,req,caller,timeout,monitorp);
if (buf != NULL)
put_int16(id, buf);
@@ -1994,7 +1990,7 @@ static int remove_multi_op(tcp_descriptor *desc, int *id_p, int *req_p,
static int enq_async_w_tmo(inet_descriptor* desc, char* buf, int req, unsigned timeout,
ErlDrvMonitor *monitorp)
{
- int id = NEW_ASYNC_ID();
+ int id = NEW_ASYNC_ID(desc);
inet_async_op* opp;
if ((opp = desc->oph) == NULL) /* queue empty */
@@ -2203,13 +2199,16 @@ static int inet_reply_ok(inet_descriptor* desc)
ErlDrvTermData caller = desc->caller;
int i = 0;
+ desc->caller = 0;
+ if (is_not_internal_pid(caller))
+ return 0;
+
i = LOAD_ATOM(spec, i, am_inet_reply);
i = LOAD_PORT(spec, i, desc->dport);
i = LOAD_ATOM(spec, i, am_ok);
i = LOAD_TUPLE(spec, i, 3);
ASSERT(i == sizeof(spec)/sizeof(*spec));
- desc->caller = 0;
return erl_drv_send_term(desc->dport, caller, spec, i);
}
@@ -3725,6 +3724,7 @@ static void inet_init_sctp(void) {
INIT_ATOM(tclass);
INIT_ATOM(ipv6_v6only);
INIT_ATOM(netns);
+ INIT_ATOM(bind_to_device);
/* Option names */
INIT_ATOM(sctp_rtoinfo);
@@ -4018,13 +4018,30 @@ static char* inet_set_address(int family, inet_address* dst,
int n;
if (*len == 0) return str_einval;
n = *((unsigned char*)(*src)); /* Length field */
- if ((*len < 1+n) || (sizeof(dst->sal.sun_path) < n+1)) {
+ if (*len < 1+n) return str_einval;
+ if (n +
+#ifdef __linux__
+ /* Make sure the address gets zero terminated
+ * except when the first byte is \0 because then it is
+ * sort of zero terminated although the zero termination
+ * comes before the address...
+ * This fix handles Linux's nonportable
+ * abstract socket address extension.
+ */
+ ((*len) > 1 && (*src)[1] == '\0' ? 0 : 1)
+#else
+ 1
+#endif
+ > sizeof(dst->sal.sun_path)) {
return str_einval;
}
sys_memzero((char*)dst, sizeof(struct sockaddr_un));
dst->sal.sun_family = family;
sys_memcpy(dst->sal.sun_path, (*src)+1, n);
*len = offsetof(struct sockaddr_un, sun_path) + n;
+#ifndef NO_SA_LEN
+ dst->sal.sun_len = *len;
+#endif
*src += 1 + n;
return NULL;
}
@@ -4132,8 +4149,8 @@ static char *inet_set_faddress(int family, inet_address* dst,
/* Get a inaddr structure
** src = inaddr structure
-** *len is the lenght of structure
** dst is filled with [F,P1,P0,X1,....]
+** *len is the length of structure
** where F is the family code (coded)
** and *len is the length of dst on return
** (suitable to deliver to erlang)
@@ -4169,15 +4186,16 @@ static int inet_get_address(char* dst, inet_address* src, unsigned int* len)
if (*len < offsetof(struct sockaddr_un, sun_path)) return -1;
n = *len - offsetof(struct sockaddr_un, sun_path);
if (255 < n) return -1;
- /* Portability fix: Assume that the address is a zero terminated
- * string, except when the first byte is \0 i.e the
- * string length is 0. Then use the reported length instead.
- * This fix handles Linux's abstract socket address
- * nonportable extension.
- */
m = my_strnlen(src->sal.sun_path, n);
- if ((m == 0) && is_nonzero(src->sal.sun_path, n))
- m = n;
+#ifdef __linux__
+ /* Assume that the address is a zero terminated string,
+ * except when the first byte is \0 i.e the string length is 0,
+ * then use the reported length instead.
+ * This fix handles Linux's nonportable
+ * abstract socket address extension.
+ */
+ if (m == 0) m = n;
+#endif
dst[0] = INET_AF_LOCAL;
dst[1] = (char) ((unsigned char) m);
sys_memcpy(dst+2, src->sal.sun_path, m);
@@ -4234,15 +4252,16 @@ inet_address_to_erlang(char *dst, inet_address **src, SOCKLEN_T sz) {
if (sz < offsetof(struct sockaddr_un, sun_path)) return -1;
n = sz - offsetof(struct sockaddr_un, sun_path);
if (255 < n) return -1;
- /* Portability fix: Assume that the address is a zero terminated
- * string, except when the first byte is \0 i.e the
- * string length is 0. Then use the reported length instead.
- * This fix handles Linux's abstract socket address
- * nonportable extension.
- */
m = my_strnlen((*src)->sal.sun_path, n);
- if ((m == 0) && is_nonzero((*src)->sal.sun_path, n))
- m = n;
+#ifdef __linux__
+ /* Assume that the address is a zero terminated string,
+ * except when the first byte is \0 i.e the string length is 0,
+ * Then use the reported length instead.
+ * This fix handles Linux's nonportable
+ * abstract socket address extension.
+ */
+ if (m == 0) m = n;
+#endif
if (dst) {
dst[0] = INET_AF_LOCAL;
dst[1] = (char) ((unsigned char) m);
@@ -4320,6 +4339,12 @@ static void desc_close(inet_descriptor* desc)
desc->event = INVALID_EVENT; /* closed by stop_select callback */
desc->s = INVALID_SOCKET;
desc->event_mask = 0;
+
+ /* mark as disconnected in case when socket is left lingering due to
+ * {exit_on_close, false} option in gen_tcp socket creation. Next
+ * write to socket should produce {error, enotconn} and send a
+ * message {tcp_error,#Port<>,econnreset} */
+ desc->state &= ~INET_STATE_CONNECTED;
}
}
@@ -5946,6 +5971,9 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len)
int ival;
char* arg_ptr;
int arg_sz;
+#ifdef SO_BINDTODEVICE
+ char ifname[IFNAMSIZ];
+#endif
enum PacketParseType old_htype = desc->htype;
int old_active = desc->active;
int propagate; /* Set to 1 if failure to set this option
@@ -6331,6 +6359,29 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len)
len -= arg_sz;
break;
+#ifdef SO_BINDTODEVICE
+ case INET_OPT_BIND_TO_DEVICE:
+ if (ival < 0) return -1;
+ if (len < ival) return -1;
+ if (ival > sizeof(ifname)) {
+ return -1;
+ }
+ memcpy(ifname, ptr, ival);
+ ifname[ival] = '\0';
+ ptr += ival;
+ len -= ival;
+
+ proto = SOL_SOCKET;
+ type = SO_BINDTODEVICE;
+ arg_ptr = (char*)&ifname;
+ arg_sz = sizeof(ifname);
+ propagate = 1; /* We do want to know if this fails */
+
+ DEBUGF(("inet_set_opts(%ld): s=%d, SO_BINDTODEVICE=%s\r\n",
+ (long)desc->port, desc->s, ifname));
+ break;
+#endif
+
default:
return -1;
}
@@ -6463,6 +6514,9 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len)
# ifdef SCTP_DELAYED_ACK_TIME
struct sctp_assoc_value av; /* Not in SOLARIS10 */
# endif
+# ifdef SO_BINDTODEVICE
+ char ifname[IFNAMSIZ];
+# endif
}
arg;
@@ -6702,6 +6756,23 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len)
continue; /* Option not supported -- ignore it */
# endif
+#ifdef SO_BINDTODEVICE
+ case INET_OPT_BIND_TO_DEVICE:
+ arg_sz = get_int32(curr); curr += 4;
+ CHKLEN(curr, arg_sz);
+ if (arg_sz >= sizeof(arg.ifname))
+ return -1;
+ memcpy(arg.ifname, curr, arg_sz);
+ arg.ifname[arg_sz] = '\0';
+ curr += arg_sz;
+
+ proto = SOL_SOCKET;
+ type = SO_BINDTODEVICE;
+ arg_ptr = (char*) (&arg.ifname);
+ arg_sz = sizeof ( arg.ifname);
+ break;
+#endif
+
case SCTP_OPT_AUTOCLOSE:
{
arg.ival= get_int32 (curr); curr += 4;
@@ -6967,6 +7038,9 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc,
ErlDrvSizeT dest_used = 0;
ErlDrvSizeT dest_allocated = destlen;
char *orig_dest = *dest;
+#ifdef SO_BINDTODEVICE
+ char ifname[IFNAMSIZ];
+#endif
/* Ptr is a name parameter */
#define RETURN_ERROR() \
@@ -7302,6 +7376,26 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc,
put_int32(arg_sz,ptr);
continue;
}
+
+#ifdef SO_BINDTODEVICE
+ case INET_OPT_BIND_TO_DEVICE:
+ arg_sz = sizeof(ifname);
+ TRUNCATE_TO(0,ptr);
+ PLACE_FOR(5 + arg_sz,ptr);
+ arg_ptr = ptr + 5;
+ if (IS_SOCKET_ERROR(sock_getopt(desc->s,SOL_SOCKET,SO_BINDTODEVICE,
+ arg_ptr,&arg_sz))) {
+ TRUNCATE_TO(0,ptr);
+ continue;
+ }
+ arg_sz = my_strnlen(arg_ptr, arg_sz);
+ TRUNCATE_TO(arg_sz + 5,ptr);
+ *ptr++ = opt;
+ put_int32(arg_sz,ptr);
+ ptr += arg_sz;
+ continue;
+#endif
+
default:
RETURN_ERROR();
}
@@ -7583,6 +7677,25 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc,
i = LOAD_TUPLE (spec, i, 2);
break;
}
+
+#ifdef SO_BINDTODEVICE
+ /* The following option returns a binary: */
+ case INET_OPT_BIND_TO_DEVICE: {
+ char ifname[IFNAMSIZ];
+ unsigned int sz = sizeof(ifname);
+
+ if (sock_getopt(desc->s, SOL_SOCKET, SO_BINDTODEVICE,
+ &ifname, &sz) < 0) continue;
+ /* Fill in the response: */
+ PLACE_FOR(spec, i,
+ LOAD_ATOM_CNT + LOAD_BUF2BINARY_CNT + LOAD_TUPLE_CNT);
+ i = LOAD_ATOM (spec, i, am_bind_to_device);
+ i = LOAD_BUF2BINARY(spec, i, ifname, my_strnlen(ifname, sz));
+ i = LOAD_TUPLE (spec, i, 2);
+ break;
+ }
+#endif
+
/* The following options just return an integer value: */
case INET_OPT_RCVBUF :
case INET_OPT_SNDBUF :
@@ -8310,6 +8423,7 @@ static ErlDrvData inet_start(ErlDrvPort port, int size, int protocol)
desc->delimiter = '\n'; /* line delimiting char */
desc->oph = NULL;
desc->opt = NULL;
+ desc->op_ref = 0;
desc->peer_ptr = NULL;
desc->name_ptr = NULL;
@@ -8345,10 +8459,10 @@ static ErlDrvData inet_start(ErlDrvPort port, int size, int protocol)
return (ErlDrvData)desc;
}
-
-#ifndef MAXHOSTNAMELEN
-#define MAXHOSTNAMELEN 256
-#endif
+/* MAXHOSTNAMELEN could be 64 or 255 depending
+on the platform. Instead, use INET_MAXHOSTNAMELEN
+which is always 255 across all platforms */
+#define INET_MAXHOSTNAMELEN 255
/*
** common TCP/UDP/SCTP control command
@@ -8525,13 +8639,14 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
}
case INET_REQ_GETHOSTNAME: { /* get host name */
- char tbuf[MAXHOSTNAMELEN];
+ char tbuf[INET_MAXHOSTNAMELEN + 1];
DEBUGF(("inet_ctl(%ld): GETHOSTNAME\r\n", (long)desc->port));
if (len != 0)
return ctl_error(EINVAL, rbuf, rsize);
- if (IS_SOCKET_ERROR(sock_hostname(tbuf, MAXHOSTNAMELEN)))
+ /* gethostname requires len to be max(hostname) + 1 */
+ if (IS_SOCKET_ERROR(sock_hostname(tbuf, INET_MAXHOSTNAMELEN + 1)))
return ctl_error(sock_errno(), rbuf, rsize);
return ctl_reply(INET_REP_OK, tbuf, strlen(tbuf), rbuf, rsize);
}
@@ -8584,6 +8699,7 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
else {
ptr = &peer;
sz = sizeof(peer);
+ sys_memzero((char *) &peer, sz);
if (IS_SOCKET_ERROR
(sock_peer
(desc->s, (struct sockaddr*)ptr, &sz)))
@@ -9138,16 +9254,31 @@ static void tcp_inet_stop(ErlDrvData e)
tcp_descriptor* desc = (tcp_descriptor*)e;
DEBUGF(("tcp_inet_stop(%ld) {s=%d\r\n",
(long)desc->inet.port, desc->inet.s));
+
tcp_close_check(desc);
- /* free input buffer & output buffer */
- if (desc->i_buf != NULL)
- release_buffer(desc->i_buf);
- desc->i_buf = NULL; /* net_mess2 may call this function recursively when
- faulty messages arrive on dist ports*/
+ tcp_clear_input(desc);
+
DEBUGF(("tcp_inet_stop(%ld) }\r\n", (long)desc->inet.port));
inet_stop(INETP(desc));
}
+/* Closes a tcp descriptor without leaving things hanging; the VM keeps trying
+ * to flush IO queues as long as it contains anything even after the port has
+ * been closed from the erlang side, which is desired behavior (Think escripts
+ * writing to files) but pretty hopeless if the underlying fd has been set to
+ * INVALID_SOCKET through desc_close.
+ *
+ * This function should be used in place of desc_close/erl_inet_close in all
+ * TCP-related operations. Note that this only closes the desc cleanly; it
+ * will be freed through tcp_inet_stop later on. */
+static void tcp_desc_close(tcp_descriptor* desc)
+{
+ tcp_clear_input(desc);
+ tcp_clear_output(desc);
+
+ erl_inet_close(INETP(desc));
+}
+
/* TCP requests from Erlang */
static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd,
char* buf, ErlDrvSizeT len,
@@ -9392,7 +9523,7 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd,
case INET_REQ_CLOSE:
DEBUGF(("tcp_inet_ctl(%ld): CLOSE\r\n", (long)desc->inet.port));
tcp_close_check(desc);
- erl_inet_close(INETP(desc));
+ tcp_desc_close(desc);
return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize);
@@ -9516,7 +9647,7 @@ static void tcp_inet_timeout(ErlDrvData e)
set_busy_port(desc->inet.port, 0);
inet_reply_error_am(INETP(desc), am_timeout);
if (desc->send_timeout_close) {
- erl_inet_close(INETP(desc));
+ tcp_desc_close(desc);
}
}
else {
@@ -9530,7 +9661,7 @@ static void tcp_inet_timeout(ErlDrvData e)
else if ((state & INET_STATE_CONNECTING) == INET_STATE_CONNECTING) {
/* assume connect timeout */
/* close the socket since it's not usable (see man pages) */
- erl_inet_close(INETP(desc));
+ tcp_desc_close(desc);
async_error_am(INETP(desc), am_timeout);
}
else if ((state & INET_STATE_ACCEPTING) == INET_STATE_ACCEPTING) {
@@ -9693,8 +9824,7 @@ static int tcp_recv_closed(tcp_descriptor* desc)
/* passive mode do not terminate port ! */
tcp_clear_input(desc);
if (desc->inet.exitf) {
- tcp_clear_output(desc);
- desc_close(INETP(desc));
+ tcp_desc_close(desc);
} else {
desc_close_read(INETP(desc));
}
@@ -9737,7 +9867,7 @@ static int tcp_recv_error(tcp_descriptor* desc, int err)
driver_cancel_timer(desc->inet.port);
tcp_clear_input(desc);
if (desc->inet.exitf) {
- desc_close(INETP(desc));
+ tcp_desc_close(desc);
} else {
desc_close_read(INETP(desc));
}
@@ -10386,9 +10516,6 @@ static int tcp_send_or_shutdown_error(tcp_descriptor* desc, int err)
set_busy_port(desc->inet.port, 0);
}
- tcp_clear_output(desc);
- tcp_clear_input(desc);
-
/*
* We used to handle "expected errors" differently from unexpected ones.
* Now we handle all errors in the same way (unless the show_econnreset
@@ -10409,10 +10536,10 @@ static int tcp_send_or_shutdown_error(tcp_descriptor* desc, int err)
if (desc->inet.exitf)
driver_exit(desc->inet.port, 0);
else
- desc_close(INETP(desc));
+ tcp_desc_close(desc);
} else {
tcp_close_check(desc);
- erl_inet_close(INETP(desc));
+ tcp_desc_close(desc);
if (desc->inet.caller) {
if (show_econnreset)
@@ -10735,10 +10862,11 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event)
#ifndef SO_ERROR
{
- int sz = sizeof(desc->inet.remote);
- int code = sock_peer(desc->inet.s,
- (struct sockaddr*) &desc->inet.remote, &sz);
-
+ int sz, code;
+ sz = sizeof(desc->inet.remote);
+ sys_memzero((char *) &desc->inet.remote, sz);
+ code = sock_peer(desc->inet.s,
+ (struct sockaddr*) &desc->inet.remote, &sz);
if (IS_SOCKET_ERROR(code)) {
desc->inet.state = INET_STATE_OPEN; /* restore state */
ret = async_error(INETP(desc), sock_errno());
diff --git a/erts/emulator/drivers/common/zlib_drv.c b/erts/emulator/drivers/common/zlib_drv.c
deleted file mode 100644
index 440ba956d8..0000000000
--- a/erts/emulator/drivers/common/zlib_drv.c
+++ /dev/null
@@ -1,736 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 2003-2016. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- */
-
-/*
- * ZLib interface for erlang
- *
- */
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-#include <stdio.h>
-#include <zlib.h>
-#include <errno.h>
-#include <string.h>
-
-#include "erl_driver.h"
-
-
-#define DEFLATE_INIT 1
-#define DEFLATE_INIT2 2
-#define DEFLATE_SETDICT 3
-#define DEFLATE_RESET 4
-#define DEFLATE_END 5
-#define DEFLATE_PARAMS 6
-#define DEFLATE 7
-
-#define INFLATE_INIT 8
-#define INFLATE_INIT2 9
-#define INFLATE_SETDICT 10
-#define INFLATE_SYNC 11
-#define INFLATE_RESET 12
-#define INFLATE_END 13
-#define INFLATE 14
-
-#define CRC32_0 15
-#define CRC32_1 16
-#define CRC32_2 17
-
-#define SET_BUFSZ 18
-#define GET_BUFSZ 19
-#define GET_QSIZE 20
-
-#define ADLER32_1 21
-#define ADLER32_2 22
-
-#define CRC32_COMBINE 23
-#define ADLER32_COMBINE 24
-
-#define INFLATE_CHUNK 25
-
-
-#define DEFAULT_BUFSZ 4000
-
-/* This flag is used in the same places, where zlib return codes
- * (Z_OK, Z_STREAM_END, Z_NEED_DICT) are. So, we need to set it to
- * relatively large value to avoid possible value clashes in future.
- * */
-#define INFLATE_HAS_MORE 100
-
-static int zlib_init(void);
-static ErlDrvData zlib_start(ErlDrvPort port, char* buf);
-static void zlib_stop(ErlDrvData e);
-static void zlib_flush(ErlDrvData e);
-static ErlDrvSSizeT zlib_ctl(ErlDrvData drv_data, unsigned int command, char *buf,
- ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen);
-static void zlib_outputv(ErlDrvData drv_data, ErlIOVec *ev);
-
-ErlDrvEntry zlib_driver_entry = {
- zlib_init,
- zlib_start,
- zlib_stop,
- NULL, /* output */
- NULL, /* ready_input */
- NULL, /* ready_output */
- "zlib_drv",
- NULL, /* finish */
- NULL, /* handle */
- zlib_ctl,
- NULL, /* timeout */
- zlib_outputv,
- NULL, /* read_async */
- zlib_flush,
- NULL, /* call */
- NULL, /* event */
- ERL_DRV_EXTENDED_MARKER,
- ERL_DRV_EXTENDED_MAJOR_VERSION,
- ERL_DRV_EXTENDED_MINOR_VERSION,
- ERL_DRV_FLAG_USE_PORT_LOCKING,
- NULL, /* handle2 */
- NULL, /* process_exit */
-};
-
-typedef enum {
- ST_NONE = 0,
- ST_DEFLATE = 1,
- ST_INFLATE = 2
-} ZLibState;
-
-
-typedef struct {
- z_stream s;
- ZLibState state;
- ErlDrvBinary* bin;
- int binsz;
- int binsz_need;
- uLong crc;
- int inflate_eos_seen;
- int want_crc; /* 1 if crc is calculated on clear text */
- ErlDrvPort port; /* the associcated port */
-} ZLibData;
-
-static int zlib_inflate(ZLibData* d, int flush);
-static int zlib_deflate(ZLibData* d, int flush);
-
-#if defined(__WIN32__)
-static int i32(char* buf)
-#else
-static __inline__ int i32(char* buf)
-#endif
-{
- return (int) (
- (((int)((unsigned char*)buf)[0]) << 24) |
- (((int)((unsigned char*)buf)[1]) << 16) |
- (((int)((unsigned char*)buf)[2]) << 8) |
- (((int)((unsigned char*)buf)[3]) << 0));
-}
-
-static char* zlib_reason(int code, int* err)
-{
- switch(code) {
- case Z_OK:
- *err = 0;
- return "ok";
- case Z_STREAM_END:
- *err = 0;
- return "stream_end";
- case Z_ERRNO:
- *err = 1;
- return erl_errno_id(errno);
- case Z_STREAM_ERROR:
- *err = 1;
- return "stream_error";
- case Z_DATA_ERROR:
- *err = 1;
- return "data_error";
- case Z_MEM_ERROR:
- *err = 1;
- return "mem_error";
- case Z_BUF_ERROR:
- *err = 1;
- return "buf_error";
- case Z_VERSION_ERROR:
- *err = 1;
- return "version_error";
- default:
- *err = 1;
- return "unknown_error";
- }
-}
-
-
-static ErlDrvSSizeT zlib_return(int code, char** rbuf, ErlDrvSizeT rlen)
-{
- int msg_code = 0; /* 0=ok, 1=error */
- char* dst = *rbuf;
- char* src;
- ErlDrvSizeT len = 0;
-
- src = zlib_reason(code, &msg_code);
- *dst++ = msg_code;
- rlen--;
- len = 1;
-
- while((rlen > 0) && *src) {
- *dst++ = *src++;
- rlen--;
- len++;
- }
- return len;
-}
-
-static ErlDrvSSizeT zlib_value2(int msg_code, int value,
- char** rbuf, ErlDrvSizeT rlen)
-{
- char* dst = *rbuf;
-
- if (rlen < 5) {
- return -1;
- }
- *dst++ = msg_code;
- *dst++ = (value >> 24) & 0xff;
- *dst++ = (value >> 16) & 0xff;
- *dst++ = (value >> 8) & 0xff;
- *dst++ = value & 0xff;
- return 5;
-}
-
-static ErlDrvSSizeT zlib_value(int value, char** rbuf, ErlDrvSizeT rlen)
-{
- return zlib_value2(2, value, rbuf, rlen);
-}
-
-static int zlib_output_init(ZLibData* d)
-{
- if (d->bin != NULL)
- driver_free_binary(d->bin);
- if ((d->bin = driver_alloc_binary(d->binsz_need)) == NULL)
- return -1;
- d->binsz = d->binsz_need;
- d->s.next_out = (unsigned char*)d->bin->orig_bytes;
- d->s.avail_out = d->binsz;
- return 0;
-}
-
-/*
- * Send compressed or uncompressed data
- * and restart output procesing
- */
-static int zlib_output(ZLibData* d)
-{
- if (d->bin != NULL) {
- int len = d->binsz - d->s.avail_out;
- if (len > 0) {
- if (driver_output_binary(d->port, NULL, 0, d->bin, 0, len) < 0)
- return -1;
- }
- driver_free_binary(d->bin);
- d->bin = NULL;
- d->binsz = 0;
- }
- return zlib_output_init(d);
-}
-
-static int zlib_inflate(ZLibData* d, int flush)
-{
- int res = Z_OK;
-
- if ((d->bin == NULL) && (zlib_output_init(d) < 0)) {
- errno = ENOMEM;
- return Z_ERRNO;
- }
-
- while ((driver_sizeq(d->port) > 0) && (res != Z_STREAM_END)) {
- int vlen;
- SysIOVec* iov = driver_peekq(d->port, &vlen);
- int len;
- int possibly_more_output = 0;
-
- d->s.next_in = iov[0].iov_base;
- d->s.avail_in = iov[0].iov_len;
- while((possibly_more_output || (d->s.avail_in > 0)) && (res != Z_STREAM_END)) {
- res = inflate(&d->s, Z_NO_FLUSH);
- if (res == Z_NEED_DICT) {
- /* Essential to eat the header bytes that zlib has looked at */
- len = iov[0].iov_len - d->s.avail_in;
- driver_deq(d->port, len);
- return res;
- }
- if (res == Z_BUF_ERROR) {
- /* Was possible more output, but actually not */
- res = Z_OK;
- }
- else if (res < 0) {
- return res;
- }
- if (d->s.avail_out != 0) {
- possibly_more_output = 0;
- } else {
- if (d->want_crc)
- d->crc = crc32(d->crc, (unsigned char*)d->bin->orig_bytes,
- d->binsz - d->s.avail_out);
- zlib_output(d);
- possibly_more_output = 1;
- }
- }
- len = iov[0].iov_len - d->s.avail_in;
- driver_deq(d->port, len);
- }
-
- if (d->want_crc) {
- d->crc = crc32(d->crc, (unsigned char*) d->bin->orig_bytes,
- d->binsz - d->s.avail_out);
- }
- zlib_output(d);
- if (res == Z_STREAM_END) {
- d->inflate_eos_seen = 1;
- }
- return res;
-}
-
-static int zlib_inflate_chunk(ZLibData* d)
-{
- int res = Z_OK;
-
- if ((d->bin == NULL) && (zlib_output_init(d) < 0)) {
- errno = ENOMEM;
- return Z_ERRNO;
- }
-
- while ((driver_sizeq(d->port) > 0) && (d->s.avail_out > 0) &&
- (res != Z_STREAM_END)) {
- int vlen;
- SysIOVec* iov = driver_peekq(d->port, &vlen);
- int len;
-
- d->s.next_in = iov[0].iov_base;
- d->s.avail_in = iov[0].iov_len;
- while((d->s.avail_in > 0) && (d->s.avail_out > 0) && (res != Z_STREAM_END)) {
- res = inflate(&d->s, Z_NO_FLUSH);
- if (res == Z_NEED_DICT) {
- /* Essential to eat the header bytes that zlib has looked at */
- len = iov[0].iov_len - d->s.avail_in;
- driver_deq(d->port, len);
- return res;
- }
- if (res == Z_BUF_ERROR) {
- /* Was possible more output, but actually not */
- res = Z_OK;
- }
- else if (res < 0) {
- return res;
- }
- }
- len = iov[0].iov_len - d->s.avail_in;
- driver_deq(d->port, len);
- }
-
- /* We are here because all input was consumed or EOS reached or output
- * buffer is full */
- if (d->want_crc) {
- d->crc = crc32(d->crc, (unsigned char*) d->bin->orig_bytes,
- d->binsz - d->s.avail_out);
- }
- zlib_output(d);
- if ((res == Z_OK) && (d->s.avail_in > 0))
- res = INFLATE_HAS_MORE;
- else if (res == Z_STREAM_END) {
- d->inflate_eos_seen = 1;
- }
- return res;
-}
-
-static int zlib_deflate(ZLibData* d, int flush)
-{
- int res = Z_OK;
-
- if ((d->bin == NULL) && (zlib_output_init(d) < 0)) {
- errno = ENOMEM;
- return Z_ERRNO;
- }
-
- while ((driver_sizeq(d->port) > 0) && (res != Z_STREAM_END)) {
- int vlen;
- SysIOVec* iov = driver_peekq(d->port, &vlen);
- int len;
-
- d->s.next_in = iov[0].iov_base;
- d->s.avail_in = iov[0].iov_len;
-
- while((d->s.avail_in > 0) && (res != Z_STREAM_END)) {
- if ((res = deflate(&d->s, Z_NO_FLUSH)) < 0) {
- return res;
- }
- if (d->s.avail_out == 0) {
- zlib_output(d);
- }
- }
- len = iov[0].iov_len - d->s.avail_in;
- if (d->want_crc) {
- d->crc = crc32(d->crc, iov[0].iov_base, len);
- }
- driver_deq(d->port, len);
- }
-
- if (flush != Z_NO_FLUSH) {
- if ((res = deflate(&d->s, flush)) < 0) {
- return res;
- }
- if (flush == Z_FINISH) {
- while (d->s.avail_out < d->binsz) {
- zlib_output(d);
- if (res == Z_STREAM_END) {
- break;
- }
- if ((res = deflate(&d->s, flush)) < 0) {
- return res;
- }
- }
- } else {
- while (d->s.avail_out == 0) {
- zlib_output(d);
- if ((res = deflate(&d->s, flush)) < 0) {
- return res;
- }
- }
- if (d->s.avail_out < d->binsz) {
- zlib_output(d);
- }
- }
- }
- return res;
-}
-
-
-
-static void* zlib_alloc(void* data, unsigned int items, unsigned int size)
-{
- return (void*) driver_alloc(items*size);
-}
-
-static void zlib_free(void* data, void* addr)
-{
- driver_free(addr);
-}
-
-static int zlib_init()
-{
- return 0;
-}
-
-static ErlDrvData zlib_start(ErlDrvPort port, char* buf)
-{
- ZLibData* d;
-
- if ((d = (ZLibData*) driver_alloc(sizeof(ZLibData))) == NULL)
- return ERL_DRV_ERROR_GENERAL;
-
- memset(&d->s, 0, sizeof(z_stream));
-
- d->s.zalloc = zlib_alloc;
- d->s.zfree = zlib_free;
- d->s.opaque = d;
- d->s.data_type = Z_BINARY;
-
- d->port = port;
- d->state = ST_NONE;
- d->bin = NULL;
- d->binsz = 0;
- d->binsz_need = DEFAULT_BUFSZ;
- d->crc = crc32(0L, Z_NULL, 0);
- d->inflate_eos_seen = 0;
- d->want_crc = 0;
- return (ErlDrvData)d;
-}
-
-
-static void zlib_stop(ErlDrvData e)
-{
- ZLibData* d = (ZLibData*)e;
-
- if (d->state == ST_DEFLATE)
- deflateEnd(&d->s);
- else if (d->state == ST_INFLATE)
- inflateEnd(&d->s);
-
- if (d->bin != NULL)
- driver_free_binary(d->bin);
-
- driver_free(d);
-}
-
-static void zlib_flush(ErlDrvData drv_data)
-{
- ZLibData* d = (ZLibData*) drv_data;
-
- driver_deq(d->port, driver_sizeq(d->port));
-}
-
-static ErlDrvSSizeT zlib_ctl(ErlDrvData drv_data, unsigned int command, char *buf,
- ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen)
-{
- ZLibData* d = (ZLibData*)drv_data;
- int res;
-
- switch(command) {
- case DEFLATE_INIT:
- if (len != 4) goto badarg;
- if (d->state != ST_NONE) goto badarg;
- res = deflateInit(&d->s, i32(buf));
- if (res == Z_OK) {
- d->state = ST_DEFLATE;
- d->want_crc = 0;
- d->crc = crc32(0L, Z_NULL, 0);
- }
- return zlib_return(res, rbuf, rlen);
-
- case DEFLATE_INIT2: {
- int wbits;
-
- if (len != 20) goto badarg;
- if (d->state != ST_NONE) goto badarg;
- wbits = i32(buf+8);
- res = deflateInit2(&d->s, i32(buf), i32(buf+4), wbits,
- i32(buf+12), i32(buf+16));
- if (res == Z_OK) {
- d->state = ST_DEFLATE;
- d->want_crc = (wbits < 0);
- d->crc = crc32(0L, Z_NULL, 0);
- }
- return zlib_return(res, rbuf, rlen);
- }
-
- case DEFLATE_SETDICT:
- if (d->state != ST_DEFLATE) goto badarg;
- res = deflateSetDictionary(&d->s, (unsigned char*)buf, len);
- if (res == Z_OK) {
- return zlib_value(d->s.adler, rbuf, rlen);
- } else {
- return zlib_return(res, rbuf, rlen);
- }
-
- case DEFLATE_RESET:
- if (len != 0) goto badarg;
- if (d->state != ST_DEFLATE) goto badarg;
- driver_deq(d->port, driver_sizeq(d->port));
- res = deflateReset(&d->s);
- return zlib_return(res, rbuf, rlen);
-
- case DEFLATE_END:
- if (len != 0) goto badarg;
- if (d->state != ST_DEFLATE) goto badarg;
- driver_deq(d->port, driver_sizeq(d->port));
- res = deflateEnd(&d->s);
- d->state = ST_NONE;
- return zlib_return(res, rbuf, rlen);
-
- case DEFLATE_PARAMS:
- if (len != 8) goto badarg;
- if (d->state != ST_DEFLATE) goto badarg;
- res = deflateParams(&d->s, i32(buf), i32(buf+4));
- return zlib_return(res, rbuf, rlen);
-
- case DEFLATE:
- if (d->state != ST_DEFLATE) goto badarg;
- if (len != 4) goto badarg;
- res = zlib_deflate(d, i32(buf));
- return zlib_return(res, rbuf, rlen);
-
- case INFLATE_INIT:
- if (len != 0) goto badarg;
- if (d->state != ST_NONE) goto badarg;
- res = inflateInit(&d->s);
- if (res == Z_OK) {
- d->state = ST_INFLATE;
- d->inflate_eos_seen = 0;
- d->want_crc = 0;
- d->crc = crc32(0L, Z_NULL, 0);
- }
- return zlib_return(res, rbuf, rlen);
-
- case INFLATE_INIT2: {
- int wbits;
-
- if (len != 4) goto badarg;
- if (d->state != ST_NONE) goto badarg;
- wbits = i32(buf);
- res = inflateInit2(&d->s, wbits);
- if (res == Z_OK) {
- d->state = ST_INFLATE;
- d->inflate_eos_seen = 0;
- d->want_crc = (wbits < 0);
- d->crc = crc32(0L, Z_NULL, 0);
- }
- return zlib_return(res, rbuf, rlen);
- }
-
- case INFLATE_SETDICT:
- if (d->state != ST_INFLATE) goto badarg;
- res = inflateSetDictionary(&d->s, (unsigned char*)buf, len);
- return zlib_return(res, rbuf, rlen);
-
- case INFLATE_SYNC:
- if (d->state != ST_INFLATE) goto badarg;
- if (len != 0) goto badarg;
- if (driver_sizeq(d->port) == 0) {
- res = Z_BUF_ERROR;
- } else {
- int vlen;
- SysIOVec* iov = driver_peekq(d->port, &vlen);
-
- d->s.next_in = iov[0].iov_base;
- d->s.avail_in = iov[0].iov_len;
- res = inflateSync(&d->s);
- }
- return zlib_return(res, rbuf, rlen);
-
- case INFLATE_RESET:
- if (d->state != ST_INFLATE) goto badarg;
- if (len != 0) goto badarg;
- driver_deq(d->port, driver_sizeq(d->port));
- res = inflateReset(&d->s);
- d->inflate_eos_seen = 0;
- return zlib_return(res, rbuf, rlen);
-
- case INFLATE_END:
- if (d->state != ST_INFLATE) goto badarg;
- if (len != 0) goto badarg;
- driver_deq(d->port, driver_sizeq(d->port));
- res = inflateEnd(&d->s);
- if (res == Z_OK && d->inflate_eos_seen == 0) {
- res = Z_DATA_ERROR;
- }
- d->state = ST_NONE;
- return zlib_return(res, rbuf, rlen);
-
- case INFLATE:
- if (d->state != ST_INFLATE) goto badarg;
- if (len != 4) goto badarg;
- res = zlib_inflate(d, i32(buf));
- if (res == Z_NEED_DICT) {
- return zlib_value2(3, d->s.adler, rbuf, rlen);
- } else {
- return zlib_return(res, rbuf, rlen);
- }
-
- case INFLATE_CHUNK:
- if (d->state != ST_INFLATE) goto badarg;
- if (len != 0) goto badarg;
- res = zlib_inflate_chunk(d);
- if (res == INFLATE_HAS_MORE) {
- return zlib_value2(4, 0, rbuf, rlen);
- } else if (res == Z_NEED_DICT) {
- return zlib_value2(3, d->s.adler, rbuf, rlen);
- } else {
- return zlib_return(res, rbuf, rlen);
- }
-
- case GET_QSIZE:
- return zlib_value(driver_sizeq(d->port), rbuf, rlen);
-
- case GET_BUFSZ:
- return zlib_value(d->binsz_need, rbuf, rlen);
-
- case SET_BUFSZ: {
- int need;
- if (len != 4) goto badarg;
- need = i32(buf);
- if ((need < 16) || (need > 0x00ffffff))
- goto badarg;
- if (d->binsz_need != need) {
- d->binsz_need = need;
- if (d->bin != NULL) {
- if (d->s.avail_out == d->binsz) {
- driver_free_binary(d->bin);
- d->bin = NULL;
- d->binsz = 0;
- }
- else
- zlib_output(d);
- }
- }
- return zlib_return(Z_OK, rbuf, rlen);
- }
-
- case CRC32_0:
- return zlib_value(d->crc, rbuf, rlen);
-
- case CRC32_1: {
- uLong crc = crc32(0L, Z_NULL, 0);
- crc = crc32(crc, (unsigned char*) buf, len);
- return zlib_value(crc, rbuf, rlen);
- }
-
- case CRC32_2: {
- uLong crc;
- if (len < 4) goto badarg;
- crc = (unsigned int) i32(buf);
- crc = crc32(crc, (unsigned char*) buf+4, len-4);
- return zlib_value(crc, rbuf, rlen);
- }
-
- case ADLER32_1: {
- uLong adler = adler32(0L, Z_NULL, 0);
- adler = adler32(adler, (unsigned char*) buf, len);
- return zlib_value(adler, rbuf, rlen);
- }
-
- case ADLER32_2: {
- uLong adler;
- if (len < 4) goto badarg;
- adler = (unsigned int) i32(buf);
- adler = adler32(adler, (unsigned char*) buf+4, len-4);
- return zlib_value(adler, rbuf, rlen);
- }
-
- case CRC32_COMBINE: {
- uLong crc, crc1, crc2, len2;
- if (len != 12) goto badarg;
- crc1 = (unsigned int) i32(buf);
- crc2 = (unsigned int) i32(buf+4);
- len2 = (unsigned int) i32(buf+8);
- crc = crc32_combine(crc1, crc2, len2);
- return zlib_value(crc, rbuf, rlen);
- }
-
- case ADLER32_COMBINE: {
- uLong adler, adler1, adler2, len2;
- if (len != 12) goto badarg;
- adler1 = (unsigned int) i32(buf);
- adler2 = (unsigned int) i32(buf+4);
- len2 = (unsigned int) i32(buf+8);
- adler = adler32_combine(adler1, adler2, len2);
- return zlib_value(adler, rbuf, rlen);
- }
- }
-
- badarg:
- errno = EINVAL;
- return zlib_return(Z_ERRNO, rbuf, rlen);
-}
-
-
-
-static void zlib_outputv(ErlDrvData drv_data, ErlIOVec *ev)
-{
- ZLibData* d = (ZLibData*) drv_data;
-
- driver_enqv(d->port, ev, 0);
-}