aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/drivers')
-rw-r--r--erts/emulator/drivers/common/efile_drv.c513
-rw-r--r--erts/emulator/drivers/common/erl_efile.h49
-rw-r--r--erts/emulator/drivers/common/gzio.c2
-rw-r--r--erts/emulator/drivers/common/inet_drv.c1198
-rw-r--r--erts/emulator/drivers/common/ram_file_drv.c82
-rw-r--r--erts/emulator/drivers/common/zlib_drv.c19
-rw-r--r--erts/emulator/drivers/unix/ttsl_drv.c24
-rw-r--r--erts/emulator/drivers/unix/unix_efile.c285
-rw-r--r--erts/emulator/drivers/win32/registry_drv.c21
-rw-r--r--erts/emulator/drivers/win32/ttsl_drv.c38
-rw-r--r--erts/emulator/drivers/win32/win_con.c101
-rw-r--r--[-rwxr-xr-x]erts/emulator/drivers/win32/win_efile.c128
12 files changed, 1695 insertions, 765 deletions
diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c
index f0ff3f54c5..36ed108b76 100644
--- a/erts/emulator/drivers/common/efile_drv.c
+++ b/erts/emulator/drivers/common/efile_drv.c
@@ -55,6 +55,7 @@
#define FILE_READ_LINE 29
#define FILE_FDATASYNC 30
#define FILE_FADVISE 31
+#define FILE_SENDFILE 32
/* Return codes */
@@ -69,6 +70,7 @@
#define FILE_RESP_EOF 8
#define FILE_RESP_FNAME 9
#define FILE_RESP_ALL_DATA 10
+#define FILE_RESP_LFNAME 11
/* Options */
@@ -97,7 +99,14 @@
# include "config.h"
#endif
#include <stdlib.h>
+
+// Need (NON)BLOCKING macros for sendfile
+#ifndef WANT_NONBLOCKING
+#define WANT_NONBLOCKING
+#endif
+
#include "sys.h"
+
#include "erl_driver.h"
#include "erl_efile.h"
#include "erl_threads.h"
@@ -139,6 +148,22 @@ static ErlDrvSysInfo sys_info;
#define MUTEX_UNLOCK(m)
#endif
+
+/**
+ * On DARWIN sendfile can deadlock with close if called in
+ * different threads. So until Apple fixes so that sendfile
+ * is not buggy we disable usage of the async pool for
+ * DARWIN. The testcase t_sendfile_crashduring reproduces
+ * this error when using +A 10.
+ */
+#if !defined(DARWIN)
+#define USE_THRDS_FOR_SENDFILE (sys_info.async_threads > 0)
+#else
+#define USE_THRDS_FOR_SENDFILE 0
+#endif /* !DARWIN */
+
+
+
#if 0
/* Experimental, for forcing all file operations to use the same thread. */
static unsigned file_fixed_key = 1;
@@ -184,6 +209,7 @@ static ErlDrvSysInfo sys_info;
# define RESBUFSIZE BUFSIZ
#endif
+#define READDIR_CHUNKS (5)
@@ -215,17 +241,25 @@ typedef unsigned char uchar;
static ErlDrvData file_start(ErlDrvPort port, char* command);
static int file_init(void);
static void file_stop(ErlDrvData);
-static void file_output(ErlDrvData, char* buf, int len);
-static int file_control(ErlDrvData, unsigned int command,
- char* buf, int len, char **rbuf, int rlen);
+static void file_output(ErlDrvData, char* buf, ErlDrvSizeT len);
+static ErlDrvSSizeT file_control(ErlDrvData, unsigned int command,
+ char* buf, ErlDrvSizeT len,
+ char **rbuf, ErlDrvSizeT rlen);
static void file_timeout(ErlDrvData);
static void file_outputv(ErlDrvData, ErlIOVec*);
static void file_async_ready(ErlDrvData, ErlDrvThreadData);
static void file_flush(ErlDrvData);
+#ifdef HAVE_SENDFILE
+static void file_ready_output(ErlDrvData data, ErlDrvEvent event);
+static void file_stop_select(ErlDrvEvent event, void* _);
+#endif /* HAVE_SENDFILE */
enum e_timer {timer_idle, timer_again, timer_write};
+#ifdef HAVE_SENDFILE
+enum e_sendfile {sending, not_sending};
+#endif /* HAVE_SENDFILE */
struct t_data;
@@ -240,6 +274,9 @@ typedef struct {
struct t_data *cq_head; /* Queue of incoming commands */
struct t_data *cq_tail; /* -""- */
enum e_timer timer_state;
+#ifdef HAVE_SENDFILE
+ enum e_sendfile sendfile_state;
+#endif /* HAVE_SENDFILE */
size_t read_bufsize;
ErlDrvBinary *read_binp;
size_t read_offset;
@@ -262,7 +299,11 @@ struct erl_drv_entry efile_driver_entry = {
file_stop,
file_output,
NULL,
+#ifdef HAVE_SENDFILE
+ file_ready_output,
+#else
NULL,
+#endif /* HAVE_SENDFILE */
"efile",
NULL,
NULL,
@@ -277,7 +318,13 @@ struct erl_drv_entry efile_driver_entry = {
ERL_DRV_EXTENDED_MAJOR_VERSION,
ERL_DRV_EXTENDED_MINOR_VERSION,
ERL_DRV_FLAG_USE_PORT_LOCKING,
+ NULL,
+ NULL,
+#ifdef HAVE_SENDFILE
+ file_stop_select
+#else
NULL
+#endif /* HAVE_SENDFILE */
};
@@ -317,15 +364,16 @@ struct t_preadv {
Sint64 offsets[1];
};
-#define READDIR_BUFSIZE (8*1024)
-#if READDIR_BUFSIZE < (FILENAME_CHARSIZE*2*(MAXPATHLEN+1))
+#define READDIR_BUFSIZE (8*1024)*READDIR_CHUNKS
+#if READDIR_BUFSIZE < (1 + (2 + MAXPATHLEN)*FILENAME_CHARSIZE*READDIR_CHUNKS)
# undef READDIR_BUFSIZE
-# define READDIR_BUFSIZE (FILENAME_CHARSIZE*2*(MAXPATHLEN+1))
+# define READDIR_BUFSIZE (1 + (2 + MAXPATHLEN)*FILENAME_CHARSIZE*READDIR_CHUNKS)
#endif
struct t_readdir_buf {
- struct t_readdir_buf *next;
- char buf[READDIR_BUFSIZE];
+ struct t_readdir_buf *next;
+ size_t n;
+ char buf[READDIR_BUFSIZE];
};
struct t_data
@@ -395,6 +443,14 @@ struct t_data
Sint64 length;
int advise;
} fadvise;
+#ifdef HAVE_SENDFILE
+ struct {
+ int out_fd;
+ off_t offset;
+ Uint64 nbytes;
+ Uint64 written;
+ } sendfile;
+#endif /* HAVE_SENDFILE */
} c;
char b[1];
};
@@ -482,7 +538,6 @@ static void *ef_safe_realloc(void *op, Uint s)
: 0)
-
#if 0
static void ev_clear(ErlIOVec *ev) {
@@ -610,7 +665,6 @@ static struct t_data *cq_deq(file_descriptor *desc) {
}
-
/*********************************************************************
* Driver entry point -> init
*/
@@ -625,6 +679,7 @@ file_init(void)
? atoi(buf)
: 0);
driver_system_info(&sys_info, sizeof(ErlDrvSysInfo));
+
return 0;
}
@@ -652,6 +707,9 @@ file_start(ErlDrvPort port, char* command)
desc->cq_head = NULL;
desc->cq_tail = NULL;
desc->timer_state = timer_idle;
+#ifdef HAVE_SENDFILE
+ desc->sendfile_state = not_sending;
+#endif
desc->read_bufsize = 0;
desc->read_binp = NULL;
desc->read_offset = 0;
@@ -694,6 +752,15 @@ file_stop(ErlDrvData e)
TRACE_C('p');
+#ifdef HAVE_SENDFILE
+ if (desc->sendfile_state == sending && !USE_THRDS_FOR_SENDFILE) {
+ driver_select(desc->port,(ErlDrvEvent)(long)desc->d->c.sendfile.out_fd,
+ ERL_DRV_WRITE|ERL_DRV_USE,0);
+ } else if (desc->sendfile_state == sending) {
+ SET_NONBLOCKING(desc->d->c.sendfile.out_fd);
+ }
+#endif /* HAVE_SENDFILE */
+
if (desc->fd != FILE_FD_INVALID) {
do_close(desc->flags, desc->fd);
desc->fd = FILE_FD_INVALID;
@@ -759,7 +826,16 @@ static void reply_Uint_posix_error(file_descriptor *desc, Uint num,
driver_output2(desc->port, response, t-response, NULL, 0);
}
+static void reply_string_error(file_descriptor *desc, char* str) {
+ char response[256]; /* Response buffer. */
+ char* s;
+ char* t;
+ response[0] = FILE_RESP_ERROR;
+ for (s = str, t = response+1; *s; s++, t++)
+ *t = tolower(*s);
+ driver_output2(desc->port, response, t-response, NULL, 0);
+}
static int reply_error(file_descriptor *desc,
Efile_error *errInfo) /* The error codes. */
@@ -890,8 +966,6 @@ static int reply_eof(file_descriptor *desc) {
driver_output2(desc->port, &c, 1, NULL, 0);
return 0;
}
-
-
static void invoke_name(void *data, int (*f)(Efile_error *, char *))
{
@@ -1010,7 +1084,7 @@ static void invoke_read_line(void *data)
d->c.read_line.read_offset - d->c.read_line.read_size;
if (size == 0) {
/* Need more place */
- size_t need = (d->c.read_line.read_size >= DEFAULT_LINEBUF_SIZE) ?
+ ErlDrvSizeT need = (d->c.read_line.read_size >= DEFAULT_LINEBUF_SIZE) ?
d->c.read_line.read_size + DEFAULT_LINEBUF_SIZE : DEFAULT_LINEBUF_SIZE;
ErlDrvBinary *newbin = driver_alloc_binary(need);
if (newbin == NULL) {
@@ -1311,7 +1385,11 @@ static void invoke_writev(void *data) {
size = d->c.writev.size;
}
- /* Copy the io vector to avoid locking the port que while writing */
+ /* Copy the io vector to avoid locking the port que while writing,
+ * also, both we and efile_writev might/will change the SysIOVec
+ * when segmenting or due to partial write and we do not want to
+ * tamper with the actual queue that we get from driver_peekq
+ */
MUTEX_LOCK(d->c.writev.q_mtx); /* Lock before accessing the port queue */
iov0 = driver_peekq(d->c.writev.port, &iovlen);
@@ -1350,7 +1428,7 @@ static void invoke_writev(void *data) {
} else {
d->result_ok = efile_writev(&d->errInfo,
d->flags, (int) d->fd,
- iov, iovcnt, size);
+ iov, iovcnt);
}
} else if (iovlen == 0) {
d->result_ok = 1;
@@ -1598,54 +1676,46 @@ static void invoke_lseek(void *data)
static void invoke_readdir(void *data)
{
struct t_data *d = (struct t_data *) data;
- int s;
char *p = NULL;
- int buf_sz = 0;
- size_t tmp_bs;
+ size_t file_bs;
+ size_t n = 0, total = 0;
+ struct t_readdir_buf *b = NULL;
+ int res = 0;
d->again = 0;
d->errInfo.posix_errno = 0;
- while (1) {
- char *str;
- if (buf_sz < (4 /* sz */ + 1 /* cmd */ +
- FILENAME_CHARSIZE*(MAXPATHLEN + 1))) {
- struct t_readdir_buf *b;
- if (p) {
- put_int32(0, p); /* EOB */
- }
- b = EF_SAFE_ALLOC(sizeof(struct t_readdir_buf));
- b->next = NULL;
- if (d->c.read_dir.last_buf)
- d->c.read_dir.last_buf->next = b;
- else
- d->c.read_dir.first_buf = b;
- d->c.read_dir.last_buf = b;
- p = &b->buf[0];
- buf_sz = READDIR_BUFSIZE - 4/* EOB */;
- }
-
- p[4] = FILE_RESP_FNAME;
- buf_sz -= 4 + 1;
- str = p + 4 + 1;
- ASSERT(buf_sz >= MAXPATHLEN + 1);
- tmp_bs = buf_sz;
- s = efile_readdir(&d->errInfo, d->b, &d->dir_handle, str, &tmp_bs);
-
- if (s) {
- put_int32(tmp_bs + 1 /* 1 byte for opcode */, p);
- p += 4 + tmp_bs + 1;
- ASSERT(p == (str + tmp_bs));
- buf_sz -= tmp_bs;
- }
- else {
- put_int32(1, p);
- p += 4 + 1;
- put_int32(0, p); /* EOB */
- d->result_ok = (d->errInfo.posix_errno == 0);
- break;
+ do {
+ total = READDIR_BUFSIZE;
+ n = 1;
+ b = EF_SAFE_ALLOC(sizeof(struct t_readdir_buf));
+ b->next = NULL;
+
+ if (d->c.read_dir.last_buf) {
+ d->c.read_dir.last_buf->next = b;
+ } else {
+ d->c.read_dir.first_buf = b;
}
- }
+ d->c.read_dir.last_buf = b;
+
+ p = &b->buf[0];
+ p[0] = FILE_RESP_LFNAME;
+ file_bs = READDIR_BUFSIZE - n;
+
+ do {
+ res = efile_readdir(&d->errInfo, d->b, &d->dir_handle, p + n + 2, &file_bs);
+
+ if (res) {
+ put_int16((Uint16)file_bs, p + n);
+ n += 2 + file_bs;
+ file_bs = READDIR_BUFSIZE - n;
+ }
+ } while( res && ((total - n - 2) >= MAXPATHLEN*FILENAME_CHARSIZE));
+
+ b->n = n;
+ } while(res);
+
+ d->result_ok = (d->errInfo.posix_errno == 0);
}
static void invoke_open(void *data)
@@ -1699,6 +1769,66 @@ static void invoke_fadvise(void *data)
d->result_ok = efile_fadvise(&d->errInfo, fd, offset, length, advise);
}
+#ifdef HAVE_SENDFILE
+static void invoke_sendfile(void *data)
+{
+ struct t_data *d = (struct t_data *)data;
+ int fd = d->fd;
+ int out_fd = (int)d->c.sendfile.out_fd;
+ Uint64 nbytes = d->c.sendfile.nbytes;
+ int result = 0;
+ d->again = 0;
+
+ result = efile_sendfile(&d->errInfo, fd, out_fd, &d->c.sendfile.offset, &nbytes, NULL);
+
+ d->c.sendfile.written += nbytes;
+
+ if (result == 1) {
+ if (USE_THRDS_FOR_SENDFILE) {
+ d->result_ok = 0;
+ } else if (d->c.sendfile.nbytes == 0 && nbytes != 0) {
+ d->result_ok = 1;
+ } else if ((d->c.sendfile.nbytes - nbytes) != 0) {
+ d->result_ok = 1;
+ d->c.sendfile.nbytes -= nbytes;
+ } else {
+ d->result_ok = 0;
+ }
+ } else if (result == 0 && (d->errInfo.posix_errno == EAGAIN
+ || d->errInfo.posix_errno == EINTR)) {
+ d->result_ok = 1;
+ } else {
+ d->result_ok = -1;
+ }
+}
+
+static void free_sendfile(void *data) {
+ EF_FREE(data);
+}
+
+static void file_ready_output(ErlDrvData data, ErlDrvEvent event)
+{
+ file_descriptor* fd = (file_descriptor*) data;
+
+ switch (fd->d->command) {
+ case FILE_SENDFILE:
+ driver_select(fd->port, event,
+ (int)ERL_DRV_WRITE,(int) 0);
+ invoke_sendfile((void *)fd->d);
+ file_async_ready(data, (ErlDrvThreadData)fd->d);
+ break;
+ default:
+ break;
+ }
+}
+
+static void file_stop_select(ErlDrvEvent event, void* _)
+{
+
+}
+#endif /* HAVE_SENDFILE */
+
+
static void free_readdir(void *data)
{
struct t_data *d = (struct t_data *) data;
@@ -1760,6 +1890,10 @@ static void cq_execute(file_descriptor *desc) {
register void *void_ptr; /* Soft cast variable */
if (desc->timer_state == timer_again)
return;
+#ifdef HAVE_SENDFILE
+ if (desc->sendfile_state == sending)
+ return;
+#endif
if (! (d = cq_deq(desc)))
return;
TRACE_F(("x%i", (int) d->command));
@@ -2026,24 +2160,25 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data)
if (d->result_ok) {
resbuf[0] = FILE_RESP_INFO;
- put_int32(d->info.size_high, &resbuf[1 + (0 * 4)]);
- put_int32(d->info.size_low, &resbuf[1 + (1 * 4)]);
- put_int32(d->info.type, &resbuf[1 + (2 * 4)]);
-
- PUT_TIME(d->info.accessTime, resbuf + 1 + 3*4);
- PUT_TIME(d->info.modifyTime, resbuf + 1 + 9*4);
- PUT_TIME(d->info.cTime, resbuf + 1 + 15*4);
-
- put_int32(d->info.mode, &resbuf[1 + (21 * 4)]);
- put_int32(d->info.links, &resbuf[1 + (22 * 4)]);
- put_int32(d->info.major_device, &resbuf[1 + (23 * 4)]);
- put_int32(d->info.minor_device, &resbuf[1 + (24 * 4)]);
- put_int32(d->info.inode, &resbuf[1 + (25 * 4)]);
- put_int32(d->info.uid, &resbuf[1 + (26 * 4)]);
- put_int32(d->info.gid, &resbuf[1 + (27 * 4)]);
- put_int32(d->info.access, &resbuf[1 + (28 * 4)]);
-
-#define RESULT_SIZE (1 + (29 * 4))
+ put_int32(d->info.size_high, &resbuf[1 + ( 0 * 4)]);
+ put_int32(d->info.size_low, &resbuf[1 + ( 1 * 4)]);
+ put_int32(d->info.type, &resbuf[1 + ( 2 * 4)]);
+
+ /* Note 64 bit indexing in resbuf here */
+ put_int64(d->info.accessTime, &resbuf[1 + ( 3 * 4)]);
+ put_int64(d->info.modifyTime, &resbuf[1 + ( 5 * 4)]);
+ put_int64(d->info.cTime, &resbuf[1 + ( 7 * 4)]);
+
+ put_int32(d->info.mode, &resbuf[1 + ( 9 * 4)]);
+ put_int32(d->info.links, &resbuf[1 + (10 * 4)]);
+ put_int32(d->info.major_device, &resbuf[1 + (11 * 4)]);
+ put_int32(d->info.minor_device, &resbuf[1 + (12 * 4)]);
+ put_int32(d->info.inode, &resbuf[1 + (13 * 4)]);
+ put_int32(d->info.uid, &resbuf[1 + (14 * 4)]);
+ put_int32(d->info.gid, &resbuf[1 + (15 * 4)]);
+ put_int32(d->info.access, &resbuf[1 + (16 * 4)]);
+
+#define RESULT_SIZE (1 + (17 * 4))
TRACE_C('R');
driver_output2(desc->port, resbuf, RESULT_SIZE, NULL, 0);
#undef RESULT_SIZE
@@ -2053,30 +2188,24 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data)
free_data(data);
break;
case FILE_READDIR:
- if (!d->result_ok)
+ if (!d->result_ok) {
reply_error(desc, &d->errInfo);
- else {
+ } else {
struct t_readdir_buf *b1 = d->c.read_dir.first_buf;
+ char op = FILE_RESP_LFNAME;
+
TRACE_C('R');
ASSERT(b1);
+
while (b1) {
struct t_readdir_buf *b2 = b1;
char *p = &b1->buf[0];
- int sz = get_int32(p);
- while (sz) { /* 0 == EOB */
- p += 4;
- if (sz - 1 > 0) {
- driver_output2(desc->port, p, 1, p+1, sz-1);
- } else {
- driver_output2(desc->port, p, 1, NULL, 0);
- }
- p += sz;
- sz = get_int32(p);
- }
+ driver_output2(desc->port, p, 1, p + 1, b1->n - 1);
b1 = b1->next;
EF_FREE(b2);
}
-
+ driver_output2(desc->port, &op, 1, NULL, 0);
+
d->c.read_dir.first_buf = NULL;
d->c.read_dir.last_buf = NULL;
}
@@ -2116,6 +2245,42 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data)
}
free_preadv(data);
break;
+#ifdef HAVE_SENDFILE
+ case FILE_SENDFILE:
+ if (d->result_ok == -1) {
+ desc->sendfile_state = not_sending;
+ if (d->errInfo.posix_errno == ECONNRESET ||
+ d->errInfo.posix_errno == ENOTCONN ||
+ d->errInfo.posix_errno == EPIPE)
+ reply_string_error(desc,"closed");
+ else
+ reply_error(desc, &d->errInfo);
+ if (USE_THRDS_FOR_SENDFILE) {
+ SET_NONBLOCKING(d->c.sendfile.out_fd);
+ free_sendfile(data);
+ } else {
+ driver_select(desc->port, (ErlDrvEvent)(long)d->c.sendfile.out_fd,
+ ERL_DRV_USE, 0);
+ free_sendfile(data);
+ }
+ } else if (d->result_ok == 0) {
+ desc->sendfile_state = not_sending;
+ reply_Sint64(desc, d->c.sendfile.written);
+ if (USE_THRDS_FOR_SENDFILE) {
+ SET_NONBLOCKING(d->c.sendfile.out_fd);
+ free_sendfile(data);
+ } else {
+ driver_select(desc->port, (ErlDrvEvent)(long)d->c.sendfile.out_fd, ERL_DRV_USE, 0);
+ free_sendfile(data);
+ }
+ } else if (d->result_ok == 1) { // If we are using select to send the rest of the data
+ desc->sendfile_state = sending;
+ desc->d = d;
+ driver_select(desc->port, (ErlDrvEvent)(long)d->c.sendfile.out_fd,
+ ERL_DRV_USE|ERL_DRV_WRITE, 1);
+ }
+ break;
+#endif
default:
abort();
}
@@ -2126,11 +2291,12 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data)
cq_execute(desc);
}
+
/*********************************************************************
* Driver entry point -> output
*/
static void
-file_output(ErlDrvData e, char* buf, int count)
+file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
{
file_descriptor* desc = (file_descriptor*)e;
Efile_error errInfo; /* The error codes for the last operation. */
@@ -2246,19 +2412,46 @@ file_output(ErlDrvData e, char* buf, int count)
#endif
{
size_t resbufsize;
- char resbuf[RESBUFSIZE+1];
+ size_t n = 0, total = 0;
+ int res = 0;
+ char resbuf[READDIR_BUFSIZE];
+
EFILE_DIR_HANDLE dir_handle; /* Handle to open directory. */
+ total = READDIR_BUFSIZE;
errInfo.posix_errno = 0;
- dir_handle = NULL;
- resbuf[0] = FILE_RESP_FNAME;
- resbufsize = RESBUFSIZE;
-
- while (efile_readdir(&errInfo, name, &dir_handle,
- resbuf+1, &resbufsize)) {
- driver_output2(desc->port, resbuf, 1, resbuf+1, resbufsize);
- resbufsize = RESBUFSIZE;
- }
+ dir_handle = NULL;
+ resbuf[0] = FILE_RESP_LFNAME;
+
+ /* Fill the buffer with multiple directory listings before sending it to the
+ * receiving process. READDIR_CHUNKS is minimum number of files sent to the
+ * receiver.
+ * Format for each driver_output2:
+ * ------------------------------------
+ * | Type | Len | Filename | ...
+ * | 1 byte | 2 bytes | Len bytes | ...
+ * ------------------------------------
+ */
+
+ do {
+ n = 1;
+ resbufsize = READDIR_BUFSIZE - n;
+
+ do {
+ res = efile_readdir(&errInfo, name, &dir_handle, resbuf + n + 2, &resbufsize);
+
+ if (res) {
+ put_int16((Uint16)resbufsize, resbuf + n);
+ n += 2 + resbufsize;
+ resbufsize = READDIR_BUFSIZE - n;
+ }
+ } while( res && ((total - n - 2) >= MAXPATHLEN*FILENAME_CHARSIZE));
+
+ if (n > 1) {
+ driver_output2(desc->port, resbuf, 1, resbuf + 1, n - 1);
+ }
+ } while(res);
+
if (errInfo.posix_errno != 0) {
reply_error(desc, &errInfo);
return;
@@ -2338,15 +2531,16 @@ file_output(ErlDrvData e, char* buf, int count)
case FILE_WRITE_INFO:
{
d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1
- + FILENAME_BYTELEN(buf+21*4) + FILENAME_CHARSIZE);
+ + FILENAME_BYTELEN(buf + 9*4) + FILENAME_CHARSIZE);
- d->info.mode = get_int32(buf + 0 * 4);
- d->info.uid = get_int32(buf + 1 * 4);
- d->info.gid = get_int32(buf + 2 * 4);
- GET_TIME(d->info.accessTime, buf + 3 * 4);
- GET_TIME(d->info.modifyTime, buf + 9 * 4);
- GET_TIME(d->info.cTime, buf + 15 * 4);
- FILENAME_COPY(d->b, buf+21*4);
+ d->info.mode = get_int32(buf + 0 * 4);
+ d->info.uid = get_int32(buf + 1 * 4);
+ d->info.gid = get_int32(buf + 2 * 4);
+ d->info.accessTime = (time_t)((Sint64)get_int64(buf + 3 * 4));
+ d->info.modifyTime = (time_t)((Sint64)get_int64(buf + 5 * 4));
+ d->info.cTime = (time_t)((Sint64)get_int64(buf + 7 * 4));
+
+ FILENAME_COPY(d->b, buf + 9*4);
d->command = command;
d->invoke = invoke_write_info;
d->free = free_data;
@@ -2455,16 +2649,22 @@ file_output(ErlDrvData e, char* buf, int count)
static void
file_flush(ErlDrvData e) {
file_descriptor *desc = (file_descriptor *)e;
+#ifdef DEBUG
int r;
+#endif
TRACE_C('f');
- r = flush_write(desc, NULL);
+#ifdef DEBUG
+ r =
+#endif
+ flush_write(desc, NULL);
/* Only possible reason for bad return value is ENOMEM, and
* there is nobody to tell...
*/
+#ifdef DEBUG
ASSERT(r == 0);
- r = 0; /* Avoiding warning */
+#endif
cq_execute(desc);
}
@@ -2473,16 +2673,23 @@ file_flush(ErlDrvData e) {
/*********************************************************************
* Driver entry point -> control
*/
-static int
+static ErlDrvSSizeT
file_control(ErlDrvData e, unsigned int command,
- char* buf, int len, char **rbuf, int rlen) {
+ char* buf, ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen) {
+ /*
+ * warning: variable ‘desc’ set but not used
+ * [-Wunused-but-set-variable]
+ * ... no kidding ...
+ *
+ *
file_descriptor *desc = (file_descriptor *)e;
switch (command) {
default:
return 0;
- } /* switch (command) */
+ }
ASSERT(0);
- desc = NULL; /* XXX Avoid warning while empty switch */
+ desc = NULL;
+ */
return 0;
}
@@ -2507,12 +2714,14 @@ file_timeout(ErlDrvData e) {
driver_async(desc->port, KEY(desc), desc->invoke, desc->d, desc->free);
break;
case timer_write: {
- int r = flush_write(desc, NULL);
+#ifdef DEBUG
+ int r =
+#endif
+ flush_write(desc, NULL);
/* Only possible reason for bad return value is ENOMEM, and
* there is nobody to tell...
*/
ASSERT(r == 0);
- r = 0; /* Avoiding warning */
cq_execute(desc);
} break;
} /* case */
@@ -2767,8 +2976,8 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
cq_enq(desc, d);
} goto done;
case FILE_WRITE: {
- int skip = 1;
- int size = ev->size - skip;
+ ErlDrvSizeT skip = 1;
+ ErlDrvSizeT size = ev->size - skip;
if (lseek_flush_read(desc, &err) < 0) {
reply_posix_error(desc, err);
goto done;
@@ -2777,7 +2986,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
reply_posix_error(desc, EBADF);
goto done;
}
- if (size <= 0) {
+ if (size == 0) {
reply_Uint(desc, size);
goto done;
}
@@ -2891,7 +3100,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
EF_FREE(d);
reply_Uint(desc, 0);
} else {
- size_t skip = 1 + 4 + 8*(2*n);
+ ErlDrvSizeT skip = 1 + 4 + 8*(2*n);
if (skip + total != ev->size) {
/* Actual amount of data does not match
* total of all pos/size specs
@@ -3213,9 +3422,69 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
goto done;
} /* case FILE_OPT_DELAYED_WRITE: */
} ASSERT(0); goto done; /* case FILE_SETOPT: */
-
+
+ case FILE_SENDFILE: {
+
+#ifdef HAVE_SENDFILE
+ struct t_data *d;
+ Uint32 out_fd, offsetH, offsetL, hd_len, tl_len;
+ Uint64 nbytes;
+ char flags;
+
+ if (ev->size < 1 + 7 * sizeof(Uint32) + sizeof(char)
+ || !EV_GET_UINT32(ev, &out_fd, &p, &q)
+ || !EV_GET_CHAR(ev, &flags, &p, &q)
+ || !EV_GET_UINT32(ev, &offsetH, &p, &q)
+ || !EV_GET_UINT32(ev, &offsetL, &p, &q)
+ || !EV_GET_UINT64(ev, &nbytes, &p, &q)
+ || !EV_GET_UINT32(ev, &hd_len, &p, &q)
+ || !EV_GET_UINT32(ev, &tl_len, &p, &q)) {
+ /* Buffer has wrong length to contain all the needed values */
+ reply_posix_error(desc, EINVAL);
+ goto done;
+ }
+
+ if (hd_len != 0 || tl_len != 0 || flags != 0) {
+ // We do not allow header, trailers and/or flags right now
+ reply_posix_error(desc, EINVAL);
+ goto done;
+ }
+
+ d = EF_SAFE_ALLOC(sizeof(struct t_data));
+ d->fd = desc->fd;
+ d->command = command;
+ d->invoke = invoke_sendfile;
+ d->free = NULL;
+ d->level = 2;
+
+ d->c.sendfile.out_fd = (int) out_fd;
+ d->c.sendfile.written = 0;
+
+ #if SIZEOF_OFF_T == 4
+ if (offsetH != 0) {
+ reply_posix_error(desc, EINVAL);
+ goto done;
+ }
+ d->c.sendfile.offset = (off_t) offsetL;
+ #else
+ d->c.sendfile.offset = ((off_t) offsetH << 32) | offsetL;
+ #endif
+
+ d->c.sendfile.nbytes = nbytes;
+
+ if (USE_THRDS_FOR_SENDFILE) {
+ SET_BLOCKING(d->c.sendfile.out_fd);
+ }
+
+ cq_enq(desc, d);
+#else
+ reply_posix_error(desc, ENOTSUP);
+#endif
+ goto done;
+ } /* case FILE_SENDFILE: */
+
} /* switch(command) */
-
+
if (lseek_flush_read(desc, &err) < 0) {
reply_posix_error(desc, err);
goto done;
diff --git a/erts/emulator/drivers/common/erl_efile.h b/erts/emulator/drivers/common/erl_efile.h
index 3097ded3f1..69ad02633c 100644
--- a/erts/emulator/drivers/common/erl_efile.h
+++ b/erts/emulator/drivers/common/erl_efile.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2010. All Rights Reserved.
+ * Copyright Ericsson AB 1997-2011. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -67,6 +67,11 @@
#define FILENAMES_16BIT 1
#endif
+// We use sendfilev if it exist on solaris
+#if !defined(HAVE_SENDFILE) && defined(HAVE_SENDFILEV)
+#define HAVE_SENDFILE
+#endif
+
/*
* An handle to an open directory. To be cast to the correct type
* in the system-dependent directory functions.
@@ -85,14 +90,15 @@ typedef struct _Efile_error {
/*
* This structure contains date and time.
*/
-typedef struct _Efile_time {
- unsigned year; /* (4 digits). */
- unsigned month; /* (1..12). */
- unsigned day; /* (1..31). */
- unsigned hour; /* (0..23). */
- unsigned minute; /* (0..59). */
- unsigned second; /* (0..59). */
-} Efile_time;
+
+//typedef struct _Efile_time {
+// unsigned year; /* (4 digits). */
+// unsigned month; /* (1..12). */
+// unsigned day; /* (1..31). */
+// unsigned hour; /* (0..23). */
+// unsigned minute; /* (0..59). */
+// unsigned second; /* (0..59). */
+//} Efile_time;
/*
@@ -111,13 +117,26 @@ typedef struct _Efile_info {
Uint32 inode; /* Inode number. */
Uint32 uid; /* User id of owner. */
Uint32 gid; /* Group id of owner. */
- Efile_time accessTime; /* Last time the file was accessed. */
- Efile_time modifyTime; /* Last time the file was modified. */
- Efile_time cTime; /* Creation time (Windows) or last
+ time_t accessTime; /* Last time the file was accessed. */
+ time_t modifyTime; /* Last time the file was modified. */
+ time_t cTime; /* Creation time (Windows) or last
* inode change (Unix).
*/
} Efile_info;
+
+#ifdef HAVE_SENDFILE
+/*
+ * Describes the structure of headers/trailers for sendfile
+ */
+struct t_sendfile_hdtl {
+ SysIOVec *headers;
+ int hdr_cnt;
+ SysIOVec *trailers;
+ int trl_cnt;
+};
+#endif /* HAVE_SENDFILE */
+
/*
* Functions.
*/
@@ -143,7 +162,7 @@ int efile_write_info(Efile_error* errInfo, Efile_info* pInfo, char *name);
int efile_write(Efile_error* errInfo, int flags, int fd,
char* buf, size_t count);
int efile_writev(Efile_error* errInfo, int flags, int fd,
- SysIOVec* iov, int iovcnt, size_t size);
+ SysIOVec* iov, int iovcnt);
int efile_read(Efile_error* errInfo, int flags, int fd,
char* buf, size_t count, size_t* pBytesRead);
int efile_seek(Efile_error* errInfo, int fd,
@@ -162,3 +181,7 @@ int efile_symlink(Efile_error* errInfo, char* old, char* new);
int efile_may_openfile(Efile_error* errInfo, char *name);
int efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset, Sint64 length,
int advise);
+#ifdef HAVE_SENDFILE
+int efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd,
+ off_t *offset, Uint64 *nbytes, struct t_sendfile_hdtl *hdtl);
+#endif /* HAVE_SENDFILE */
diff --git a/erts/emulator/drivers/common/gzio.c b/erts/emulator/drivers/common/gzio.c
index 741cb6ae20..a9303d55bc 100644
--- a/erts/emulator/drivers/common/gzio.c
+++ b/erts/emulator/drivers/common/gzio.c
@@ -27,7 +27,9 @@
#endif
#ifdef __WIN32__
+#ifndef HAVE_CONFLICTING_FREAD_DECLARATION
#define HAVE_CONFLICTING_FREAD_DECLARATION
+#endif
#define FILENAMES_16BIT 1
#endif
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index ebc4469a23..47a99fdbe6 100644
--- a/erts/emulator/drivers/common/inet_drv.c
+++ b/erts/emulator/drivers/common/inet_drv.c
@@ -80,6 +80,13 @@
#endif
#ifdef __WIN32__
+#define LLU "%I64u"
+#else
+#define LLU "%llu"
+#endif
+typedef unsigned long long llu_t;
+
+#ifdef __WIN32__
#define STRNCASECMP strncasecmp
#define INCL_WINSOCK_API_TYPEDEFS 1
@@ -110,6 +117,77 @@
#undef EWOULDBLOCK
#undef ETIMEDOUT
+#ifdef EINPROGRESS
+#undef EINPROGRESS
+#endif
+#ifdef EALREADY
+#undef EALREADY
+#endif
+#ifdef ENOTSOCK
+#undef ENOTSOCK
+#endif
+#ifdef EDESTADDRREQ
+#undef EDESTADDRREQ
+#endif
+#ifdef EMSGSIZE
+#undef EMSGSIZE
+#endif
+#ifdef EPROTOTYPE
+#undef EPROTOTYPE
+#endif
+#ifdef ENOPROTOOPT
+#undef ENOPROTOOPT
+#endif
+#ifdef EPROTONOSUPPORT
+#undef EPROTONOSUPPORT
+#endif
+#ifdef EOPNOTSUPP
+#undef EOPNOTSUPP
+#endif
+#ifdef EAFNOSUPPORT
+#undef EAFNOSUPPORT
+#endif
+#ifdef EADDRINUSE
+#undef EADDRINUSE
+#endif
+#ifdef EADDRNOTAVAIL
+#undef EADDRNOTAVAIL
+#endif
+#ifdef ENETDOWN
+#undef ENETDOWN
+#endif
+#ifdef ENETUNREACH
+#undef ENETUNREACH
+#endif
+#ifdef ENETRESET
+#undef ENETRESET
+#endif
+#ifdef ECONNABORTED
+#undef ECONNABORTED
+#endif
+#ifdef ECONNRESET
+#undef ECONNRESET
+#endif
+#ifdef ENOBUFS
+#undef ENOBUFS
+#endif
+#ifdef EISCONN
+#undef EISCONN
+#endif
+#ifdef ENOTCONN
+#undef ENOTCONN
+#endif
+#ifdef ECONNREFUSED
+#undef ECONNREFUSED
+#endif
+#ifdef ELOOP
+#undef ELOOP
+#endif
+#ifdef EHOSTUNREACH
+#undef EHOSTUNREACH
+#endif
+
+
#define HAVE_MULTICAST_SUPPORT
#define ERRNO_BLOCK WSAEWOULDBLOCK
@@ -280,6 +358,57 @@ static unsigned long one_value = 1;
# define SCTP_EOF MSG_EOF
#endif
+/* More Solaris 10 fixes: */
+#if ! HAVE_DECL_SCTP_CLOSED && HAVE_DECL_SCTPS_IDLE
+# define SCTP_CLOSED SCTPS_IDLE
+# undef HAVE_DECL_SCTP_CLOSED
+# define HAVE_DECL_SCTP_CLOSED 1
+#endif
+#if ! HAVE_DECL_SCTP_BOUND && HAVE_DECL_SCTPS_BOUND
+# define SCTP_BOUND SCTPS_BOUND
+# undef HAVE_DECL_SCTP_BOUND
+# define HAVE_DECL_SCTP_BOUND 1
+#endif
+#if ! HAVE_DECL_SCTP_LISTEN && HAVE_DECL_SCTPS_LISTEN
+# define SCTP_LISTEN SCTPS_LISTEN
+# undef HAVE_DECL_SCTP_LISTEN
+# define HAVE_DECL_SCTP_LISTEN 1
+#endif
+#if ! HAVE_DECL_SCTP_COOKIE_WAIT && HAVE_DECL_SCTPS_COOKIE_WAIT
+# define SCTP_COOKIE_WAIT SCTPS_COOKIE_WAIT
+# undef HAVE_DECL_SCTP_COOKIE_WAIT
+# define HAVE_DECL_SCTP_COOKIE_WAIT 1
+#endif
+#if ! HAVE_DECL_SCTP_COOKIE_ECHOED && HAVE_DECL_SCTPS_COOKIE_ECHOED
+# define SCTP_COOKIE_ECHOED SCTPS_COOKIE_ECHOED
+# undef HAVE_DECL_SCTP_COOKIE_ECHOED
+# define HAVE_DECL_SCTP_COOKIE_ECHOED 1
+#endif
+#if ! HAVE_DECL_SCTP_ESTABLISHED && HAVE_DECL_SCTPS_ESTABLISHED
+# define SCTP_ESTABLISHED SCTPS_ESTABLISHED
+# undef HAVE_DECL_SCTP_ESTABLISHED
+# define HAVE_DECL_SCTP_ESTABLISHED 1
+#endif
+#if ! HAVE_DECL_SCTP_SHUTDOWN_PENDING && HAVE_DECL_SCTPS_SHUTDOWN_PENDING
+# define SCTP_SHUTDOWN_PENDING SCTPS_SHUTDOWN_PENDING
+# undef HAVE_DECL_SCTP_SHUTDOWN_PENDING
+# define HAVE_DECL_SCTP_SHUTDOWN_PENDING 1
+#endif
+#if ! HAVE_DECL_SCTP_SHUTDOWN_SENT && HAVE_DECL_SCTPS_SHUTDOWN_SENT
+# define SCTP_SHUTDOWN_SENT SCTPS_SHUTDOWN_SENT
+# undef HAVE_DECL_SCTP_SHUTDOWN_SENT
+# define HAVE_DECL_SCTP_SHUTDOWN_SENT 1
+#endif
+#if ! HAVE_DECL_SCTP_SHUTDOWN_RECEIVED && HAVE_DECL_SCTPS_SHUTDOWN_RECEIVED
+# define SCTP_SHUTDOWN_RECEIVED SCTPS_SHUTDOWN_RECEIVED
+# undef HAVE_DECL_SCTP_SHUTDOWN_RECEIVED
+# define HAVE_DECL_SCTP_SHUTDOWN_RECEIVED 1
+#endif
+#if ! HAVE_DECL_SCTP_SHUTDOWN_ACK_SENT && HAVE_DECL_SCTPS_SHUTDOWN_ACK_SENT
+# define SCTP_SHUTDOWN_ACK_SENT SCTPS_SHUTDOWN_ACK_SENT
+# undef HAVE_DECL_SCTP_SHUTDOWN_ACK_SENT
+# define HAVE_DECL_SCTP_SHUTDOWN_ACK_SENT 1
+#endif
/* New spelling in lksctp 2.6.22 or maybe even earlier:
* adaption -> adaptation
*/
@@ -294,12 +423,13 @@ static unsigned long one_value = 1;
# define sctp_adaptation_layer_event sctp_adaption_layer_event
#endif
-static void *h_libsctp = NULL;
#ifdef __GNUC__
static typeof(sctp_bindx) *p_sctp_bindx = NULL;
+static typeof(sctp_peeloff) *p_sctp_peeloff = NULL;
#else
static int (*p_sctp_bindx)(int sd, struct sockaddr *addrs,
int addrcnt, int flags) = NULL;
+static int (*p_sctp_peeloff)(int sd, sctp_assoc_t assoc_id) = NULL;
#endif
#endif /* SCTP supported */
@@ -393,6 +523,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
driver_select(port, e, mode | (on?ERL_DRV_USE:0), on)
#define sock_select(d, flags, onoff) do { \
+ ASSERT(!(d)->is_ignored); \
(d)->event_mask = (onoff) ? \
((d)->event_mask | (flags)) : \
((d)->event_mask & ~(flags)); \
@@ -415,6 +546,13 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
(((unsigned char*) (s))[1] << 8) | \
(((unsigned char*) (s))[0]))
+
+#ifdef VALGRIND
+# include <valgrind/memcheck.h>
+#else
+# define VALGRIND_MAKE_MEM_DEFINED(ptr,size)
+#endif
+
/*----------------------------------------------------------------------------
** Interface constants.
**
@@ -427,7 +565,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
#define INET_AF_ANY 3 /* INADDR_ANY or IN6ADDR_ANY_INIT */
#define INET_AF_LOOPBACK 4 /* INADDR_LOOPBACK or IN6ADDR_LOOPBACK_INIT */
-/* INET_REQ_GETTYPE enumeration */
+/* open and INET_REQ_GETTYPE enumeration */
#define INET_TYPE_STREAM 1
#define INET_TYPE_DGRAM 2
#define INET_TYPE_SEQPACKET 3
@@ -484,16 +622,21 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
#define INET_REQ_IFSET 23
#define INET_REQ_SUBSCRIBE 24
#define INET_REQ_GETIFADDRS 25
+#define INET_REQ_ACCEPT 26
+#define INET_REQ_LISTEN 27
+#define INET_REQ_IGNOREFD 28
+
/* TCP requests */
-#define TCP_REQ_ACCEPT 40
-#define TCP_REQ_LISTEN 41
+/* #define TCP_REQ_ACCEPT 40 MOVED */
+/* #define TCP_REQ_LISTEN 41 MERGED */
#define TCP_REQ_RECV 42
#define TCP_REQ_UNRECV 43
#define TCP_REQ_SHUTDOWN 44
/* UDP and SCTP requests */
#define PACKET_REQ_RECV 60 /* Common for UDP and SCTP */
-#define SCTP_REQ_LISTEN 61 /* Different from TCP; not for UDP */
+/* #define SCTP_REQ_LISTEN 61 MERGED Different from TCP; not for UDP */
#define SCTP_REQ_BINDX 62 /* Multi-home SCTP bind */
+#define SCTP_REQ_PEELOFF 63
/* INET_REQ_SUBSCRIBE sub-requests */
#define INET_SUBS_EMPTY_OUT_Q 1
@@ -507,7 +650,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
/* *_REQ_* replies */
#define INET_REP_ERROR 0
#define INET_REP_OK 1
-#define INET_REP_SCTP 2
+#define INET_REP 2
/* INET_REQ_SETOPTS and INET_REQ_GETOPTS options */
#define INET_OPT_REUSEADDR 0 /* enable/disable local address reuse */
@@ -628,10 +771,14 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
** End of interface constants.
**--------------------------------------------------------------------------*/
-#define INET_STATE_CLOSED 0
-#define INET_STATE_OPEN (INET_F_OPEN)
-#define INET_STATE_BOUND (INET_STATE_OPEN | INET_F_BOUND)
-#define INET_STATE_CONNECTED (INET_STATE_BOUND | INET_F_ACTIVE)
+#define INET_STATE_CLOSED (0)
+#define INET_STATE_OPEN (INET_F_OPEN)
+#define INET_STATE_BOUND (INET_STATE_OPEN | INET_F_BOUND)
+#define INET_STATE_CONNECTED (INET_STATE_BOUND | INET_F_ACTIVE)
+#define INET_STATE_LISTENING (INET_STATE_BOUND | INET_F_LISTEN)
+#define INET_STATE_CONNECTING (INET_STATE_BOUND | INET_F_CON)
+#define INET_STATE_ACCEPTING (INET_STATE_LISTENING | INET_F_ACC)
+#define INET_STATE_MULTI_ACCEPTING (INET_STATE_ACCEPTING | INET_F_MULTI_CLIENT)
#define IS_OPEN(d) \
(((d)->state & INET_F_OPEN) == INET_F_OPEN)
@@ -666,6 +813,11 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
/* Max interface name */
#define INET_IFNAMSIZ 16
+/* INET Ignore states */
+#define INET_IGNORE_NONE 0
+#define INET_IGNORE_READ 1
+#define INET_IGNORE_WRITE 1 << 1
+
/* Max length of Erlang Term Buffer (for outputting structured terms): */
#ifdef HAVE_SCTP
#define PACKET_ERL_DRV_TERM_DATA_LEN 512
@@ -674,7 +826,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
#endif
-#define BIN_REALLOC_LIMIT(x) (((x)*3)/4) /* 75% */
+#define BIN_REALLOC_MARGIN(x) ((x)/4) /* 25% */
/* The general purpose sockaddr */
typedef union {
@@ -805,20 +957,13 @@ typedef struct {
double send_avg; /* average packet size sent */
subs_list empty_out_q_subs; /* Empty out queue subscribers */
+ int is_ignored; /* if a fd is ignored by the inet_drv.
+ This flag should be set to true when
+ the fd is used outside of inet_drv. */
} inet_descriptor;
-#define TCP_STATE_CLOSED INET_STATE_CLOSED
-#define TCP_STATE_OPEN (INET_F_OPEN)
-#define TCP_STATE_BOUND (TCP_STATE_OPEN | INET_F_BOUND)
-#define TCP_STATE_CONNECTED (TCP_STATE_BOUND | INET_F_ACTIVE)
-#define TCP_STATE_LISTEN (TCP_STATE_BOUND | INET_F_LISTEN)
-#define TCP_STATE_CONNECTING (TCP_STATE_BOUND | INET_F_CON)
-#define TCP_STATE_ACCEPTING (TCP_STATE_LISTEN | INET_F_ACC)
-#define TCP_STATE_MULTI_ACCEPTING (TCP_STATE_ACCEPTING | INET_F_MULTI_CLIENT)
-
-
#define TCP_MAX_PACKET_SIZE 0x4000000 /* 64 M */
#define MAX_VSIZE 16 /* Max number of entries allowed in an I/O
@@ -827,13 +972,14 @@ typedef struct {
static int tcp_inet_init(void);
static void tcp_inet_stop(ErlDrvData);
-static void tcp_inet_command(ErlDrvData, char*, int);
+static void tcp_inet_command(ErlDrvData, char*, ErlDrvSizeT);
static void tcp_inet_commandv(ErlDrvData, ErlIOVec*);
static void tcp_inet_flush(ErlDrvData drv_data);
static void tcp_inet_drv_input(ErlDrvData, ErlDrvEvent);
static void tcp_inet_drv_output(ErlDrvData data, ErlDrvEvent event);
static ErlDrvData tcp_inet_start(ErlDrvPort, char* command);
-static int tcp_inet_ctl(ErlDrvData, unsigned int, char*, int, char**, int);
+static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData, unsigned int,
+ char*, ErlDrvSizeT, char**, ErlDrvSizeT);
static void tcp_inet_timeout(ErlDrvData);
static void tcp_inet_process_exit(ErlDrvData, ErlDrvMonitor *);
static void inet_stop_select(ErlDrvEvent, void*);
@@ -874,25 +1020,19 @@ static struct erl_drv_entry tcp_inet_driver_entry =
inet_stop_select
};
-#define PACKET_STATE_CLOSED INET_STATE_CLOSED
-#define PACKET_STATE_OPEN (INET_F_OPEN)
-#define PACKET_STATE_BOUND (PACKET_STATE_OPEN | INET_F_BOUND)
-#define SCTP_STATE_LISTEN (PACKET_STATE_BOUND | INET_F_LISTEN)
-#define SCTP_STATE_CONNECTING (PACKET_STATE_BOUND | INET_F_CON)
-#define PACKET_STATE_CONNECTED (PACKET_STATE_BOUND | INET_F_ACTIVE)
static int packet_inet_init(void);
static void packet_inet_stop(ErlDrvData);
-static void packet_inet_command(ErlDrvData, char*, int);
+static void packet_inet_command(ErlDrvData, char*, ErlDrvSizeT);
static void packet_inet_drv_input(ErlDrvData data, ErlDrvEvent event);
static void packet_inet_drv_output(ErlDrvData data, ErlDrvEvent event);
static ErlDrvData udp_inet_start(ErlDrvPort, char* command);
#ifdef HAVE_SCTP
static ErlDrvData sctp_inet_start(ErlDrvPort, char* command);
#endif
-static int packet_inet_ctl(ErlDrvData, unsigned int, char*,
- int, char**, int);
+static ErlDrvSSizeT packet_inet_ctl(ErlDrvData, unsigned int, char*,
+ ErlDrvSizeT, char**, ErlDrvSizeT);
static void packet_inet_timeout(ErlDrvData);
#ifdef __WIN32__
static void packet_inet_event(ErlDrvData, ErlDrvEvent);
@@ -986,7 +1126,7 @@ typedef struct {
} tcp_descriptor;
/* send function */
-static int tcp_send(tcp_descriptor* desc, char* ptr, int len);
+static int tcp_send(tcp_descriptor* desc, char* ptr, ErlDrvSizeT len);
static int tcp_sendv(tcp_descriptor* desc, ErlIOVec* ev);
static int tcp_recv(tcp_descriptor* desc, int request_len);
static int tcp_deliver(tcp_descriptor* desc, int len);
@@ -997,6 +1137,9 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event);
typedef struct {
inet_descriptor inet; /* common data structure (DON'T MOVE) */
int read_packets; /* Number of packets to read per invocation */
+ int i_bufsz; /* current input buffer size */
+ ErlDrvBinary* i_buf; /* current binary buffer */
+ char* i_ptr; /* current pos in buf */
} udp_descriptor;
@@ -1050,7 +1193,7 @@ static ErlDrvTermData am_tos;
static int inet_init(void);
-static int ctl_reply(int, char*, int, char**, int);
+static ErlDrvSSizeT ctl_reply(int, char*, ErlDrvSizeT, char**, ErlDrvSizeT);
struct erl_drv_entry inet_driver_entry =
{
@@ -1060,7 +1203,23 @@ struct erl_drv_entry inet_driver_entry =
NULL, /* output */
NULL, /* ready_input */
NULL, /* ready_output */
- "inet"
+ "inet",
+ NULL,
+ NULL, /* handle */
+ NULL, /* control */
+ NULL, /* timeout */
+ NULL, /* outputv */
+ NULL, /* ready_async */
+ NULL, /* flush */
+ NULL, /* call */
+ NULL, /* event */
+ ERL_DRV_EXTENDED_MARKER,
+ ERL_DRV_EXTENDED_MAJOR_VERSION,
+ ERL_DRV_EXTENDED_MINOR_VERSION,
+ 0,
+ NULL,
+ NULL,
+ NULL,
};
/* XXX: is this a driver interface function ??? */
@@ -1074,7 +1233,7 @@ void erl_exit(int n, char*, ...);
#ifdef FATAL_MALLOC
-static void *alloc_wrapper(size_t size){
+static void *alloc_wrapper(ErlDrvSizeT size){
void *ret = driver_alloc(size);
if(ret == NULL)
erl_exit(1,"Out of virtual memory in malloc (%s)", __FILE__);
@@ -1082,7 +1241,7 @@ static void *alloc_wrapper(size_t size){
}
#define ALLOC(X) alloc_wrapper(X)
-static void *realloc_wrapper(void *current, size_t size){
+static void *realloc_wrapper(void *current, ErlDrvSizeT size){
void *ret = driver_realloc(current,size);
if(ret == NULL)
erl_exit(1,"Out of virtual memory in realloc (%s)", __FILE__);
@@ -1311,11 +1470,11 @@ static InetDrvBufStk *get_bufstk(void)
return bs;
}
-static ErlDrvBinary* alloc_buffer(long minsz)
+static ErlDrvBinary* alloc_buffer(ErlDrvSizeT minsz)
{
InetDrvBufStk *bs = get_bufstk();
- DEBUGF(("alloc_buffer: %ld\r\n", minsz));
+ DEBUGF(("alloc_buffer: "LLU"\r\n", (llu_t)minsz));
if (bs && bs->buf.pos > 0) {
long size;
@@ -1391,7 +1550,7 @@ static void release_buffer(ErlDrvBinary* buf)
}
}
-static ErlDrvBinary* realloc_buffer(ErlDrvBinary* buf, long newsz)
+static ErlDrvBinary* realloc_buffer(ErlDrvBinary* buf, ErlDrvSizeT newsz)
{
return driver_realloc_binary(buf, newsz);
}
@@ -1420,8 +1579,9 @@ static ErlDrvData dummy_start(ErlDrvPort port, char* command)
return (ErlDrvData)port;
}
-static int dummy_ctl(ErlDrvData data, unsigned int cmd, char* buf, int len,
- char** rbuf, int rsize)
+static ErlDrvSSizeT dummy_ctl(ErlDrvData data, unsigned int cmd,
+ char* buf, ErlDrvSizeT len, char** rbuf,
+ ErlDrvSizeT rsize)
{
static char error[] = "no_winsock2";
@@ -1429,7 +1589,7 @@ static int dummy_ctl(ErlDrvData data, unsigned int cmd, char* buf, int len,
return ctl_reply(INET_REP_ERROR, error, sizeof(error), rbuf, rsize);
}
-static void dummy_command(ErlDrvData data, char* buf, int len)
+static void dummy_command(ErlDrvData data, char* buf, ErlDrvSizeT len)
{
}
@@ -1486,7 +1646,8 @@ static struct erl_drv_entry dummy_sctp_driver_entry =
#endif
/* general control reply function */
-static int ctl_reply(int rep, char* buf, int len, char** rbuf, int rsize)
+static ErlDrvSSizeT ctl_reply(int rep, char* buf, ErlDrvSizeT len,
+ char** rbuf, ErlDrvSizeT rsize)
{
char* ptr;
@@ -1502,7 +1663,7 @@ static int ctl_reply(int rep, char* buf, int len, char** rbuf, int rsize)
}
/* general control error reply function */
-static int ctl_error(int err, char** rbuf, int rsize)
+static ErlDrvSSizeT ctl_error(int err, char** rbuf, ErlDrvSizeT rsize)
{
char response[256]; /* Response buffer. */
char* s;
@@ -1513,7 +1674,7 @@ static int ctl_error(int err, char** rbuf, int rsize)
return ctl_reply(INET_REP_ERROR, response, t-response, rbuf, rsize);
}
-static int ctl_xerror(char* xerr, char** rbuf, int rsize)
+static ErlDrvSSizeT ctl_xerror(char* xerr, char** rbuf, ErlDrvSizeT rsize)
{
int n = strlen(xerr);
return ctl_reply(INET_REP_ERROR, xerr, n, rbuf, rsize);
@@ -1851,6 +2012,26 @@ static int inet_reply_ok(inet_descriptor* desc)
return driver_send_term(desc->port, caller, spec, i);
}
+#ifdef HAVE_SCTP
+static int inet_reply_ok_port(inet_descriptor* desc, ErlDrvTermData dport)
+{
+ ErlDrvTermData spec[2*LOAD_ATOM_CNT + 2*LOAD_PORT_CNT + 2*LOAD_TUPLE_CNT];
+ ErlDrvTermData caller = desc->caller;
+ int i = 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_PORT(spec, i, dport);
+ i = LOAD_TUPLE(spec, i, 2);
+ i = LOAD_TUPLE(spec, i, 3);
+ ASSERT(i == sizeof(spec)/sizeof(*spec));
+
+ desc->caller = 0;
+ return driver_send_term(desc->port, caller, spec, i);
+}
+#endif
+
/* send:
** {inet_reply, S, {error, Reason}}
*/
@@ -2389,14 +2570,19 @@ static ErlDrvTermData am_sctp_rtoinfo, /* Option names */
am_active, am_inactive,
/* For #sctp_status{}: */
- am_empty, am_closed,
+# if HAVE_DECL_SCTP_EMPTY
+ am_empty,
+# endif
+# if HAVE_DECL_SCTP_BOUND
+ am_bound,
+# endif
+# if HAVE_DECL_SCTP_LISTEN
+ am_listen,
+# endif
am_cookie_wait, am_cookie_echoed,
am_established, am_shutdown_pending,
am_shutdown_sent, am_shutdown_received,
am_shutdown_ack_sent;
- /* Not yet implemented in the Linux kernel:
- ** am_bound, am_listen;
- */
/*
** Parsing of "sctp_sndrcvinfo": ancillary data coming with received msgs.
@@ -2665,7 +2851,8 @@ static int sctp_parse_async_event
# ifdef HAVE_STRUCT_SCTP_REMOTE_ERROR_SRE_DATA
chunk = (char*) (&(sptr->sre_data));
# else
- chunk = ((char*)sptr) + sizeof(*sptr);
+ chunk = ((char*) &(sptr->sre_assoc_id))
+ + sizeof(sptr->sre_assoc_id);
# endif
chlen = sptr->sre_length - (chunk - (char *)sptr);
i = sctp_parse_error_chunk(spec, i, chunk, chlen);
@@ -2716,7 +2903,8 @@ static int sctp_parse_async_event
# ifdef HAVE_STRUCT_SCTP_SEND_FAILED_SSF_DATA
chunk = (char*) (&(sptr->ssf_data));
# else
- chunk = ((char*)sptr) + sizeof(*sptr);
+ chunk = ((char*) &(sptr->ssf_assoc_id))
+ + sizeof(sptr->ssf_assoc_id);
# endif
chlen = sptr->ssf_length - (chunk - (char*) sptr);
choff = chunk - bin->orig_bytes;
@@ -3390,8 +3578,15 @@ static void inet_init_sctp(void) {
INIT_ATOM(inactive);
/* For #sctp_status{}: */
+# if HAVE_DECL_SCTP_EMPTY
INIT_ATOM(empty);
- INIT_ATOM(closed);
+# endif
+# if HAVE_DECL_SCTP_BOUND
+ INIT_ATOM(bound);
+# endif
+# if HAVE_DECL_SCTP_LISTEN
+ INIT_ATOM(listen);
+# endif
INIT_ATOM(cookie_wait);
INIT_ATOM(cookie_echoed);
INIT_ATOM(established);
@@ -3399,10 +3594,6 @@ static void inet_init_sctp(void) {
INIT_ATOM(shutdown_sent);
INIT_ATOM(shutdown_received);
INIT_ATOM(shutdown_ack_sent);
- /* Not yet implemented in the Linux kernel:
- ** INIT_ATOM(bound);
- ** INIT_ATOM(listen);
- */
}
#endif /* HAVE_SCTP */
@@ -3453,17 +3644,32 @@ static int inet_init()
/* Check the size of SCTP AssocID -- currently both this driver and the
Erlang part require 32 bit: */
ASSERT(sizeof(sctp_assoc_t)==ASSOC_ID_LEN);
-# ifndef LIBSCTP
-# error LIBSCTP not defined
-# endif
- if (erts_sys_ddll_open_noext(STRINGIFY(LIBSCTP), &h_libsctp, NULL) == 0) {
- void *ptr;
- if (erts_sys_ddll_sym(h_libsctp, "sctp_bindx", &ptr) == 0) {
- p_sctp_bindx = ptr;
- inet_init_sctp();
- add_driver_entry(&sctp_inet_driver_entry);
+# if defined(HAVE_SCTP_BINDX) && defined (HAVE_SCTP_PEELOFF)
+ p_sctp_bindx = sctp_bindx;
+ p_sctp_peeloff = sctp_peeloff;
+ inet_init_sctp();
+ add_driver_entry(&sctp_inet_driver_entry);
+# else
+# ifndef LIBSCTP
+# error LIBSCTP not defined
+# endif
+ {
+ static void *h_libsctp = NULL;
+
+ if (erts_sys_ddll_open_noext(STRINGIFY(LIBSCTP), &h_libsctp, NULL)
+ == 0) {
+ void *ptr;
+ if (erts_sys_ddll_sym(h_libsctp, "sctp_bindx", &ptr) == 0) {
+ p_sctp_bindx = ptr;
+ inet_init_sctp();
+ add_driver_entry(&sctp_inet_driver_entry);
+ if (erts_sys_ddll_sym(h_libsctp, "sctp_peeloff", &ptr) == 0) {
+ p_sctp_peeloff = ptr;
+ }
+ }
}
}
+# endif
#endif
/* remove the dummy inet driver */
@@ -3485,7 +3691,8 @@ static int inet_init()
** and is set to actual length of dst on return
** return NULL on error and ptr after port address on success
*/
-static char* inet_set_address(int family, inet_address* dst, char* src, int* len)
+static char* inet_set_address(int family, inet_address* dst,
+ char* src, ErlDrvSizeT* len)
{
short port;
@@ -3521,7 +3728,7 @@ static char* inet_set_address(int family, inet_address* dst, char* src, int* len
** src = [TAG,P1,P0,X1,X2,...] when TAG = INET_AF_INET | INET_AF_INET6
*/
static char *inet_set_faddress(int family, inet_address* dst,
- char *src, int* len) {
+ char *src, ErlDrvSizeT* len) {
int tag;
if (*len < 1) return NULL;
@@ -3636,7 +3843,13 @@ static void desc_close(inet_descriptor* desc)
desc->forced_events = 0;
desc->send_would_block = 0;
#endif
- driver_select(desc->port, (ErlDrvEvent)(long)desc->event, ERL_DRV_USE, 0);
+ // We should close the fd here, but the other driver might still
+ // be selecting on it.
+ if (!desc->is_ignored)
+ driver_select(desc->port,(ErlDrvEvent)(long)desc->event,
+ ERL_DRV_USE, 0);
+ else
+ inet_stop_select((ErlDrvEvent)(long)desc->event,NULL);
desc->event = INVALID_EVENT; /* closed by stop_select callback */
desc->s = INVALID_SOCKET;
desc->event_mask = 0;
@@ -3679,8 +3892,8 @@ static int erl_inet_close(inet_descriptor* desc)
}
-static int inet_ctl_open(inet_descriptor* desc, int domain, int type,
- char** rbuf, int rsize)
+static ErlDrvSSizeT inet_ctl_open(inet_descriptor* desc, int domain, int type,
+ char** rbuf, ErlDrvSizeT rsize)
{
if (desc->state != INET_STATE_CLOSED)
return ctl_xerror(EXBADSEQ, rbuf, rsize);
@@ -3700,8 +3913,8 @@ static int inet_ctl_open(inet_descriptor* desc, int domain, int type,
/* as inet_open but pass in an open socket (MUST BE OF RIGHT TYPE) */
-static int inet_ctl_fdopen(inet_descriptor* desc, int domain, int type,
- SOCKET s, char** rbuf, int rsize)
+static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type,
+ SOCKET s, char** rbuf, ErlDrvSizeT rsize)
{
inet_address name;
unsigned int sz = sizeof(name);
@@ -3905,14 +4118,15 @@ static char* buf_to_sockaddr(char* ptr, char* end, struct sockaddr* addr)
#if defined(__WIN32__) && defined(SIO_GET_INTERFACE_LIST)
-static int inet_ctl_getiflist(inet_descriptor* desc, char** rbuf, int rsize)
+static ErlDrvSSizeT inet_ctl_getiflist(inet_descriptor* desc,
+ char** rbuf, ErlDrvSizeT rsize)
{
char ifbuf[BUFSIZ];
char sbuf[BUFSIZ];
char* sptr;
INTERFACE_INFO* ifp;
DWORD len;
- int n;
+ ErlDrvSizeT n;
int err;
ifp = (INTERFACE_INFO*) ifbuf;
@@ -3942,8 +4156,8 @@ static int inet_ctl_getiflist(inet_descriptor* desc, char** rbuf, int rsize)
/* input is an ip-address in string format i.e A.B.C.D
** scan the INTERFACE_LIST to get the options
*/
-static int inet_ctl_ifget(inet_descriptor* desc, char* buf, int len,
- char** rbuf, int rsize)
+static ErlDrvSSizeT inet_ctl_ifget(inet_descriptor* desc, char* buf,
+ ErlDrvSizeT len, char** rbuf, ErlDrvSizeT rsize)
{
char ifbuf[BUFSIZ];
int n;
@@ -4044,8 +4258,9 @@ static int inet_ctl_ifget(inet_descriptor* desc, char* buf, int len,
}
/* not supported */
-static int inet_ctl_ifset(inet_descriptor* desc, char* buf, int len,
- char** rbuf, int rsize)
+static ErlDrvSSizeT inet_ctl_ifset(inet_descriptor* desc,
+ char* buf, ErlDrvSizeT len,
+ char** rbuf, ErlDrvSizeT rsize)
{
return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize);
}
@@ -4088,12 +4303,13 @@ static void free_ifconf(struct ifconf *ifcp) {
FREE(ifcp->ifc_buf);
}
-static int inet_ctl_getiflist(inet_descriptor* desc, char** rbuf, int rsize)
+static ErlDrvSSizeT inet_ctl_getiflist(inet_descriptor* desc,
+ char** rbuf, ErlDrvSizeT rsize)
{
struct ifconf ifc;
struct ifreq *ifrp;
char *sbuf, *sp;
- int i;
+ ErlDrvSizeT i;
/* Courtesy of Per Bergqvist and W. Richard Stevens */
@@ -4105,7 +4321,7 @@ static int inet_ctl_getiflist(inet_descriptor* desc, char** rbuf, int rsize)
*sp++ = INET_REP_OK;
i = 0;
for (;;) {
- int n;
+ ErlDrvSizeT n;
ifrp = (struct ifreq *) VOIDP(ifc.ifc_buf + i);
n = sizeof(ifrp->ifr_name) + SIZEA(ifrp->ifr_addr);
@@ -4131,13 +4347,39 @@ static int inet_ctl_getiflist(inet_descriptor* desc, char** rbuf, int rsize)
return sp - sbuf;
}
+#ifdef HAVE_LIBDLPI_H
+#include <libdlpi.h>
+static int hwaddr_libdlpi_lookup(const char *ifnm,
+ uchar_t *addr, size_t *alen)
+{
+ dlpi_handle_t handle;
+ dlpi_info_t linkinfo;
+ int ret = -1;
+
+ if (dlpi_open(ifnm, &handle, 0) != DLPI_SUCCESS) {
+ return -1;
+ }
+
+ if (dlpi_get_physaddr(handle, DL_CURR_PHYS_ADDR,
+ addr, alen) == DLPI_SUCCESS &&
+ dlpi_info(handle, &linkinfo, 0) == DLPI_SUCCESS)
+ {
+ ret = 0;
+ }
+
+ dlpi_close(handle);
+ return ret;
+}
+#endif
+
/* FIXME: temporary hack */
#ifndef IFHWADDRLEN
#define IFHWADDRLEN 6
#endif
-static int inet_ctl_ifget(inet_descriptor* desc, char* buf, int len,
- char** rbuf, int rsize)
+static ErlDrvSSizeT inet_ctl_ifget(inet_descriptor* desc,
+ char* buf, ErlDrvSizeT len,
+ char** rbuf, ErlDrvSizeT rsize)
{
char sbuf[BUFSIZ];
char* sptr;
@@ -4166,7 +4408,24 @@ static int inet_ctl_ifget(inet_descriptor* desc, char* buf, int len,
break;
case INET_IFOPT_HWADDR: {
-#ifdef SIOCGIFHWADDR
+#ifdef HAVE_LIBDLPI_H
+ /*
+ ** OpenSolaris have SIGCGIFHWADDR, but no ifr_hwaddr member..
+ ** The proper way to get the mac address would be to
+ ** use libdlpi...
+ */
+ uchar_t addr[DLPI_PHYSADDR_MAX];
+ size_t alen = sizeof(addr);
+
+ if (hwaddr_libdlpi_lookup(ifreq.ifr_name, addr, &alen) == 0) {
+ buf_check(sptr, s_end, 1+2+alen);
+ *sptr++ = INET_IFOPT_HWADDR;
+ put_int16(alen, sptr);
+ sptr += 2;
+ sys_memcpy(sptr, addr, alen);
+ sptr += alen;
+ }
+#elif defined(SIOCGIFHWADDR) && defined(HAVE_STRUCT_IFREQ_IFR_HWADDR)
if (ioctl(desc->s, SIOCGIFHWADDR, (char *)&ifreq) < 0)
break;
buf_check(sptr, s_end, 1+2+IFHWADDRLEN);
@@ -4175,7 +4434,7 @@ static int inet_ctl_ifget(inet_descriptor* desc, char* buf, int len,
/* raw memcpy (fix include autoconf later) */
sys_memcpy(sptr, (char*)(&ifreq.ifr_hwaddr.sa_data), IFHWADDRLEN);
sptr += IFHWADDRLEN;
-#elif defined(SIOCGENADDR)
+#elif defined(SIOCGENADDR) && defined(HAVE_STRUCT_IFREQ_IFR_ENADDR)
if (ioctl(desc->s, SIOCGENADDR, (char *)&ifreq) < 0)
break;
buf_check(sptr, s_end, 1+2+sizeof(ifreq.ifr_enaddr));
@@ -4314,8 +4573,9 @@ static int inet_ctl_ifget(inet_descriptor* desc, char* buf, int len,
}
-static int inet_ctl_ifset(inet_descriptor* desc, char* buf, int len,
- char** rbuf, int rsize)
+static ErlDrvSSizeT inet_ctl_ifset(inet_descriptor* desc,
+ char* buf, ErlDrvSizeT len,
+ char** rbuf, ErlDrvSizeT rsize)
{
struct ifreq ifreq;
int namlen;
@@ -4338,19 +4598,19 @@ static int inet_ctl_ifset(inet_descriptor* desc, char* buf, int len,
break;
case INET_IFOPT_HWADDR: {
- unsigned int len;
+ unsigned int hwalen;
buf_check(buf, b_end, 2);
- len = get_int16(buf); buf += 2;
- buf_check(buf, b_end, len);
+ hwalen = get_int16(buf); buf += 2;
+ buf_check(buf, b_end, hwalen);
#ifdef SIOCSIFHWADDR
/* raw memcpy (fix include autoconf later) */
sys_memset((char*)(&ifreq.ifr_hwaddr.sa_data),
'\0', sizeof(ifreq.ifr_hwaddr.sa_data));
- sys_memcpy((char*)(&ifreq.ifr_hwaddr.sa_data), buf, len);
+ sys_memcpy((char*)(&ifreq.ifr_hwaddr.sa_data), buf, hwalen);
(void) ioctl(desc->s, SIOCSIFHWADDR, (char *)&ifreq);
#endif
- buf += len;
+ buf += hwalen;
break;
}
@@ -4436,21 +4696,24 @@ static int inet_ctl_ifset(inet_descriptor* desc, char* buf, int len,
#else
-static int inet_ctl_getiflist(inet_descriptor* desc, char** rbuf, int rsize)
+static ErlDrvSSizeT inet_ctl_getiflist(inet_descriptor* desc,
+ char** rbuf, ErlDrvSizeT rsize)
{
return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize);
}
-static int inet_ctl_ifget(inet_descriptor* desc, char* buf, int len,
- char** rbuf, int rsize)
+static ErlDrvSSizeT inet_ctl_ifget(inet_descriptor* desc,
+ char* buf, ErlDrvSizeT len,
+ char** rbuf, ErlDrvSizeT rsize)
{
return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize);
}
-static int inet_ctl_ifset(inet_descriptor* desc, char* buf, int len,
- char** rbuf, int rsize)
+static ErlDrvSSizeT inet_ctl_ifset(inet_descriptor* desc,
+ char* buf, ErlDrvSizeT len,
+ char** rbuf, ErlDrvSizeT rsize)
{
return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize);
}
@@ -4459,6 +4722,7 @@ static int inet_ctl_ifset(inet_descriptor* desc, char* buf, int len,
+#if defined(__WIN32__) || defined(HAVE_GETIFADDRS)
/* Latin-1 to utf8 */
static int utf8_len(const char *c, int m) {
@@ -4481,6 +4745,7 @@ static void utf8_encode(const char *c, int m, char *p) {
}
}
}
+#endif
#if defined(__WIN32__)
@@ -4505,8 +4770,8 @@ int eq_masked_bytes(char *a, char *b, int pref_len) {
return !0;
}
-static int inet_ctl_getifaddrs(inet_descriptor* desc_p,
- char **rbuf_pp, int rsize)
+static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p,
+ char **rbuf_pp, ErlDrvSizeT rsize)
{
int i;
DWORD ret, n;
@@ -4516,7 +4781,7 @@ static int inet_ctl_getifaddrs(inet_descriptor* desc_p,
char *buf_p;
char *buf_alloc_p;
- int buf_size =512;
+ ErlDrvSizeT buf_size = 512;
# define BUF_ENSURE(Size) \
do { \
int NEED_, GOT_ = buf_p - buf_alloc_p; \
@@ -4890,12 +5155,12 @@ done:
#elif defined(HAVE_GETIFADDRS)
-static int inet_ctl_getifaddrs(inet_descriptor* desc_p,
- char **rbuf_pp, int rsize)
+static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p,
+ char **rbuf_pp, ErlDrvSizeT rsize)
{
struct ifaddrs *ifa_p, *ifa_free_p;
- int buf_size;
+ ErlDrvSizeT buf_size;
char *buf_p;
char *buf_alloc_p;
@@ -4998,8 +5263,8 @@ static int inet_ctl_getifaddrs(inet_descriptor* desc_p,
#else
-static int inet_ctl_getifaddrs(inet_descriptor* desc_p,
- char **rbuf_pp, int rsize)
+static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p,
+ char **rbuf_pp, ErlDrvSizeT rsize)
{
return ctl_error(ENOTSUP, rbuf_pp, rsize);
}
@@ -5800,7 +6065,7 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len)
case SCTP_OPT_PRIMARY_ADDR:
case SCTP_OPT_SET_PEER_PRIMARY_ADDR:
{
- int alen;
+ ErlDrvSizeT alen;
char *after;
CHKLEN(curr, ASSOC_ID_LEN);
@@ -5842,7 +6107,7 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len)
}
case SCTP_OPT_PEER_ADDR_PARAMS:
{
- int alen;
+ ErlDrvSizeT alen;
char *after;
# ifdef HAVE_STRUCT_SCTP_PADDRPARAMS_SPP_FLAGS
int eflags, cflags, hb_enable, hb_disable,
@@ -5929,6 +6194,7 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len)
type = SCTP_DEFAULT_SEND_PARAM;
arg_ptr = (char*) (&arg.sri);
arg_sz = sizeof ( arg.sri);
+ VALGRIND_MAKE_MEM_DEFINED(arg_ptr, arg_sz); /*suppress "uninitialised bytes"*/
break;
}
case SCTP_OPT_EVENTS:
@@ -5972,7 +6238,7 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len)
proto = IPPROTO_SCTP;
type = SCTP_DELAYED_ACK_TIME;
arg_ptr = (char*) (&arg.av);
- arg_sz = sizeof ( arg.es);
+ arg_sz = sizeof ( arg.av);
break;
}
# endif
@@ -6018,8 +6284,9 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len)
** ptr should point to a buffer with 9*len +1 to be safe!!
*/
-static int inet_fill_opts(inet_descriptor* desc,
- char* buf, int len, char** dest, int destlen)
+static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc,
+ char* buf, ErlDrvSizeT len,
+ char** dest, ErlDrvSizeT destlen)
{
int type;
int proto;
@@ -6029,8 +6296,8 @@ static int inet_fill_opts(inet_descriptor* desc,
char* arg_ptr;
unsigned int arg_sz;
char *ptr = NULL;
- int dest_used = 0;
- int dest_allocated = destlen;
+ ErlDrvSizeT dest_used = 0;
+ ErlDrvSizeT dest_allocated = destlen;
char *orig_dest = *dest;
/* Ptr is a name parameter */
@@ -6045,7 +6312,7 @@ static int inet_fill_opts(inet_descriptor* desc,
#define PLACE_FOR(Size,Ptr) \
do { \
- int need = dest_used + (Size); \
+ ErlDrvSizeT need = dest_used + (Size); \
if (need > INET_MAX_OPT_BUFFER) { \
RETURN_ERROR(); \
} \
@@ -6066,7 +6333,7 @@ static int inet_fill_opts(inet_descriptor* desc,
/* Ptr is a name parameter */
#define TRUNCATE_TO(Size,Ptr) \
do { \
- int new_need = ((Ptr) - (*dest)) + (Size); \
+ ErlDrvSizeT new_need = ((Ptr) - (*dest)) + (Size); \
if (new_need > dest_used) { \
erl_exit(1,"Internal error in inet_drv, " \
"miscalculated buffer size"); \
@@ -6356,8 +6623,9 @@ static int load_paddrinfo (ErlDrvTermData * spec, int i,
/*
** "sctp_fill_opts": Returns {ok, Results}, or an error:
*/
-static int sctp_fill_opts(inet_descriptor* desc, char* buf, int buflen,
- char** dest, int destlen)
+static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc,
+ char* buf, ErlDrvSizeT buflen,
+ char** dest, ErlDrvSizeT destlen)
{
/* In contrast to the generic "inet_fill_opts", the output here is
represented by tuples/records, which are formed in the "spec":
@@ -6539,7 +6807,7 @@ static int sctp_fill_opts(inet_descriptor* desc, char* buf, int buflen,
struct linger lg;
unsigned int sz = sizeof(lg);
- if (sock_getopt(desc->s, IPPROTO_SCTP, SO_LINGER,
+ if (sock_getopt(desc->s, SOL_SOCKET, SO_LINGER,
&lg, &sz) < 0) continue;
/* Fill in the response: */
PLACE_FOR(spec, i,
@@ -6575,7 +6843,7 @@ static int sctp_fill_opts(inet_descriptor* desc, char* buf, int buflen,
{
case INET_OPT_RCVBUF :
{
- proto = IPPROTO_SCTP;
+ proto = SOL_SOCKET;
type = SO_RCVBUF;
is_int = 1;
tag = am_recbuf;
@@ -6583,7 +6851,7 @@ static int sctp_fill_opts(inet_descriptor* desc, char* buf, int buflen,
}
case INET_OPT_SNDBUF :
{
- proto = IPPROTO_SCTP;
+ proto = SOL_SOCKET;
type = SO_SNDBUF;
is_int = 1;
tag = am_sndbuf;
@@ -6736,7 +7004,7 @@ static int sctp_fill_opts(inet_descriptor* desc, char* buf, int buflen,
2*LOAD_ATOM_CNT + LOAD_INT_CNT + 2*LOAD_TUPLE_CNT);
i = LOAD_ATOM (spec, i, am_sctp_adaptation_layer);
i = LOAD_ATOM (spec, i, am_sctp_setadaptation);
- i = LOAD_INT (spec, i, ad.ssb_adaptation_ind);
+ i = LOAD_INT (spec, i, sock_ntohl(ad.ssb_adaptation_ind));
i = LOAD_TUPLE (spec, i, 2);
i = LOAD_TUPLE (spec, i, 2);
break;
@@ -6747,7 +7015,7 @@ static int sctp_fill_opts(inet_descriptor* desc, char* buf, int buflen,
unsigned int sz = sizeof(ap);
int n;
char *after;
- int alen;
+ ErlDrvSizeT alen;
if (buflen < ASSOC_ID_LEN) RETURN_ERROR(spec, -EINVAL);
ap.spp_assoc_id = GET_ASSOC_ID(buf);
@@ -6879,7 +7147,7 @@ static int sctp_fill_opts(inet_descriptor* desc, char* buf, int buflen,
break;
}
/* The following option is not available in Solaris 10: */
-# ifdef SCTP_DELAYED_ACK_TIME
+# if HAVE_DECL_SCTP_DELAYED_ACK_TIME
case SCTP_OPT_DELAYED_ACK_TIME:
{
struct sctp_assoc_value av;
@@ -6926,7 +7194,7 @@ static int sctp_fill_opts(inet_descriptor* desc, char* buf, int buflen,
switch(st.sstat_state)
{
/* SCTP_EMPTY is not supported on SOLARIS10: */
-# ifdef SCTP_EMPTY
+# if HAVE_DECL_SCTP_EMPTY
case SCTP_EMPTY:
i = LOAD_ATOM (spec, i, am_empty);
break;
@@ -6934,14 +7202,16 @@ static int sctp_fill_opts(inet_descriptor* desc, char* buf, int buflen,
case SCTP_CLOSED:
i = LOAD_ATOM (spec, i, am_closed);
break;
- /* The following states are not supported by Linux Kernel SCTP yet:
+# if HAVE_DECL_SCTP_BOUND
case SCTP_BOUND:
i = LOAD_ATOM (spec, i, am_bound);
break;
+# endif
+# if HAVE_DECL_SCTP_LISTEN
case SCTP_LISTEN:
i = LOAD_ATOM (spec, i, am_listen);
break;
- */
+# endif
case SCTP_COOKIE_WAIT:
i = LOAD_ATOM (spec, i, am_cookie_wait);
break;
@@ -6985,7 +7255,7 @@ static int sctp_fill_opts(inet_descriptor* desc, char* buf, int buflen,
struct sctp_paddrinfo pai;
unsigned int sz = sizeof(pai);
char *after;
- int alen;
+ ErlDrvSizeT alen;
if (buflen < ASSOC_ID_LEN) RETURN_ERROR(spec, -EINVAL);
pai.spinfo_assoc_id = GET_ASSOC_ID(buf);
@@ -7012,7 +7282,7 @@ static int sctp_fill_opts(inet_descriptor* desc, char* buf, int buflen,
default:
RETURN_ERROR(spec, -EINVAL); /* No more valid options */
}
- /* If we get here one result has been succesfully loaded */
+ /* If we get here one result has been successfully loaded */
length ++;
}
if (buflen != 0) RETURN_ERROR(spec, -EINVAL); /* Optparam mismatch */
@@ -7029,11 +7299,10 @@ static int sctp_fill_opts(inet_descriptor* desc, char* buf, int buflen,
i = LOAD_TUPLE(spec, i, 3);
/* Now, convert "spec" into the returnable term: */
- /* desc->caller = 0; What does it mean? */
- driver_output_term(desc->port, spec, i);
+ driver_send_term(desc->port, driver_caller(desc->port), spec, i);
FREE(spec);
- (*dest)[0] = INET_REP_SCTP;
+ (*dest)[0] = INET_REP;
return 1; /* Response length */
# undef PLACE_FOR
# undef RETURN_ERROR
@@ -7043,7 +7312,8 @@ static int sctp_fill_opts(inet_descriptor* desc, char* buf, int buflen,
/* fill statistics reply, op codes from src and result in dest
** dst area must be a least 5*len + 1 bytes
*/
-static int inet_fill_stat(inet_descriptor* desc, char* src, int len, char* dst)
+static ErlDrvSSizeT inet_fill_stat(inet_descriptor* desc,
+ char* src, ErlDrvSizeT len, char* dst)
{
unsigned long val;
int op;
@@ -7076,7 +7346,7 @@ static int inet_fill_stat(inet_descriptor* desc, char* src, int len, char* dst)
val = (unsigned long) desc->send_avg;
break;
case INET_STAT_SEND_PND:
- val = driver_sizeq(desc->port);
+ val = (unsigned long) driver_sizeq(desc->port);
break;
case INET_STAT_RECV_OCT:
put_int32(desc->recv_oct[1], dst); /* write high 32bit */
@@ -7121,7 +7391,8 @@ send_empty_out_q_msgs(inet_descriptor* desc)
/* subscribe and fill subscription reply, op codes from src and
** result in dest dst area must be a least 5*len + 1 bytes
*/
-static int inet_subscribe(inet_descriptor* desc, char* src, int len, char* dst)
+static ErlDrvSSizeT inet_subscribe(inet_descriptor* desc,
+ char* src, ErlDrvSizeT len, char* dst)
{
unsigned long val;
int op;
@@ -7208,6 +7479,8 @@ static ErlDrvData inet_start(ErlDrvPort port, int size, int protocol)
sys_memzero((char *)&desc->remote,sizeof(desc->remote));
+ desc->is_ignored = 0;
+
return (ErlDrvData)desc;
}
@@ -7219,14 +7492,14 @@ static ErlDrvData inet_start(ErlDrvPort port, int size, int protocol)
/*
** common TCP/UDP/SCTP control command
*/
-static int inet_ctl(inet_descriptor* desc, int cmd, char* buf, int len,
- char** rbuf, int rsize)
+static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
+ ErlDrvSizeT len, char** rbuf, ErlDrvSizeT rsize)
{
switch (cmd) {
case INET_REQ_GETSTAT: {
char* dst;
- int i;
+ ErlDrvSizeT i;
int dstlen = 1; /* Reply code */
for (i = 0; i < len; i++) {
@@ -7266,7 +7539,7 @@ static int inet_ctl(inet_descriptor* desc, int cmd, char* buf, int len,
}
case INET_REQ_GETOPTS: { /* get options */
- int replen;
+ ErlDrvSSizeT replen;
DEBUGF(("inet_ctl(%ld): GETOPTS\r\n", (long)desc->port));
#ifdef HAVE_SCTP
if (IS_SCTP(desc))
@@ -7490,6 +7763,33 @@ static int inet_ctl(inet_descriptor* desc, int cmd, char* buf, int len,
return ctl_reply(INET_REP_OK, tbuf, 2, rbuf, rsize);
}
+ case INET_REQ_IGNOREFD: {
+ DEBUGF(("inet_ctl(%ld): IGNOREFD, IGNORED = %d\r\n",
+ (long)desc->port,(int)*buf));
+
+ /*
+ * FD can only be ignored for connected TCP connections for now,
+ * possible to add UDP and SCTP support if needed.
+ */
+ if (!IS_CONNECTED(desc))
+ return ctl_error(ENOTCONN, rbuf, rsize);
+
+ if (!desc->stype == SOCK_STREAM)
+ return ctl_error(EINVAL, rbuf, rsize);
+
+ if (*buf == 1 && !desc->is_ignored) {
+ sock_select(desc, (FD_READ|FD_WRITE|FD_CLOSE|ERL_DRV_USE_NO_CALLBACK), 0);
+ desc->is_ignored = INET_IGNORE_READ;
+ } else if (*buf == 0 && desc->is_ignored) {
+ int flags = (FD_READ|FD_CLOSE|((desc->is_ignored & INET_IGNORE_WRITE)?FD_WRITE:0));
+ desc->is_ignored = INET_IGNORE_NONE;
+ sock_select(desc, flags, 1);
+ } else
+ return ctl_error(EINVAL, rbuf, rsize);
+
+ return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize);
+ }
+
#ifndef VXWORKS
case INET_REQ_GETSERVBYNAME: { /* L1 Name-String L2 Proto-String */
@@ -7550,7 +7850,7 @@ static int inet_ctl(inet_descriptor* desc, int cmd, char* buf, int len,
}
/* update statistics on output packets */
-static void inet_output_count(inet_descriptor* desc, int len)
+static void inet_output_count(inet_descriptor* desc, ErlDrvSizeT len)
{
unsigned long n = desc->send_cnt + 1;
unsigned long t = desc->send_oct[0] + len;
@@ -7570,7 +7870,7 @@ static void inet_output_count(inet_descriptor* desc, int len)
}
/* update statistics on input packets */
-static void inet_input_count(inet_descriptor* desc, int len)
+static void inet_input_count(inet_descriptor* desc, ErlDrvSizeT len)
{
unsigned long n = desc->recv_cnt + 1;
unsigned long t = desc->recv_oct[0] + len;
@@ -7693,7 +7993,7 @@ static void tcp_clear_input(tcp_descriptor* desc)
static void tcp_clear_output(tcp_descriptor* desc)
{
ErlDrvPort ix = desc->inet.port;
- int qsz = driver_sizeq(ix);
+ ErlDrvSizeT qsz = driver_sizeq(ix);
driver_deq(ix, qsz);
send_empty_out_q_msgs(INETP(desc));
@@ -7808,22 +8108,22 @@ static tcp_descriptor* tcp_inet_copy(tcp_descriptor* desc,SOCKET s,
static void tcp_close_check(tcp_descriptor* desc)
{
/* XXX:PaN - multiple clients to handle! */
- if (desc->inet.state == TCP_STATE_ACCEPTING) {
+ if (desc->inet.state == INET_STATE_ACCEPTING) {
inet_async_op *this_op = desc->inet.opt;
sock_select(INETP(desc), FD_ACCEPT, 0);
- desc->inet.state = TCP_STATE_LISTEN;
+ desc->inet.state = INET_STATE_LISTENING;
if (this_op != NULL) {
driver_demonitor_process(desc->inet.port, &(this_op->monitor));
}
async_error_am(INETP(desc), am_closed);
}
- else if (desc->inet.state == TCP_STATE_MULTI_ACCEPTING) {
+ else if (desc->inet.state == INET_STATE_MULTI_ACCEPTING) {
int id,req;
ErlDrvTermData caller;
ErlDrvMonitor monitor;
sock_select(INETP(desc), FD_ACCEPT, 0);
- desc->inet.state = TCP_STATE_LISTEN;
+ desc->inet.state = INET_STATE_LISTENING;
while (deq_multi_op(desc,&id,&req,&caller,NULL,&monitor) == 0) {
driver_demonitor_process(desc->inet.port, &monitor);
send_async_error(desc->inet.port, desc->inet.dport, id, caller, am_closed);
@@ -7831,10 +8131,10 @@ static void tcp_close_check(tcp_descriptor* desc)
clean_multi_timers(&(desc->mtd), desc->inet.port);
}
- else if (desc->inet.state == TCP_STATE_CONNECTING) {
+ else if (desc->inet.state == INET_STATE_CONNECTING) {
async_error_am(INETP(desc), am_closed);
}
- else if (desc->inet.state == TCP_STATE_CONNECTED) {
+ else if (desc->inet.state == INET_STATE_CONNECTED) {
async_error_am_all(INETP(desc), am_closed);
}
}
@@ -7861,45 +8161,69 @@ static void tcp_inet_stop(ErlDrvData e)
/* TCP requests from Erlang */
-static int tcp_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len,
- char** rbuf, int rsize)
+static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd,
+ char* buf, ErlDrvSizeT len,
+ char** rbuf, ErlDrvSizeT rsize)
{
tcp_descriptor* desc = (tcp_descriptor*)e;
+
switch(cmd) {
- case INET_REQ_OPEN: /* open socket and return internal index */
+ case INET_REQ_OPEN: { /* open socket and return internal index */
+ int domain;
DEBUGF(("tcp_inet_ctl(%ld): OPEN\r\n", (long)desc->inet.port));
- if ((len == 1) && (buf[0] == INET_AF_INET))
- return
- inet_ctl_open(INETP(desc), AF_INET, SOCK_STREAM, rbuf, rsize);
+ if (len != 2) return ctl_error(EINVAL, rbuf, rsize);
+ switch(buf[0]) {
+ case INET_AF_INET:
+ domain = AF_INET;
+ break;
#if defined(HAVE_IN6) && defined(AF_INET6)
- else if ((len == 1) && (buf[0] == INET_AF_INET6))
- return
- inet_ctl_open(INETP(desc), AF_INET6, SOCK_STREAM, rbuf, rsize);
+ case INET_AF_INET6:
+ domain = AF_INET6;
+ break;
#else
- else if ((len == 1) && (buf[0] == INET_AF_INET6))
- return ctl_xerror("eafnosupport",rbuf,rsize);
+ case INET_AF_INET6:
+ return ctl_xerror("eafnosupport", rbuf, rsize);
+ break;
#endif
- else
+ default:
return ctl_error(EINVAL, rbuf, rsize);
+ }
+ if (buf[1] != INET_TYPE_STREAM) return ctl_error(EINVAL, rbuf, rsize);
+ return inet_ctl_open(INETP(desc), domain, SOCK_STREAM, rbuf, rsize);
+ break;
+ }
- case INET_REQ_FDOPEN: /* pass in an open socket */
- DEBUGF(("tcp_inet_ctl(%ld): FDOPEN\r\n", (long)desc->inet.port));
- if ((len == 5) && (buf[0] == INET_AF_INET))
- return inet_ctl_fdopen(INETP(desc), AF_INET, SOCK_STREAM,
- (SOCKET) get_int32(buf+1), rbuf, rsize);
+ case INET_REQ_FDOPEN: { /* pass in an open socket */
+ int domain;
+ DEBUGF(("tcp_inet_ctl(%ld): FDOPEN\r\n", (long)desc->inet.port));
+ if (len != 6) return ctl_error(EINVAL, rbuf, rsize);
+ switch(buf[0]) {
+ case INET_AF_INET:
+ domain = AF_INET;
+ break;
#if defined(HAVE_IN6) && defined(AF_INET6)
- else if ((len == 5) && (buf[0] == INET_AF_INET6))
- return inet_ctl_fdopen(INETP(desc), AF_INET6, SOCK_STREAM,
- (SOCKET) get_int32(buf+1), rbuf, rsize);
+ case INET_AF_INET6:
+ domain = AF_INET6;
+ break;
+#else
+ case INET_AF_INET6:
+ return ctl_xerror("eafnosupport", rbuf, rsize);
+ break;
#endif
- else
+ default:
return ctl_error(EINVAL, rbuf, rsize);
+ }
+ if (buf[1] != INET_TYPE_STREAM) return ctl_error(EINVAL, rbuf, rsize);
+ return inet_ctl_fdopen(INETP(desc), domain, SOCK_STREAM,
+ (SOCKET) get_int32(buf+2), rbuf, rsize);
+ break;
+ }
- case TCP_REQ_LISTEN: { /* argument backlog */
+ case INET_REQ_LISTEN: { /* argument backlog */
int backlog;
DEBUGF(("tcp_inet_ctl(%ld): LISTEN\r\n", (long)desc->inet.port));
- if (desc->inet.state == TCP_STATE_CLOSED)
+ if (desc->inet.state == INET_STATE_CLOSED)
return ctl_xerror(EXBADPORT, rbuf, rsize);
if (!IS_OPEN(INETP(desc)))
return ctl_xerror(EXBADPORT, rbuf, rsize);
@@ -7910,7 +8234,7 @@ static int tcp_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len,
backlog = get_int16(buf);
if (IS_SOCKET_ERROR(sock_listen(desc->inet.s, backlog)))
return ctl_error(sock_errno(), rbuf, rsize);
- desc->inet.state = TCP_STATE_LISTEN;
+ desc->inet.state = INET_STATE_LISTENING;
return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize);
}
@@ -7946,13 +8270,13 @@ static int tcp_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len,
((sock_errno() == ERRNO_BLOCK) || /* Winsock2 */
(sock_errno() == EINPROGRESS))) { /* Unix & OSE!! */
sock_select(INETP(desc), FD_CONNECT, 1);
- desc->inet.state = TCP_STATE_CONNECTING;
+ desc->inet.state = INET_STATE_CONNECTING;
if (timeout != INET_INFINITY)
driver_set_timer(desc->inet.port, timeout);
enq_async(INETP(desc), tbuf, INET_REQ_CONNECT);
}
else if (code == 0) { /* ok we are connected */
- desc->inet.state = TCP_STATE_CONNECTED;
+ desc->inet.state = INET_STATE_CONNECTED;
if (desc->inet.active)
sock_select(INETP(desc), (FD_READ|FD_CLOSE), 1);
enq_async(INETP(desc), tbuf, INET_REQ_CONNECT);
@@ -7964,7 +8288,7 @@ static int tcp_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len,
return ctl_reply(INET_REP_OK, tbuf, 2, rbuf, rsize);
}
- case TCP_REQ_ACCEPT: { /* do async accept */
+ case INET_REQ_ACCEPT: { /* do async accept */
char tbuf[2];
unsigned timeout;
inet_address remote;
@@ -7974,14 +8298,14 @@ static int tcp_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len,
DEBUGF(("tcp_inet_ctl(%ld): ACCEPT\r\n", (long)desc->inet.port));
/* INPUT: Timeout(4) */
- if ((desc->inet.state != TCP_STATE_LISTEN && desc->inet.state != TCP_STATE_ACCEPTING &&
- desc->inet.state != TCP_STATE_MULTI_ACCEPTING) || len != 4) {
+ if ((desc->inet.state != INET_STATE_LISTENING && desc->inet.state != INET_STATE_ACCEPTING &&
+ desc->inet.state != INET_STATE_MULTI_ACCEPTING) || len != 4) {
return ctl_error(EINVAL, rbuf, rsize);
}
timeout = get_int32(buf);
- if (desc->inet.state == TCP_STATE_ACCEPTING) {
+ if (desc->inet.state == INET_STATE_ACCEPTING) {
unsigned long time_left = 0;
int oid = 0;
ErlDrvTermData ocaller = ERL_DRV_NIL;
@@ -8010,10 +8334,10 @@ static int tcp_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len,
mtd = add_multi_timer(&(desc->mtd), desc->inet.port, caller,
timeout, &tcp_inet_multi_timeout);
}
- enq_multi_op(desc, tbuf, TCP_REQ_ACCEPT, caller, mtd, &monitor);
- desc->inet.state = TCP_STATE_MULTI_ACCEPTING;
+ enq_multi_op(desc, tbuf, INET_REQ_ACCEPT, caller, mtd, &monitor);
+ desc->inet.state = INET_STATE_MULTI_ACCEPTING;
return ctl_reply(INET_REP_OK, tbuf, 2, rbuf, rsize);
- } else if (desc->inet.state == TCP_STATE_MULTI_ACCEPTING) {
+ } else if (desc->inet.state == INET_STATE_MULTI_ACCEPTING) {
ErlDrvTermData caller = driver_caller(desc->inet.port);
MultiTimerData *mtd = NULL;
ErlDrvMonitor monitor;
@@ -8025,7 +8349,7 @@ static int tcp_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len,
mtd = add_multi_timer(&(desc->mtd), desc->inet.port, caller,
timeout, &tcp_inet_multi_timeout);
}
- enq_multi_op(desc, tbuf, TCP_REQ_ACCEPT, caller, mtd, &monitor);
+ enq_multi_op(desc, tbuf, INET_REQ_ACCEPT, caller, mtd, &monitor);
return ctl_reply(INET_REP_OK, tbuf, 2, rbuf, rsize);
} else {
n = sizeof(desc->inet.remote);
@@ -8037,8 +8361,8 @@ static int tcp_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len,
&monitor) != 0) {
return ctl_xerror("noproc", rbuf, rsize);
}
- enq_async_w_tmo(INETP(desc), tbuf, TCP_REQ_ACCEPT, timeout, &monitor);
- desc->inet.state = TCP_STATE_ACCEPTING;
+ enq_async_w_tmo(INETP(desc), tbuf, INET_REQ_ACCEPT, timeout, &monitor);
+ desc->inet.state = INET_STATE_ACCEPTING;
sock_select(INETP(desc),FD_ACCEPT,1);
if (timeout != INET_INFINITY) {
driver_set_timer(desc->inet.port, timeout);
@@ -8065,8 +8389,8 @@ static int tcp_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len,
driver_select(accept_desc->inet.port, accept_desc->inet.event,
ERL_DRV_READ, 1);
#endif
- accept_desc->inet.state = TCP_STATE_CONNECTED;
- enq_async(INETP(desc), tbuf, TCP_REQ_ACCEPT);
+ accept_desc->inet.state = INET_STATE_CONNECTED;
+ enq_async(INETP(desc), tbuf, INET_REQ_ACCEPT);
async_ok_port(INETP(desc), accept_desc->inet.dport);
}
return ctl_reply(INET_REP_OK, tbuf, 2, rbuf, rsize);
@@ -8108,13 +8432,14 @@ static int tcp_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len,
if (enq_async(INETP(desc), tbuf, TCP_REQ_RECV) < 0)
return ctl_error(EALREADY, rbuf, rsize);
- if (tcp_recv(desc, n) == 0) {
+ if (INETP(desc)->is_ignored || tcp_recv(desc, n) == 0) {
if (timeout == 0)
async_error_am(INETP(desc), am_timeout);
else {
if (timeout != INET_INFINITY)
- driver_set_timer(desc->inet.port, timeout);
- sock_select(INETP(desc),(FD_READ|FD_CLOSE),1);
+ driver_set_timer(desc->inet.port, timeout);
+ if (!INETP(desc)->is_ignored)
+ sock_select(INETP(desc),(FD_READ|FD_CLOSE),1);
}
}
return ctl_reply(INET_REP_OK, tbuf, 2, rbuf, rsize);
@@ -8172,7 +8497,7 @@ static void tcp_inet_timeout(ErlDrvData e)
(long)desc->inet.port, desc->inet.s));
if ((state & INET_F_MULTI_CLIENT)) { /* Multi-client always means multi-timers */
fire_multi_timers(&(desc->mtd), desc->inet.port, e);
- } else if ((state & TCP_STATE_CONNECTED) == TCP_STATE_CONNECTED) {
+ } else if ((state & INET_STATE_CONNECTED) == INET_STATE_CONNECTED) {
if (desc->busy_on_send) {
ASSERT(IS_BUSY(INETP(desc)));
desc->inet.caller = desc->inet.busy_caller;
@@ -8192,20 +8517,20 @@ static void tcp_inet_timeout(ErlDrvData e)
async_error_am(INETP(desc), am_timeout);
}
}
- else if ((state & TCP_STATE_CONNECTING) == TCP_STATE_CONNECTING) {
+ 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));
async_error_am(INETP(desc), am_timeout);
}
- else if ((state & TCP_STATE_ACCEPTING) == TCP_STATE_ACCEPTING) {
+ else if ((state & INET_STATE_ACCEPTING) == INET_STATE_ACCEPTING) {
inet_async_op *this_op = desc->inet.opt;
/* timer is set on accept */
sock_select(INETP(desc), FD_ACCEPT, 0);
if (this_op != NULL) {
driver_demonitor_process(desc->inet.port, &(this_op->monitor));
}
- desc->inet.state = TCP_STATE_LISTEN;
+ desc->inet.state = INET_STATE_LISTENING;
async_error_am(INETP(desc), am_timeout);
}
DEBUGF(("tcp_inet_timeout(%ld) }\r\n", (long)desc->inet.port));
@@ -8223,7 +8548,7 @@ static void tcp_inet_multi_timeout(ErlDrvData e, ErlDrvTermData caller)
driver_demonitor_process(desc->inet.port, &monitor);
if (desc->multi_first == NULL) {
sock_select(INETP(desc),FD_ACCEPT,0);
- desc->inet.state = TCP_STATE_LISTEN; /* restore state */
+ desc->inet.state = INET_STATE_LISTENING; /* restore state */
}
send_async_error(desc->inet.port, desc->inet.dport, id, caller, am_timeout);
}
@@ -8239,7 +8564,7 @@ static void tcp_inet_multi_timeout(ErlDrvData e, ErlDrvTermData caller)
** but distribution still uses the tcp_inet_command!!
*/
-static void tcp_inet_command(ErlDrvData e, char *buf, int len)
+static void tcp_inet_command(ErlDrvData e, char *buf, ErlDrvSizeT len)
{
tcp_descriptor* desc = (tcp_descriptor*)e;
desc->inet.caller = driver_caller(desc->inet.port);
@@ -8289,7 +8614,7 @@ static void tcp_inet_process_exit(ErlDrvData e, ErlDrvMonitor *monitorp)
ErlDrvTermData who = driver_get_monitored_process(desc->inet.port,monitorp);
int state = desc->inet.state;
- if ((state & TCP_STATE_MULTI_ACCEPTING) == TCP_STATE_MULTI_ACCEPTING) {
+ if ((state & INET_STATE_MULTI_ACCEPTING) == INET_STATE_MULTI_ACCEPTING) {
int id,req;
MultiTimerData *timeout;
if (remove_multi_op(desc, &id, &req, who, &timeout, NULL) != 0) {
@@ -8300,15 +8625,15 @@ static void tcp_inet_process_exit(ErlDrvData e, ErlDrvMonitor *monitorp)
}
if (desc->multi_first == NULL) {
sock_select(INETP(desc),FD_ACCEPT,0);
- desc->inet.state = TCP_STATE_LISTEN; /* restore state */
+ desc->inet.state = INET_STATE_LISTENING; /* restore state */
}
- } else if ((state & TCP_STATE_ACCEPTING) == TCP_STATE_ACCEPTING) {
+ } else if ((state & INET_STATE_ACCEPTING) == INET_STATE_ACCEPTING) {
int did,drid;
ErlDrvTermData dcaller;
deq_async(INETP(desc), &did, &dcaller, &drid);
driver_cancel_timer(desc->inet.port);
sock_select(INETP(desc),FD_ACCEPT,0);
- desc->inet.state = TCP_STATE_LISTEN; /* restore state */
+ desc->inet.state = INET_STATE_LISTENING; /* restore state */
}
}
@@ -8458,8 +8783,15 @@ static int tcp_remain(tcp_descriptor* desc, int* len)
else if (tlen == 0) { /* need unknown more */
*len = 0;
if (nsz == 0) {
- if (nfill == n)
- goto error;
+ if (nfill == n) {
+ if (desc->inet.psize != 0 && desc->inet.psize > nfill) {
+ if (tcp_expand_buffer(desc, desc->inet.psize) < 0)
+ return -1;
+ return desc->inet.psize;
+ }
+ else
+ goto error;
+ }
DEBUGF((" => restart more=%d\r\n", nfill - n));
return nfill - n;
}
@@ -8498,32 +8830,29 @@ static int tcp_deliver(tcp_descriptor* desc, int len)
}
while (len > 0) {
- int code = 0;
+ int code;
inet_input_count(INETP(desc), len);
/* deliver binary? */
if (len*4 >= desc->i_buf->orig_size*3) { /* >=75% */
+ code = tcp_reply_binary_data(desc, desc->i_buf,
+ (desc->i_ptr_start -
+ desc->i_buf->orig_bytes),
+ len);
+ if (code < 0)
+ return code;
+
/* something after? */
if (desc->i_ptr_start + len == desc->i_ptr) { /* no */
- code = tcp_reply_binary_data(desc, desc->i_buf,
- (desc->i_ptr_start -
- desc->i_buf->orig_bytes),
- len);
tcp_clear_input(desc);
}
else { /* move trail to beginning of a new buffer */
- ErlDrvBinary* bin;
+ ErlDrvBinary* bin = alloc_buffer(desc->i_bufsz);
char* ptr_end = desc->i_ptr_start + len;
int sz = desc->i_ptr - ptr_end;
- bin = alloc_buffer(desc->i_bufsz);
memcpy(bin->orig_bytes, ptr_end, sz);
-
- code = tcp_reply_binary_data(desc, desc->i_buf,
- (desc->i_ptr_start-
- desc->i_buf->orig_bytes),
- len);
free_buffer(desc->i_buf);
desc->i_buf = bin;
desc->i_ptr_start = desc->i_buf->orig_bytes;
@@ -8535,17 +8864,15 @@ static int tcp_deliver(tcp_descriptor* desc, int len)
code = tcp_reply_data(desc, desc->i_ptr_start, len);
/* XXX The buffer gets thrown away on error (code < 0) */
/* Windows needs workaround for this in tcp_inet_event... */
+ if (code < 0)
+ return code;
desc->i_ptr_start += len;
if (desc->i_ptr_start == desc->i_ptr)
tcp_clear_input(desc);
else
desc->i_remain = 0;
-
}
- if (code < 0)
- return code;
-
count++;
len = 0;
@@ -8850,8 +9177,8 @@ static void tcp_inet_event(ErlDrvData e, ErlDrvEvent event)
/* socket has input:
-** 1. TCP_STATE_ACCEPTING => non block accept ?
-** 2. TCP_STATE_CONNECTED => read input
+** 1. INET_STATE_ACCEPTING => non block accept ?
+** 2. INET_STATE_CONNECTED => read input
*/
static int tcp_inet_input(tcp_descriptor* desc, HANDLE event)
{
@@ -8859,8 +9186,9 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event)
#ifdef DEBUG
long port = (long) desc->inet.port; /* Used after driver_exit() */
#endif
+ ASSERT(!INETP(desc)->is_ignored);
DEBUGF(("tcp_inet_input(%ld) {s=%d\r\n", port, desc->inet.s));
- if (desc->inet.state == TCP_STATE_ACCEPTING) {
+ if (desc->inet.state == INET_STATE_ACCEPTING) {
SOCKET s;
unsigned int len;
inet_address remote;
@@ -8875,7 +9203,7 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event)
}
sock_select(INETP(desc),FD_ACCEPT,0);
- desc->inet.state = TCP_STATE_LISTEN; /* restore state */
+ desc->inet.state = INET_STATE_LISTENING; /* restore state */
if (this_op != NULL) {
driver_demonitor_process(desc->inet.port, &(this_op->monitor));
@@ -8915,11 +9243,11 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event)
driver_select(accept_desc->inet.port, accept_desc->inet.event,
ERL_DRV_READ, 1);
#endif
- accept_desc->inet.state = TCP_STATE_CONNECTED;
+ accept_desc->inet.state = INET_STATE_CONNECTED;
ret = async_ok_port(INETP(desc), accept_desc->inet.dport);
goto done;
}
- } else if (desc->inet.state == TCP_STATE_MULTI_ACCEPTING) {
+ } else if (desc->inet.state == INET_STATE_MULTI_ACCEPTING) {
SOCKET s;
unsigned int len;
inet_address remote;
@@ -8931,7 +9259,7 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event)
int times = 0;
#endif
- while (desc->inet.state == TCP_STATE_MULTI_ACCEPTING) {
+ while (desc->inet.state == INET_STATE_MULTI_ACCEPTING) {
len = sizeof(desc->inet.remote);
s = sock_accept(desc->inet.s, (struct sockaddr*) &remote, &len);
@@ -8951,7 +9279,7 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event)
if (desc->multi_first == NULL) {
sock_select(INETP(desc),FD_ACCEPT,0);
- desc->inet.state = TCP_STATE_LISTEN; /* restore state */
+ desc->inet.state = INET_STATE_LISTENING; /* restore state */
}
if (timeout != NULL) {
@@ -8982,7 +9310,7 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event)
driver_select(accept_desc->inet.port, accept_desc->inet.event,
ERL_DRV_READ, 1);
#endif
- accept_desc->inet.state = TCP_STATE_CONNECTED;
+ accept_desc->inet.state = INET_STATE_CONNECTED;
ret = send_async_ok_port(desc->inet.port, desc->inet.dport,
id, caller, accept_desc->inet.dport);
}
@@ -9065,12 +9393,12 @@ static int tcp_send_error(tcp_descriptor* desc, int err)
*/
static int tcp_sendv(tcp_descriptor* desc, ErlIOVec* ev)
{
- int sz;
+ ErlDrvSizeT sz;
char buf[4];
- int h_len;
- int n;
+ ErlDrvSizeT h_len;
+ ssize_t n;
ErlDrvPort ix = desc->inet.port;
- int len = ev->size;
+ ErlDrvSizeT len = ev->size;
switch(desc->inet.htype) {
case TCP_PB_1:
@@ -9118,9 +9446,13 @@ static int tcp_sendv(tcp_descriptor* desc, ErlIOVec* ev)
else {
int vsize = (ev->vsize > MAX_VSIZE) ? MAX_VSIZE : ev->vsize;
- DEBUGF(("tcp_sendv(%ld): s=%d, about to send %d,%d bytes\r\n",
- (long)desc->inet.port, desc->inet.s, h_len, len));
- if (desc->tcp_add_flags & TCP_ADDF_DELAY_SEND) {
+ DEBUGF(("tcp_sendv(%ld): s=%d, about to send "LLU","LLU" bytes\r\n",
+ (long)desc->inet.port, desc->inet.s, (llu_t)h_len, (llu_t)len));
+
+ if (INETP(desc)->is_ignored) {
+ INETP(desc)->is_ignored |= INET_IGNORE_WRITE;
+ n = 0;
+ } else if (desc->tcp_add_flags & TCP_ADDF_DELAY_SEND) {
n = 0;
} else if (IS_SOCKET_ERROR(sock_sendv(desc->inet.s, ev->iov,
vsize, &n, 0))) {
@@ -9141,14 +9473,17 @@ static int tcp_sendv(tcp_descriptor* desc, ErlIOVec* ev)
return 0;
}
else {
- DEBUGF(("tcp_sendv(%ld): s=%d, only sent %d/%d of %d/%d bytes/items\r\n",
- (long)desc->inet.port, desc->inet.s, n, vsize, ev->size, ev->vsize));
+ DEBUGF(("tcp_sendv(%ld): s=%d, only sent "
+ LLU"/%d of "LLU"/%d bytes/items\r\n",
+ (long)desc->inet.port, desc->inet.s,
+ (llu_t)n, vsize, (llu_t)ev->size, ev->vsize));
}
DEBUGF(("tcp_sendv(%ld): s=%d, Send failed, queuing\r\n",
(long)desc->inet.port, desc->inet.s));
driver_enqv(ix, ev, n);
- sock_select(INETP(desc),(FD_WRITE|FD_CLOSE), 1);
+ if (!INETP(desc)->is_ignored)
+ sock_select(INETP(desc),(FD_WRITE|FD_CLOSE), 1);
}
return 0;
}
@@ -9156,7 +9491,7 @@ static int tcp_sendv(tcp_descriptor* desc, ErlIOVec* ev)
/*
** Send non blocking data
*/
-static int tcp_send(tcp_descriptor* desc, char* ptr, int len)
+static int tcp_send(tcp_descriptor* desc, char* ptr, ErlDrvSizeT len)
{
int sz;
char buf[4];
@@ -9211,9 +9546,12 @@ static int tcp_send(tcp_descriptor* desc, char* ptr, int len)
iov[1].iov_base = ptr;
iov[1].iov_len = len;
- DEBUGF(("tcp_send(%ld): s=%d, about to send %d,%d bytes\r\n",
- (long)desc->inet.port, desc->inet.s, h_len, len));
- if (desc->tcp_add_flags & TCP_ADDF_DELAY_SEND) {
+ DEBUGF(("tcp_send(%ld): s=%d, about to send "LLU","LLU" bytes\r\n",
+ (long)desc->inet.port, desc->inet.s, (llu_t)h_len, (llu_t)len));
+ if (INETP(desc)->is_ignored) {
+ INETP(desc)->is_ignored |= INET_IGNORE_WRITE;
+ n = 0;
+ } else if (desc->tcp_add_flags & TCP_ADDF_DELAY_SEND) {
sock_send(desc->inet.s, buf, 0, 0);
n = 0;
} else if (IS_SOCKET_ERROR(sock_sendv(desc->inet.s,iov,2,&n,0))) {
@@ -9244,7 +9582,8 @@ static int tcp_send(tcp_descriptor* desc, char* ptr, int len)
n -= h_len;
driver_enq(ix, ptr+n, len-n);
}
- sock_select(INETP(desc),(FD_WRITE|FD_CLOSE), 1);
+ if (!INETP(desc)->is_ignored)
+ sock_select(INETP(desc),(FD_WRITE|FD_CLOSE), 1);
}
return 0;
}
@@ -9260,17 +9599,18 @@ static void tcp_inet_drv_input(ErlDrvData data, ErlDrvEvent event)
}
/* socket ready for ouput:
-** 1. TCP_STATE_CONNECTING => non block connect ?
-** 2. TCP_STATE_CONNECTED => write output
+** 1. INET_STATE_CONNECTING => non block connect ?
+** 2. INET_STATE_CONNECTED => write output
*/
static int tcp_inet_output(tcp_descriptor* desc, HANDLE event)
{
int ret = 0;
ErlDrvPort ix = desc->inet.port;
+ ASSERT(!INETP(desc)->is_ignored);
DEBUGF(("tcp_inet_output(%ld) {s=%d\r\n",
(long)desc->inet.port, desc->inet.s));
- if (desc->inet.state == TCP_STATE_CONNECTING) {
+ if (desc->inet.state == INET_STATE_CONNECTING) {
sock_select(INETP(desc),FD_CONNECT,0);
driver_cancel_timer(ix); /* posssibly cancel a timer */
@@ -9290,7 +9630,7 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event)
(struct sockaddr*) &desc->inet.remote, &sz);
if (IS_SOCKET_ERROR(code)) {
- desc->inet.state = TCP_STATE_BOUND; /* restore state */
+ desc->inet.state = INET_STATE_BOUND; /* restore state */
ret = async_error(INETP(desc), sock_errno());
goto done;
}
@@ -9303,15 +9643,15 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event)
(void *)&error, &sz);
if ((code < 0) || error) {
- desc->inet.state = TCP_STATE_BOUND; /* restore state */
+ desc->inet.state = INET_STATE_BOUND; /* restore state */
ret = async_error(INETP(desc), error);
goto done;
}
}
-#endif /* SOCKOPT_CONNECT_STAT */
+#endif /* SO_ERROR */
#endif /* !__WIN32__ */
- desc->inet.state = TCP_STATE_CONNECTED;
+ desc->inet.state = INET_STATE_CONNECTED;
if (desc->inet.active)
sock_select(INETP(desc),(FD_READ|FD_CLOSE),1);
async_ok(INETP(desc));
@@ -9319,7 +9659,7 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event)
else if (IS_CONNECTED(INETP(desc))) {
for (;;) {
int vsize;
- int n;
+ ssize_t n;
SysIOVec* iov;
if ((iov = driver_peekq(ix, &vsize)) == NULL) {
@@ -9411,6 +9751,59 @@ static int should_use_so_bsdcompat(void)
#endif /* __linux__ */
#endif /* HAVE_SO_BSDCOMPAT */
+
+
+#ifdef HAVE_SCTP
+/* Copy a descriptor, by creating a new port with same settings
+ * as the descriptor desc.
+ * return NULL on error (ENFILE no ports avail)
+ */
+static udp_descriptor* sctp_inet_copy(udp_descriptor* desc, SOCKET s, int* err)
+{
+ ErlDrvPort port = desc->inet.port;
+ udp_descriptor* copy_desc;
+
+ copy_desc = (udp_descriptor*) sctp_inet_start(port, NULL);
+
+ /* Setup event if needed */
+ if ((copy_desc->inet.s = s) != INVALID_SOCKET) {
+ if ((copy_desc->inet.event = sock_create_event(INETP(copy_desc))) ==
+ INVALID_EVENT) {
+ *err = sock_errno();
+ FREE(copy_desc);
+ return NULL;
+ }
+ }
+
+ /* Some flags must be inherited at this point */
+ copy_desc->inet.mode = desc->inet.mode;
+ copy_desc->inet.exitf = desc->inet.exitf;
+ copy_desc->inet.bit8f = desc->inet.bit8f;
+ copy_desc->inet.deliver = desc->inet.deliver;
+ copy_desc->inet.htype = desc->inet.htype;
+ copy_desc->inet.psize = desc->inet.psize;
+ copy_desc->inet.stype = desc->inet.stype;
+ copy_desc->inet.sfamily = desc->inet.sfamily;
+ copy_desc->inet.hsz = desc->inet.hsz;
+ copy_desc->inet.bufsz = desc->inet.bufsz;
+
+ /* The new port will be linked and connected to the caller */
+ port = driver_create_port(port, desc->inet.caller, "sctp_inet",
+ (ErlDrvData) copy_desc);
+ if ((long)port == -1) {
+ *err = ENFILE;
+ FREE(copy_desc);
+ return NULL;
+ }
+ copy_desc->inet.port = port;
+ copy_desc->inet.dport = driver_mk_port(port);
+ *err = 0;
+ return copy_desc;
+}
+#endif
+
+
+
static int packet_inet_init()
{
return 0;
@@ -9429,6 +9822,9 @@ static ErlDrvData packet_inet_start(ErlDrvPort port, char* args, int protocol)
return ERL_DRV_ERROR_ERRNO;
desc->read_packets = INET_PACKET_POLL;
+ desc->i_bufsz = 0;
+ desc->i_buf = NULL;
+ desc->i_ptr = NULL;
return drvd;
}
@@ -9453,6 +9849,10 @@ static void packet_inet_stop(ErlDrvData e)
*/
udp_descriptor * udesc = (udp_descriptor*) e;
inet_descriptor* descr = INETP(udesc);
+ if (udesc->i_buf != NULL) {
+ release_buffer(udesc->i_buf);
+ udesc->i_buf = NULL;
+ }
ASSERT(NO_SUBSCRIBERS(&(descr->empty_out_q_subs)));
inet_stop(descr);
@@ -9470,28 +9870,38 @@ static int packet_error(udp_descriptor* udesc, int err)
/*
** Various functions accessible via "port_control" on the Erlang side:
*/
-static int packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len,
- char** rbuf, int rsize)
+static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf,
+ ErlDrvSizeT len, char** rbuf, ErlDrvSizeT rsize)
{
- int replen;
+ ErlDrvSSizeT replen;
udp_descriptor * udesc = (udp_descriptor *) e;
inet_descriptor* desc = INETP(udesc);
int type = SOCK_DGRAM;
- int af;
-#ifdef HAVE_SCTP
- if (IS_SCTP(desc)) type = SOCK_SEQPACKET;
-#endif
+ int af = AF_INET;
switch(cmd) {
case INET_REQ_OPEN: /* open socket and return internal index */
DEBUGF(("packet_inet_ctl(%ld): OPEN\r\n", (long)desc->port));
- if (len != 1) {
+ if (len != 2) {
return ctl_error(EINVAL, rbuf, rsize);
}
switch (buf[0]) {
case INET_AF_INET: af = AF_INET; break;
#if defined(HAVE_IN6) && defined(AF_INET6)
- case INET_AF_INET6: af = AF_INET6; break;
+ case INET_AF_INET6: af = AF_INET6; break;
+#else
+ case INET_AF_INET6:
+ return ctl_xerror("eafnosupport", rbuf, rsize);
+ break;
+#endif
+ default:
+ return ctl_error(EINVAL, rbuf, rsize);
+ }
+ switch (buf[1]) {
+ case INET_TYPE_STREAM: type = SOCK_STREAM; break;
+ case INET_TYPE_DGRAM: type = SOCK_DGRAM; break;
+#ifdef HAVE_SCTP
+ case INET_TYPE_SEQPACKET: type = SOCK_SEQPACKET; break;
#endif
default:
return ctl_error(EINVAL, rbuf, rsize);
@@ -9518,18 +9928,35 @@ static int packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len,
return replen;
- case INET_REQ_FDOPEN: /* pass in an open (and bound) socket */
+ case INET_REQ_FDOPEN: { /* pass in an open (and bound) socket */
+ SOCKET s;
DEBUGF(("packet inet_ctl(%ld): FDOPEN\r\n", (long)desc->port));
- if ((len == 5) && (buf[0] == INET_AF_INET))
- replen = inet_ctl_fdopen(desc, AF_INET, SOCK_DGRAM,
- (SOCKET)get_int32(buf+1),rbuf,rsize);
+ if (len != 6) {
+ return ctl_error(EINVAL, rbuf, rsize);
+ }
+ switch (buf[0]) {
+ case INET_AF_INET: af = AF_INET; break;
#if defined(HAVE_IN6) && defined(AF_INET6)
- else if ((len == 5) && (buf[0] == INET_AF_INET6))
- replen = inet_ctl_fdopen(desc, AF_INET6, SOCK_DGRAM,
- (SOCKET)get_int32(buf+1),rbuf,rsize);
+ case INET_AF_INET6: af = AF_INET6; break;
+#else
+ case INET_AF_INET6:
+ return ctl_xerror("eafnosupport", rbuf, rsize);
+ break;
#endif
- else
+ default:
+ return ctl_error(EINVAL, rbuf, rsize);
+ }
+ switch (buf[1]) {
+ case INET_TYPE_STREAM: type = SOCK_STREAM; break;
+ case INET_TYPE_DGRAM: type = SOCK_DGRAM; break;
+#ifdef HAVE_SCTP
+ case INET_TYPE_SEQPACKET: type = SOCK_SEQPACKET; break;
+#endif
+ default:
return ctl_error(EINVAL, rbuf, rsize);
+ }
+ s = (SOCKET)get_int32(buf+2);
+ replen = inet_ctl_fdopen(desc, af, type, s, rbuf, rsize);
if ((*rbuf)[0] != INET_REP_ERROR) {
if (desc->active)
@@ -9549,13 +9976,13 @@ static int packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len,
#endif
}
return replen;
+ }
case INET_REQ_CLOSE:
DEBUGF(("packet_inet_ctl(%ld): CLOSE\r\n", (long)desc->port));
erl_inet_close(desc);
return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize);
- return 0;
case INET_REQ_CONNECT: {
@@ -9568,8 +9995,9 @@ static int packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len,
*/
int code;
char tbuf[2];
+#ifdef HAVE_SCTP
unsigned timeout;
-
+#endif
DEBUGF(("packet_inet_ctl(%ld): CONNECT\r\n", (long)desc->port));
/* INPUT: [ Timeout(4), Port(2), Address(N) ] */
@@ -9601,14 +10029,14 @@ static int packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len,
if (IS_SOCKET_ERROR(code) && (sock_errno() == EINPROGRESS)) {
/* XXX: Unix only -- WinSock would have a different cond! */
- desc->state = SCTP_STATE_CONNECTING;
+ desc->state = INET_STATE_CONNECTING;
if (timeout != INET_INFINITY)
driver_set_timer(desc->port, timeout);
enq_async(desc, tbuf, INET_REQ_CONNECT);
}
else if (code == 0) { /* OK we are connected */
sock_select(desc, FD_CONNECT, 0);
- desc->state = PACKET_STATE_CONNECTED;
+ desc->state = INET_STATE_CONNECTED;
enq_async(desc, tbuf, INET_REQ_CONNECT);
async_ok(desc);
}
@@ -9630,7 +10058,7 @@ static int packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len,
else if (len < 6)
return ctl_error(EINVAL, rbuf, rsize);
else {
- timeout = get_int32(buf); /* IGNORED */
+ /* Ignore timeout */
buf += 4;
len -= 4;
if (inet_set_address(desc->sfamily,
@@ -9654,11 +10082,11 @@ static int packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len,
}
#ifdef HAVE_SCTP
- case SCTP_REQ_LISTEN:
+ case INET_REQ_LISTEN:
{ /* LISTEN is only for SCTP sockets, not UDP. This code is borrowed
from the TCP section. Returns: {ok,[]} on success.
*/
- int flag;
+ int backlog;
DEBUGF(("packet_inet_ctl(%ld): LISTEN\r\n", (long)desc->port));
if (!IS_SCTP(desc))
@@ -9668,15 +10096,14 @@ static int packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len,
if (!IS_BOUND(desc))
return ctl_xerror(EXBADSEQ, rbuf, rsize);
- /* The arg is a binary value: 1:enable, 0:disable */
- if (len != 1)
+ if (len != 2)
return ctl_error(EINVAL, rbuf, rsize);
- flag = get_int8(buf);
+ backlog = get_int16(buf);
- if (IS_SOCKET_ERROR(sock_listen(desc->s, flag)))
+ if (IS_SOCKET_ERROR(sock_listen(desc->s, backlog)))
return ctl_error(sock_errno(), rbuf, rsize);
- desc->state = SCTP_STATE_LISTEN; /* XXX: not used? */
+ desc->state = INET_STATE_LISTENING; /* XXX: not used? */
return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize);
}
@@ -9701,7 +10128,7 @@ static int packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len,
/* List item format: Port(2), IP(4|16) -- compatible with
"inet_set_address": */
inet_address tmp;
- int alen = buf + len - curr;
+ ErlDrvSizeT alen = buf + len - curr;
curr = inet_set_address(desc->sfamily, &tmp, curr, &alen);
if (curr == NULL)
return ctl_error(EINVAL, rbuf, rsize);
@@ -9722,6 +10149,46 @@ static int packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len,
return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize);
}
+
+ case SCTP_REQ_PEELOFF:
+ {
+ Uint32 assoc_id;
+ udp_descriptor* new_udesc;
+ int err;
+ SOCKET new_socket;
+
+ DEBUGF(("packet_inet_ctl(%ld): PEELOFF\r\n", (long)desc->port));
+ if (!IS_SCTP(desc))
+ return ctl_xerror(EXBADPORT, rbuf, rsize);
+ if (!IS_OPEN(desc))
+ return ctl_xerror(EXBADPORT, rbuf, rsize);
+ if (!IS_BOUND(desc))
+ return ctl_xerror(EXBADSEQ, rbuf, rsize);
+ if (! p_sctp_peeloff)
+ return ctl_error(ENOTSUP, rbuf, rsize);
+
+ if (len != 4)
+ return ctl_error(EINVAL, rbuf, rsize);
+ assoc_id = get_int32(buf);
+
+ new_socket = p_sctp_peeloff(desc->s, assoc_id);
+ if (IS_SOCKET_ERROR(new_socket)) {
+ return ctl_error(sock_errno(), rbuf, rsize);
+ }
+
+ desc->caller = driver_caller(desc->port);
+ if ((new_udesc = sctp_inet_copy(udesc, new_socket, &err)) == NULL) {
+ sock_close(new_socket);
+ desc->caller = 0;
+ return ctl_error(err, rbuf, rsize);
+ }
+ new_udesc->inet.state = INET_STATE_CONNECTED;
+ new_udesc->inet.stype = SOCK_STREAM;
+
+ inet_reply_ok_port(desc, new_udesc->inet.dport);
+ (*rbuf)[0] = INET_REP;
+ return 1;
+ }
#endif /* HAVE_SCTP */
case PACKET_REQ_RECV:
@@ -9786,13 +10253,13 @@ static void packet_inet_timeout(ErlDrvData e)
** There is no destination address -- SCTYP send is performed over
** an existing association, using "sctp_sndrcvinfo" specified.
*/
-static void packet_inet_command(ErlDrvData e, char* buf, int len)
+static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len)
{
udp_descriptor * udesc= (udp_descriptor*) e;
inet_descriptor* desc = INETP(udesc);
char* ptr = buf;
char* qtr;
- int sz;
+ ErlDrvSizeT sz;
int code;
inet_address other;
@@ -9810,7 +10277,7 @@ static void packet_inet_command(ErlDrvData e, char* buf, int len)
#ifdef HAVE_SCTP
if (IS_SCTP(desc))
{
- int data_len;
+ ErlDrvSizeT data_len;
struct iovec iov[1]; /* For real data */
struct msghdr mhdr; /* Message wrapper */
struct sctp_sndrcvinfo *sri; /* The actual ancilary data */
@@ -9846,6 +10313,7 @@ static void packet_inet_command(ErlDrvData e, char* buf, int len)
mhdr.msg_iovlen = 1;
mhdr.msg_control = cmsg.ancd; /* For ancilary data */
mhdr.msg_controllen = cmsg.hdr.cmsg_len;
+ VALGRIND_MAKE_MEM_DEFINED(mhdr.msg_control, mhdr.msg_controllen); /*suppress "uninitialised bytes"*/
mhdr.msg_flags = 0; /* Not used with "sendmsg" */
/* Now do the actual sending. NB: "flags" in "sendmsg" itself are NOT
@@ -9920,12 +10388,8 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event)
{
inet_descriptor* desc = INETP(udesc);
int n;
- unsigned int len;
inet_address other;
char abuf[sizeof(inet_address)]; /* buffer address; enough??? */
- int sz;
- char* ptr;
- ErlDrvBinary* buf; /* binary */
int packet_count = udesc->read_packets;
int count = 0; /* number of packets delivered to owner */
#ifdef HAVE_SCTP
@@ -9936,23 +10400,39 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event)
#endif
while(packet_count--) {
- len = sizeof(other);
- sz = desc->bufsz;
- /* Allocate space for message and address. NB: "bufsz" is in "desc",
- but the "buf" itself is allocated separately:
- */
- if ((buf = alloc_buffer(sz+len)) == NULL)
- return packet_error(udesc, ENOMEM);
- ptr = buf->orig_bytes + len; /* pointer to message part */
+ unsigned int len = sizeof(other);
+
+ /* udesc->i_buf is only kept between SCTP fragments */
+ if (udesc->i_buf == NULL) {
+ udesc->i_bufsz = desc->bufsz + len;
+ if ((udesc->i_buf = alloc_buffer(udesc->i_bufsz)) == NULL)
+ return packet_error(udesc, ENOMEM);
+ /* pointer to message start */
+ udesc->i_ptr = udesc->i_buf->orig_bytes + len;
+ } else {
+ ErlDrvBinary* tmp;
+ int bufsz;
+ bufsz = desc->bufsz + (udesc->i_ptr - udesc->i_buf->orig_bytes);
+ if ((tmp = realloc_buffer(udesc->i_buf, bufsz)) == NULL) {
+ release_buffer(udesc->i_buf);
+ udesc->i_buf = NULL;
+ return packet_error(udesc, ENOMEM);
+ } else {
+ udesc->i_ptr =
+ tmp->orig_bytes + (udesc->i_ptr - udesc->i_buf->orig_bytes);
+ udesc->i_buf = tmp;
+ udesc->i_bufsz = bufsz;
+ }
+ }
/* Note: On Windows NT, recvfrom() fails if the socket is connected. */
#ifdef HAVE_SCTP
/* For SCTP we must use recvmsg() */
if (IS_SCTP(desc)) {
- iov->iov_base = ptr; /* Data will come here */
- iov->iov_len = sz; /* Remaining buffer space */
+ iov->iov_base = udesc->i_ptr; /* Data will come here */
+ iov->iov_len = desc->bufsz; /* Remaining buffer space */
- mhdr.msg_name = &other; /* Peer addr comes into "other" */
+ mhdr.msg_name = &other; /* Peer addr comes into "other" */
mhdr.msg_namelen = len;
mhdr.msg_iov = iov;
mhdr.msg_iovlen = 1;
@@ -9962,42 +10442,28 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event)
/* Do the actual SCTP receive: */
n = sock_recvmsg(desc->s, &mhdr, 0);
+ len = mhdr.msg_namelen;
goto check_result;
}
#endif
/* Use recv() instead on connected sockets. */
if ((desc->state & INET_F_ACTIVE)) {
- n = sock_recv(desc->s, ptr, sz, 0);
+ n = sock_recv(desc->s, udesc->i_ptr, desc->bufsz, 0);
other = desc->remote;
+ goto check_result;
}
- else
- n = sock_recvfrom(desc->s, ptr, sz, 0, &other.sa, &len);
-
-#ifdef HAVE_SCTP
+ n = sock_recvfrom(desc->s, udesc->i_ptr, desc->bufsz,
+ 0, &other.sa, &len);
check_result:
-#endif
/* Analyse the result: */
- if (IS_SOCKET_ERROR(n)
-#ifdef HAVE_SCTP
- || (short_recv = (IS_SCTP(desc) && !(mhdr.msg_flags & MSG_EOR)))
- /* NB: here we check for EOR not being set -- this is an error as
- well, we don't support partial msgs:
- */
-#endif
- ) {
+ if (IS_SOCKET_ERROR(n)) {
int err = sock_errno();
- release_buffer(buf);
if (err != ERRNO_BLOCK) {
+ /* real error */
+ release_buffer(udesc->i_buf);
+ udesc->i_buf = NULL;
if (!desc->active) {
-#ifdef HAVE_SCTP
- if (short_recv) {
- async_error_am(desc, am_short_recv);
- } else {
- async_error(desc, err);
- }
-#else
async_error(desc, err);
-#endif
driver_cancel_timer(desc->port);
sock_select(desc,FD_READ,0);
}
@@ -10005,46 +10471,72 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event)
/* This is for an active desc only: */
packet_error_message(udesc, err);
}
+ return count;
}
- else if (!desc->active)
+ /* would block error - try again */
+ if (!desc->active
+#ifdef HAVE_SCTP
+ || short_recv
+#endif
+ ) {
sock_select(desc,FD_READ,1);
+ }
return count; /* strange, not ready */
}
- else {
- int offs;
- int nsz;
+
+#ifdef HAVE_SCTP
+ if (IS_SCTP(desc) && (short_recv = !(mhdr.msg_flags & MSG_EOR))) {
+ /* SCTP non-final message fragment */
+ inet_input_count(desc, n);
+ udesc->i_ptr += n;
+ continue; /* wait for more fragments */
+ }
+#endif
+
+ {
+ /* message received */
int code;
- unsigned int alen = len;
void * extra = NULL;
+ char * ptr;
+ int nsz;
inet_input_count(desc, n);
- inet_get_address(desc->sfamily, abuf, &other, &alen);
- /* Copy formatted address to the buffer allocated; "alen" is the
- actual length which must be <= than the original reserved "len".
+ udesc->i_ptr += n;
+ inet_get_address(desc->sfamily, abuf, &other, &len);
+ /* Copy formatted address to the buffer allocated; "len" is the
+ actual length which must be <= than the original reserved.
This means that the addr + data in the buffer are contiguous,
- but they may start not at the "orig_bytes", but with some "offs"
- from them:
+ but they may start not at the "orig_bytes", instead at "ptr":
*/
- ASSERT (alen <= len);
- sys_memcpy(ptr - alen, abuf, alen);
- ptr -= alen;
- nsz = n + alen; /* nsz = data + address */
- offs = ptr - buf->orig_bytes; /* initial pointer offset */
+ ASSERT (len <= sizeof(other));
+ ptr = udesc->i_buf->orig_bytes + sizeof(other) - len;
+ sys_memcpy(ptr, abuf, len);
+
+ nsz = udesc->i_ptr - ptr;
/* Check if we need to reallocate binary */
- if ((desc->mode == INET_MODE_BINARY) &&
- (desc->hsz < n) && (nsz < BIN_REALLOC_LIMIT(sz))) {
+ if ((desc->mode == INET_MODE_BINARY)
+ && (desc->hsz < (nsz - len))
+ && (nsz + BIN_REALLOC_MARGIN(desc->bufsz) < udesc->i_bufsz)) {
ErlDrvBinary* tmp;
- if ((tmp = realloc_buffer(buf,nsz+offs)) != NULL)
- buf = tmp;
+ int bufsz;
+ bufsz = udesc->i_ptr - udesc->i_buf->orig_bytes;
+ if ((tmp = realloc_buffer(udesc->i_buf, bufsz)) != NULL) {
+ udesc->i_buf = tmp;
+ udesc->i_bufsz = bufsz;
+ udesc->i_ptr = NULL; /* not used from here */
+ }
}
#ifdef HAVE_SCTP
if (IS_SCTP(desc)) extra = &mhdr;
#endif
/* Actual parsing and return of the data received, occur here: */
- code = packet_reply_binary_data(desc, (unsigned int)alen,
- buf, offs, nsz, extra);
- free_buffer(buf);
+ code = packet_reply_binary_data(desc, len, udesc->i_buf,
+ (sizeof(other) - len),
+ nsz,
+ extra);
+ free_buffer(udesc->i_buf);
+ udesc->i_buf = NULL;
if (code < 0)
return count;
count++;
@@ -10054,7 +10546,17 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event)
return count; /* passive mode (read one packet only) */
}
}
+ } /* while(packet_count--) { */
+
+ /* we ran out of tries (packet_count) either on an active socket
+ * that got that many messages or an SCTP socket that got that
+ * many message fragments but still not the final
+ */
+#ifdef HAVE_SCTP
+ if (short_recv) {
+ sock_select(desc, FD_READ, 1);
}
+#endif
return count;
}
@@ -10064,7 +10566,7 @@ static void packet_inet_drv_output(ErlDrvData e, ErlDrvEvent event)
}
/* UDP/SCTP socket ready for output:
-** This is a Back-End for Non-Block SCTP Connect (SCTP_STATE_CONNECTING)
+** This is a Back-End for Non-Block SCTP Connect (INET_STATE_CONNECTING)
*/
static int packet_inet_output(udp_descriptor* udesc, HANDLE event)
{
@@ -10075,7 +10577,7 @@ static int packet_inet_output(udp_descriptor* udesc, HANDLE event)
DEBUGF(("packet_inet_output(%ld) {s=%d\r\n",
(long)desc->port, desc->s));
- if (desc->state == SCTP_STATE_CONNECTING) {
+ if (desc->state == INET_STATE_CONNECTING) {
sock_select(desc, FD_CONNECT, 0);
driver_cancel_timer(ix); /* posssibly cancel a timer */
@@ -10095,7 +10597,7 @@ static int packet_inet_output(udp_descriptor* udesc, HANDLE event)
(struct sockaddr*) &desc->remote, &sz);
if (IS_SOCKET_ERROR(code)) {
- desc->state = PACKET_STATE_BOUND; /* restore state */
+ desc->state = INET_STATE_BOUND; /* restore state */
ret = async_error(desc, sock_errno());
goto done;
}
@@ -10108,15 +10610,15 @@ static int packet_inet_output(udp_descriptor* udesc, HANDLE event)
(void *)&error, &sz);
if ((code < 0) || error) {
- desc->state = PACKET_STATE_BOUND; /* restore state */
+ desc->state = INET_STATE_BOUND; /* restore state */
ret = async_error(desc, error);
goto done;
}
}
-#endif /* SOCKOPT_CONNECT_STAT */
+#endif /* SO_ERROR */
#endif /* !__WIN32__ */
- desc->state = PACKET_STATE_CONNECTED;
+ desc->state = INET_STATE_CONNECTED;
async_ok(desc);
}
else {
@@ -10523,7 +11025,7 @@ int erts_sock_connect(erts_sock_t socket, byte *ip_addr, int len, Uint16 port)
{
SOCKET s = (SOCKET) socket;
char buf[2 + 4];
- int blen = 6;
+ ErlDrvSizeT blen = 6;
inet_address addr;
if (socket == ERTS_SOCK_INVALID_SOCKET || len != 4)
diff --git a/erts/emulator/drivers/common/ram_file_drv.c b/erts/emulator/drivers/common/ram_file_drv.c
index abedcc933a..a109e40333 100644
--- a/erts/emulator/drivers/common/ram_file_drv.c
+++ b/erts/emulator/drivers/common/ram_file_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2010. All Rights Reserved.
+ * Copyright Ericsson AB 1997-2011. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -98,7 +98,7 @@ typedef unsigned char uchar;
static ErlDrvData rfile_start(ErlDrvPort, char*);
static int rfile_init(void);
static void rfile_stop(ErlDrvData);
-static void rfile_command(ErlDrvData, char*, int);
+static void rfile_command(ErlDrvData, char*, ErlDrvSizeT);
struct erl_drv_entry ram_file_driver_entry = {
@@ -108,7 +108,23 @@ struct erl_drv_entry ram_file_driver_entry = {
rfile_command,
NULL,
NULL,
- "ram_file_drv"
+ "ram_file_drv",
+ NULL,
+ NULL, /* handle */
+ NULL, /* control */
+ NULL, /* timeout */
+ NULL, /* outputv */
+ NULL, /* ready_async */
+ NULL, /* flush */
+ NULL, /* call */
+ NULL, /* event */
+ ERL_DRV_EXTENDED_MARKER,
+ ERL_DRV_EXTENDED_MAJOR_VERSION,
+ ERL_DRV_EXTENDED_MINOR_VERSION,
+ 0,
+ NULL,
+ NULL,
+ NULL,
};
/* A File is represented as a array of bytes, this array is
@@ -121,9 +137,9 @@ typedef struct ram_file {
int flags; /* flags read/write */
ErlDrvBinary* bin; /* binary to hold binary file */
char* buf; /* buffer start (in binary) */
- int size; /* buffer size (allocated) */
- int cur; /* current position in buffer */
- int end; /* end position in buffer */
+ ErlDrvSSizeT size; /* buffer size (allocated) */
+ ErlDrvSSizeT cur; /* current position in buffer */
+ ErlDrvSSizeT end; /* end position in buffer */
} RamFile;
#ifdef LOADABLE
@@ -211,7 +227,7 @@ static int reply(RamFile *f, int ok, int err)
return 0;
}
-static int numeric_reply(RamFile *f, int result)
+static int numeric_reply(RamFile *f, ErlDrvSSizeT result)
{
char tmp[5];
@@ -231,7 +247,8 @@ static int numeric_reply(RamFile *f, int result)
/* install bin as the new binary reset all pointer */
-static void ram_file_set(RamFile *f, ErlDrvBinary *bin, int bsize, int len)
+static void ram_file_set(RamFile *f, ErlDrvBinary *bin,
+ ErlDrvSSizeT bsize, ErlDrvSSizeT len)
{
f->size = bsize;
f->buf = bin->orig_bytes;
@@ -240,9 +257,9 @@ static void ram_file_set(RamFile *f, ErlDrvBinary *bin, int bsize, int len)
f->bin = bin;
}
-static int ram_file_init(RamFile *f, char *buf, int count, int *error)
+static int ram_file_init(RamFile *f, char *buf, ErlDrvSSizeT count, int *error)
{
- int bsize;
+ ErlDrvSSizeT bsize;
ErlDrvBinary* bin;
if (count < 0) {
@@ -268,9 +285,9 @@ static int ram_file_init(RamFile *f, char *buf, int count, int *error)
return count;
}
-static int ram_file_expand(RamFile *f, int size, int *error)
+static ErlDrvSSizeT ram_file_expand(RamFile *f, ErlDrvSSizeT size, int *error)
{
- int bsize;
+ ErlDrvSSizeT bsize;
ErlDrvBinary* bin;
if (size < 0) {
@@ -298,10 +315,10 @@ static int ram_file_expand(RamFile *f, int size, int *error)
}
-static int ram_file_write(RamFile *f, char *buf, int len,
- int *location, int *error)
+static ErlDrvSSizeT ram_file_write(RamFile *f, char *buf, ErlDrvSSizeT len,
+ ErlDrvSSizeT *location, int *error)
{
- int cur = f->cur;
+ ErlDrvSSizeT cur = f->cur;
if (!(f->flags & RAM_FILE_MODE_WRITE)) {
*error = EBADF;
@@ -322,11 +339,11 @@ static int ram_file_write(RamFile *f, char *buf, int len,
return len;
}
-static int ram_file_read(RamFile *f, int len, ErlDrvBinary **bp,
- int *location, int *error)
+static ErlDrvSSizeT ram_file_read(RamFile *f, ErlDrvSSizeT len, ErlDrvBinary **bp,
+ ErlDrvSSizeT *location, int *error)
{
ErlDrvBinary* bin;
- int cur = f->cur;
+ ErlDrvSSizeT cur = f->cur;
if (!(f->flags & RAM_FILE_MODE_READ)) {
*error = EBADF;
@@ -352,9 +369,10 @@ static int ram_file_read(RamFile *f, int len, ErlDrvBinary **bp,
return len;
}
-static int ram_file_seek(RamFile *f, int offset, int whence, int *error)
+static ErlDrvSSizeT ram_file_seek(RamFile *f, ErlDrvSSizeT offset, int whence,
+ int *error)
{
- int pos;
+ ErlDrvSSizeT pos;
if (f->flags == 0) {
*error = EBADF;
@@ -389,13 +407,13 @@ static int ram_file_seek(RamFile *f, int offset, int whence, int *error)
static int ram_file_uuencode(RamFile *f)
{
- int code_len = UULINE(UNIX_LINE);
- int len = f->end;
- int usize = 4*((len+2)/3) + 2*((len+code_len-1)/code_len) + 2;
+ ErlDrvSSizeT code_len = UULINE(UNIX_LINE);
+ ErlDrvSSizeT len = f->end;
+ ErlDrvSSizeT usize = 4*((len+2)/3) + 2*((len+code_len-1)/code_len) + 2;
ErlDrvBinary* bin;
uchar* inp;
uchar* outp;
- int count = 0;
+ ErlDrvSSizeT count = 0;
if ((bin = driver_alloc_binary(usize)) == NULL)
return error_reply(f, ENOMEM);
@@ -447,8 +465,8 @@ static int ram_file_uuencode(RamFile *f)
static int ram_file_uudecode(RamFile *f)
{
- int len = f->end;
- int usize = ( (len+3) / 4 ) * 3;
+ ErlDrvSSizeT len = f->end;
+ ErlDrvSSizeT usize = ( (len+3) / 4 ) * 3;
ErlDrvBinary* bin;
uchar* inp;
uchar* outp;
@@ -510,7 +528,7 @@ static int ram_file_uudecode(RamFile *f)
static int ram_file_compress(RamFile *f)
{
- int size = f->end;
+ ErlDrvSSizeT size = f->end;
ErlDrvBinary* bin;
if ((bin = erts_gzdeflate_buffer(f->buf, size)) == NULL) {
@@ -528,7 +546,7 @@ static int ram_file_compress(RamFile *f)
static int ram_file_uncompress(RamFile *f)
{
- int size = f->end;
+ ErlDrvSSizeT size = f->end;
ErlDrvBinary* bin;
if ((bin = erts_gzinflate_buffer(f->buf, size)) == NULL) {
@@ -541,15 +559,15 @@ static int ram_file_uncompress(RamFile *f)
}
-static void rfile_command(ErlDrvData e, char* buf, int count)
+static void rfile_command(ErlDrvData e, char* buf, ErlDrvSizeT count)
{
RamFile* f = (RamFile*)e;
int error = 0;
ErlDrvBinary* bin;
char header[5]; /* result code + count */
- int offset;
- int origin; /* Origin of seek. */
- int n;
+ ErlDrvSSizeT offset;
+ ErlDrvSSizeT origin; /* Origin of seek. */
+ ErlDrvSSizeT n;
count--;
switch(*(uchar*)buf++) {
diff --git a/erts/emulator/drivers/common/zlib_drv.c b/erts/emulator/drivers/common/zlib_drv.c
index f50899a730..da4a17db1a 100644
--- a/erts/emulator/drivers/common/zlib_drv.c
+++ b/erts/emulator/drivers/common/zlib_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2010. All Rights Reserved.
+ * Copyright Ericsson AB 2003-2011. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -64,8 +64,8 @@
static int zlib_init(void);
static ErlDrvData zlib_start(ErlDrvPort port, char* buf);
static void zlib_stop(ErlDrvData e);
-static int zlib_ctl(ErlDrvData drv_data, unsigned int command, char *buf,
- int len, char **rbuf, int rlen);
+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 = {
@@ -162,12 +162,12 @@ static char* zlib_reason(int code, int* err)
}
-static int zlib_return(int code, char** rbuf, int rlen)
+static ErlDrvSSizeT zlib_return(int code, char** rbuf, ErlDrvSizeT rlen)
{
int msg_code = 0; /* 0=ok, 1=error */
char* dst = *rbuf;
char* src;
- int len = 0;
+ ErlDrvSizeT len = 0;
src = zlib_reason(code, &msg_code);
*dst++ = msg_code;
@@ -182,7 +182,8 @@ static int zlib_return(int code, char** rbuf, int rlen)
return len;
}
-static int zlib_value2(int msg_code, int value, char** rbuf, int rlen)
+static ErlDrvSSizeT zlib_value2(int msg_code, int value,
+ char** rbuf, ErlDrvSizeT rlen)
{
char* dst = *rbuf;
@@ -197,7 +198,7 @@ static int zlib_value2(int msg_code, int value, char** rbuf, int rlen)
return 5;
}
-static int zlib_value(int value, char** rbuf, int rlen)
+static ErlDrvSSizeT zlib_value(int value, char** rbuf, ErlDrvSizeT rlen)
{
return zlib_value2(2, value, rbuf, rlen);
}
@@ -409,8 +410,8 @@ static void zlib_stop(ErlDrvData e)
driver_free(d);
}
-static int zlib_ctl(ErlDrvData drv_data, unsigned int command, char *buf,
- int len, char **rbuf, int rlen)
+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;
diff --git a/erts/emulator/drivers/unix/ttsl_drv.c b/erts/emulator/drivers/unix/ttsl_drv.c
index d782b044a9..b29f80a8ba 100644
--- a/erts/emulator/drivers/unix/ttsl_drv.c
+++ b/erts/emulator/drivers/unix/ttsl_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2010. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2011. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -106,7 +106,7 @@ static int lpos; /* The current "cursor position" in the line buf
/* Main interface functions. */
static void ttysl_stop(ErlDrvData);
-static void ttysl_from_erlang(ErlDrvData, char*, int);
+static void ttysl_from_erlang(ErlDrvData, char*, ErlDrvSizeT);
static void ttysl_from_tty(ErlDrvData, ErlDrvEvent);
static void ttysl_stop_select(ErlDrvEvent, void*);
static Sint16 get_sint16(char*);
@@ -141,7 +141,8 @@ static void update_cols(void);
static int tty_init(int,int,int,int);
static int tty_set(int);
static int tty_reset(int);
-static int ttysl_control(ErlDrvData, unsigned int, char *, int, char **, int);
+static ErlDrvSSizeT ttysl_control(ErlDrvData, unsigned int,
+ char *, ErlDrvSizeT, char **, ErlDrvSizeT);
#ifdef ERTS_NOT_USED
static RETSIGTYPE suspend(int);
#endif
@@ -242,7 +243,7 @@ static ErlDrvData ttysl_start(ErlDrvPort port, char* buf)
#ifndef HAVE_TERMCAP
return ERL_DRV_ERROR_GENERAL;
#else
- char *s, *t, c, *l;
+ char *s, *t, *l;
int canon, echo, sig; /* Terminal characteristics */
int flag;
extern int using_oldshell; /* set this to let the rest of erts know */
@@ -262,7 +263,6 @@ static ErlDrvData ttysl_start(ErlDrvPort port, char* buf)
s++;
/* Find end of this argument (start of next) and insert NUL. */
if ((t = strchr(s, ' '))) {
- c = *t;
*t = '\0';
}
if ((flag = ((*s == '+') ? 1 : ((*s == '-') ? -1 : 0)))) {
@@ -346,13 +346,13 @@ static void ttysl_get_window_size(Uint32 *width, Uint32 *height)
*height = DEF_HEIGHT;
}
-static int ttysl_control(ErlDrvData drv_data,
- unsigned int command,
- char *buf, int len,
- char **rbuf, int rlen)
+static ErlDrvSSizeT ttysl_control(ErlDrvData drv_data,
+ unsigned int command,
+ char *buf, ErlDrvSizeT len,
+ char **rbuf, ErlDrvSizeT rlen)
{
char resbuff[2*sizeof(Uint32)];
- int res_size;
+ ErlDrvSizeT res_size;
switch (command) {
case CTRL_OP_GET_WINSIZE:
{
@@ -634,14 +634,14 @@ static int check_buf_size(byte *s, int n)
}
-static void ttysl_from_erlang(ErlDrvData ttysl_data, char* buf, int count)
+static void ttysl_from_erlang(ErlDrvData ttysl_data, char* buf, ErlDrvSizeT count)
{
if (lpos > MAXSIZE)
put_chars((byte*)"\n", 1);
switch (buf[0]) {
case OP_PUTC:
- DEBUGLOG(("OP: Putc(%d)",count-1));
+ DEBUGLOG(("OP: Putc(%lu)",(unsigned long) count-1));
if (check_buf_size((byte*)buf+1, count-1) == 0)
return;
put_chars((byte*)buf+1, count-1);
diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c
index 4b3934657c..796843a735 100644
--- a/erts/emulator/drivers/unix/unix_efile.c
+++ b/erts/emulator/drivers/unix/unix_efile.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2010. All Rights Reserved.
+ * Copyright Ericsson AB 1997-2011. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -33,6 +33,9 @@
#include <sys/types.h>
#include <sys/uio.h>
#endif
+#if defined(HAVE_SENDFILE) && (defined(__linux__) || (defined(__sun) && defined(__SVR4)))
+#include <sys/sendfile.h>
+#endif
#if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__)
#define DARWIN 1
@@ -813,7 +816,6 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo,
char* name, int info_for_link)
{
struct stat statbuf; /* Information about the file */
- struct tm *timep; /* Broken-apart filetime. */
int result;
#ifdef VXWORKS
@@ -880,40 +882,17 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo,
else
pInfo->type = FT_OTHER;
-#if defined(HAVE_LOCALTIME_R) || defined(VXWORKS)
- {
- /* Use the reentrant version of localtime() */
- static struct tm local_tm;
-#define localtime(a) (localtime_r((a), &local_tm), &local_tm)
-#endif
-
-
-#define GET_TIME(dst, src) \
- timep = localtime(&statbuf.src); \
- (dst).year = timep->tm_year+1900; \
- (dst).month = timep->tm_mon+1; \
- (dst).day = timep->tm_mday; \
- (dst).hour = timep->tm_hour; \
- (dst).minute = timep->tm_min; \
- (dst).second = timep->tm_sec
-
- GET_TIME(pInfo->accessTime, st_atime);
- GET_TIME(pInfo->modifyTime, st_mtime);
- GET_TIME(pInfo->cTime, st_ctime);
-
-#undef GET_TIME
+ pInfo->accessTime = statbuf.st_atime;
+ pInfo->modifyTime = statbuf.st_mtime;
+ pInfo->cTime = statbuf.st_ctime;
-#if defined(HAVE_LOCALTIME_R) || defined(VXWORKS)
- }
-#endif
-
- pInfo->mode = statbuf.st_mode;
- pInfo->links = statbuf.st_nlink;
+ pInfo->mode = statbuf.st_mode;
+ pInfo->links = statbuf.st_nlink;
pInfo->major_device = statbuf.st_dev;
pInfo->minor_device = statbuf.st_rdev;
- pInfo->inode = statbuf.st_ino;
- pInfo->uid = statbuf.st_uid;
- pInfo->gid = statbuf.st_gid;
+ pInfo->inode = statbuf.st_ino;
+ pInfo->uid = statbuf.st_uid;
+ pInfo->gid = statbuf.st_gid;
return 1;
}
@@ -921,6 +900,8 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo,
int
efile_write_info(Efile_error *errInfo, Efile_info *pInfo, char *name)
{
+ struct utimbuf tval;
+
CHECK_PATHLEN(name, errInfo);
#ifdef VXWORKS
@@ -973,38 +954,18 @@ efile_write_info(Efile_error *errInfo, Efile_info *pInfo, char *name)
#endif /* !VXWORKS */
- if (pInfo->accessTime.year != -1 && pInfo->modifyTime.year != -1) {
- struct utimbuf tval;
- struct tm timebuf;
-
-#define MKTIME(tb, ts) \
- timebuf.tm_year = ts.year-1900; \
- timebuf.tm_mon = ts.month-1; \
- timebuf.tm_mday = ts.day; \
- timebuf.tm_hour = ts.hour; \
- timebuf.tm_min = ts.minute; \
- timebuf.tm_sec = ts.second; \
- timebuf.tm_isdst = -1; \
- if ((tb = mktime(&timebuf)) == (time_t) -1) { \
- errno = EINVAL; \
- return check_error(-1, errInfo); \
- }
+ tval.actime = pInfo->accessTime;
+ tval.modtime = pInfo->modifyTime;
- MKTIME(tval.actime, pInfo->accessTime);
- MKTIME(tval.modtime, pInfo->modifyTime);
-#undef MKTIME
-
#ifdef VXWORKS
- /* VxWorks' utime doesn't work when the file is a nfs mounted
- * one, don't report error if utime fails.
- */
- utime(name, &tval);
- return 1;
+ /* VxWorks' utime doesn't work when the file is a nfs mounted
+ * one, don't report error if utime fails.
+ */
+ utime(name, &tval);
+ return 1;
#else
- return check_error(utime(name, &tval), errInfo);
+ return check_error(utime(name, &tval), errInfo);
#endif
- }
- return 1;
}
@@ -1043,13 +1004,11 @@ efile_writev(Efile_error* errInfo, /* Where to return error codes */
* opened */
int fd, /* File descriptor to write to */
SysIOVec* iov, /* Vector of buffer structs.
- * The structs are unchanged
- * after the call */
- int iovcnt, /* Number of structs in vector */
- size_t size) /* Number of bytes to write */
+ * The structs may be changed i.e.
+ * due to incomplete writes */
+ int iovcnt) /* Number of structs in vector */
{
int cnt = 0; /* Buffers so far written */
- int p = 0; /* Position in next buffer */
ASSERT(iovcnt >= 0);
@@ -1060,66 +1019,47 @@ efile_writev(Efile_error* errInfo, /* Where to return error codes */
#endif
while (cnt < iovcnt) {
+ if ((! iov[cnt].iov_base) || (iov[cnt].iov_len <= 0)) {
+ /* Empty buffer - skip */
+ cnt++;
+ } else { /* Non-empty buffer */
+ ssize_t w; /* Bytes written in this call */
#ifdef HAVE_WRITEV
- int w; /* Bytes written in this call */
- int b = iovcnt - cnt; /* Buffers to write */
- if (b > MAXIOV)
- b = MAXIOV;
- if (iov[cnt].iov_base && iov[cnt].iov_len > 0) {
- if (b == 1) {
- /* Degenerated io vector */
- do {
- w = write(fd, iov[cnt].iov_base + p, iov[cnt].iov_len - p);
- } while (w < 0 && errno == EINTR);
- } else {
- /* Non-empty vector first.
- * Adjust pos in first buffer in case of
- * previous incomplete writev */
- iov[cnt].iov_base += p;
- iov[cnt].iov_len -= p;
+ int b = iovcnt - cnt; /* Buffers to write */
+ /* Use as many buffers as MAXIOV allows */
+ if (b > MAXIOV)
+ b = MAXIOV;
+ if (b > 1) {
do {
w = writev(fd, &iov[cnt], b);
} while (w < 0 && errno == EINTR);
- iov[cnt].iov_base -= p;
- iov[cnt].iov_len += p;
- }
- if (w < 0)
- return check_error(-1, errInfo);
- } else {
- /* Empty vector first - skip */
- cnt++;
- continue;
- }
- ASSERT(w >= 0);
- /* Move forward to next vector to write */
- for (; cnt < iovcnt; cnt++) {
- if (iov[cnt].iov_base && iov[cnt].iov_len > 0) {
- if (w < iov[cnt].iov_len)
- break;
- else
- w -= iov[cnt].iov_len;
- }
- }
- ASSERT(w >= 0);
- p = w > 0 ? w : 0; /* Skip p bytes next writev */
-#else /* #ifdef HAVE_WRITEV */
- if (iov[cnt].iov_base && iov[cnt].iov_len > 0) {
- /* Non-empty vector */
- int w; /* Bytes written in this call */
- while (p < iov[cnt].iov_len) {
- do {
- w = write(fd, iov[cnt].iov_base + p, iov[cnt].iov_len - p);
- } while (w < 0 && errno == EINTR);
- if (w < 0)
- return check_error(-1, errInfo);
- p += w;
+ } else
+ /* Degenerated io vector - use regular write */
+#endif
+ {
+ do {
+ w = write(fd, iov[cnt].iov_base, iov[cnt].iov_len);
+ } while (w < 0 && errno == EINTR);
+ ASSERT(w <= iov[cnt].iov_len);
+ }
+ if (w < 0) return check_error(-1, errInfo);
+ /* Move forward to next buffer to write */
+ for (; cnt < iovcnt && w > 0; cnt++) {
+ if (iov[cnt].iov_base && iov[cnt].iov_len > 0) {
+ if (w < iov[cnt].iov_len) {
+ /* Adjust the buffer for next write */
+ iov[cnt].iov_len -= w;
+ iov[cnt].iov_base += w;
+ w = 0;
+ break;
+ } else {
+ w -= iov[cnt].iov_len;
+ }
+ }
}
- }
- cnt++;
- p = 0;
-#endif /* #ifdef HAVE_WRITEV */
+ ASSERT(w == 0);
+ } /* else Non-empty buffer */
} /* while (cnt< iovcnt) */
- size = 0; /* Avoid compiler warning */
return 1;
}
@@ -1464,3 +1404,108 @@ efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset,
return check_error(0, errInfo);
#endif
}
+
+#ifdef HAVE_SENDFILE
+// For some reason the maximum size_t cannot be used as the max size
+// 3GB seems to work on all platforms
+#define SENDFILE_CHUNK_SIZE ((1UL << 30) -1)
+
+/*
+ * sendfile: The implementation of the sendfile system call varies
+ * a lot on different *nix platforms so to make the api similar in all
+ * we have to emulate some things in linux and play with variables on
+ * bsd/darwin.
+ *
+ * All of the calls will split a command which tries to send more than
+ * SENDFILE_CHUNK_SIZE of data at once.
+ *
+ * On platforms where *nbytes of 0 does not mean the entire file, this is
+ * simulated.
+ *
+ * It could be possible to implement header/trailer in sendfile. Though
+ * you would have to emulate it in linux and on BSD/Darwin some complex
+ * calculations have to be made when using a non blocking socket to figure
+ * out how much of the header/file/trailer was sent in each command.
+ */
+
+int
+efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd,
+ off_t *offset, Uint64 *nbytes, struct t_sendfile_hdtl* hdtl)
+{
+ Uint64 written = 0;
+#if defined(__linux__)
+ ssize_t retval;
+ do {
+ // check if *nbytes is 0 or greater than chunk size
+ if (*nbytes == 0 || *nbytes > SENDFILE_CHUNK_SIZE)
+ retval = sendfile(out_fd, in_fd, offset, SENDFILE_CHUNK_SIZE);
+ else
+ retval = sendfile(out_fd, in_fd, offset, *nbytes);
+ if (retval > 0) {
+ written += retval;
+ *nbytes -= retval;
+ }
+ } while (retval == SENDFILE_CHUNK_SIZE);
+ *nbytes = written;
+ return check_error(retval == -1 ? -1 : 0, errInfo);
+#elif defined(__sun) && defined(__SVR4) && defined(HAVE_SENDFILEV)
+ ssize_t retval;
+ size_t len;
+ sendfilevec_t fdrec;
+ fdrec.sfv_fd = in_fd;
+ fdrec.sfv_flag = 0;
+ do {
+ fdrec.sfv_off = *offset;
+ len = 0;
+ // check if *nbytes is 0 or greater than chunk size
+ if (*nbytes == 0 || *nbytes > SENDFILE_CHUNK_SIZE)
+ fdrec.sfv_len = SENDFILE_CHUNK_SIZE;
+ else
+ fdrec.sfv_len = *nbytes;
+ retval = sendfilev(out_fd, &fdrec, 1, &len);
+ if (retval != -1 || errno == EAGAIN || errno == EINTR) {
+ *offset += len;
+ *nbytes -= len;
+ written += len;
+ }
+ } while (len == SENDFILE_CHUNK_SIZE);
+ *nbytes = written;
+ return check_error(retval == -1 ? -1 : 0, errInfo);
+#elif defined(DARWIN)
+ int retval;
+ off_t len;
+ do {
+ // check if *nbytes is 0 or greater than chunk size
+ if(*nbytes > SENDFILE_CHUNK_SIZE)
+ len = SENDFILE_CHUNK_SIZE;
+ else
+ len = *nbytes;
+ retval = sendfile(in_fd, out_fd, *offset, &len, NULL, 0);
+ if (retval != -1 || errno == EAGAIN || errno == EINTR) {
+ *offset += len;
+ *nbytes -= len;
+ written += len;
+ }
+ } while (len == SENDFILE_CHUNK_SIZE);
+ *nbytes = written;
+ return check_error(retval, errInfo);
+#elif defined(__FreeBSD__) || defined(__DragonFly__)
+ off_t len;
+ int retval;
+ do {
+ if (*nbytes > SENDFILE_CHUNK_SIZE)
+ retval = sendfile(in_fd, out_fd, *offset, SENDFILE_CHUNK_SIZE,
+ NULL, &len, 0);
+ else
+ retval = sendfile(in_fd, out_fd, *offset, *nbytes, NULL, &len, 0);
+ if (retval != -1 || errno == EAGAIN || errno == EINTR) {
+ *offset += len;
+ *nbytes -= len;
+ written += len;
+ }
+ } while(len == SENDFILE_CHUNK_SIZE);
+ *nbytes = written;
+ return check_error(retval, errInfo);
+#endif
+}
+#endif /* HAVE_SENDFILE */
diff --git a/erts/emulator/drivers/win32/registry_drv.c b/erts/emulator/drivers/win32/registry_drv.c
index 05fd2ea55f..1fad34e380 100644
--- a/erts/emulator/drivers/win32/registry_drv.c
+++ b/erts/emulator/drivers/win32/registry_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1997-2011. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -84,7 +84,7 @@ static int maperror(DWORD error);
static int reg_init(void);
static ErlDrvData reg_start(ErlDrvPort, char*);
static void reg_stop(ErlDrvData);
-static void reg_from_erlang(ErlDrvData, char*, int);
+static void reg_from_erlang(ErlDrvData, char*, ErlDrvSizeT);
struct erl_drv_entry registry_driver_entry = {
reg_init,
@@ -95,10 +95,21 @@ struct erl_drv_entry registry_driver_entry = {
NULL,
"registry__drv__",
NULL,
+ NULL, /* handle */
+ NULL, /* control */
+ NULL, /* timeout */
+ NULL, /* outputv */
+ NULL, /* ready_async */
+ NULL, /* flush */
+ NULL, /* call */
+ NULL, /* event */
+ ERL_DRV_EXTENDED_MARKER,
+ ERL_DRV_EXTENDED_MAJOR_VERSION,
+ ERL_DRV_EXTENDED_MINOR_VERSION,
+ 0,
NULL,
NULL,
NULL,
- NULL
};
static int
@@ -158,7 +169,7 @@ reg_stop(ErlDrvData clientData)
}
static void
-reg_from_erlang(ErlDrvData clientData, char* buf, int count)
+reg_from_erlang(ErlDrvData clientData, char* buf, ErlDrvSizeT count)
{
RegPort* rp = (RegPort *) clientData;
int cmd;
@@ -301,7 +312,7 @@ reg_from_erlang(ErlDrvData clientData, char* buf, int count)
buf = (char *) &dword;
ASSERT(count == 4);
}
- result = RegSetValueEx(rp->hkey, name, 0, type, buf, count);
+ result = RegSetValueEx(rp->hkey, name, 0, type, buf, (DWORD)count);
reply(rp, result);
}
break;
diff --git a/erts/emulator/drivers/win32/ttsl_drv.c b/erts/emulator/drivers/win32/ttsl_drv.c
index fd88dafd34..1a74d21e99 100644
--- a/erts/emulator/drivers/win32/ttsl_drv.c
+++ b/erts/emulator/drivers/win32/ttsl_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2011. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -21,6 +21,9 @@
* smart line for output.
*/
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
#include "sys.h"
#include <ctype.h>
#include <stdlib.h>
@@ -80,8 +83,9 @@ int lpos; /* The current "cursor position" in the line buf
static int ttysl_init(void);
static ErlDrvData ttysl_start(ErlDrvPort, char*);
static void ttysl_stop(ErlDrvData);
-static int ttysl_control(ErlDrvData, unsigned int, char *, int, char **, int);
-static void ttysl_from_erlang(ErlDrvData, char*, int);
+static ErlDrvSSizeT ttysl_control(ErlDrvData, unsigned int,
+ char *, ErlDrvSizeT, char **, ErlDrvSizeT);
+static void ttysl_from_erlang(ErlDrvData, char*, ErlDrvSizeT);
static void ttysl_from_tty(ErlDrvData, ErlDrvEvent);
static Sint16 get_sint16(char *s);
@@ -117,7 +121,19 @@ struct erl_drv_entry ttsl_driver_entry = {
NULL,
NULL,
ttysl_control,
- NULL
+ NULL, /* timeout */
+ NULL, /* outputv */
+ NULL, /* ready_async */
+ NULL, /* flush */
+ NULL, /* call */
+ NULL, /* event */
+ ERL_DRV_EXTENDED_MARKER,
+ ERL_DRV_EXTENDED_MAJOR_VERSION,
+ ERL_DRV_EXTENDED_MINOR_VERSION,
+ 0,
+ NULL,
+ NULL,
+ NULL,
};
static int utf8_mode = 0;
@@ -151,13 +167,13 @@ static void ttysl_get_window_size(Uint32 *width, Uint32 *height)
}
-static int ttysl_control(ErlDrvData drv_data,
+static ErlDrvSSizeT ttysl_control(ErlDrvData drv_data,
unsigned int command,
- char *buf, int len,
- char **rbuf, int rlen)
+ char *buf, ErlDrvSizeT len,
+ char **rbuf, ErlDrvSizeT rlen)
{
char resbuff[2*sizeof(Uint32)];
- int res_size;
+ ErlDrvSizeT res_size;
switch (command) {
case CTRL_OP_GET_WINSIZE:
{
@@ -173,7 +189,7 @@ static int ttysl_control(ErlDrvData drv_data,
res_size = 1;
break;
case CTRL_OP_SET_UNICODE_STATE:
- if (len > 0) {
+ if (len != 0) {
int m = (int) *buf;
*resbuff = (utf8_mode) ? 1 : 0;
res_size = 1;
@@ -435,14 +451,14 @@ static int check_buf_size(byte *s, int n)
}
-static void ttysl_from_erlang(ErlDrvData ttysl_data, char* buf, int count)
+static void ttysl_from_erlang(ErlDrvData ttysl_data, char* buf, ErlDrvSizeT count)
{
if (lpos > MAXSIZE)
put_chars((byte*)"\n", 1);
switch (buf[0]) {
case OP_PUTC:
- DEBUGLOG(("OP: Putc(%d)",count-1));
+ DEBUGLOG(("OP: Putc(%I64u)",(unsigned long long)count-1));
if (check_buf_size((byte*)buf+1, count-1) == 0)
return;
put_chars((byte*)buf+1, count-1);
diff --git a/erts/emulator/drivers/win32/win_con.c b/erts/emulator/drivers/win32/win_con.c
index c788ad409d..6b45b92cbe 100644
--- a/erts/emulator/drivers/win32/win_con.c
+++ b/erts/emulator/drivers/win32/win_con.c
@@ -21,6 +21,9 @@
#define _UNICODE 1
#include <tchar.h>
#include <stdio.h>
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
#include "sys.h"
#include <windowsx.h>
#include "resource.h"
@@ -34,6 +37,23 @@
#define REALLOC(X,Y) realloc(X,Y)
#define FREE(X) free(X)
+#if SIZEOF_VOID_P == 8
+#define WIN64 1
+#ifndef GCL_HBRBACKGROUND
+#define GCL_HBRBACKGROUND GCLP_HBRBACKGROUND
+#endif
+#define DIALOG_PROC_RET INT_PTR
+#define CF_HOOK_RET INT_PTR
+#define CC_HOOK_RET INT_PTR
+#define OFN_HOOK_RET INT_PTR
+#else
+#define DIALOG_PROC_RET BOOL
+#define CF_HOOK_RET UINT
+#define CC_HOOK_RET UINT
+#define OFN_HOOK_RET UINT
+#endif
+
+
#ifndef STATE_SYSTEM_INVISIBLE
/* Mingw problem with oleacc.h and WIN32_LEAN_AND_MEAN */
#define STATE_SYSTEM_INVISIBLE 0x00008000
@@ -150,7 +170,7 @@ static TCHAR *erlang_window_title = TEXT("Erlang");
static unsigned __stdcall ConThreadInit(LPVOID param);
static LRESULT CALLBACK ClientWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
-static BOOL CALLBACK AboutDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam);
+static DIALOG_PROC_RET CALLBACK AboutDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam);
static ScreenLine_t *ConNewLine(void);
static void DeleteTopLine(void);
static void ensure_line_below(void);
@@ -1608,7 +1628,7 @@ OnEditSelAll(HWND hwnd)
InvalidateRect(hwnd, NULL, TRUE);
}
-UINT APIENTRY CFHookProc(HWND hDlg,UINT iMsg,WPARAM wParam,LPARAM lParam)
+CF_HOOK_RET APIENTRY CFHookProc(HWND hDlg,UINT iMsg,WPARAM wParam,LPARAM lParam)
{
/* Hook procedure for font dialog box */
HWND hOwner;
@@ -1626,11 +1646,11 @@ UINT APIENTRY CFHookProc(HWND hDlg,UINT iMsg,WPARAM wParam,LPARAM lParam)
OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom);
SetWindowPos(hDlg,HWND_TOP,rcOwner.left + (rc.right / 2),
rcOwner.top + (rc.bottom / 2),0,0,SWP_NOSIZE);
- return 1;
+ return (CF_HOOK_RET) 1;
default:
break;
}
- return 0; /* Let the default procedure process the message */
+ return (CF_HOOK_RET) 0; /* Let the default procedure process the message */
}
static BOOL
@@ -1705,7 +1725,7 @@ ConSetFont(HWND hwnd)
InvalidateRect(hwnd, NULL, TRUE);
}
-UINT APIENTRY
+CC_HOOK_RET APIENTRY
CCHookProc(HWND hDlg,UINT iMsg,WPARAM wParam,LPARAM lParam)
{
/* Hook procedure for choose color dialog box */
@@ -1724,11 +1744,11 @@ CCHookProc(HWND hDlg,UINT iMsg,WPARAM wParam,LPARAM lParam)
OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom);
SetWindowPos(hDlg,HWND_TOP,rcOwner.left + (rc.right / 2),
rcOwner.top + (rc.bottom / 2),0,0,SWP_NOSIZE);
- return 1;
+ return (CC_HOOK_RET) 1;
default:
break;
}
- return 0; /* Let the default procedure process the message */
+ return (CC_HOOK_RET) 0; /* Let the default procedure process the message */
}
void ConChooseColor(HWND hwnd)
@@ -1758,7 +1778,8 @@ void ConChooseColor(HWND hwnd)
}
}
-UINT APIENTRY OFNHookProc(HWND hwndDlg,UINT iMsg,WPARAM wParam,LPARAM lParam)
+OFN_HOOK_RET APIENTRY OFNHookProc(HWND hwndDlg,UINT iMsg,
+ WPARAM wParam,LPARAM lParam)
{
/* Hook procedure for open file dialog box */
HWND hOwner,hDlg;
@@ -1777,11 +1798,11 @@ UINT APIENTRY OFNHookProc(HWND hwndDlg,UINT iMsg,WPARAM wParam,LPARAM lParam)
OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom);
SetWindowPos(hDlg,HWND_TOP,rcOwner.left + (rc.right / 2),
rcOwner.top + (rc.bottom / 2),0,0,SWP_NOSIZE);
- return 1;
+ return (OFN_HOOK_RET) 1;
default:
break;
}
- return 0; /* the let default procedure process the message */
+ return (OFN_HOOK_RET) 0; /* the let default procedure process the message */
}
static void
@@ -1933,7 +1954,7 @@ write_outbuf(TCHAR *data, int num_chars)
return num_chars;
}
-BOOL CALLBACK AboutDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
+DIALOG_PROC_RET CALLBACK AboutDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
HWND hOwner;
RECT rc,rcOwner,rcDlg;
@@ -1953,17 +1974,17 @@ BOOL CALLBACK AboutDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
rcOwner.top + (rc.bottom / 2),0,0,SWP_NOSIZE);
SetDlgItemText(hDlg, ID_VERSIONSTRING,
TEXT("Erlang emulator version ") TEXT(ERLANG_VERSION));
- return TRUE;
+ return (DIALOG_PROC_RET) TRUE;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDOK:
case IDCANCEL:
EndDialog(hDlg,0);
- return TRUE;
+ return (DIALOG_PROC_RET) TRUE;
}
break;
}
- return FALSE;
+ return (DIALOG_PROC_RET) FALSE;
}
static void
@@ -2117,7 +2138,7 @@ AddToCmdHistory(void)
}
}
-static TBBUTTON tbb[] =
+/*static TBBUTTON tbb[] =
{
0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
@@ -2149,6 +2170,39 @@ static TBBUTTON tbb[] =
2, IDMENU_FONT, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, 0, 0, 0, 0,
3, IDMENU_ABOUT, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, 0, 0, 0, 0,
0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0,
+ };*/
+static TBBUTTON tbb[] =
+{
+ {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
+ {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
+ {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
+ {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
+ {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
+ {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
+ {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
+ {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
+ {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
+ {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
+ {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
+ {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
+ {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
+ {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
+ {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
+ {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
+ {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
+ {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
+ {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
+ {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
+ {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
+ {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
+ {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
+ {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
+ {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
+ {0, IDMENU_COPY, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE},
+ {1, IDMENU_PASTE, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE},
+ {2, IDMENU_FONT, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE},
+ {3, IDMENU_ABOUT, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE},
+ {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}
};
static TBADDBITMAP tbbitmap =
@@ -2156,6 +2210,17 @@ static TBADDBITMAP tbbitmap =
HINST_COMMCTRL, IDB_STD_SMALL_COLOR,
};
+#ifdef HARDDEBUG
+/* For really hard GUI startup debugging, place DEBUGBOX() macros in code
+ and get modal message boxes with the line number. */
+static void debug_box(int line) {
+ TCHAR buff[1024];
+ swprintf(buff,1024,TEXT("DBG:%d"),line);
+ MessageBox(NULL,buff,TEXT("DBG"),MB_OK|MB_APPLMODAL);
+}
+
+#define DEBUGBOX() debug_box(__LINE__)
+#endif
static HWND
InitToolBar(HWND hwndParent)
@@ -2169,7 +2234,6 @@ InitToolBar(HWND hwndParent)
COLORMAP colorMap;
colorMap.from = RGB(192, 192, 192);
colorMap.to = backgroundColor;
-
/* Create toolbar window with tooltips */
hwndTB = CreateWindowEx(0,TOOLBARCLASSNAME,(TCHAR *)NULL,
WS_CHILD|CCS_TOP|WS_CLIPSIBLINGS|TBSTYLE_TOOLTIPS,
@@ -2180,9 +2244,10 @@ InitToolBar(HWND hwndParent)
tbbitmap.hInst = NULL;
tbbitmap.nID = (UINT) CreateMappedBitmap(beam_module, 1,0, &colorMap, 1);
SendMessage(hwndTB, TB_ADDBITMAP, (WPARAM) 4,
- (WPARAM) &tbbitmap);
+ (LPARAM) &tbbitmap);
+
SendMessage(hwndTB,TB_ADDBUTTONS, (WPARAM) 30,
- (LPARAM) (LPTBBUTTON) tbb);
+ (LPARAM) tbb);
if (toolbarVisible)
ShowWindow(hwndTB, SW_SHOW);
diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c
index 3d59564f7b..606fa1d7de 100755..100644
--- a/erts/emulator/drivers/win32/win_efile.c
+++ b/erts/emulator/drivers/win32/win_efile.c
@@ -21,6 +21,9 @@
*/
#include <windows.h>
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
#include "sys.h"
#include <ctype.h>
#include <wchar.h>
@@ -42,6 +45,26 @@
#define INVALID_FILE_ATTRIBUTES ((DWORD) 0xFFFFFFFF)
#endif
+#define TICKS_PER_SECOND (10000000ULL)
+#define EPOCH_DIFFERENCE (11644473600LL)
+
+#define FILETIME_TO_EPOCH(epoch, ft) \
+ do { \
+ ULARGE_INTEGER ull; \
+ ull.LowPart = (ft).dwLowDateTime; \
+ ull.HighPart = (ft).dwHighDateTime; \
+ (epoch) = ((ull.QuadPart / TICKS_PER_SECOND) - EPOCH_DIFFERENCE); \
+ } while(0)
+
+#define EPOCH_TO_FILETIME(ft, epoch) \
+ do { \
+ ULARGE_INTEGER ull; \
+ ull.QuadPart = (((epoch) + EPOCH_DIFFERENCE) * TICKS_PER_SECOND); \
+ (ft).dwLowDateTime = ull.LowPart; \
+ (ft).dwHighDateTime = ull.HighPart; \
+ } while(0)
+
+
static int check_error(int result, Efile_error* errInfo);
static int set_error(Efile_error* errInfo);
static int is_root_unc_name(const WCHAR *path);
@@ -127,6 +150,8 @@ static int errno_map(DWORD last_error) {
return EBUSY;
case ERROR_NO_PROC_SLOTS:
return EAGAIN;
+ case ERROR_CANT_RESOLVE_FILENAME:
+ return EMLINK;
case ERROR_ARENA_TRASHED:
case ERROR_INVALID_BLOCK:
case ERROR_BAD_ENVIRONMENT:
@@ -859,14 +884,7 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo,
findbuf.cFileName[0] = L'\0';
pInfo->links = 1;
- pInfo->modifyTime.year = 1980;
- pInfo->modifyTime.month = 1;
- pInfo->modifyTime.day = 1;
- pInfo->modifyTime.hour = 0;
- pInfo->modifyTime.minute = 0;
- pInfo->modifyTime.second = 0;
-
- pInfo->accessTime = pInfo->modifyTime;
+ pInfo->cTime = pInfo->accessTime = pInfo->modifyTime = 0;
} else {
SYSTEMTIME SystemTime;
FILETIME LocalFTime;
@@ -900,34 +918,21 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo,
}
}
-#define GET_TIME(dst, src) \
-if (!FileTimeToLocalFileTime(&findbuf.src, &LocalFTime) || \
- !FileTimeToSystemTime(&LocalFTime, &SystemTime)) { \
- return set_error(errInfo); \
-} \
-(dst).year = SystemTime.wYear; \
-(dst).month = SystemTime.wMonth; \
-(dst).day = SystemTime.wDay; \
-(dst).hour = SystemTime.wHour; \
-(dst).minute = SystemTime.wMinute; \
-(dst).second = SystemTime.wSecond;
-
- GET_TIME(pInfo->modifyTime, ftLastWriteTime);
+ FILETIME_TO_EPOCH(pInfo->modifyTime, findbuf.ftLastWriteTime);
if (findbuf.ftLastAccessTime.dwLowDateTime == 0 &&
findbuf.ftLastAccessTime.dwHighDateTime == 0) {
pInfo->accessTime = pInfo->modifyTime;
} else {
- GET_TIME(pInfo->accessTime, ftLastAccessTime);
+ FILETIME_TO_EPOCH(pInfo->accessTime, findbuf.ftLastAccessTime);
}
if (findbuf.ftCreationTime.dwLowDateTime == 0 &&
findbuf.ftCreationTime.dwHighDateTime == 0) {
pInfo->cTime = pInfo->modifyTime;
} else {
- GET_TIME(pInfo->cTime, ftCreationTime);
+ FILETIME_TO_EPOCH(pInfo->cTime ,findbuf.ftCreationTime);
}
-#undef GET_TIME
FindClose(findhandle);
}
@@ -963,17 +968,12 @@ efile_write_info(Efile_error* errInfo,
char* name)
{
SYSTEMTIME timebuf;
- FILETIME LocalFileTime;
FILETIME ModifyFileTime;
FILETIME AccessFileTime;
FILETIME CreationFileTime;
HANDLE fd;
- FILETIME* mtime = NULL;
- FILETIME* atime = NULL;
- FILETIME* ctime = NULL;
DWORD attr;
DWORD tempAttr;
- BOOL modifyTime = FALSE;
WCHAR *wname = (WCHAR *) name;
/*
@@ -998,57 +998,36 @@ efile_write_info(Efile_error* errInfo,
* Construct all file times.
*/
-#define MKTIME(tb, ts, ptr) \
- timebuf.wYear = ts.year; \
- timebuf.wMonth = ts.month; \
- timebuf.wDay = ts.day; \
- timebuf.wHour = ts.hour; \
- timebuf.wMinute = ts.minute; \
- timebuf.wSecond = ts.second; \
- timebuf.wMilliseconds = 0; \
- if (ts.year != -1) { \
- modifyTime = TRUE; \
- ptr = &tb; \
- if (!SystemTimeToFileTime(&timebuf, &LocalFileTime ) || \
- !LocalFileTimeToFileTime(&LocalFileTime, &tb)) { \
- errno = EINVAL; \
- return check_error(-1, errInfo); \
- } \
- }
-
- MKTIME(ModifyFileTime, pInfo->modifyTime, mtime);
- MKTIME(AccessFileTime, pInfo->accessTime, atime);
- MKTIME(CreationFileTime, pInfo->cTime, ctime);
-#undef MKTIME
+ EPOCH_TO_FILETIME(ModifyFileTime, pInfo->modifyTime);
+ EPOCH_TO_FILETIME(AccessFileTime, pInfo->accessTime);
+ EPOCH_TO_FILETIME(CreationFileTime, pInfo->cTime);
/*
* If necessary, set the file times.
*/
- if (modifyTime) {
- /*
- * If the has read only access, we must temporarily turn on
- * write access (this is necessary for native filesystems,
- * but not for NFS filesystems).
- */
+ /*
+ * If the has read only access, we must temporarily turn on
+ * write access (this is necessary for native filesystems,
+ * but not for NFS filesystems).
+ */
- if (tempAttr & FILE_ATTRIBUTE_READONLY) {
- tempAttr &= ~FILE_ATTRIBUTE_READONLY;
- if (!SetFileAttributesW(wname, tempAttr)) {
- return set_error(errInfo);
- }
+ if (tempAttr & FILE_ATTRIBUTE_READONLY) {
+ tempAttr &= ~FILE_ATTRIBUTE_READONLY;
+ if (!SetFileAttributesW(wname, tempAttr)) {
+ return set_error(errInfo);
}
+ }
- fd = CreateFileW(wname, GENERIC_READ|GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- if (fd != INVALID_HANDLE_VALUE) {
- BOOL result = SetFileTime(fd, ctime, atime, mtime);
- if (!result) {
- return set_error(errInfo);
- }
- CloseHandle(fd);
+ fd = CreateFileW(wname, GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (fd != INVALID_HANDLE_VALUE) {
+ BOOL result = SetFileTime(fd, &CreationFileTime, &AccessFileTime, &ModifyFileTime);
+ if (!result) {
+ return set_error(errInfo);
}
+ CloseHandle(fd);
}
/*
@@ -1136,8 +1115,7 @@ efile_writev(Efile_error* errInfo, /* Where to return error codes */
SysIOVec* iov, /* Vector of buffer structs.
* The structs are unchanged
* after the call */
- int iovcnt, /* Number of structs in vector */
- size_t size) /* Number of bytes to write */
+ int iovcnt) /* Number of structs in vector */
{
int cnt; /* Buffers so far written */
OVERLAPPED overlapped;
@@ -1405,7 +1383,7 @@ efile_readlink(Efile_error* errInfo, char* name, char* buffer, size_t size)
DWORD fileAttributes = GetFileAttributesW(wname);
if ((fileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
BOOLEAN success = 0;
- HANDLE h = CreateFileW(wname, GENERIC_READ, 0,NULL, OPEN_EXISTING, 0, NULL);
+ HANDLE h = CreateFileW(wname, GENERIC_READ, 0,NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
int len;
if(h != INVALID_HANDLE_VALUE) {
success = pGetFinalPathNameByHandle(h, wbuffer, size,0);
@@ -1421,7 +1399,7 @@ efile_readlink(Efile_error* errInfo, char* name, char* buffer, size_t size)
if (*wbuffer == L'\\')
*wbuffer = L'/';
CloseHandle(h);
- }
+ }
FreeLibrary(hModule);
if (success) {
return 1;