From 41989072fdfa766916489088aa7eae48a7d89961 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Fri, 12 Jul 2013 15:42:33 +0200 Subject: Implement emulator netns support for TCP and UDP --- erts/emulator/drivers/common/inet_drv.c | 106 ++++++++++++++++++++++++++++++-- 1 file changed, 102 insertions(+), 4 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 301ce2d0e2..9ef2a1cfc0 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -282,7 +282,7 @@ static BOOL (WINAPI *fpSetHandleInformation)(HANDLE,DWORD,DWORD); static unsigned long zero_value = 0; static unsigned long one_value = 1; -#else +#else /* #ifdef __WIN32__ */ #include #ifdef NETDB_H_NEEDS_IN_H @@ -315,9 +315,17 @@ static unsigned long one_value = 1; #include +#ifdef HAVE_SCHED_H +#include +#endif + +#ifdef HAVE_SETNS_H +#include +#endif + /* SCTP support -- currently for UNIX platforms only: */ #undef HAVE_SCTP -#if (!defined(__WIN32__) && defined(HAVE_SCTP_H)) +#if defined(HAVE_SCTP_H) #include @@ -418,7 +426,7 @@ static int (*p_sctp_bindx)(int sd, struct sockaddr *addrs, static int (*p_sctp_peeloff)(int sd, sctp_assoc_t assoc_id) = NULL; #endif -#endif /* SCTP supported */ +#endif /* #if defined(HAVE_SCTP_H) */ #ifndef WANT_NONBLOCKING #define WANT_NONBLOCKING @@ -512,7 +520,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) } while(0) -#endif /* __WIN32__ */ +#endif /* #ifdef __WIN32__ #else */ #ifdef HAVE_SOCKLEN_T # define SOCKLEN_T socklen_t @@ -680,6 +688,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #define INET_LOPT_TCP_SEND_TIMEOUT_CLOSE 35 /* auto-close on send timeout or not */ #define INET_LOPT_MSGQ_HIWTRMRK 36 /* set local msgq high watermark */ #define INET_LOPT_MSGQ_LOWTRMRK 37 /* set local msgq low watermark */ +#define INET_LOPT_NETNS 38 /* Network namespace pathname */ /* SCTP options: a separate range, from 100: */ #define SCTP_OPT_RTOINFO 100 #define SCTP_OPT_ASSOCINFO 101 @@ -955,6 +964,10 @@ typedef struct { 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. */ +#ifdef HAVE_SETNS + char *netns; /* Socket network namespace name + as full file path */ +#endif } inet_descriptor; @@ -3908,10 +3921,57 @@ static int erl_inet_close(inet_descriptor* desc) static ErlDrvSSizeT inet_ctl_open(inet_descriptor* desc, int domain, int type, char** rbuf, ErlDrvSizeT rsize) { +#ifdef HAVE_SETNS + int current_ns, new_ns, save_errno; + current_ns = new_ns = save_errno = 0; +#endif if (desc->state != INET_STATE_CLOSED) return ctl_xerror(EXBADSEQ, rbuf, rsize); +#ifdef HAVE_SETNS + if (desc->netns != NULL) { + current_ns = open("/proc/self/ns/net", O_RDONLY); + if (current_ns == INVALID_SOCKET) + return ctl_error(sock_errno(), rbuf, rsize); + new_ns = open(desc->netns, O_RDONLY); + if (new_ns == INVALID_SOCKET) { + save_errno = sock_errno(); + while (close(current_ns) == INVALID_SOCKET && + sock_errno() == EINTR); + return ctl_error(save_errno, rbuf, rsize); + } + if (setns(new_ns, CLONE_NEWNET) != 0) { + save_errno = sock_errno(); + while (close(new_ns) == INVALID_SOCKET && + sock_errno() == EINTR); + while (close(current_ns) == INVALID_SOCKET && + sock_errno() == EINTR); + return ctl_error(save_errno, rbuf, rsize); + } + else { + while (close(new_ns) == INVALID_SOCKET && + sock_errno() == EINTR); + } + } +#endif if ((desc->s = sock_open(domain, type, desc->sprotocol)) == INVALID_SOCKET) return ctl_error(sock_errno(), rbuf, rsize); +#ifdef HAVE_SETNS + if (desc->netns != NULL) { + if (setns(current_ns, CLONE_NEWNET) != 0) { + save_errno = sock_errno(); + while (close(desc->s) == INVALID_SOCKET && + sock_errno() == EINTR); + desc->s = INVALID_SOCKET; + while (close(current_ns) == INVALID_SOCKET && + sock_errno() == EINTR); + return ctl_error(save_errno, rbuf, rsize); + } + else { + while (close(current_ns) == INVALID_SOCKET && + sock_errno() == EINTR); + } + } +#endif if ((desc->event = sock_create_event(desc)) == INVALID_EVENT) return ctl_error(sock_errno(), rbuf, rsize); SET_NONBLOCKING(desc->s); @@ -5529,6 +5589,20 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) } continue; +#ifdef HAVE_SETNS + case INET_LOPT_NETNS: + /* It is annoying that ival and len are both (signed) int */ + if (ival < 0) return -1; + if (len < ival) return -1; + if (desc->netns != NULL) FREE(desc->netns); + desc->netns = ALLOC(((unsigned int) ival) + 1); + memcpy(desc->netns, ptr, ival); + desc->netns[ival] = '\0'; + ptr += ival; + len -= ival; + continue; +#endif + case INET_OPT_REUSEADDR: #ifdef __WIN32__ continue; /* Bjorn says */ @@ -6454,6 +6528,22 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc, } continue; +#ifdef HAVE_SETNS + case INET_LOPT_NETNS: + if (desc->netns != NULL) { + size_t netns_len; + netns_len = strlen(desc->netns); + *ptr++ = opt; + put_int32(netns_len, ptr); + PLACE_FOR(netns_len, ptr); + memcpy(ptr, desc->netns, netns_len); + ptr += netns_len; + } else { + TRUNCATE_TO(0,ptr); + } + continue; +#endif + case INET_OPT_PRIORITY: #ifdef SO_PRIORITY type = SO_PRIORITY; @@ -7458,6 +7548,10 @@ static ErlDrvSSizeT inet_subscribe(inet_descriptor* desc, static void inet_stop(inet_descriptor* desc) { erl_inet_close(desc); +#ifdef HAVE_SETNS + if (desc->netns != NULL) + FREE(desc->netns); +#endif FREE(desc); } @@ -7537,6 +7631,10 @@ static ErlDrvData inet_start(ErlDrvPort port, int size, int protocol) desc->is_ignored = 0; +#ifdef HAVE_SETNS + desc->netns = NULL; +#endif + return (ErlDrvData)desc; } -- cgit v1.2.3 From 08ff3673e25fdd184ff92d45d4609cd423fd1e34 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Tue, 16 Jul 2013 15:14:50 +0200 Subject: Implement netns for SCTP + bugfixes --- erts/emulator/drivers/common/inet_drv.c | 67 ++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 6 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 9ef2a1cfc0..60db50e80a 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -1194,6 +1194,7 @@ static ErlDrvTermData am_dontroute; static ErlDrvTermData am_priority; static ErlDrvTermData am_tos; static ErlDrvTermData am_ipv6_v6only; +static ErlDrvTermData am_netns; #endif /* speical errors for bad ports and sequences */ @@ -3511,6 +3512,7 @@ static void inet_init_sctp(void) { INIT_ATOM(priority); INIT_ATOM(tos); INIT_ATOM(ipv6_v6only); + INIT_ATOM(netns); /* Option names */ INIT_ATOM(sctp_rtoinfo); @@ -3921,14 +3923,21 @@ static int erl_inet_close(inet_descriptor* desc) static ErlDrvSSizeT inet_ctl_open(inet_descriptor* desc, int domain, int type, char** rbuf, ErlDrvSizeT rsize) { + int save_errno; #ifdef HAVE_SETNS - int current_ns, new_ns, save_errno; - current_ns = new_ns = save_errno = 0; + int current_ns, new_ns; + current_ns = new_ns = 0; #endif + save_errno = 0; + if (desc->state != INET_STATE_CLOSED) return ctl_xerror(EXBADSEQ, rbuf, rsize); + #ifdef HAVE_SETNS if (desc->netns != NULL) { + /* Temporarily change network namespace for this thread + * while creating the socket + */ current_ns = open("/proc/self/ns/net", O_RDONLY); if (current_ns == INVALID_SOCKET) return ctl_error(sock_errno(), rbuf, rsize); @@ -3954,11 +3963,18 @@ static ErlDrvSSizeT inet_ctl_open(inet_descriptor* desc, int domain, int type, } #endif if ((desc->s = sock_open(domain, type, desc->sprotocol)) == INVALID_SOCKET) - return ctl_error(sock_errno(), rbuf, rsize); + save_errno = sock_errno(); #ifdef HAVE_SETNS if (desc->netns != NULL) { + /* Restore network namespace */ if (setns(current_ns, CLONE_NEWNET) != 0) { - save_errno = sock_errno(); + /* XXX Failed to restore network namespace. + * What to do? Tidy up and return an error... + * Note that the thread now might still be in the namespace. + * Can this even happen? Should the emulator be aborted? + */ + if (desc->s != INVALID_SOCKET) + save_errno = sock_errno(); while (close(desc->s) == INVALID_SOCKET && sock_errno() == EINTR); desc->s = INVALID_SOCKET; @@ -3972,8 +3988,16 @@ static ErlDrvSSizeT inet_ctl_open(inet_descriptor* desc, int domain, int type, } } #endif - if ((desc->event = sock_create_event(desc)) == INVALID_EVENT) - return ctl_error(sock_errno(), rbuf, rsize); + if (desc->s == INVALID_SOCKET) + return ctl_error(save_errno, rbuf, rsize); + + if ((desc->event = sock_create_event(desc)) == INVALID_EVENT) { + save_errno = sock_errno(); + while (close(desc->s) == INVALID_SOCKET && + sock_errno() == EINTR); + desc->s = INVALID_SOCKET; + return ctl_error(save_errno, rbuf, rsize); + } SET_NONBLOCKING(desc->s); #ifdef __WIN32__ driver_select(desc->port, desc->event, ERL_DRV_READ, 1); @@ -5932,6 +5956,21 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) res = 0; continue; +#ifdef HAVE_SETNS + case INET_LOPT_NETNS: + { + size_t ns_len; + ns_len = get_int32(curr); curr += 4; + CHKLEN(curr, ns_len); + if (desc->netns != NULL) FREE(desc->netns); + desc->netns = ALLOC(ns_len + 1); + memcpy(desc->netns, curr, ns_len); + desc->netns[ns_len] = '\0'; + curr += ns_len; + } + continue; +#endif + /* SCTP options and applicable generic INET options: */ case SCTP_OPT_RTOINFO: @@ -6827,6 +6866,22 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc, break; } +#ifdef HAVE_SETNS + case INET_LOPT_NETNS: + if (desc->netns != NULL) { + PLACE_FOR + (spec, i, + LOAD_ATOM_CNT + LOAD_BUF2BINARY_CNT + LOAD_TUPLE_CNT); + i = LOAD_ATOM (spec, i, am_netns); + i = LOAD_BUF2BINARY + (spec, i, desc->netns, strlen(desc->netns)); + i = LOAD_TUPLE (spec, i, 2); + break; + } + else + continue; /* Ignore */ +#endif + /* SCTP and generic INET options: */ case SCTP_OPT_RTOINFO: -- cgit v1.2.3 From 9f3dc09c1a70bd485b211768bedf989bed7fbf21 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Mon, 12 Aug 2013 16:04:31 +0200 Subject: erts: Refactor non-pure macros to functions This is needed as some gcc versions seems to optimize this undefined behaviour in a way which breaks this code. --- erts/emulator/drivers/common/efile_drv.c | 100 +++++++++++++++++++------------ 1 file changed, 61 insertions(+), 39 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 595b0488a8..edcb56de1d 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -546,53 +546,75 @@ static void *ef_safe_realloc(void *op, Uint s) (((char *)(ev)->iov[(q)].iov_base) + (p)) /* int EV_GET_CHAR(ErlIOVec *ev, char *p, int *pp, int *qp) */ -#define EV_GET_CHAR(ev, p, pp, qp) \ - (*(pp)+1 <= (ev)->iov[*(qp)].iov_len \ - ? (*(p) = *EV_CHAR_P(ev, *(pp), *(qp)), \ - *(pp) = ( *(pp)+1 < (ev)->iov[*(qp)].iov_len \ - ? *(pp)+1 \ - : ((*(qp))++, 0)), \ - !0) \ - : 0) +#define EV_GET_CHAR(ev, p, pp, qp) efile_ev_get_char(ev, p ,pp, qp) +static int +efile_ev_get_char(ErlIOVec *ev, char *p, int *pp, int *qp) { + if (*(pp)+1 <= (ev)->iov[*(qp)].iov_len) { + *(p) = *EV_CHAR_P(ev, *(pp), *(qp)); + if (*(pp)+1 < (ev)->iov[*(qp)].iov_len) + *(pp) = *(pp)+1; + else + (*(qp))++; + return !0; + } + return 0; +} /* Uint32 EV_UINT32(ErlIOVec *ev, int p, int q)*/ #define EV_UINT32(ev, p, q) \ ((Uint32) *(((unsigned char *)(ev)->iov[(q)].iov_base) + (p))) /* int EV_GET_UINT32(ErlIOVec *ev, Uint32 *p, int *pp, int *qp) */ -#define EV_GET_UINT32(ev, p, pp, qp) \ - (*(pp)+4 <= (ev)->iov[*(qp)].iov_len \ - ? (*(p) = (EV_UINT32(ev, *(pp), *(qp)) << 24) \ - | (EV_UINT32(ev, *(pp)+1, *(qp)) << 16) \ - | (EV_UINT32(ev, *(pp)+2, *(qp)) << 8) \ - | (EV_UINT32(ev, *(pp)+3, *(qp))), \ - *(pp) = ( *(pp)+4 < (ev)->iov[*(qp)].iov_len \ - ? *(pp)+4 \ - : ((*(qp))++, 0)), \ - !0) \ - : 0) +#define EV_GET_UINT32(ev, p, pp, qp) efile_ev_get_uint32(ev,p,pp,qp) +static int +efile_ev_get_uint32(ErlIOVec *ev, Uint32 *p, int *pp, int *qp) { + if (*(pp)+4 <= (ev)->iov[*(qp)].iov_len) { + *(p) = (EV_UINT32(ev, *(pp), *(qp)) << 24) + | (EV_UINT32(ev, *(pp)+1, *(qp)) << 16) + | (EV_UINT32(ev, *(pp)+2, *(qp)) << 8) + | (EV_UINT32(ev, *(pp)+3, *(qp))); + if (*(pp)+4 < (ev)->iov[*(qp)].iov_len) + *(pp) = *(pp)+4; + else + (*(qp))++; + return !0; + } + return 0; +} /* Uint64 EV_UINT64(ErlIOVec *ev, int p, int q)*/ #define EV_UINT64(ev, p, q) \ ((Uint64) *(((unsigned char *)(ev)->iov[(q)].iov_base) + (p))) -/* int EV_GET_UINT64(ErlIOVec *ev, Uint32 *p, int *pp, int *qp) */ -#define EV_GET_UINT64(ev, p, pp, qp) \ - (*(pp)+8 <= (ev)->iov[*(qp)].iov_len \ - ? (*(p) = (EV_UINT64(ev, *(pp), *(qp)) << 56) \ - | (EV_UINT64(ev, *(pp)+1, *(qp)) << 48) \ - | (EV_UINT64(ev, *(pp)+2, *(qp)) << 40) \ - | (EV_UINT64(ev, *(pp)+3, *(qp)) << 32) \ - | (EV_UINT64(ev, *(pp)+4, *(qp)) << 24) \ - | (EV_UINT64(ev, *(pp)+5, *(qp)) << 16) \ - | (EV_UINT64(ev, *(pp)+6, *(qp)) << 8) \ - | (EV_UINT64(ev, *(pp)+7, *(qp))), \ - *(pp) = ( *(pp)+8 < (ev)->iov[*(qp)].iov_len \ - ? *(pp)+8 \ - : ((*(qp))++, 0)), \ - !0) \ - : 0) +/* int EV_GET_UINT64(ErlIOVec *ev, Uint64 *p, int *pp, int *qp) */ +#define EV_GET_UINT64(ev, p, pp, qp) efile_ev_get_uint64(ev,p,pp,qp) +static int +efile_ev_get_uint64(ErlIOVec *ev, Uint64 *p, int *pp, int *qp) { + if (*(pp)+8 <= (ev)->iov[*(qp)].iov_len) { + *(p) = (EV_UINT64(ev, *(pp), *(qp)) << 56) + | (EV_UINT64(ev, *(pp)+1, *(qp)) << 48) + | (EV_UINT64(ev, *(pp)+2, *(qp)) << 40) + | (EV_UINT64(ev, *(pp)+3, *(qp)) << 32) + | (EV_UINT64(ev, *(pp)+4, *(qp)) << 24) + | (EV_UINT64(ev, *(pp)+5, *(qp)) << 16) + | (EV_UINT64(ev, *(pp)+6, *(qp)) << 8) + | (EV_UINT64(ev, *(pp)+7, *(qp))); + if (*(pp)+8 < (ev)->iov[*(qp)].iov_len) + *(pp) = *(pp)+8; + else + (*(qp))++; + return !0; + } + return 0; +} +/* int EV_GET_SINT64(ErlIOVec *ev, Uint64 *p, int *pp, int *qp) */ +#define EV_GET_SINT64(ev, p, pp, qp) efile_ev_get_sint64(ev,p,pp,qp) +static int +efile_ev_get_sint64(ErlIOVec *ev, Sint64 *p, int *pp, int *qp) { + Uint64 *tmp = (Uint64*)p; + return EV_GET_UINT64(ev,tmp,pp,qp); +} #if 0 @@ -3604,7 +3626,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { for(i = 0; i < n; i++) { Uint32 sizeH, sizeL; size_t size; - if ( !EV_GET_UINT64(ev, &d->c.pwritev.specs[i].offset, &p, &q) + if ( !EV_GET_SINT64(ev, &d->c.pwritev.specs[i].offset, &p, &q) || !EV_GET_UINT32(ev, &sizeH, &p, &q) || !EV_GET_UINT32(ev, &sizeL, &p, &q)) { /* Misalignment in buffer */ @@ -3746,7 +3768,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { for (i = 1; i < 1+n; i++) { Uint32 sizeH, sizeL; size_t size; - if ( !EV_GET_UINT64(ev, &d->c.preadv.offsets[i-1], &p, &q) + if ( !EV_GET_SINT64(ev, &d->c.preadv.offsets[i-1], &p, &q) || !EV_GET_UINT32(ev, &sizeH, &p, &q) || !EV_GET_UINT32(ev, &sizeL, &p, &q)) { reply_posix_error(desc, EINVAL); @@ -3814,7 +3836,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { Uint32 origin; /* Origin of seek. */ if (ev->size < 1+8+4 - || !EV_GET_UINT64(ev, &offset, &p, &q) + || !EV_GET_SINT64(ev, &offset, &p, &q) || !EV_GET_UINT32(ev, &origin, &p, &q)) { /* Wrong length of buffer to contain offset and origin */ reply_posix_error(desc, EINVAL); @@ -3927,7 +3949,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { goto done; } if (ev->size < 1+1+8+4 - || !EV_GET_UINT64(ev, &hdr_offset, &p, &q) + || !EV_GET_SINT64(ev, &hdr_offset, &p, &q) || !EV_GET_UINT32(ev, &max_size, &p, &q)) { /* Buffer too short to contain * the header offset and max size spec */ -- cgit v1.2.3 From 3b1d9f46c187ecdad3930c52fa4fbe4d547277c8 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Tue, 20 Aug 2013 17:19:36 +0200 Subject: erts: Fix bug in translating ev macros to functions --- erts/emulator/drivers/common/efile_drv.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index edcb56de1d..9e95325c24 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -553,8 +553,10 @@ efile_ev_get_char(ErlIOVec *ev, char *p, int *pp, int *qp) { *(p) = *EV_CHAR_P(ev, *(pp), *(qp)); if (*(pp)+1 < (ev)->iov[*(qp)].iov_len) *(pp) = *(pp)+1; - else + else { (*(qp))++; + *pp = 0; + } return !0; } return 0; @@ -575,8 +577,10 @@ efile_ev_get_uint32(ErlIOVec *ev, Uint32 *p, int *pp, int *qp) { | (EV_UINT32(ev, *(pp)+3, *(qp))); if (*(pp)+4 < (ev)->iov[*(qp)].iov_len) *(pp) = *(pp)+4; - else + else { (*(qp))++; + *pp = 0; + } return !0; } return 0; @@ -601,8 +605,10 @@ efile_ev_get_uint64(ErlIOVec *ev, Uint64 *p, int *pp, int *qp) { | (EV_UINT64(ev, *(pp)+7, *(qp))); if (*(pp)+8 < (ev)->iov[*(qp)].iov_len) *(pp) = *(pp)+8; - else + else { (*(qp))++; + *pp = 0; + } return !0; } return 0; -- cgit v1.2.3 From c82784a8fc24ede2760cc96b5f5d6596684ba7e2 Mon Sep 17 00:00:00 2001 From: Patrik Nyblom Date: Fri, 16 Aug 2013 14:42:53 +0200 Subject: Add debug functionality to retrieve async key --- erts/emulator/drivers/common/efile_drv.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 9e95325c24..779ecd1bd2 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -3133,25 +3133,25 @@ file_flush(ErlDrvData e) { /********************************************************************* * Driver entry point -> control + * Only debug functionality... */ static ErlDrvSSizeT file_control(ErlDrvData e, unsigned int command, 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) { + case 'K' : + if (rlen < 4) { + *rbuf = EF_ALLOC(4); + } + (*rbuf)[0] = ((desc->key) >> 24) & 0xFF; + (*rbuf)[1] = ((desc->key) >> 16) & 0xFF; + (*rbuf)[2] = ((desc->key) >> 8) & 0xFF; + (*rbuf)[3] = (desc->key) & 0xFF; + return 4; default: return 0; - } - ASSERT(0); - desc = NULL; - */ - return 0; + } } /********************************************************************* -- cgit v1.2.3 From 7204e78d8d16e41769cfd4b7b4051545052c335e Mon Sep 17 00:00:00 2001 From: Patrik Nyblom Date: Thu, 22 Aug 2013 17:17:03 +0200 Subject: Initialize errno properly in win32 efile_may_openfile --- erts/emulator/drivers/win32/win_efile.c | 1 + 1 file changed, 1 insertion(+) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c index be3d86a1d2..b36a103f8e 100644 --- a/erts/emulator/drivers/win32/win_efile.c +++ b/erts/emulator/drivers/win32/win_efile.c @@ -772,6 +772,7 @@ efile_may_openfile(Efile_error* errInfo, char *name) { DWORD attr; if ((attr = GetFileAttributesW(wname)) == INVALID_FILE_ATTRIBUTES) { + errno = ENOENT; return check_error(-1, errInfo); } -- cgit v1.2.3 From 6d1f1d43aa0a9e0a2cb275ef760339c49518fc69 Mon Sep 17 00:00:00 2001 From: Patrik Nyblom Date: Fri, 16 Aug 2013 17:14:25 +0200 Subject: Create better distribution of files over async threads The actual port id is used to create a key from the pointer value which is the ErlDrvPort. To do this a new driver api function driver_async_port_key is added and the driver API minor version is updated. The documentation is updated and the faulty description of how to spread ports over async threads is updated to use the new API. Testcase also added. --- erts/emulator/drivers/common/efile_drv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 779ecd1bd2..c997fe1bf9 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -772,6 +772,7 @@ file_init(void) return 0; } + /********************************************************************* * Driver entry point -> start */ @@ -788,7 +789,7 @@ file_start(ErlDrvPort port, char* command) } desc->fd = FILE_FD_INVALID; desc->port = port; - desc->key = (unsigned int) (UWord) port; + desc->key = driver_async_port_key(port); desc->flags = 0; desc->invoke = NULL; desc->d = NULL; -- cgit v1.2.3 From c4da6eed78d30670d3602f746030e03c46137ead Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Mon, 2 Sep 2013 15:10:18 +0200 Subject: Fix EV_* macros and functions signedness flaws --- erts/emulator/drivers/common/efile_drv.c | 119 ++++++++++++++++--------------- 1 file changed, 60 insertions(+), 59 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index c997fe1bf9..8de578d8b7 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -542,84 +542,84 @@ static void *ef_safe_realloc(void *op, Uint s) */ /* char EV_CHAR_P(ErlIOVec *ev, int p, int q) */ -#define EV_CHAR_P(ev, p, q) \ - (((char *)(ev)->iov[(q)].iov_base) + (p)) +#define EV_CHAR_P(ev, p, q) \ + (((char *)(ev)->iov[q].iov_base) + (p)) /* int EV_GET_CHAR(ErlIOVec *ev, char *p, int *pp, int *qp) */ #define EV_GET_CHAR(ev, p, pp, qp) efile_ev_get_char(ev, p ,pp, qp) static int -efile_ev_get_char(ErlIOVec *ev, char *p, int *pp, int *qp) { - if (*(pp)+1 <= (ev)->iov[*(qp)].iov_len) { - *(p) = *EV_CHAR_P(ev, *(pp), *(qp)); - if (*(pp)+1 < (ev)->iov[*(qp)].iov_len) - *(pp) = *(pp)+1; - else { - (*(qp))++; - *pp = 0; +efile_ev_get_char(ErlIOVec *ev, char *p, size_t *pp, size_t *qp) { + if (*pp + 1 <= ev->iov[*qp].iov_len) { + *p = *EV_CHAR_P(ev, *pp, *qp); + if (*pp + 1 < ev->iov[*qp].iov_len) + *pp += 1; + else { + *qp += 1; + *pp = 0; + } + return !0; } - return !0; - } - return 0; + return 0; } /* Uint32 EV_UINT32(ErlIOVec *ev, int p, int q)*/ -#define EV_UINT32(ev, p, q) \ - ((Uint32) *(((unsigned char *)(ev)->iov[(q)].iov_base) + (p))) +#define EV_UINT32(ev, p, q) \ + ((Uint32) ((unsigned char *)(ev)->iov[q].iov_base)[p]) /* int EV_GET_UINT32(ErlIOVec *ev, Uint32 *p, int *pp, int *qp) */ -#define EV_GET_UINT32(ev, p, pp, qp) efile_ev_get_uint32(ev,p,pp,qp) +#define EV_GET_UINT32(ev, p, pp, qp) efile_ev_get_uint32(ev, p, pp, qp) static int -efile_ev_get_uint32(ErlIOVec *ev, Uint32 *p, int *pp, int *qp) { - if (*(pp)+4 <= (ev)->iov[*(qp)].iov_len) { - *(p) = (EV_UINT32(ev, *(pp), *(qp)) << 24) - | (EV_UINT32(ev, *(pp)+1, *(qp)) << 16) - | (EV_UINT32(ev, *(pp)+2, *(qp)) << 8) - | (EV_UINT32(ev, *(pp)+3, *(qp))); - if (*(pp)+4 < (ev)->iov[*(qp)].iov_len) - *(pp) = *(pp)+4; - else { - (*(qp))++; - *pp = 0; +efile_ev_get_uint32(ErlIOVec *ev, Uint32 *p, size_t *pp, size_t *qp) { + if (*pp + 4 <= ev->iov[*qp].iov_len) { + *p = (EV_UINT32(ev, *pp, *qp) << 24) + | (EV_UINT32(ev, *pp + 1, *qp) << 16) + | (EV_UINT32(ev, *pp + 2, *qp) << 8) + | (EV_UINT32(ev, *pp + 3, *qp)); + if (*pp + 4 < ev->iov[*qp].iov_len) + *pp += 4; + else { + *qp += 1; + *pp = 0; + } + return !0; } - return !0; - } - return 0; + return 0; } /* Uint64 EV_UINT64(ErlIOVec *ev, int p, int q)*/ -#define EV_UINT64(ev, p, q) \ - ((Uint64) *(((unsigned char *)(ev)->iov[(q)].iov_base) + (p))) +#define EV_UINT64(ev, p, q) \ + ((Uint64) ((unsigned char *)(ev)->iov[q].iov_base)[p]) /* int EV_GET_UINT64(ErlIOVec *ev, Uint64 *p, int *pp, int *qp) */ -#define EV_GET_UINT64(ev, p, pp, qp) efile_ev_get_uint64(ev,p,pp,qp) +#define EV_GET_UINT64(ev, p, pp, qp) efile_ev_get_uint64(ev, p, pp, qp) static int -efile_ev_get_uint64(ErlIOVec *ev, Uint64 *p, int *pp, int *qp) { - if (*(pp)+8 <= (ev)->iov[*(qp)].iov_len) { - *(p) = (EV_UINT64(ev, *(pp), *(qp)) << 56) - | (EV_UINT64(ev, *(pp)+1, *(qp)) << 48) - | (EV_UINT64(ev, *(pp)+2, *(qp)) << 40) - | (EV_UINT64(ev, *(pp)+3, *(qp)) << 32) - | (EV_UINT64(ev, *(pp)+4, *(qp)) << 24) - | (EV_UINT64(ev, *(pp)+5, *(qp)) << 16) - | (EV_UINT64(ev, *(pp)+6, *(qp)) << 8) - | (EV_UINT64(ev, *(pp)+7, *(qp))); - if (*(pp)+8 < (ev)->iov[*(qp)].iov_len) - *(pp) = *(pp)+8; - else { - (*(qp))++; - *pp = 0; +efile_ev_get_uint64(ErlIOVec *ev, Uint64 *p, size_t *pp, size_t *qp) { + if (*pp + 8 <= ev->iov[*qp].iov_len) { + *p = (EV_UINT64(ev, *pp, *qp) << 56) + | (EV_UINT64(ev, *pp + 1, *qp) << 48) + | (EV_UINT64(ev, *pp + 2, *qp) << 40) + | (EV_UINT64(ev, *pp + 3, *qp) << 32) + | (EV_UINT64(ev, *pp + 4, *qp) << 24) + | (EV_UINT64(ev, *pp + 5, *qp) << 16) + | (EV_UINT64(ev, *pp + 6, *qp) << 8) + | (EV_UINT64(ev, *pp + 7, *qp)); + if (*pp + 8 < ev->iov[*qp].iov_len) + *pp += 8; + else { + *qp += 1; + *pp = 0; + } + return !0; } - return !0; - } - return 0; + return 0; } /* int EV_GET_SINT64(ErlIOVec *ev, Uint64 *p, int *pp, int *qp) */ -#define EV_GET_SINT64(ev, p, pp, qp) efile_ev_get_sint64(ev,p,pp,qp) +#define EV_GET_SINT64(ev, p, pp, qp) efile_ev_get_sint64(ev, p, pp, qp) static int -efile_ev_get_sint64(ErlIOVec *ev, Sint64 *p, int *pp, int *qp) { - Uint64 *tmp = (Uint64*)p; - return EV_GET_UINT64(ev,tmp,pp,qp); +efile_ev_get_sint64(ErlIOVec *ev, Sint64 *p, size_t *pp, size_t *qp) { + Uint64 *tmp = (Uint64*)p; + return EV_GET_UINT64(ev, tmp, pp, qp); } #if 0 @@ -1139,7 +1139,7 @@ static void invoke_read(void *data) read_size = erts_gzread((gzFile)d->fd, d->c.read.binp->orig_bytes + d->c.read.bin_offset, size); - status = (read_size != -1); + status = (read_size != (size_t) -1); if (!status) { d->errInfo.posix_errno = EIO; } @@ -1213,7 +1213,7 @@ static void invoke_read_line(void *data) d->c.read_line.binp->orig_bytes + d->c.read_line.read_offset + d->c.read_line.read_size, size); - status = (read_size != -1); + status = (read_size != (size_t) -1); if (!status) { d->errInfo.posix_errno = EIO; } @@ -1707,8 +1707,9 @@ static void invoke_pwritev(void *data) { ASSERT(written == size); d->again = 0; } - } else + } else { ASSERT(written >= FILE_SEGMENT_WRITE); + } MUTEX_LOCK(d->c.writev.q_mtx); driver_deq(d->c.pwritev.port, written); @@ -3205,7 +3206,7 @@ static void file_outputv(ErlDrvData e, ErlIOVec *ev) { file_descriptor* desc = (file_descriptor*)e; char command; - int p, q; + size_t p, q; int err; struct t_data *d = NULL; #ifdef USE_VM_PROBES -- cgit v1.2.3 From 21095e6830f37676dd29c33a590851ba2c76499b Mon Sep 17 00:00:00 2001 From: Pierre Fenoll Date: Tue, 10 Sep 2013 15:48:29 +0100 Subject: Remove ^L characters hidden randomly in the code. Not those used in text files as delimiters. While working on a tool that processes Erlang code and testing it against this repo, I found out about those little sneaky 0xff. I thought it may be of help to other people build such tools to remove non-conforming-to-standard characters. --- erts/emulator/drivers/unix/ttsl_drv.c | 8 ++++---- erts/emulator/drivers/win32/win_efile.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/unix/ttsl_drv.c b/erts/emulator/drivers/unix/ttsl_drv.c index 1e436830e7..491e0a090e 100644 --- a/erts/emulator/drivers/unix/ttsl_drv.c +++ b/erts/emulator/drivers/unix/ttsl_drv.c @@ -745,7 +745,7 @@ static Sint16 get_sint16(char *s) { return ((*s << 8) | ((byte*)s)[1]); } - + static int start_lbuf(void) { if (!lbuf && !(lbuf = ( Uint32*) driver_alloc(lbuf_size * sizeof(Uint32)))) @@ -1091,7 +1091,7 @@ static int move_cursor(int from, int to) move_left(-dc); return TRUE; } - + static int start_termcap(void) { int eres; @@ -1187,7 +1187,7 @@ static int move_down(int n) tputs(down, 1, outc); return TRUE; } - + /* * Updates cols if terminal has resized (SIGWINCH). Should be called @@ -1209,7 +1209,7 @@ static void update_cols(void) cols = width; } } - + /* * Put a terminal device into non-canonical mode with ECHO off. diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c index b36a103f8e..319065f57b 100644 --- a/erts/emulator/drivers/win32/win_efile.c +++ b/erts/emulator/drivers/win32/win_efile.c @@ -1216,7 +1216,7 @@ int flags; return 1; } - + /* * is_root_unc_name - returns TRUE if the argument is a UNC name specifying * a root share. That is, if it is of the form \\server\share\. -- cgit v1.2.3 From 7fbf2c26ac063988818230a0e18a9df48c2fbf2d Mon Sep 17 00:00:00 2001 From: Steve Vinoski Date: Tue, 27 Aug 2013 11:42:00 -0400 Subject: add {active,N} socket option for TCP, UDP, and SCTP Add the {active,N} socket option, where N is an integer in the range -32768..32767, to allow a caller to specify the number of data messages to be delivered to the controlling process. Once the socket's delivered message count either reaches 0 or is explicitly set to 0 with inet:setopts/2 or by including {active,0} as an option when the socket is created, the socket transitions to passive ({active, false}) mode and the socket's controlling process receives a message to inform it of the transition. TCP sockets receive {tcp_passive,Socket}, UDP sockets receive {udp_passive,Socket} and SCTP sockets receive {sctp_passive,Socket}. The socket's delivered message counter defaults to 0, but it can be set using {active,N} via any gen_tcp, gen_udp, or gen_sctp function that takes socket options as arguments, or via inet:setopts/2. New N values are added to the socket's current counter value, and negative numbers can be used to reduce the counter value. Specifying a number that would cause the socket's counter value to go above 32767 causes an einval error. If a negative number is specified such that the counter value would become negative, the socket's counter value is set to 0 and the socket transitions to passive mode. If the counter value is already 0 and inet:setopts(Socket, [{active,0}]) is specified, the counter value remains at 0 but the appropriate passive mode transition message is generated for the socket. This commit contains a modified preloaded prim_inet.beam due to changes in prim_inet.erl. Add tests for {active,N} mode for TCP, UDP, and SCTP sockets. Add documentation for {active,N} mode for inet, gen_tcp, gen_udp, and gen_sctp. --- erts/emulator/drivers/common/inet_drv.c | 119 +++++++++++++++++++++++++++++--- 1 file changed, 109 insertions(+), 10 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 60db50e80a..7dcb191a83 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -86,6 +86,13 @@ #endif typedef unsigned long long llu_t; +#ifndef INT16_MIN +#define INT16_MIN (-32768) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif + #ifdef __WIN32__ #define STRNCASECMP strncasecmp @@ -581,6 +588,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #define INET_PASSIVE 0 /* false */ #define INET_ACTIVE 1 /* true */ #define INET_ONCE 2 /* true; active once then passive */ +#define INET_MULTI 3 /* true; active N then passive */ /* INET_REQ_GETSTATUS enumeration */ #define INET_F_OPEN 0x0001 @@ -925,6 +933,7 @@ typedef struct { inet_async_op op_queue[INET_MAX_ASYNC]; /* call queue */ int active; /* 0 = passive, 1 = active, 2 = active once */ + Sint16 active_count; /* counter for {active,N} */ int stype; /* socket type: SOCK_STREAM/SOCK_DGRAM/SOCK_SEQPACKET */ int sprotocol; /* socket protocol: @@ -1160,22 +1169,36 @@ static int packet_inet_output(udp_descriptor* udesc, HANDLE event); static int async_ref = 0; /* async reference id generator */ #define NEW_ASYNC_ID() ((async_ref++) & 0xffff) +/* check for transition from active to passive */ +#define INET_CHECK_ACTIVE_TO_PASSIVE(inet) \ + do { \ + if ((inet)->active == INET_ONCE) \ + (inet)->active = INET_PASSIVE; \ + else if ((inet)->active == INET_MULTI && --((inet)->active_count) == 0) { \ + (inet)->active = INET_PASSIVE; \ + packet_passive_message(inet); \ + } \ + } while (0) static ErlDrvTermData am_ok; static ErlDrvTermData am_tcp; static ErlDrvTermData am_udp; static ErlDrvTermData am_error; +static ErlDrvTermData am_einval; static ErlDrvTermData am_inet_async; static ErlDrvTermData am_inet_reply; static ErlDrvTermData am_timeout; static ErlDrvTermData am_closed; +static ErlDrvTermData am_tcp_passive; static ErlDrvTermData am_tcp_closed; static ErlDrvTermData am_tcp_error; +static ErlDrvTermData am_udp_passive; static ErlDrvTermData am_udp_error; static ErlDrvTermData am_empty_out_q; static ErlDrvTermData am_ssl_tls; #ifdef HAVE_SCTP static ErlDrvTermData am_sctp; +static ErlDrvTermData am_sctp_passive; static ErlDrvTermData am_sctp_error; static ErlDrvTermData am_true; static ErlDrvTermData am_false; @@ -1185,6 +1208,7 @@ static ErlDrvTermData am_list; static ErlDrvTermData am_binary; static ErlDrvTermData am_active; static ErlDrvTermData am_once; +static ErlDrvTermData am_multi; static ErlDrvTermData am_buffer; static ErlDrvTermData am_linger; static ErlDrvTermData am_recbuf; @@ -3336,6 +3360,34 @@ static int packet_binary_message return erl_drv_output_term(desc->dport, spec, i); } +/* +** active mode message: send active-to-passive transition message +** {tcp_passive, S} or +** {udp_passive, S} or +** {sctp_passive, S} +*/ + static int packet_passive_message(inet_descriptor* desc) + { + ErlDrvTermData spec[6]; + int i = 0; + + DEBUGF(("packet_passive_message(%ld):\r\n", (long)desc->port)); + + if (desc->sprotocol == IPPROTO_TCP) + i = LOAD_ATOM(spec, i, am_tcp_passive); + else { +#ifdef HAVE_SCTP + i = LOAD_ATOM(spec, i, IS_SCTP(desc) ? am_sctp_passive : am_udp_passive); +#else + i = LOAD_ATOM(spec, i, am_udp_passive); +#endif + } + i = LOAD_PORT(spec, i, desc->dport); + i = LOAD_TUPLE(spec, i, 2); + ASSERT(i <= 6); + return erl_drv_output_term(desc->dport, spec, i); + } + /* ** send active message {udp_error|sctp_error, S, Error} */ @@ -3378,7 +3430,7 @@ static int tcp_reply_data(tcp_descriptor* desc, char* buf, int len) int code; const char* body = buf; int bodylen = len; - + packet_get_body(desc->inet.htype, &body, &bodylen); if (desc->inet.deliver == INET_DELIVER_PORT) { @@ -3396,8 +3448,7 @@ static int tcp_reply_data(tcp_descriptor* desc, char* buf, int len) if (code < 0) return code; - if (desc->inet.active == INET_ONCE) - desc->inet.active = INET_PASSIVE; + INET_CHECK_ACTIVE_TO_PASSIVE(INETP(desc)); return code; } @@ -3424,8 +3475,7 @@ tcp_reply_binary_data(tcp_descriptor* desc, ErlDrvBinary* bin, int offs, int len } if (code < 0) return code; - if (desc->inet.active == INET_ONCE) - desc->inet.active = INET_PASSIVE; + INET_CHECK_ACTIVE_TO_PASSIVE(INETP(desc)); return code; } @@ -3448,8 +3498,7 @@ packet_reply_binary_data(inet_descriptor* desc, unsigned int hsz, code = packet_binary_message(desc, bin, offs, len, extra); if (code < 0) return code; - if (desc->active == INET_ONCE) - desc->active = INET_PASSIVE; + INET_CHECK_ACTIVE_TO_PASSIVE(desc); return code; } } @@ -3494,6 +3543,7 @@ sock_init(void) /* May be called multiple times. */ #ifdef HAVE_SCTP static void inet_init_sctp(void) { INIT_ATOM(sctp); + INIT_ATOM(sctp_passive); INIT_ATOM(sctp_error); INIT_ATOM(true); INIT_ATOM(false); @@ -3503,6 +3553,7 @@ static void inet_init_sctp(void) { INIT_ATOM(binary); INIT_ATOM(active); INIT_ATOM(once); + INIT_ATOM(multi); INIT_ATOM(buffer); INIT_ATOM(linger); INIT_ATOM(recbuf); @@ -3628,12 +3679,15 @@ static int inet_init() INIT_ATOM(tcp); INIT_ATOM(udp); INIT_ATOM(error); + INIT_ATOM(einval); INIT_ATOM(inet_async); INIT_ATOM(inet_reply); INIT_ATOM(timeout); INIT_ATOM(closed); + INIT_ATOM(tcp_passive); INIT_ATOM(tcp_closed); INIT_ATOM(tcp_error); + INIT_ATOM(udp_passive); INIT_ATOM(udp_error); INIT_ATOM(empty_out_q); INIT_ATOM(ssl_tls); @@ -5508,8 +5562,25 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) case INET_LOPT_ACTIVE: DEBUGF(("inet_set_opts(%ld): s=%d, ACTIVE=%d\r\n", - (long)desc->port, desc->s,ival)); + (long)desc->port, desc->s, ival)); desc->active = ival; + if (desc->active == INET_MULTI) { + long ac = desc->active_count; + Sint16 nval = get_int16(ptr); + ptr += 2; + len -= 2; + ac += nval; + if (ac > INT16_MAX || ac < INT16_MIN) + return -1; + desc->active_count += nval; + if (desc->active_count < 0) + desc->active_count = 0; + if (desc->active_count == 0) { + desc->active = INET_PASSIVE; + packet_passive_message(desc); + } + } else + desc->active_count = 0; if ((desc->stype == SOCK_STREAM) && (desc->active != INET_PASSIVE) && (desc->state == INET_STATE_CLOSED)) { tcp_closed_message((tcp_descriptor *) desc); @@ -5820,7 +5891,8 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) /* XXX fprintf(stderr,"desc->htype == %d, old_htype == %d, desc->active == %d, old_active == %d\r\n",(int)desc->htype, (int) old_htype, (int) desc->active, (int) old_active );*/ - return 1+(desc->htype == old_htype && desc->active == INET_ONCE); + return 1+(desc->htype == old_htype && + (desc->active == INET_ONCE || desc->active == INET_MULTI)); } return 0; } @@ -5953,6 +6025,21 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) case INET_LOPT_ACTIVE: desc->active = get_int32(curr); curr += 4; + if (desc->active == INET_MULTI) { + long ac = desc->active_count; + Sint16 nval = get_int16(curr); curr += 2; + ac += nval; + if (ac > INT16_MAX || ac < INT16_MIN) + return -1; + desc->active_count += nval; + if (desc->active_count < 0) + desc->active_count = 0; + if (desc->active_count == 0) { + desc->active = INET_PASSIVE; + packet_passive_message(desc); + } + } else + desc->active_count = 0; res = 0; continue; @@ -6475,6 +6562,11 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc, case INET_LOPT_ACTIVE: *ptr++ = opt; put_int32(desc->active, ptr); + if (desc->active == INET_MULTI) { + PLACE_FOR(2,ptr); + put_int16(desc->active_count, ptr); + ptr += 2; + } continue; case INET_LOPT_PACKET: *ptr++ = opt; @@ -6847,7 +6939,10 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc, } case INET_LOPT_ACTIVE: { - PLACE_FOR(spec, i, 2*LOAD_ATOM_CNT + LOAD_TUPLE_CNT); + if (desc->active == INET_MULTI) + PLACE_FOR(spec, i, LOAD_ATOM_CNT + LOAD_INT_CNT + LOAD_TUPLE_CNT); + else + PLACE_FOR(spec, i, 2*LOAD_ATOM_CNT + LOAD_TUPLE_CNT); i = LOAD_ATOM (spec, i, am_active); switch (desc->active) { @@ -6860,6 +6955,9 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc, case INET_ONCE : { i = LOAD_ATOM (spec, i, am_once); break; } + case INET_MULTI : + { i = LOAD_INT(spec, i, desc->active_count); break; } + default: ASSERT (0); } i = LOAD_TUPLE (spec, i, 2); @@ -7656,6 +7754,7 @@ static ErlDrvData inet_start(ErlDrvPort port, int size, int protocol) socket */ desc->deliver = INET_DELIVER_TERM; /* standard term format */ desc->active = INET_PASSIVE; /* start passive */ + desc->active_count = 0; desc->oph = NULL; desc->opt = NULL; -- cgit v1.2.3 From 156b011958a3b80e507039ddc916db039874ada1 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 27 Aug 2013 17:23:09 +0200 Subject: erts: Refactor the ASSERT macro Introduce unconditional ERTS_ASSERT and use that for both ASSERT and ASSERT_EXPR. --- erts/emulator/drivers/common/inet_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 60db50e80a..12f45245b5 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -4433,7 +4433,7 @@ static ErlDrvSSizeT inet_ctl_getiflist(inet_descriptor* desc, case AF_INET6: #endif case AF_INET: - ASSERT(sp+IFNAMSIZ+1 < sbuf+ifc.ifc_len+1) + ASSERT(sp+IFNAMSIZ+1 < sbuf+ifc.ifc_len+1); strncpy(sp, ifrp->ifr_name, IFNAMSIZ); sp[IFNAMSIZ] = '\0'; sp += strlen(sp), ++sp; -- cgit v1.2.3 From bb52546e9a671ed0fd55d2e5274f299a853bed51 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Tue, 5 Nov 2013 15:52:56 +0100 Subject: Implement prim_inet:socknames/1,2 and prim_inet:peernames/1,2 --- erts/emulator/drivers/common/inet_drv.c | 225 ++++++++++++++++++++++++++++++-- 1 file changed, 217 insertions(+), 8 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 60db50e80a..8d26adfa63 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -417,13 +417,44 @@ static unsigned long one_value = 1; # define sctp_adaptation_layer_event sctp_adaption_layer_event #endif -#ifdef __GNUC__ +#if defined(__GNUC__) && defined(HAVE_SCTP_BINDX) static typeof(sctp_bindx) *p_sctp_bindx = NULL; +#else +static int (*p_sctp_bindx) + (int sd, struct sockaddr *addrs, int addrcnt, int flags) = NULL; +#endif + +#if defined(__GNUC__) && defined(HAVE_SCTP_PEELOFF) 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; +static int (*p_sctp_peeloff) + (int sd, sctp_assoc_t assoc_id) = NULL; +#endif + +#if defined(__GNUC__) && defined(HAVE_SCTP_GETLADDRS) +static typeof(sctp_getladdrs) *p_sctp_getladdrs = NULL; +#else +static int (*p_sctp_getladdrs) + (int sd, sctp_assoc_t assoc_id, struct sockaddr **ss) = NULL; +#endif + +#if defined(__GNUC__) && defined(HAVE_SCTP_FREELADDRS) +static typeof(sctp_freeladdrs) *p_sctp_freeladdrs = NULL; +#else +static void (*p_sctp_freeladdrs)(struct sockaddr *addrs) = NULL; +#endif + +#if defined(__GNUC__) && defined(HAVE_SCTP_GETPADDRS) +static typeof(sctp_getpaddrs) *p_sctp_getpaddrs = NULL; +#else +static int (*p_sctp_getpaddrs) + (int sd, sctp_assoc_t assoc_id, struct sockaddr **ss) = NULL; +#endif + +#if defined(__GNUC__) && defined(HAVE_SCTP_FREEPADDRS) +static typeof(sctp_freepaddrs) *p_sctp_freepaddrs = NULL; +#else +static void (*p_sctp_freepaddrs)(struct sockaddr *addrs) = NULL; #endif #endif /* #if defined(HAVE_SCTP_H) */ @@ -593,7 +624,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #define INET_F_BUSY 0x0080 #define INET_F_MULTI_CLIENT 0x0100 /* Multiple clients for one descriptor, i.e. multi-accept */ -/* One numberspace for *_REC_* so if an e.g UDP request is issued +/* One numberspace for *_REQ_* so if an e.g UDP request is issued ** for a TCP socket, the driver can protest. */ #define INET_REQ_OPEN 1 @@ -624,6 +655,8 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #define INET_REQ_ACCEPT 26 #define INET_REQ_LISTEN 27 #define INET_REQ_IGNOREFD 28 +#define INET_REQ_GETLADDRS 29 +#define INET_REQ_GETPADDRS 30 /* TCP requests */ /* #define TCP_REQ_ACCEPT 40 MOVED */ @@ -3658,9 +3691,27 @@ 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); -# if defined(HAVE_SCTP_BINDX) && defined (HAVE_SCTP_PEELOFF) +# if defined(HAVE_SCTP_BINDX) p_sctp_bindx = sctp_bindx; +# if defined(HAVE_SCTP_PEELOFF) p_sctp_peeloff = sctp_peeloff; +# else + p_sctp_peeloff = NULL; +# endif +# if defined(HAVE_SCTP_GETLADDRS) && defined(HAVE_SCTP_FREELADDRS) + p_sctp_getladdrs = sctp_getladdrs; + p_sctp_freeladdrs = sctp_freeladdrs; +# else + p_sctp_getladdrs = NULL; + p_sctp_freeladdrs = NULL; +# endif +# if defined(HAVE_SCTP_GETPADDRS) && defined(HAVE_SCTP_FREEPADDRS) + p_sctp_getpaddrs = sctp_getpaddrs; + p_sctp_freepaddrs = sctp_freepaddrs; +# else + p_sctp_getpaddrs = NULL; + p_sctp_freepaddrs = NULL; +# endif inet_init_sctp(); add_driver_entry(&sctp_inet_driver_entry); # else @@ -3675,12 +3726,36 @@ static int inet_init() 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; } + else p_sctp_peeloff = NULL; + if (erts_sys_ddll_sym(h_libsctp, "sctp_getladdrs", &ptr) == 0) { + p_sctp_getladdrs = ptr; + } + else p_sctp_getladdrs = NULL; + if (erts_sys_ddll_sym(h_libsctp, "sctp_freeladdrs", &ptr) == 0) { + p_sctp_freeladdrs = ptr; + } + else { + p_sctp_freeladdrs = NULL; + p_sctp_getladdrs = NULL; + } + if (erts_sys_ddll_sym(h_libsctp, "sctp_getpaddrs", &ptr) == 0) { + p_sctp_getpaddrs = ptr; + } + else p_sctp_getpaddrs = NULL; + if (erts_sys_ddll_sym(h_libsctp, "sctp_freepaddrs", &ptr) == 0) { + p_sctp_freepaddrs = ptr; + } + else { + p_sctp_freepaddrs = NULL; + p_sctp_getpaddrs = NULL; + } + inet_init_sctp(); + add_driver_entry(&sctp_inet_driver_entry); } + else p_sctp_bindx = NULL; } } # endif @@ -3860,6 +3935,74 @@ static int inet_get_address(int family, char* dst, inet_address* src, unsigned i return -1; } +/* Same as the above, but take family from the address structure, +** and advance the address pointer to the next address +** according to the size of the current, +** and return the resulting encoded size +*/ +static int inet_address_to_erlang(char *dst, inet_address **src) { + short port; + + switch ((*src)->sa.sa_family) { + case AF_INET: + if (dst) { + dst[0] = INET_AF_INET; + port = sock_ntohs((*src)->sai.sin_port); + put_int16(port, dst+1); + sys_memcpy(dst+1+2, (char *) &(*src)->sai.sin_addr, 4); + } + (*src) = (inet_address *) (&(*src)->sai + 1); + return 1 + 2 + 4; +#if defined(HAVE_IN6) && defined(AF_INET6) + case AF_INET6: + if (dst) { + dst[0] = INET_AF_INET6; + port = sock_ntohs((*src)->sai6.sin6_port); + put_int16(port, dst+1); + sys_memcpy(dst+1+2, (char *) &(*src)->sai6.sin6_addr, 16); + } + (*src) = (inet_address *) (&(*src)->sai6 + 1); + return 1 + 2 + 16; +#endif + default: + return -1; + } +} + +/* Encode n encoded addresses from addrs in the result buffer +*/ +static ErlDrvSizeT reply_inet_addrs +(int n, inet_address *addrs, char **rbuf, ErlDrvSizeT rsize) { + inet_address *ia; + int i, s; + ErlDrvSizeT rlen; + + if (IS_SOCKET_ERROR(n)) return ctl_error(sock_errno(), rbuf, rsize); + if (n == 0) return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); + + /* Calculate result length */ + rlen = 1; + ia = addrs; + for (i = 0; i < n; i++) { + s = inet_address_to_erlang(NULL, &ia); + if (s < 0) break; + rlen += s; + } + + if (rlen > rsize) (*rbuf) = ALLOC(rlen); + + (*rbuf)[0] = INET_REP_OK; + rlen = 1; + ia = addrs; + for (i = 0; i < n; i++) { + s = inet_address_to_erlang((*rbuf)+rlen, &ia); + if (s < 0) break; + rlen += s; + } + + return rlen; +} + static void desc_close(inet_descriptor* desc) { if (desc->s != INVALID_SOCKET) { @@ -7879,6 +8022,39 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, return ctl_reply(INET_REP_OK, tbuf, strlen(tbuf), rbuf, rsize); } + case INET_REQ_GETPADDRS: { + DEBUGF(("inet_ctl(%ld): INET_GETPADDRS\r\n", (long)desc->port)); + + if (len != 4) return ctl_error(EINVAL, rbuf, rsize); + + if (! IS_OPEN(desc)) return ctl_xerror(EXBADPORT, rbuf, rsize); + if (! IS_BOUND(desc)) return ctl_xerror(EXBADSEQ, rbuf, rsize); + +#ifdef HAVE_SCTP + if (IS_SCTP(desc) && p_sctp_getpaddrs) { + struct sockaddr *sa; + Uint32 assoc_id; + int n; + ErlDrvSizeT rlen; + + assoc_id = get_int32(buf); + n = p_sctp_getpaddrs(desc->s, assoc_id, &sa); + rlen = reply_inet_addrs(n, (inet_address *) sa, rbuf, rsize); + if (n > 0) p_sctp_freepaddrs(sa); + return rlen; + } +#endif + { /* Fallback to sock_peer */ + inet_address addr; + unsigned int sz; + int i; + + sz = sizeof(addr); + i = sock_peer(desc->s, (struct sockaddr *) &addr, &sz); + return reply_inet_addrs(i >= 0 ? 1 : i, &addr, rbuf, rsize); + } + } + case INET_REQ_PEER: { /* get peername */ char tbuf[sizeof(inet_address)]; inet_address peer; @@ -7915,6 +8091,39 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, } } + case INET_REQ_GETLADDRS: { + DEBUGF(("inet_ctl(%ld): INET_GETLADDRS\r\n", (long)desc->port)); + + if (len != 4) return ctl_error(EINVAL, rbuf, rsize); + + if (! IS_OPEN(desc)) return ctl_xerror(EXBADPORT, rbuf, rsize); + if (! IS_BOUND(desc)) return ctl_xerror(EXBADSEQ, rbuf, rsize); + +#ifdef HAVE_SCTP + if (IS_SCTP(desc) && p_sctp_getladdrs) { + struct sockaddr *sa; + Uint32 assoc_id; + int n; + ErlDrvSizeT rlen; + + assoc_id = get_int32(buf); + n = p_sctp_getladdrs(desc->s, assoc_id, &sa); + rlen = reply_inet_addrs(n, (inet_address *) sa, rbuf, rsize); + if (n > 0) p_sctp_freeladdrs(sa); + return rlen; + } +#endif + { /* Fallback to sock_name */ + inet_address addr; + unsigned int sz; + int i; + + sz = sizeof(addr); + i = sock_name(desc->s, (struct sockaddr *) &addr, &sz); + return reply_inet_addrs(i >= 0 ? 1 : i, &addr, rbuf, rsize); + } + } + case INET_REQ_NAME: { /* get sockname */ char tbuf[sizeof(inet_address)]; inet_address name; -- cgit v1.2.3 From 2e96b554bd0374224aed1c28e48d139fad42c38e Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Mon, 11 Nov 2013 15:07:14 +0100 Subject: Clean up address family handling towards Erlang --- erts/emulator/drivers/common/inet_drv.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 8d26adfa63..de18656273 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -1450,8 +1450,7 @@ static int load_ip_address(ErlDrvTermData* spec, int i, int family, char* buf) #ifdef HAVE_SCTP /* For SCTP, we often need to return {IP, Port} tuples: */ -static int inet_get_address - (int family, char* dst, inet_address* src, unsigned int* len); +static int inet_get_address(char* dst, inet_address* src, unsigned int* len); #define LOAD_IP_AND_PORT_CNT \ (8*LOAD_INT_CNT + LOAD_TUPLE_CNT + LOAD_INT_CNT + LOAD_TUPLE_CNT) @@ -1466,8 +1465,7 @@ static int load_ip_and_port unsigned int len = sizeof(struct sockaddr_storage); unsigned int alen = len; char abuf [len]; - int res = - inet_get_address(desc->sfamily, abuf, (inet_address*) addr, &alen); + int res = inet_get_address(abuf, (inet_address*) addr, &alen); ASSERT(res==0); res = 0; /* Now "abuf" contains: Family(1b), Port(2b), IP(4|16b) */ @@ -3910,10 +3908,12 @@ static char *inet_set_faddress(int family, inet_address* dst, ** and *len is the length of dst on return ** (suitable to deliver to erlang) */ -static int inet_get_address(int family, char* dst, inet_address* src, unsigned int* len) +static int inet_get_address(char* dst, inet_address* src, unsigned int* len) { + int family; short port; + family = src->sa.sa_family; if ((family == AF_INET) && (*len >= sizeof(struct sockaddr_in))) { dst[0] = INET_AF_INET; port = sock_ntohs(src->sai.sin_port); @@ -8070,7 +8070,7 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, if (IS_SOCKET_ERROR(sock_peer(desc->s, (struct sockaddr*)ptr,&sz))) return ctl_error(sock_errno(), rbuf, rsize); } - if (inet_get_address(desc->sfamily, tbuf, ptr, &sz) < 0) + if (inet_get_address(tbuf, ptr, &sz) < 0) return ctl_error(EINVAL, rbuf, rsize); return ctl_reply(INET_REP_OK, tbuf, sz, rbuf, rsize); } @@ -8140,7 +8140,7 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, if (IS_SOCKET_ERROR(sock_name(desc->s, (struct sockaddr*)ptr, &sz))) return ctl_error(sock_errno(), rbuf, rsize); } - if (inet_get_address(desc->sfamily, tbuf, ptr, &sz) < 0) + if (inet_get_address(tbuf, ptr, &sz) < 0) return ctl_error(EINVAL, rbuf, rsize); return ctl_reply(INET_REP_OK, tbuf, sz, rbuf, rsize); } @@ -10979,7 +10979,7 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event) inet_input_count(desc, n); udesc->i_ptr += n; - inet_get_address(desc->sfamily, abuf, &other, &len); + inet_get_address(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, -- cgit v1.2.3 From f47c818746c1df4055b1de8aabf47364f502274c Mon Sep 17 00:00:00 2001 From: Joseph Blomstedt Date: Thu, 29 Nov 2012 14:50:42 -0800 Subject: Add sync option to file:open/2 The sync option adds the POSIX O_SYNC flag to the open system call on platforms that support the flag or its equivalent, e.g., FILE_FLAG_WRITE_THROUGH on Windows. For platforms that don't support it, file:open/2 returns {error, enotsup} if the sync option is passed in. The semantics of O_SYNC are platform-specific. For example, not all platforms guarantee that all file metadata are written to the disk along with the file data when the flag is in effect. This issue is noted in the documentation this commit adds for the sync option. Add a test for the sync option. Note however that the underlying OS semantics for O_SYNC can't be tested automatically in any practical way, so the test assumes the OS does the right thing with the flag when present. For manual verification, dtruss on OS X and strace on Linux were both run against beam processes to watch calls to open(), and file:open/2 was called in Erlang shells to open files for writing, both with and without the sync option. Both the dtruss output and the strace output showed that the O_SYNC flag was present in the open() calls when sync was specified and was clear when sync was not specified. --- erts/emulator/drivers/common/erl_efile.h | 1 + erts/emulator/drivers/unix/unix_efile.c | 9 +++++++++ erts/emulator/drivers/win32/win_efile.c | 7 ++++++- 3 files changed, 16 insertions(+), 1 deletion(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/erl_efile.h b/erts/emulator/drivers/common/erl_efile.h index 5387f75efc..95c036db8f 100644 --- a/erts/emulator/drivers/common/erl_efile.h +++ b/erts/emulator/drivers/common/erl_efile.h @@ -34,6 +34,7 @@ #define EFILE_COMPRESSED 8 #define EFILE_MODE_EXCL 16 #define EFILE_NO_TRUNCATE 32 /* Special for reopening on VxWorks */ +#define EFILE_MODE_SYNC 64 /* * Seek modes for efile_seek(). diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c index 55539b44dd..8ffc05da99 100644 --- a/erts/emulator/drivers/unix/unix_efile.c +++ b/erts/emulator/drivers/unix/unix_efile.c @@ -405,6 +405,15 @@ efile_openfile(Efile_error* errInfo, /* Where to return error codes. */ mode |= O_EXCL; } + if (flags & EFILE_MODE_SYNC) { +#ifdef O_SYNC + mode |= O_SYNC; +#else + errno = ENOTSUP; + return check_error(-1, errInfo); +#endif + } + fd = open(name, mode, FILE_MODE); if (!check_error(fd, errInfo)) diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c index 319065f57b..d693d7d593 100644 --- a/erts/emulator/drivers/win32/win_efile.c +++ b/erts/emulator/drivers/win32/win_efile.c @@ -698,6 +698,7 @@ efile_openfile(Efile_error* errInfo, /* Where to return error codes. */ HANDLE fd; /* Handle to open file. */ DWORD access; /* Access mode: GENERIC_READ, GENERIC_WRITE. */ DWORD crFlags; + DWORD flagsAndAttrs = FILE_ATTRIBUTE_NORMAL; WCHAR *wname = (WCHAR *) name; switch (flags & (EFILE_MODE_READ|EFILE_MODE_WRITE)) { @@ -719,6 +720,10 @@ efile_openfile(Efile_error* errInfo, /* Where to return error codes. */ return 0; } + if (flags & EFILE_MODE_SYNC) { + flagsAndAttrs = FILE_FLAG_WRITE_THROUGH; + } + if (flags & EFILE_MODE_APPEND) { crFlags = OPEN_ALWAYS; } @@ -727,7 +732,7 @@ efile_openfile(Efile_error* errInfo, /* Where to return error codes. */ } fd = CreateFileW(wname, access, FILE_SHARE_FLAGS, - NULL, crFlags, FILE_ATTRIBUTE_NORMAL, NULL); + NULL, crFlags, flagsAndAttrs, NULL); /* * Check for errors. -- cgit v1.2.3 From cd5f69d2148b77c2700d216939938e250477b5f7 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 19 Nov 2013 19:19:06 +0100 Subject: Suppress false valgrind warnings caused by sctp_getpaddrs --- erts/emulator/drivers/common/inet_drv.c | 1 + 1 file changed, 1 insertion(+) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index de18656273..f55e6efacc 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -3959,6 +3959,7 @@ static int inet_address_to_erlang(char *dst, inet_address **src) { dst[0] = INET_AF_INET6; port = sock_ntohs((*src)->sai6.sin6_port); put_int16(port, dst+1); + VALGRIND_MAKE_MEM_DEFINED(&(*src)->sai6.sin6_addr,16); /* false undefs from syscall sctp_get[lp]addrs */ sys_memcpy(dst+1+2, (char *) &(*src)->sai6.sin6_addr, 16); } (*src) = (inet_address *) (&(*src)->sai6 + 1); -- cgit v1.2.3 From bcb310808d548ece9a7c6b78ab0846d2cd06e81f Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 21 Nov 2013 18:19:12 +0100 Subject: erts: Remove unused file winsock_func.h --- erts/emulator/drivers/win32/winsock_func.h | 102 ----------------------------- 1 file changed, 102 deletions(-) delete mode 100644 erts/emulator/drivers/win32/winsock_func.h (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/win32/winsock_func.h b/erts/emulator/drivers/win32/winsock_func.h deleted file mode 100644 index 9d2c099c4d..0000000000 --- a/erts/emulator/drivers/win32/winsock_func.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1997-2009. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ - -typedef struct _WinSockFuncs { - int (WSAAPI *WSAStartup)(WORD wVersionRequired, LPWSADATA lpWSAData); - int (WSAAPI *WSACleanup)(void); - int (WSAAPI *WSAGetLastError)(void); - DWORD (WSAAPI *WSAWaitForMultipleEvents) (DWORD cEvents, - const WSAEVENT FAR * lphEvents, - BOOL fWaitAll, - DWORD dwTimeout, - BOOL fAlertable); - WSAEVENT (WSAAPI *WSACreateEvent)(void); - BOOL (WSAAPI *WSACloseEvent)(WSAEVENT hEvent); - - BOOL (WSAAPI *WSASetEvent)(WSAEVENT hEvent); - BOOL (WSAAPI *WSAResetEvent)(WSAEVENT hEvent); - int (WSAAPI *WSAEventSelect)(SOCKET s, WSAEVENT hEventObject, - long lNetworkEvents); - int (WSAAPI *WSAEnumNetworkEvents)(SOCKET s, - WSAEVENT hEventObject, - LPWSANETWORKEVENTS lpNetworkEvents); - int (WSAAPI *WSAIoctl)(SOCKET s, - DWORD dwIoControlCode, - LPVOID lpvInBuffer, - DWORD cbInBuffer, - LPVOID lpvOUTBuffer, - DWORD cbOUTBuffer, - LPDWORD lpcbBytesReturned, - LPWSAOVERLAPPED lpOverlapped, - LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionROUTINE - ); - SOCKET (WSAAPI *accept)(SOCKET s, struct sockaddr FAR *addr, - int FAR *addrlen); - int (WSAAPI *bind)(SOCKET s, const struct sockaddr FAR *addr, - int namelen); - int (WSAAPI *closesocket)(SOCKET s); - int (WSAAPI *connect)(SOCKET s, const struct sockaddr FAR *name, - int namelen); - int (WSAAPI *ioctlsocket)(SOCKET s, long cmd, u_long FAR *argp); - int (WSAAPI *getsockopt)(SOCKET s, int level, int optname, - char FAR * optval, int FAR *optlen); - u_long (WSAAPI *htonl)(u_long hostlong); - u_short (WSAAPI *htons)(u_short hostshort); - unsigned long (WSAAPI *inet_addr)(const char FAR * cp); - char FAR * (WSAAPI *inet_ntoa)(struct in_addr in); - int (WSAAPI *listen)(SOCKET s, int backlog); - u_short (WSAAPI *ntohs)(u_short netshort); - int (WSAAPI *recv)(SOCKET s, char FAR * buf, int len, int flags); - int (WSAAPI *send)(SOCKET s, const char FAR * buf, int len, int flags); - int (WSAAPI *setsockopt)(SOCKET s, int level, int optname, - const char FAR * optval, int optlen); - int (WSAAPI *shutdown)(SOCKET s, int how); - SOCKET (WSAAPI *socket)(int af, int type, int protocol); - struct hostent FAR * (WSAAPI *gethostbyname)(const char FAR * name); - struct hostent FAR * (WSAAPI *gethostbyaddr)(const char FAR *addr, - int addrlen, int addrtype); - int (WSAAPI *gethostname)(char FAR * name, int namelen); - struct servent FAR * (WSAAPI *getservbyname)(const char FAR * name, - const char FAR * proto); - struct servent FAR * (WSAAPI *getservbyport)(int port, - const char FAR * proto); - int (WSAAPI *getsockname)(SOCKET sock, struct sockaddr FAR *name, - int FAR *namelen); - - /* - * New, added for inet_drv. - */ - - int (WSAAPI *getpeername)(SOCKET s, struct sockaddr FAR * name, - int FAR * namelen); - u_long (WSAAPI *ntohl)(u_long netlong); - int (WSAAPI *WSASend)(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, - LPDWORD lpNumberOfBytesSent, DWORD dwFlags, - LPWSAOVERLAPPED lpOverlapped, - LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); - int (WSAAPI *sendto)(SOCKET s, const char FAR * buf, int len, - int flags, const struct sockaddr FAR * to, int tolen); - int (WSAAPI *recvfrom)(SOCKET s, char FAR * buf, int len, int flags, - struct sockaddr FAR * from, int FAR * fromlen); -} WinSockFuncs; - - -extern WinSockFuncs winSock; - -extern int tcp_lookup_functions(void); -- cgit v1.2.3 From 02f75aa7d187f1e2462f7b8793446b1f9be7c612 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 13 Dec 2013 16:10:03 +0100 Subject: erts: Fix compiler warning --- erts/emulator/drivers/common/inet_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 978a766de9..80937dfcc8 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -1490,8 +1490,8 @@ static int load_ip_and_port unsigned int alen = len; char abuf [len]; int res = inet_get_address(abuf, (inet_address*) addr, &alen); - ASSERT(res==0); - res = 0; + ASSERT(res==0); (void)res; + /* Now "abuf" contains: Family(1b), Port(2b), IP(4|16b) */ /* NB: the following functions are safe to use, as they create tuples -- cgit v1.2.3 From 8a147a73651713efebb9ac973f618a6d66685eca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Fri, 10 Jan 2014 12:52:20 +0100 Subject: Don't make gzio.c dependent on the zutil.h header file gzio.c is our own replacement for zlib's gzopen() etc (based on a version of gzio.c that was included in an old version of zlib). Unfortunately, gzio.c still depends on the *internal* zlib header file zutil.h which is not supposed to be used outside of the zlib source code. The dependencies are the use of the gzFile typedef and the F_OPEN() macro. Instead of gzFile, define and use our own ErtsGzFile. To get rid of the F_OPEN() macro, call open() of _wfopen() directly. --- erts/emulator/drivers/common/efile_drv.c | 15 ++++----- erts/emulator/drivers/common/gzio.c | 53 +++++++++++++++---------------- erts/emulator/drivers/common/gzio.h | 16 ++++++---- erts/emulator/drivers/common/gzio_zutil.h | 9 ------ 4 files changed, 43 insertions(+), 50 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 8de578d8b7..dca979c13a 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -111,7 +111,6 @@ #include "erl_driver.h" #include "erl_efile.h" #include "erl_threads.h" -#include "zlib.h" #include "gzio.h" #include "dtrace-wrapper.h" #include @@ -818,7 +817,7 @@ file_start(ErlDrvPort port, char* command) static void do_close(int flags, SWord fd) { if (flags & EFILE_COMPRESSED) { - erts_gzclose((gzFile)(fd)); + erts_gzclose((ErtsGzFile)(fd)); } else { efile_closefile((int) fd); } @@ -1136,7 +1135,7 @@ static void invoke_read(void *data) } read_size = size; if (d->flags & EFILE_COMPRESSED) { - read_size = erts_gzread((gzFile)d->fd, + read_size = erts_gzread((ErtsGzFile)d->fd, d->c.read.binp->orig_bytes + d->c.read.bin_offset, size); status = (read_size != (size_t) -1); @@ -1209,7 +1208,7 @@ static void invoke_read_line(void *data) size = need - d->c.read_line.read_size; } if (d->flags & EFILE_COMPRESSED) { - read_size = erts_gzread((gzFile)d->fd, + read_size = erts_gzread((ErtsGzFile)d->fd, d->c.read_line.binp->orig_bytes + d->c.read_line.read_offset + d->c.read_line.read_size, size); @@ -1250,7 +1249,7 @@ static void invoke_read_line(void *data) d->c.read_line.read_size -= too_much; ASSERT(d->c.read_line.read_size >= 0); if (d->flags & EFILE_COMPRESSED) { - Sint64 location = erts_gzseek((gzFile)d->fd, + Sint64 location = erts_gzseek((ErtsGzFile)d->fd, -((Sint64) too_much), EFILE_SEEK_CUR); if (location == -1) { d->result_ok = 0; @@ -1535,7 +1534,7 @@ static void invoke_writev(void *data) { */ errno = EINVAL; if (! (status = - erts_gzwrite((gzFile)d->fd, + erts_gzwrite((ErtsGzFile)d->fd, iov[i].iov_base, iov[i].iov_len)) == iov[i].iov_len) { d->errInfo.posix_errno = @@ -1797,7 +1796,7 @@ static void invoke_lseek(void *data) d->errInfo.posix_errno = EINVAL; status = 0; } else { - d->c.lseek.location = erts_gzseek((gzFile)d->fd, + d->c.lseek.location = erts_gzseek((ErtsGzFile)d->fd, offset, d->c.lseek.origin); if (d->c.lseek.location == -1) { d->errInfo.posix_errno = errno; @@ -1885,7 +1884,7 @@ static void invoke_open(void *data) if (status || (d->errInfo.posix_errno != EISDIR)) { mode = (d->flags & EFILE_MODE_READ) ? "rb" : "wb"; d->fd = (SWord) erts_gzopen(d->b, mode); - if ((gzFile)d->fd) { + if ((ErtsGzFile)d->fd) { status = 1; } else { if (errno == 0) { diff --git a/erts/emulator/drivers/common/gzio.c b/erts/emulator/drivers/common/gzio.c index e085c262b0..653f3954b1 100644 --- a/erts/emulator/drivers/common/gzio.c +++ b/erts/emulator/drivers/common/gzio.c @@ -77,7 +77,7 @@ typedef struct gz_stream { * this structure. */ } gz_stream; -local gzFile gz_open OF((const char *path, const char *mode)); +local ErtsGzFile gz_open OF((const char *path, const char *mode)); local int get_byte OF((gz_stream *s)); local void check_header OF((gz_stream *s)); local int destroy OF((gz_stream *s)); @@ -144,7 +144,7 @@ local uLong getLong OF((gz_stream *s)); can be checked to distinguish the two cases (if errno is zero, the zlib error is Z_MEM_ERROR). */ -local gzFile gz_open (path, mode) +local ErtsGzFile gz_open (path, mode) const char *path; const char *mode; { @@ -179,7 +179,7 @@ local gzFile gz_open (path, mode) s->path = (char*)ALLOC(FILENAME_BYTELEN(path)+FILENAME_CHARSIZE); if (s->path == NULL) { - return s->destroy(s), (gzFile)Z_NULL; + return s->destroy(s), (ErtsGzFile)Z_NULL; } FILENAME_COPY(s->path, path); /* do this early for debugging */ @@ -197,7 +197,7 @@ local gzFile gz_open (path, mode) } while (*p++ && m < fmode + sizeof(fmode) - 1); *m = '\0'; if (s->mode == '\0') - return s->destroy(s), (gzFile)Z_NULL; + return s->destroy(s), (ErtsGzFile)Z_NULL; if (s->mode == 'w') { err = deflateInit2(&(s->stream), level, @@ -207,7 +207,7 @@ local gzFile gz_open (path, mode) s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); if (err != Z_OK || s->outbuf == Z_NULL) { - return s->destroy(s), (gzFile)Z_NULL; + return s->destroy(s), (ErtsGzFile)Z_NULL; } } else { /* @@ -221,7 +221,7 @@ local gzFile gz_open (path, mode) s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); if (err != Z_OK || s->inbuf == Z_NULL) { - return s->destroy(s), (gzFile)Z_NULL; + return s->destroy(s), (ErtsGzFile)Z_NULL; } } s->stream.avail_out = Z_BUFSIZE; @@ -229,17 +229,16 @@ local gzFile gz_open (path, mode) errno = 0; #if defined(FILENAMES_16BIT) { - char wfmode[160]; - int i=0,j; - for(j=0;fmode[j] != '\0';++j) { - wfmode[i++]=fmode[j]; - wfmode[i++]='\0'; + WCHAR wfmode[80]; + int i = 0; + int j; + for(j = 0; fmode[j] != '\0'; ++j) { + wfmode[i++] = (WCHAR) fmode[j]; } - wfmode[i++] = '\0'; - wfmode[i++] = '\0'; - s->file = F_OPEN(path, wfmode); + wfmode[i++] = L'\0'; + s->file = _wfopen((WCHAR *)path, wfmode); if (s->file == NULL) { - return s->destroy(s), (gzFile)Z_NULL; + return s->destroy(s), (ErtsGzFile)Z_NULL; } } #elif defined(UNIX) @@ -249,18 +248,18 @@ local gzFile gz_open (path, mode) s->file = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666); } if (s->file == -1) { - return s->destroy(s), (gzFile)Z_NULL; + return s->destroy(s), (ErtsGzFile)Z_NULL; } #else - s->file = F_OPEN(path, fmode); + s->file = fopen(path, fmode); if (s->file == NULL) { - return s->destroy(s), (gzFile)Z_NULL; + return s->destroy(s), (ErtsGzFile)Z_NULL; } #endif if (s->mode == 'r') { check_header(s); /* skip the .gz header */ } - return (gzFile)s; + return (ErtsGzFile)s; } /* =========================================================================== @@ -296,7 +295,7 @@ local int gz_rewind (gz_stream *s) /* =========================================================================== Opens a gzip (.gz) file for reading or writing. */ -gzFile erts_gzopen (path, mode) +ErtsGzFile erts_gzopen (path, mode) const char *path; const char *mode; { @@ -447,7 +446,7 @@ local int destroy (s) gzread returns the number of bytes actually read (0 for end of file). */ int -erts_gzread(gzFile file, voidp buf, unsigned len) +erts_gzread(ErtsGzFile file, voidp buf, unsigned len) { gz_stream *s = (gz_stream*)file; Bytef *start = buf; /* starting point for crc computation */ @@ -557,7 +556,7 @@ erts_gzread(gzFile file, voidp buf, unsigned len) gzwrite returns the number of bytes actually written (0 in case of error). */ int -erts_gzwrite(gzFile file, voidp buf, unsigned len) +erts_gzwrite(ErtsGzFile file, voidp buf, unsigned len) { gz_stream *s = (gz_stream*)file; @@ -593,7 +592,7 @@ erts_gzwrite(gzFile file, voidp buf, unsigned len) */ int -erts_gzseek(gzFile file, int offset, int whence) +erts_gzseek(ErtsGzFile file, int offset, int whence) { int pos; gz_stream* s = (gz_stream *) file; @@ -655,7 +654,7 @@ erts_gzseek(gzFile file, int offset, int whence) degrade compression. */ int -erts_gzflush(gzFile file, int flush) +erts_gzflush(ErtsGzFile file, int flush) { uInt len; int done = 0; @@ -714,7 +713,7 @@ local uLong getLong (s) and deallocates all the (de)compression state. */ int -erts_gzclose(gzFile file) +erts_gzclose(ErtsGzFile file) { int err; gz_stream *s = (gz_stream*)file; @@ -723,9 +722,9 @@ erts_gzclose(gzFile file) if (s->mode == 'w') { err = erts_gzflush (file, Z_FINISH); - if (err != Z_OK) return s->destroy(file); + if (err != Z_OK) return s->destroy(s); } - return s->destroy(file); + return s->destroy(s); } diff --git a/erts/emulator/drivers/common/gzio.h b/erts/emulator/drivers/common/gzio.h index 3f1e546140..ea50d922ec 100644 --- a/erts/emulator/drivers/common/gzio.h +++ b/erts/emulator/drivers/common/gzio.h @@ -17,11 +17,15 @@ * %CopyrightEnd% */ -gzFile erts_gzopen (const char *path, const char *mode); -int erts_gzread(gzFile file, voidp buf, unsigned len); -int erts_gzwrite(gzFile file, voidp buf, unsigned len); -int erts_gzseek(gzFile, int, int); -int erts_gzflush(gzFile file, int flush); -int erts_gzclose(gzFile file); +#include "zlib.h" + +typedef struct erts_gzFile* ErtsGzFile; + +ErtsGzFile erts_gzopen (const char *path, const char *mode); +int erts_gzread(ErtsGzFile file, voidp buf, unsigned len); +int erts_gzwrite(ErtsGzFile file, voidp buf, unsigned len); +int erts_gzseek(ErtsGzFile, int, int); +int erts_gzflush(ErtsGzFile file, int flush); +int erts_gzclose(ErtsGzFile file); ErlDrvBinary* erts_gzinflate_buffer(char*, uLong); ErlDrvBinary* erts_gzdeflate_buffer(char*, uLong); diff --git a/erts/emulator/drivers/common/gzio_zutil.h b/erts/emulator/drivers/common/gzio_zutil.h index 00eccc80fc..854205cc2c 100644 --- a/erts/emulator/drivers/common/gzio_zutil.h +++ b/erts/emulator/drivers/common/gzio_zutil.h @@ -23,12 +23,6 @@ * that may change or not exist at all. */ -#ifndef HAVE_LIBZ -/* Use our "real" copy of zutil.h if we don't use shared zlib */ -#include "zutil.h" - -#else /* HAVE_LIBZ: Shared zlib is used */ - #define local static #define DEF_MEM_LEVEL 8 #define zmemcpy sys_memcpy @@ -77,6 +71,3 @@ # define OS_CODE 0x03 /* assume Unix */ #endif - -#endif /* HAVE_LIBZ */ - -- cgit v1.2.3 From 0b36ce01e81744f4c0b41bfe1f62b4bf5d0ece97 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Mon, 27 Jan 2014 12:01:45 +0100 Subject: erts/kernel: sendfile no longer uses async threads This has been done because a slow client attack is possible if the async thread pool is used. The scenario is: Client does a request for a file and then slowly receives the file one byte at a time. This will eventually fill the async thread pool with blocking sendfile operations and thus starving the vm of all file operations. If you still want to use the async threads pool for sendfile an option to enable it has been introduced. --- erts/emulator/drivers/common/efile_drv.c | 33 +++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 8de578d8b7..23c5cde7ed 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -168,7 +168,7 @@ dt_private *get_dt_private(int); #ifdef USE_THREADS -#define IF_THRDS if (sys_info.async_threads > 0) +#define THRDS_AVAILABLE (sys_info.async_threads > 0) #ifdef HARDDEBUG /* HARDDEBUG in io.c is expected too */ #define TRACE_DRIVER fprintf(stderr, "Efile: ") #else @@ -178,24 +178,26 @@ dt_private *get_dt_private(int); #define MUTEX_LOCK(m) do { IF_THRDS { TRACE_DRIVER; driver_pdl_lock(m); } } while (0) #define MUTEX_UNLOCK(m) do { IF_THRDS { TRACE_DRIVER; driver_pdl_unlock(m); } } while (0) #else -#define IF_THRDS if (0) +#define THRDS_AVAILABLE (0) #define MUTEX_INIT(m, p) #define MUTEX_LOCK(m) #define MUTEX_UNLOCK(m) #endif +#define IF_THRDS if (THRDS_AVAILABLE) +#define SENDFILE_FLGS_USE_THREADS (1 << 0) /** * 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. + * this error when using +A 10 and enabling SENDFILE_FLGS_USE_THREADS. */ #if defined(__APPLE__) && defined(__MACH__) -#define USE_THRDS_FOR_SENDFILE 0 +#define USE_THRDS_FOR_SENDFILE(DATA) 0 #else -#define USE_THRDS_FOR_SENDFILE (sys_info.async_threads > 0) +#define USE_THRDS_FOR_SENDFILE(DATA) (DATA->flags & SENDFILE_FLGS_USE_THREADS) #endif /* defined(__APPLE__) && defined(__MACH__) */ @@ -301,7 +303,7 @@ static void file_stop_select(ErlDrvEvent event, void* _); enum e_timer {timer_idle, timer_again, timer_write}; #ifdef HAVE_SENDFILE enum e_sendfile {sending, not_sending}; -static void free_sendfile(void *data); +#define SENDFILE_USE_THREADS (1 << 0) #endif /* HAVE_SENDFILE */ struct t_data; @@ -1933,7 +1935,7 @@ static void invoke_sendfile(void *data) d->c.sendfile.written += nbytes; - if (result == 1 || (result == 0 && USE_THRDS_FOR_SENDFILE)) { + if (result == 1 || (result == 0 && USE_THRDS_FOR_SENDFILE(d))) { d->result_ok = 0; } else if (result == 0 && (d->errInfo.posix_errno == EAGAIN || d->errInfo.posix_errno == EINTR)) { @@ -1950,7 +1952,7 @@ static void invoke_sendfile(void *data) static void free_sendfile(void *data) { struct t_data *d = (struct t_data *)data; - if (USE_THRDS_FOR_SENDFILE) { + if (USE_THRDS_FOR_SENDFILE(d)) { SET_NONBLOCKING(d->c.sendfile.out_fd); } else { MUTEX_LOCK(d->c.sendfile.q_mtx); @@ -4123,8 +4125,16 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { goto done; } - if (hd_len != 0 || tl_len != 0 || flags != 0) { - /* We do not allow header, trailers and/or flags right now */ + if (hd_len != 0 || tl_len != 0) { + /* We do not allow header, trailers */ + reply_posix_error(desc, EINVAL); + goto done; + } + + + if (flags & SENDFILE_FLGS_USE_THREADS && !THRDS_AVAILABLE) { + /* We do not allow use_threads flag on a system where + no threads are available. */ reply_posix_error(desc, EINVAL); goto done; } @@ -4134,6 +4144,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->command = command; d->invoke = invoke_sendfile; d->free = free_sendfile; + d->flags = flags; d->level = 2; d->c.sendfile.out_fd = (int) out_fd; @@ -4153,7 +4164,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->c.sendfile.nbytes = nbytes; - if (USE_THRDS_FOR_SENDFILE) { + if (USE_THRDS_FOR_SENDFILE(d)) { SET_BLOCKING(d->c.sendfile.out_fd); } else { /** -- cgit v1.2.3 From 8f8a03ba3556f2c2c70797bedf5d44b360659425 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Fri, 17 Jan 2014 14:37:39 +0100 Subject: erts: fix bug when using passive mode and sendfile The bug incorrectly issued driver_select when un-ignoring an fd for a socket in passive mode, which caused an incorrect error tuple to be returned when the remote end closed the connection. --- erts/emulator/drivers/common/inet_drv.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 45fac69303..fedab62866 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -846,9 +846,10 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #define INET_IFNAMSIZ 16 /* INET Ignore states */ -#define INET_IGNORE_NONE 0 -#define INET_IGNORE_READ 1 -#define INET_IGNORE_WRITE 1 << 1 +#define INET_IGNORE_NONE 0 +#define INET_IGNORE_READ (1 << 0) +#define INET_IGNORE_WRITE (1 << 1) +#define INET_IGNORE_PASSIVE (1 << 2) /* Max length of Erlang Term Buffer (for outputting structured terms): */ #ifdef HAVE_SCTP @@ -8208,11 +8209,19 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, 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; + if (desc->active) + desc->is_ignored = INET_IGNORE_READ; + else + desc->is_ignored = INET_IGNORE_PASSIVE; } else if (*buf == 0 && desc->is_ignored) { - int flags = (FD_READ|FD_CLOSE|((desc->is_ignored & INET_IGNORE_WRITE)?FD_WRITE:0)); + int flags = FD_CLOSE; + if (desc->is_ignored & INET_IGNORE_READ) + flags |= FD_READ; + if (desc->is_ignored & INET_IGNORE_WRITE) + flags |= FD_WRITE; desc->is_ignored = INET_IGNORE_NONE; - sock_select(desc, flags, 1); + if (flags != FD_CLOSE) + sock_select(desc, flags, 1); } else return ctl_error(EINVAL, rbuf, rsize); @@ -8889,6 +8898,8 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, driver_set_timer(desc->inet.port, timeout); if (!INETP(desc)->is_ignored) sock_select(INETP(desc),(FD_READ|FD_CLOSE),1); + else + INETP(desc)->is_ignored |= INET_IGNORE_READ; } } return ctl_reply(INET_REP_OK, tbuf, 2, rbuf, rsize); -- cgit v1.2.3 From 21f2d57e5f7919d468fe89e38c52f978e15c1dfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 4 Feb 2014 15:04:24 +0100 Subject: gzio.c: Remove unnecessary usage of the OF() macro Daniel Goertzen reported that commit 8a147a7365 broke building of Erlang/OTP on Gentoo Linux because the macro OF() was missing. Apparently, on Gentoo the OF() macro in zconf.h has been renamed to _Z_OF() (to avoid polluting the global namespace). Don't use the OF() macro in gzio.c since it no longer serves any useful purpose (it provided compatibility with pre-ANSI/ISO C compilers, but the rest of Erlang/OTP requires an ANSI/ISO C compiler anyway). --- erts/emulator/drivers/common/gzio.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/gzio.c b/erts/emulator/drivers/common/gzio.c index 653f3954b1..8ec2c3f762 100644 --- a/erts/emulator/drivers/common/gzio.c +++ b/erts/emulator/drivers/common/gzio.c @@ -73,15 +73,15 @@ typedef struct gz_stream { int transparent; /* 1 if input file is not a .gz file */ char mode; /* 'w' or 'r' */ int position; /* Position (for seek) */ - int (*destroy)OF((struct gz_stream*)); /* Function to destroy + int (*destroy)(struct gz_stream*); /* Function to destroy * this structure. */ } gz_stream; -local ErtsGzFile gz_open OF((const char *path, const char *mode)); -local int get_byte OF((gz_stream *s)); -local void check_header OF((gz_stream *s)); -local int destroy OF((gz_stream *s)); -local uLong getLong OF((gz_stream *s)); +local ErtsGzFile gz_open (const char *path, const char *mode); +local int get_byte (gz_stream *s); +local void check_header (gz_stream *s); +local int destroy (gz_stream *s); +local uLong getLong (gz_stream *s); #ifdef UNIX /* -- cgit v1.2.3 From 200fbe924466720bd2a8c5eb05b05d67b0a2414c Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Thu, 14 Mar 2013 15:42:19 +0100 Subject: Added support for ENEA OSE This port has support for both non-smp and smp. It contains a new way to do io checking in which erts_poll_wait receives the payload of the polled entity. This has implications for all linked-in drivers. --- erts/emulator/drivers/common/efile_drv.c | 3 + erts/emulator/drivers/common/inet_drv.c | 110 ++- erts/emulator/drivers/ose/ose_efile.c | 1090 ++++++++++++++++++++++++++++++ 3 files changed, 1202 insertions(+), 1 deletion(-) create mode 100644 erts/emulator/drivers/ose/ose_efile.c (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index e040864d24..fbd72c6c1b 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -373,6 +373,9 @@ struct erl_drv_entry efile_driver_entry = { #else NULL #endif /* HAVE_SENDFILE */ +#ifdef __OSE__ + ,NULL +#endif }; diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 4a861b121c..357a4b7bcb 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -121,6 +121,10 @@ typedef unsigned long long llu_t; #undef WANT_NONBLOCKING #include "sys.h" +#ifdef __OSE__ +#include "inet.h" +#endif + #undef EWOULDBLOCK #undef ETIMEDOUT @@ -289,7 +293,111 @@ static BOOL (WINAPI *fpSetHandleInformation)(HANDLE,DWORD,DWORD); static unsigned long zero_value = 0; static unsigned long one_value = 1; -#else /* #ifdef __WIN32__ */ +#elif defined (__OSE__) +#include "sys/socket.h" +#include "sys/uio.h" +#include "sfk/sys/sfk_uio.h" +#include "netinet/in.h" +#include "netinet/tcp.h" +#include "netdb.h" + +ssize_t writev(int fd, const struct iovec *iov, int iovcnt) +{ + return 0; +} + +#define INVALID_SOCKET -1 +#define INVALID_EVENT -1 +#define SOCKET_ERROR -1 + +#define SOCKET int +#define HANDLE long int +#define FD_READ ERL_DRV_READ +#define FD_WRITE ERL_DRV_WRITE +#define FD_CLOSE 0 +#define FD_CONNECT ERL_DRV_WRITE +#define FD_ACCEPT ERL_DRV_READ + +#define sock_connect(s, addr, len) connect((s), (addr), (len)) +#define sock_listen(s, b) listen((s), (b)) +#define sock_bind(s, addr, len) bind((s), (addr), (len)) +#define sock_getopt(s,t,n,v,l) getsockopt((s),(t),(n),(v),(l)) +#define sock_setopt(s,t,n,v,l) setsockopt((s),(t),(n),(v),(l)) +#define sock_name(s, addr, len) getsockname((s), (addr), (len)) +#define sock_peer(s, addr, len) getpeername((s), (addr), (len)) +#define sock_ntohs(x) ntohs((x)) +#define sock_ntohl(x) ntohl((x)) +#define sock_htons(x) htons((x)) +#define sock_htonl(x) htonl((x)) + +#define sock_accept(s, addr, len) accept((s), (addr), (len)) +#define sock_send(s,buf,len,flag) inet_send((s),(buf),(len),(flag)) +#define sock_sendto(s,buf,blen,flag,addr,alen) \ + sendto((s),(buf),(blen),(flag),(addr),(alen)) +#define sock_sendv(s, vec, size, np, flag) \ + (*(np) = writev((s), (struct iovec*)(vec), (size))) +#define sock_sendmsg(s,msghdr,flag) sendmsg((s),(msghdr),(flag)) + +#define sock_open(af, type, proto) socket((af), (type), (proto)) +#define sock_close(s) close((s)) +#define sock_shutdown(s, how) shutdown((s), (how)) + +#define sock_hostname(buf, len) gethostname((buf), (len)) +#define sock_getservbyname(name,proto) getservbyname((name), (proto)) +#define sock_getservbyport(port,proto) getservbyport((port), (proto)) + +#define sock_recv(s,buf,len,flag) recv((s),(buf),(len),(flag)) +#define sock_recvfrom(s,buf,blen,flag,addr,alen) \ + recvfrom((s),(buf),(blen),(flag),(addr),(alen)) +#define sock_recvmsg(s,msghdr,flag) recvmsg((s),(msghdr),(flag)) + +#define sock_errno() errno +#define sock_create_event(d) ((d)->s) /* return file descriptor */ +#define sock_close_event(e) /* do nothing */ + +#define inet_driver_select(port, e, mode, on) \ + 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)); \ + DEBUGF(("sock_select(%ld): flags=%02X, onoff=%d, event_mask=%02lX\r\n", \ + (long) (d)->port, (flags), (onoff), (unsigned long) (d)->event_mask)); \ + inet_driver_select((d)->port, (ErlDrvEvent)(long)(d)->event, (flags), (onoff)); \ + } while(0) + +#ifndef WANT_NONBLOCKING +#define WANT_NONBLOCKING +#endif +#include "sys.h" + +typedef unsigned long u_long; +#define IN_CLASSA(a) ((((in_addr_t)(a)) & 0x80000000) == 0) +#define IN_CLASSA_NET 0xff000000 +#define IN_CLASSA_NSHIFT 24 +#define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET) +#define IN_CLASSA_MAX 128 + +#define IN_CLASSB(a) ((((in_addr_t)(a)) & 0xc0000000) == 0x80000000) +#define IN_CLASSB_NET 0xffff0000 +#define IN_CLASSB_NSHIFT 16 +#define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET) +#define IN_CLASSB_MAX 65536 + +#define IN_CLASSC(a) ((((in_addr_t)(a)) & 0xe0000000) == 0xc0000000) +#define IN_CLASSC_NET 0xffffff00 +#define IN_CLASSC_NSHIFT 8 +#define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET) + +#define IN_CLASSD(a) ((((in_addr_t)(a)) & 0xf0000000) == 0xe0000000) +#define IN_MULTICAST(a) IN_CLASSD(a) + +#define IN_EXPERIMENTAL(a) ((((in_addr_t)(a)) & 0xe0000000) == 0xe0000000) +#define IN_BADCLASS(a) ((((in_addr_t)(a)) & 0xf0000000) == 0xf0000000) + +#else /* !__OSE__ && !__WIN32__ */ #include #ifdef NETDB_H_NEEDS_IN_H diff --git a/erts/emulator/drivers/ose/ose_efile.c b/erts/emulator/drivers/ose/ose_efile.c new file mode 100644 index 0000000000..8cd34a7bb0 --- /dev/null +++ b/erts/emulator/drivers/ose/ose_efile.c @@ -0,0 +1,1090 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1997-2012. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Purpose: Provides file and directory operations for OSE. + */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#if defined(HAVE_POSIX_FALLOCATE) && !defined(__sun) && !defined(__sun__) +#define _XOPEN_SOURCE 600 +#endif +#if !defined(_GNU_SOURCE) && defined(HAVE_LINUX_FALLOC_H) +#define _GNU_SOURCE +#endif +#include "sys.h" +#include "erl_driver.h" +#include "erl_efile.h" +/*#include */ +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_SYS_UIO_H +#include +#include +#endif +#if defined(HAVE_SENDFILE) && (defined(__linux__) || (defined(__sun) && defined(__SVR4))) +#include +#endif + +#if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__) +#define DARWIN 1 +#endif + +#if defined(DARWIN) || defined(HAVE_LINUX_FALLOC_H) || defined(HAVE_POSIX_FALLOCATE) +#include +#endif + +#ifdef HAVE_LINUX_FALLOC_H +#include +#endif + +#ifdef SUNOS4 +# define getcwd(buf, size) getwd(buf) +#endif + +#ifdef __OSE__ +#include "sys/stat.h" +#include "dirent.h" +#endif + +/* Find a definition of MAXIOV, that is used in the code later. */ +#if defined IOV_MAX +#define MAXIOV IOV_MAX +#elif defined UIO_MAXIOV +#define MAXIOV UIO_MAXIOV +#else +#define MAXIOV 16 +#endif + + +/* + * Macros for testing file types. + */ + +#define ISDIR(st) (((st).st_mode & S_IFMT) == S_IFDIR) +#define ISREG(st) (((st).st_mode & S_IFMT) == S_IFREG) +#define ISDEV(st) \ + (((st).st_mode&S_IFMT) == S_IFCHR || ((st).st_mode&S_IFMT) == S_IFBLK) +#define ISLNK(st) (((st).st_mode & S_IFLNK) == S_IFLNK) +#ifdef NO_UMASK +#define FILE_MODE 0644 +#define DIR_MODE 0755 +#else +#define FILE_MODE 0666 +#define DIR_MODE 0777 +#endif + +#define IS_DOT_OR_DOTDOT(s) \ + (s[0] == '.' && (s[1] == '\0' || (s[1] == '.' && s[2] == '\0'))) + +static int check_error(int result, Efile_error* errInfo); + +static int +check_error(int result, Efile_error *errInfo) +{ + if (result < 0) { + errInfo->posix_errno = errInfo->os_errno = errno; + return 0; + } + return 1; +} + +int +efile_mkdir(Efile_error* errInfo, /* Where to return error codes. */ + char* name) /* Name of directory to create. */ +{ +#ifdef NO_MKDIR_MODE + return check_error(mkdir(name), errInfo); +#else + return check_error(mkdir(name, DIR_MODE), errInfo); +#endif +} + +int +efile_rmdir(Efile_error* errInfo, /* Where to return error codes. */ + char* name) /* Name of directory to delete. */ +{ + if (rmdir(name) == 0) { + return 1; + } + if (errno == ENOTEMPTY) { + errno = EEXIST; + } + if (errno == EEXIST) { + int saved_errno = errno; + struct stat file_stat; + struct stat cwd_stat; + + /* + * The error code might be wrong if this is the current directory. + */ + + if (stat(name, &file_stat) == 0 && stat(".", &cwd_stat) == 0 && + file_stat.st_ino == cwd_stat.st_ino && + file_stat.st_dev == cwd_stat.st_dev) { + saved_errno = EINVAL; + } + errno = saved_errno; + } + return check_error(-1, errInfo); +} + +int +efile_delete_file(Efile_error* errInfo, /* Where to return error codes. */ + char* name) /* Name of file to delete. */ +{ + if (unlink(name) == 0) { + return 1; + } + if (errno == EISDIR) { /* Linux sets the wrong error code. */ + errno = EPERM; + } + return check_error(-1, errInfo); +} + +/* + *--------------------------------------------------------------------------- + * + * Changes the name of an existing file or directory, from src to dst. + * If src and dst refer to the same file or directory, does nothing + * and returns success. Otherwise if dst already exists, it will be + * deleted and replaced by src subject to the following conditions: + * If src is a directory, dst may be an empty directory. + * If src is a file, dst may be a file. + * In any other situation where dst already exists, the rename will + * fail. + * + * Results: + * If the directory was successfully created, returns 1. + * Otherwise the return value is 0 and errno is set to + * indicate the error. Some possible values for errno are: + * + * EACCES: src or dst parent directory can't be read and/or written. + * EEXIST: dst is a non-empty directory. + * EINVAL: src is a root directory or dst is a subdirectory of src. + * EISDIR: dst is a directory, but src is not. + * ENOENT: src doesn't exist, or src or dst is "". + * ENOTDIR: src is a directory, but dst is not. + * EXDEV: src and dst are on different filesystems. + * + * Side effects: + * The implementation of rename may allow cross-filesystem renames, + * but the caller should be prepared to emulate it with copy and + * delete if errno is EXDEV. + * + *--------------------------------------------------------------------------- + */ + +int +efile_rename(Efile_error* errInfo, /* Where to return error codes. */ + char* src, /* Original name. */ + char* dst) /* New name. */ +{ + if (rename(src, dst) == 0) { + return 1; + } + if (errno == ENOTEMPTY) { + errno = EEXIST; + } +#if defined (sparc) + /* + * SunOS 4.1.4 reports overwriting a non-empty directory with a + * directory as EINVAL instead of EEXIST (first rule out the correct + * EINVAL result code for moving a directory into itself). Must be + * conditionally compiled because realpath() is only defined on SunOS. + */ + + if (errno == EINVAL) { + char srcPath[MAXPATHLEN], dstPath[MAXPATHLEN]; + DIR *dirPtr; + struct dirent *dirEntPtr; + +#ifdef PURIFY + memset(srcPath, '\0', sizeof(srcPath)); + memset(dstPath, '\0', sizeof(dstPath)); +#endif + + if ((realpath(src, srcPath) != NULL) + && (realpath(dst, dstPath) != NULL) + && (strncmp(srcPath, dstPath, strlen(srcPath)) != 0)) { + dirPtr = opendir(dst); + if (dirPtr != NULL) { + while ((dirEntPtr = readdir(dirPtr)) != NULL) { + if ((strcmp(dirEntPtr->d_name, ".") != 0) && + (strcmp(dirEntPtr->d_name, "..") != 0)) { + errno = EEXIST; + closedir(dirPtr); + return check_error(-1, errInfo); + } + } + closedir(dirPtr); + } + } + errno = EINVAL; + } +#endif /* sparc */ + + if (strcmp(src, "/") == 0) { + /* + * Alpha reports renaming / as EBUSY and Linux reports it as EACCES, + * instead of EINVAL. + */ + + errno = EINVAL; + } + + /* + * DEC Alpha OSF1 V3.0 returns EACCES when attempting to move a + * file across filesystems and the parent directory of that file is + * not writable. Most other systems return EXDEV. Does nothing to + * correct this behavior. + */ + + return check_error(-1, errInfo); +} + +int +efile_chdir(Efile_error* errInfo, /* Where to return error codes. */ + char* name) /* Name of directory to make current. */ +{ + return check_error(chdir(name), errInfo); +} + + +int +efile_getdcwd(Efile_error* errInfo, /* Where to return error codes. */ + int drive, /* 0 - current, 1 - A, 2 - B etc. */ + char* buffer, /* Where to return the current + directory. */ + size_t size) /* Size of buffer. */ +{ + if (drive == 0) { + if (getcwd(buffer, size) == NULL) + return check_error(-1, errInfo); + +#ifdef SIMSPARCSOLARIS + /* We get "host:" prepended to the dirname - remove!. */ + { + int i = 0; + int j = 0; + while ((buffer[i] != ':') && (buffer[i] != '\0')) i++; + if (buffer[i] == ':') { + i++; + while ((buffer[j++] = buffer[i++]) != '\0'); + } + } +#endif + return 1; + } + + /* + * Drives other than 0 is not supported on Unix. + */ + + errno = ENOTSUP; + return check_error(-1, errInfo); +} + +int +efile_readdir(Efile_error* errInfo, /* Where to return error codes. */ + char* name, /* Name of directory to open. */ + EFILE_DIR_HANDLE* p_dir_handle, /* Pointer to directory + handle of + open directory.*/ + char* buffer, /* Pointer to buffer for + one filename. */ + size_t *size) /* in-out Size of buffer, length + of name. */ +{ + DIR *dp; /* Pointer to directory structure. */ + struct dirent* dirp; /* Pointer to directory entry. */ + + /* + * If this is the first call, we must open the directory. + */ + + if (*p_dir_handle == NULL) { + dp = opendir(name); + if (dp == NULL) + return check_error(-1, errInfo); + *p_dir_handle = (EFILE_DIR_HANDLE) dp; + } + + /* + * Retrieve the name of the next file using the directory handle. + */ + + dp = *((DIR **)((void *)p_dir_handle)); + for (;;) { + dirp = readdir(dp); + if (dirp == NULL) { + closedir(dp); + return 0; + } + if (IS_DOT_OR_DOTDOT(dirp->d_name)) + continue; + buffer[0] = '\0'; + strncat(buffer, dirp->d_name, (*size)-1); + *size = strlen(dirp->d_name); + return 1; + } +} + +int +efile_openfile(Efile_error* errInfo, /* Where to return error codes. */ + char* name, /* Name of directory to open. */ + int flags, /* Flags to user for opening. */ + int* pfd, /* Where to store the file + descriptor. */ + Sint64 *pSize) /* Where to store the size of the + file. */ +{ + struct stat statbuf; + int fd; + int mode; /* Open mode. */ + + if (stat(name, &statbuf) >= 0 && !ISREG(statbuf)) { + /* + * For UNIX only, here is some ugly code to allow + * /dev/null to be opened as a file. + * + * Assumption: The i-node number for /dev/null cannot be zero. + */ + static ino_t dev_null_ino = 0; + + if (dev_null_ino == 0) { + struct stat nullstatbuf; + + if (stat("/dev/null", &nullstatbuf) >= 0) { + dev_null_ino = nullstatbuf.st_ino; + } + } + if (!(dev_null_ino && statbuf.st_ino == dev_null_ino)) { + errno = EISDIR; + return check_error(-1, errInfo); + } + } + + switch (flags & (EFILE_MODE_READ|EFILE_MODE_WRITE)) { + case EFILE_MODE_READ: + mode = O_RDONLY; + break; + case EFILE_MODE_WRITE: + if (flags & EFILE_NO_TRUNCATE) + mode = O_WRONLY | O_CREAT; + else + mode = O_WRONLY | O_CREAT | O_TRUNC; + break; + case EFILE_MODE_READ_WRITE: + mode = O_RDWR | O_CREAT; + break; + default: + errno = EINVAL; + return check_error(-1, errInfo); + } + + + if (flags & EFILE_MODE_APPEND) { + mode &= ~O_TRUNC; + mode |= O_APPEND; + } + + if (flags & EFILE_MODE_EXCL) { + mode |= O_EXCL; + } + + fd = open(name, mode, FILE_MODE); + + if (!check_error(fd, errInfo)) + return 0; + + *pfd = fd; + if (pSize) { + *pSize = statbuf.st_size; + } + return 1; +} + +int +efile_may_openfile(Efile_error* errInfo, char *name) { + struct stat statbuf; /* Information about the file */ + int result; + + result = stat(name, &statbuf); + if (!check_error(result, errInfo)) + return 0; + if (!ISREG(statbuf)) { + errno = EISDIR; + return check_error(-1, errInfo); + } + return 1; +} + +void +efile_closefile(int fd) +{ + close(fd); +} + +int +efile_fdatasync(Efile_error *errInfo, /* Where to return error codes. */ + int fd) /* File descriptor for file to sync data. */ +{ +#ifdef HAVE_FDATASYNC + return check_error(fdatasync(fd), errInfo); +#else + return efile_fsync(errInfo, fd); +#endif +} + +int +efile_fsync(Efile_error *errInfo, /* Where to return error codes. */ + int fd) /* File descriptor for file to sync. */ +{ +#ifdef NO_FSYNC + undefined fsync /* XXX: Really? */ +#else +#if defined(DARWIN) && defined(F_FULLFSYNC) + return check_error(fcntl(fd, F_FULLFSYNC), errInfo); +#else + return check_error(fsync(fd), errInfo); +#endif /* DARWIN */ +#endif /* NO_FSYNC */ +} + +int +efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, + char* name, int info_for_link) +{ + struct stat statbuf; /* Information about the file */ + int result; + + if (info_for_link) { +#ifndef __OSE__ + result = lstat(name, &statbuf); +#else + result = stat(name, &statbuf); +#endif + } else { + result = stat(name, &statbuf); + } + if (!check_error(result, errInfo)) { + return 0; + } + +#if SIZEOF_OFF_T == 4 + pInfo->size_high = 0; +#else + pInfo->size_high = (Uint32)(statbuf.st_size >> 32); +#endif + pInfo->size_low = (Uint32)statbuf.st_size; + +#ifdef NO_ACCESS + /* Just look at read/write access for owner. */ + + pInfo->access = ((statbuf.st_mode >> 6) & 07) >> 1; + +#else + pInfo->access = FA_NONE; + if (access(name, R_OK) == 0) + pInfo->access |= FA_READ; + if (access(name, W_OK) == 0) + pInfo->access |= FA_WRITE; + +#endif + + if (ISDEV(statbuf)) + pInfo->type = FT_DEVICE; + else if (ISDIR(statbuf)) + pInfo->type = FT_DIRECTORY; + else if (ISREG(statbuf)) + pInfo->type = FT_REGULAR; + else if (ISLNK(statbuf)) + pInfo->type = FT_SYMLINK; + else + pInfo->type = FT_OTHER; + + pInfo->accessTime = statbuf.st_atime; + pInfo->modifyTime = statbuf.st_mtime; + pInfo->cTime = statbuf.st_ctime; + + pInfo->mode = statbuf.st_mode; + pInfo->links = statbuf.st_nlink; + pInfo->major_device = statbuf.st_dev; +#ifndef __OSE__ + pInfo->minor_device = statbuf.st_rdev; +#endif + pInfo->inode = statbuf.st_ino; + pInfo->uid = statbuf.st_uid; + pInfo->gid = statbuf.st_gid; + + return 1; +} + +int +efile_write_info(Efile_error *errInfo, Efile_info *pInfo, char *name) +{ +#ifndef __OSE__ + struct utimbuf tval; +#endif + + /* + * On some systems chown will always fail for a non-root user unless + * POSIX_CHOWN_RESTRICTED is not set. Others will succeed as long as + * you don't try to chown a file to someone besides youself. + */ +#ifndef __OSE__ + if (chown(name, pInfo->uid, pInfo->gid) && errno != EPERM) { + return check_error(-1, errInfo); + } +#endif + + if (pInfo->mode != -1) { + mode_t newMode = pInfo->mode & (S_ISUID | S_ISGID | + S_IRWXU | S_IRWXG | S_IRWXO); + if (chmod(name, newMode)) { + newMode &= ~(S_ISUID | S_ISGID); + if (chmod(name, newMode)) { + return check_error(-1, errInfo); + } + } + } + +#ifndef __OSE__ + tval.actime = pInfo->accessTime; + tval.modtime = pInfo->modifyTime; + + return check_error(utime(name, &tval), errInfo); +#else + return 1; +#endif +} + + +int +efile_write(Efile_error* errInfo, /* Where to return error codes. */ + int flags, /* Flags given when file was + opened. */ + int fd, /* File descriptor to write to. */ + char* buf, /* Buffer to write. */ + size_t count) /* Number of bytes to write. */ +{ + ssize_t written; /* Bytes written in last operation. */ + + while (count > 0) { + if ((written = write(fd, buf, count)) < 0) { + if (errno != EINTR) + return check_error(-1, errInfo); + else + written = 0; + } + ASSERT(written <= count); + buf += written; + count -= written; + } + return 1; +} + +int +efile_writev(Efile_error* errInfo, /* Where to return error codes */ + int flags, /* Flags given when file was + * opened */ + int fd, /* File descriptor to write to */ + SysIOVec* iov, /* Vector of buffer structs. + * 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 */ + + ASSERT(iovcnt >= 0); + + 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 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); + } 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 || w == -1); + } + 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; + } + } + } + ASSERT(w == 0); + } /* else Non-empty buffer */ + } /* while (cnt< iovcnt) */ + return 1; +} + +int +efile_read(Efile_error* errInfo, /* Where to return error codes. */ + int flags, /* Flags given when file was opened. */ + int fd, /* File descriptor to read from. */ + char* buf, /* Buffer to read into. */ + size_t count, /* Number of bytes to read. */ + size_t *pBytesRead) /* Where to return number of + bytes read. */ +{ + ssize_t n; + + for (;;) { + if ((n = read(fd, buf, count)) >= 0) + break; + else if (errno != EINTR) + return check_error(-1, errInfo); + } + *pBytesRead = (size_t) n; + return 1; +} + + +/* pread() and pwrite() */ +/* Some unix systems, notably Solaris has these syscalls */ +/* It is especially nice for i.e. the dets module to have support */ +/* for this, even if the underlying OS dosn't support it, it is */ +/* reasonably easy to work around by first calling seek, and then */ +/* calling read(). */ +/* This later strategy however changes the file pointer, which pread() */ +/* does not do. We choose to ignore this and say that the location */ +/* of the file pointer is undefined after a call to any of the p functions*/ + + +int +efile_pread(Efile_error* errInfo, /* Where to return error codes. */ + int fd, /* File descriptor to read from. */ + Sint64 offset, /* Offset in bytes from BOF. */ + char* buf, /* Buffer to read into. */ + size_t count, /* Number of bytes to read. */ + size_t *pBytesRead) /* Where to return + number of bytes read. */ +{ +#if defined(HAVE_PREAD) && defined(HAVE_PWRITE) + ssize_t n; + off_t off = (off_t) offset; + if (off != offset) { + errno = EINVAL; + return check_error(-1, errInfo); + } + for (;;) { + if ((n = pread(fd, buf, count, offset)) >= 0) + break; + else if (errno != EINTR) + return check_error(-1, errInfo); + } + *pBytesRead = (size_t) n; + return 1; +#else + { + int res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL); + if (res) { + return efile_read(errInfo, 0, fd, buf, count, pBytesRead); + } else { + return res; + } + } +#endif +} + + + +int +efile_pwrite(Efile_error* errInfo, /* Where to return error codes. */ + int fd, /* File descriptor to write to. */ + char* buf, /* Buffer to write. */ + size_t count, /* Number of bytes to write. */ + Sint64 offset) /* where to write it */ +{ +#if defined(HAVE_PREAD) && defined(HAVE_PWRITE) + ssize_t written; /* Bytes written in last operation. */ + off_t off = (off_t) offset; + if (off != offset) { + errno = EINVAL; + return check_error(-1, errInfo); + } + + while (count > 0) { + if ((written = pwrite(fd, buf, count, offset)) < 0) { + if (errno != EINTR) + return check_error(-1, errInfo); + else + written = 0; + } + ASSERT(written <= count); + buf += written; + count -= written; + offset += written; + } + return 1; +#else /* For unix systems that don't support pread() and pwrite() */ + { + int res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL); + + if (res) { + return efile_write(errInfo, 0, fd, buf, count); + } else { + return res; + } + } +#endif +} + + +int +efile_seek(Efile_error* errInfo, /* Where to return error codes. */ + int fd, /* File descriptor to do the seek on. */ + Sint64 offset, /* Offset in bytes from the given + origin. */ + int origin, /* Origin of seek (SEEK_SET, SEEK_CUR, + SEEK_END). */ + Sint64 *new_location) /* Resulting new location in file. */ +{ + off_t off, result; + + switch (origin) { + case EFILE_SEEK_SET: origin = SEEK_SET; break; + case EFILE_SEEK_CUR: origin = SEEK_CUR; break; + case EFILE_SEEK_END: origin = SEEK_END; break; + default: + errno = EINVAL; + return check_error(-1, errInfo); + } + off = (off_t) offset; + if (off != offset) { + errno = EINVAL; + return check_error(-1, errInfo); + } + + errno = 0; + result = lseek(fd, off, origin); + + /* + * Note that the man page for lseek (on SunOs 5) says: + * + * "if fildes is a remote file descriptor and offset is + * negative, lseek() returns the file pointer even if it is + * negative." + */ + + if (result < 0 && errno == 0) + errno = EINVAL; + if (result < 0) + return check_error(-1, errInfo); + if (new_location) { + *new_location = result; + } + return 1; +} + + +int +efile_truncate_file(Efile_error* errInfo, int *fd, int flags) +{ +#ifndef NO_FTRUNCATE + off_t offset; + + return check_error((offset = lseek(*fd, 0, 1)) >= 0 && + ftruncate(*fd, offset) == 0 ? 1 : -1, + errInfo); +#else + return 1; +#endif +} + +int +efile_readlink(Efile_error* errInfo, char* name, char* buffer, size_t size) +{ +#ifndef __OSE__ + int len; + ASSERT(size > 0); + len = readlink(name, buffer, size-1); + if (len == -1) { + return check_error(-1, errInfo); + } + buffer[len] = '\0'; + return 1; +#else + errno = ENOTSUP; + return check_error(-1, errInfo); +#endif +} + +int +efile_altname(Efile_error* errInfo, char* name, char* buffer, size_t size) +{ + errno = ENOTSUP; + return check_error(-1, errInfo); +} + +int +efile_link(Efile_error* errInfo, char* old, char* new) +{ +#ifndef __OSE__ + return check_error(link(old, new), errInfo); +#else + errno = ENOTSUP; + return check_error(-1, errInfo); +#endif +} + +int +efile_symlink(Efile_error* errInfo, char* old, char* new) +{ +#ifndef __OSE__ + return check_error(symlink(old, new), errInfo); +#else + errno = ENOTSUP; + return check_error(-1, errInfo); +#endif +} + +int +efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset, + Sint64 length, int advise) +{ +#ifdef HAVE_POSIX_FADVISE + return check_error(posix_fadvise(fd, offset, length, advise), errInfo); +#else + 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. + * + * The semantics of the API is this: + * Return value: 1 if all data was sent and the function does not need to + * be called again. 0 if an error occures OR if there is more data which + * has to be sent (EAGAIN or EINTR will be set appropriately) + * + * The amount of data written in a call is returned through nbytes. + * + */ + +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); + if (written != 0) { + /* -1 is not returned by the linux API so we have to simulate it */ + retval = -1; + errno = EAGAIN; + } +#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); + + /* Sometimes sendfilev can return -1 and still send data. + When that happens we just pretend that no error happend. */ + if (retval != -1 || errno == EAGAIN || errno == EINTR || + len != 0) { + *offset += len; + *nbytes -= len; + written += len; + if (errno != EAGAIN && errno != EINTR && len != 0) + retval = len; + } + } while (len == SENDFILE_CHUNK_SIZE); +#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); +#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); +#endif + *nbytes = written; + return check_error(retval, errInfo); +} +#endif /* HAVE_SENDFILE */ + +#ifdef HAVE_POSIX_FALLOCATE +static int +call_posix_fallocate(int fd, Sint64 offset, Sint64 length) +{ + int ret; + + /* + * On Linux and Solaris for example, posix_fallocate() returns + * a positive error number on error and it does not set errno. + * On FreeBSD however (9.0 at least), it returns -1 on error + * and it sets errno. + */ + do { + ret = posix_fallocate(fd, (off_t) offset, (off_t) length); + if (ret > 0) { + errno = ret; + ret = -1; + } + } while (ret != 0 && errno == EINTR); + + return ret; +} +#endif /* HAVE_POSIX_FALLOCATE */ + +int +efile_fallocate(Efile_error* errInfo, int fd, Sint64 offset, Sint64 length) +{ +#if defined HAVE_FALLOCATE + /* Linux specific, more efficient than posix_fallocate. */ + int ret; + + do { + ret = fallocate(fd, FALLOC_FL_KEEP_SIZE, (off_t) offset, (off_t) length); + } while (ret != 0 && errno == EINTR); + +#if defined HAVE_POSIX_FALLOCATE + /* Fallback to posix_fallocate if available. */ + if (ret != 0) { + ret = call_posix_fallocate(fd, offset, length); + } +#endif + + return check_error(ret, errInfo); +#elif defined F_PREALLOCATE + /* Mac OS X specific, equivalent to posix_fallocate. */ + int ret; + fstore_t fs; + + memset(&fs, 0, sizeof(fs)); + fs.fst_flags = F_ALLOCATECONTIG; + fs.fst_posmode = F_VOLPOSMODE; + fs.fst_offset = (off_t) offset; + fs.fst_length = (off_t) length; + + ret = fcntl(fd, F_PREALLOCATE, &fs); + + if (-1 == ret) { + fs.fst_flags = F_ALLOCATEALL; + ret = fcntl(fd, F_PREALLOCATE, &fs); + +#if defined HAVE_POSIX_FALLOCATE + /* Fallback to posix_fallocate if available. */ + if (-1 == ret) { + ret = call_posix_fallocate(fd, offset, length); + } +#endif + } + + return check_error(ret, errInfo); +#elif defined HAVE_POSIX_FALLOCATE + /* Other Unixes, use posix_fallocate if available. */ + return check_error(call_posix_fallocate(fd, offset, length), errInfo); +#else + errno = ENOTSUP; + return check_error(-1, errInfo); +#endif +} -- cgit v1.2.3 From eed38c1bb1a12015377d30e9ceff9525e050850e Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Tue, 3 Sep 2013 11:48:00 +0200 Subject: ose: Convert EFILE_SEEK to unistd seek for gzio This is needed because OSE does not have the same integers as unix/win32 for SEEK_ST and friends. --- erts/emulator/drivers/common/gzio.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/gzio.c b/erts/emulator/drivers/common/gzio.c index 653f3954b1..9a9e297fca 100644 --- a/erts/emulator/drivers/common/gzio.c +++ b/erts/emulator/drivers/common/gzio.c @@ -20,6 +20,7 @@ #endif #include #include "erl_driver.h" +#include "erl_efile.h" #include "sys.h" #ifdef __WIN32__ @@ -597,6 +598,15 @@ erts_gzseek(ErtsGzFile file, int offset, int whence) int pos; gz_stream* s = (gz_stream *) file; + switch (whence) { + case EFILE_SEEK_SET: whence = SEEK_SET; break; + case EFILE_SEEK_CUR: whence = SEEK_CUR; break; + case EFILE_SEEK_END: whence = SEEK_END; break; + default: + errno = EINVAL; + return -1; + } + if (s == NULL) { errno = EINVAL; return -1; -- cgit v1.2.3 From e2d4b774f4141bdf530696c0abe3704655ed3aa3 Mon Sep 17 00:00:00 2001 From: Jonas Karlsson Date: Tue, 15 Oct 2013 16:59:38 +0200 Subject: ose: lseek() to use SEEK_CUR This is needed because OSE does not use 1 for SEEK_CUR --- erts/emulator/drivers/ose/ose_efile.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/ose/ose_efile.c b/erts/emulator/drivers/ose/ose_efile.c index 8cd34a7bb0..fc255e11ef 100644 --- a/erts/emulator/drivers/ose/ose_efile.c +++ b/erts/emulator/drivers/ose/ose_efile.c @@ -33,8 +33,10 @@ #include "erl_efile.h" /*#include */ #ifdef HAVE_UNISTD_H +#ifndef __OSE__ #include #endif +#endif #ifdef HAVE_SYS_UIO_H #include #include @@ -60,8 +62,11 @@ #endif #ifdef __OSE__ +#include "unistd.h" #include "sys/stat.h" #include "dirent.h" +#include "sys/time.h" +#include "time.h" #endif /* Find a definition of MAXIOV, that is used in the code later. */ @@ -826,10 +831,8 @@ efile_truncate_file(Efile_error* errInfo, int *fd, int flags) { #ifndef NO_FTRUNCATE off_t offset; - - return check_error((offset = lseek(*fd, 0, 1)) >= 0 && - ftruncate(*fd, offset) == 0 ? 1 : -1, - errInfo); + return check_error((offset = lseek(*fd, 0, SEEK_CUR)) >= 0 && + ftruncate(*fd, offset) == 0 ? 1 : -1, errInfo); #else return 1; #endif -- cgit v1.2.3 From fa3dd14716b2a7ad0c223ebacd2ffc6ecf6437e6 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Mon, 30 Sep 2013 15:07:49 +0200 Subject: ose: Add module that allows interaction with any OSE process The interface of this module is made to be as generic as possible in order for other IPC mechanisms to mimic it and allow porting of code between different os:es. --- erts/emulator/drivers/ose/ose_signal_drv.c | 884 +++++++++++++++++++++++++++++ 1 file changed, 884 insertions(+) create mode 100644 erts/emulator/drivers/ose/ose_signal_drv.c (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/ose/ose_signal_drv.c b/erts/emulator/drivers/ose/ose_signal_drv.c new file mode 100644 index 0000000000..acf09f748e --- /dev/null +++ b/erts/emulator/drivers/ose/ose_signal_drv.c @@ -0,0 +1,884 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2013-2013. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "errno.h" +#include "stdio.h" +#include "string.h" +#include "stddef.h" + +#include "sys.h" +#include "erl_driver.h" +#include "ose.h" +#include "ose_spi/ose_spi.h" + +#define DEBUG_ATTACH 0 +#define DEBUG_HUNT 0 +#define DEBUG_SEND 0 +#define DEBUG_LISTEN 0 + +#if 0 +#define DEBUGP(FMT,...) printf(FMT, __VA_ARGS__) +#else +#define DEBUGP(FMT,...) +#endif + +#if DEBUG_ATTACH +#define DEBUGP_ATTACH(...) DEBUGP( __VA_ARGS__) +#else +#define DEBUGP_ATTACH(...) +#endif + +#if DEBUG_HUNT +#define DEBUGP_HUNT(...) DEBUGP( __VA_ARGS__) +#else +#define DEBUGP_HUNT(...) +#endif + +#if DEBUG_LISTEN +#define DEBUGP_LISTEN(...) DEBUGP( __VA_ARGS__) +#else +#define DEBUGP_LISTEN(...) +#endif + +#if DEBUG_SEND +#define DEBUGP_SEND(...) DEBUGP( __VA_ARGS__) +#else +#define DEBUGP_SEND(...) +#endif + + +#define DRIVER_NAME "ose_signal_drv" +#define GET_SPID 1 +#define GET_NAME 2 +#define HUNT 100 +#define DEHUNT 101 +#define ATTACH 102 +#define DETACH 103 +#define SEND 104 +#define SEND_W_S 105 +#define LISTEN 106 +#define OPEN 200 + +#define REF_SEGMENT_SIZE 8 + +struct async { + SIGSELECT signo; + ErlDrvTermData port; + ErlDrvTermData proc; + PROCESS spid; + PROCESS target; + Uint32 ref; +}; + +/** + * OSE signals + **/ +union SIGNAL { + SIGSELECT signo; + struct async async; +}; + +/** + * The driver's context + **/ +typedef struct _driver_context { + ErlDrvPort port; + PROCESS spid; + ErlDrvEvent perm_events[2]; + ErlDrvEvent *events; + Uint32 event_cnt; + Uint32 ref; + Uint32 *outstanding_refs; + Uint32 outstanding_refs_max; + Uint32 outstanding_refs_cnt; +} driver_context_t; + +/** + * Global variables + **/ +static ErlDrvTermData a_ok; +static ErlDrvTermData a_error; +static ErlDrvTermData a_enomem; +static ErlDrvTermData a_enoent; +static ErlDrvTermData a_badarg; +static ErlDrvTermData a_mailbox_up; +static ErlDrvTermData a_mailbox_down; +static ErlDrvTermData a_ose_drv_reply; +static ErlDrvTermData a_message; +static PROCESS proxy_proc; + + +/** + * Serialize/unserialize unsigned 32-bit values + **/ +static char *put_u32(unsigned int value, char *ptr) { + *ptr++ = (value & 0xff000000) >> 24; + *ptr++ = (value & 0x00ff0000) >> 16; + *ptr++ = (value & 0x0000ff00) >> 8; + *ptr++ = (value & 0xff); + + return ptr; +} + +static unsigned int get_u32(char *ptr) { + unsigned int result = 0; + result += (ptr[0] & 0xff) << 24; + result += (ptr[1] & 0xff) << 16; + result += (ptr[2] & 0xff) << 8; + result += (ptr[3] & 0xff); + + return result; +} + + +/* Stolen from efile_drv.c */ + +/* char EV_CHAR_P(ErlIOVec *ev, int p, int q) */ +#define EV_CHAR_P(ev, p, q) \ + (((char *)(ev)->iov[(q)].iov_base) + (p)) + +/* int EV_GET_CHAR(ErlIOVec *ev, char *p, int *pp, int *qp) */ +#define EV_GET_CHAR(ev, p, pp, qp) ev_get_char(ev, p ,pp, qp) +static int +ev_get_char(ErlIOVec *ev, char *p, int *pp, int *qp) { + if (*(pp)+1 <= (ev)->iov[*(qp)].iov_len) { + *(p) = *EV_CHAR_P(ev, *(pp), *(qp)); + if (*(pp)+1 < (ev)->iov[*(qp)].iov_len) + *(pp) = *(pp)+1; + else { + (*(qp))++; + *pp = 0; + } + return !0; + } + return 0; +} + +/* Uint32 EV_UINT32(ErlIOVec *ev, int p, int q)*/ +#define EV_UINT32(ev, p, q) \ + ((Uint32) *(((unsigned char *)(ev)->iov[(q)].iov_base) + (p))) + +/* int EV_GET_UINT32(ErlIOVec *ev, Uint32 *p, int *pp, int *qp) */ +#define EV_GET_UINT32(ev, p, pp, qp) ev_get_uint32(ev,(Uint32*)(p),pp,qp) +static int +ev_get_uint32(ErlIOVec *ev, Uint32 *p, int *pp, int *qp) { + if (*(pp)+4 <= (ev)->iov[*(qp)].iov_len) { + *(p) = (EV_UINT32(ev, *(pp), *(qp)) << 24) + | (EV_UINT32(ev, *(pp)+1, *(qp)) << 16) + | (EV_UINT32(ev, *(pp)+2, *(qp)) << 8) + | (EV_UINT32(ev, *(pp)+3, *(qp))); + if (*(pp)+4 < (ev)->iov[*(qp)].iov_len) + *(pp) = *(pp)+4; + else { + (*(qp))++; + *pp = 0; + } + return !0; + } + return 0; +} + +/** + * Convinience macros + **/ +#define send_response(port,output) erl_drv_send_term(driver_mk_port(port),\ + driver_caller(port), output, sizeof(output) / sizeof(output[0])); + +void iov_memcpy(void *dest,ErlIOVec *ev,int ind,int off); +void iov_memcpy(void *dest,ErlIOVec *ev,int ind,int off) { + int i; + memcpy(dest,ev->iov[ind].iov_base+off,ev->iov[ind].iov_len-off); + for (i = ind+1; i < ev->vsize; i++) + memcpy(dest,ev->iov[i].iov_base,ev->iov[i].iov_len); +} + +/** + * Reference handling + **/ + +static int add_reference(driver_context_t *ctxt, Uint32 ref) { + + /* + * Premature optimizations may be evil, but they sure are fun. + */ + + if (ctxt->outstanding_refs == NULL) { + /* First ref to be ignored */ + ctxt->outstanding_refs = driver_alloc(REF_SEGMENT_SIZE*sizeof(Uint32)); + if (!ctxt->outstanding_refs) + return 1; + + memset(ctxt->outstanding_refs,0,REF_SEGMENT_SIZE*sizeof(Uint32)); + ctxt->outstanding_refs_max += REF_SEGMENT_SIZE; + ctxt->outstanding_refs[ctxt->outstanding_refs_cnt++] = ref; + } else if (ctxt->outstanding_refs_cnt == ctxt->outstanding_refs_max) { + /* Expand ref array */ + Uint32 *new_array; + ctxt->outstanding_refs_max += REF_SEGMENT_SIZE; + new_array = driver_realloc(ctxt->outstanding_refs, + ctxt->outstanding_refs_max*sizeof(Uint32)); + + if (!new_array) { + ctxt->outstanding_refs_max -= REF_SEGMENT_SIZE; + return 1; + } + + ctxt->outstanding_refs = new_array; + + memset(ctxt->outstanding_refs+ctxt->outstanding_refs_cnt,0, + REF_SEGMENT_SIZE*sizeof(Uint32)); + ctxt->outstanding_refs[ctxt->outstanding_refs_cnt++] = ref; + + } else { + /* Find an empty slot: + * First we try current index, + * then we scan for a slot. + */ + if (!ctxt->outstanding_refs[ctxt->outstanding_refs_cnt]) { + ctxt->outstanding_refs[ctxt->outstanding_refs_cnt++] = ref; + } else { + int i; + ASSERT(ctxt->outstanding_refs_cnt < ctxt->outstanding_refs_max); + for (i = 0; i < ctxt->outstanding_refs_max; i++) + if (!ctxt->outstanding_refs[i]) + break; + ASSERT(ctxt->outstanding_refs[i] == 0); + ctxt->outstanding_refs[i] = ref; + ctxt->outstanding_refs_cnt++; + } + } + return 0; +} + +/* Return 0 if removed, 1 if does not exist, */ +static int remove_reference(driver_context_t *ctxt, Uint32 ref) { + int i,j; + + if (ctxt->outstanding_refs_max == 0 && ctxt->outstanding_refs_cnt == 0) { + ASSERT(ctxt->outstanding_refs == NULL); + return 1; + } + + for (i = 0; i < ctxt->outstanding_refs_max; i++) { + if (ctxt->outstanding_refs[i] == ref) { + ctxt->outstanding_refs[i] = 0; + ctxt->outstanding_refs_cnt--; + i = -1; + break; + } + } + + if (i != -1) + return 1; + + if (ctxt->outstanding_refs_cnt == 0) { + driver_free(ctxt->outstanding_refs); + ctxt->outstanding_refs = NULL; + ctxt->outstanding_refs_max = 0; + } else if (ctxt->outstanding_refs_cnt == (ctxt->outstanding_refs_max - REF_SEGMENT_SIZE)) { + Uint32 *new_array; + for (i = 0, j = 0; i < ctxt->outstanding_refs_cnt; i++) { + if (ctxt->outstanding_refs[i] == 0) { + for (j = i+1; j < ctxt->outstanding_refs_max; j++) + if (ctxt->outstanding_refs[j]) { + ctxt->outstanding_refs[i] = ctxt->outstanding_refs[j]; + ctxt->outstanding_refs[j] = 0; + break; + } + } + } + ctxt->outstanding_refs_max -= REF_SEGMENT_SIZE; + new_array = driver_realloc(ctxt->outstanding_refs, + ctxt->outstanding_refs_max*sizeof(Uint32)); + if (!new_array) { + ctxt->outstanding_refs_max += REF_SEGMENT_SIZE; + return 2; + } + + ctxt->outstanding_refs = new_array; + + } + + return 0; +} + +/** + * The OSE proxy process. This only handles ERTS_SIGNAL_OSE_DRV_ATTACH. + * The process is needed because signals triggered by attach ignore + * redir tables. + * + * We have one global proxy process to save memory. An attempt to make each + * port phantom into a proxy was made, but that used way to much memory. + */ +static OS_PROCESS(driver_proxy_process) { + SIGSELECT sigs[] = {1,ERTS_SIGNAL_OSE_DRV_ATTACH}; + PROCESS master = 0; + + while (1) { + union SIGNAL *sig = receive(sigs); + + if (sig->signo == ERTS_SIGNAL_OSE_DRV_ATTACH) { + + /* The first message is used to determine who to send messages to. */ + if (master == 0) + master = sender(&sig); + + if (sig->async.target == 0) { + PROCESS from = sender(&sig); + restore(sig); + DEBUGP_ATTACH("0x%x: got attach 0x%x, sending to 0x%x\n", + current_process(),from,master); + sig->async.target = from; + send(&sig,master); + } else { + PROCESS target = sig->async.target; + restore(sig); + sig->async.target = 0; + DEBUGP_ATTACH("0x%x: doing attach on 0x%x\n",current_process(),target); + attach(&sig,target); + } + } + } +} + +/** + * Init routine for the driver + **/ +static int drv_init(void) { + + a_ok = driver_mk_atom("ok"); + a_error = driver_mk_atom("error"); + a_enomem = driver_mk_atom("enomem"); + a_enoent = driver_mk_atom("enoent"); + a_badarg = driver_mk_atom("badarg"); + a_mailbox_up = driver_mk_atom("mailbox_up"); + a_mailbox_down = driver_mk_atom("mailbox_down"); + a_ose_drv_reply = driver_mk_atom("ose_drv_reply"); + a_message = driver_mk_atom("message"); + + proxy_proc = create_process(get_ptype(current_process()), + "ose_signal_driver_proxy", + driver_proxy_process, 10000, + get_pri(current_process()), + 0, 0, NULL, 0, 0); + +#ifdef DEBUG + efs_clone(proxy_proc); +#endif + start(proxy_proc); + + return 0; +} + +/** + * Start routine for the driver + **/ +static ErlDrvData drv_start(ErlDrvPort port, char *command) +{ + driver_context_t *ctxt = driver_alloc(sizeof(driver_context_t)); + + ctxt->perm_events[0] = NULL; + ctxt->perm_events[1] = NULL; + + ctxt->spid = 0; + ctxt->port = port; + ctxt->event_cnt = 0; + ctxt->events = NULL; + ctxt->ref = 0; + ctxt->outstanding_refs = NULL; + ctxt->outstanding_refs_max = 0; + ctxt->outstanding_refs_cnt = 0; + + + /* Set the communication protocol to Erlang to be binary */ + set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY); + + /* Everything ok */ + return (ErlDrvData)ctxt; +} + +/** + * Stop routine for the driver + **/ +static void drv_stop(ErlDrvData driver_data) +{ + driver_context_t *ctxt = (driver_context_t *)driver_data; + int i; + + /* HUNT + ATTACH */ + if (ctxt->perm_events[0]) + driver_select(ctxt->port, ctxt->perm_events[0], + ERL_DRV_USE|ERL_DRV_READ, 0); + if (ctxt->perm_events[1]) + driver_select(ctxt->port, ctxt->perm_events[1], + ERL_DRV_USE|ERL_DRV_READ, 0); + + for (i = 0; i < ctxt->event_cnt; i++) { + driver_select(ctxt->port, ctxt->events[i], ERL_DRV_USE|ERL_DRV_READ, 0); + } + + if (ctxt->spid != 0) + kill_proc(ctxt->spid); + DEBUGP("0x%x: stopped\n",ctxt->spid); + if (ctxt->events) + driver_free(ctxt->events); + if (ctxt->outstanding_refs) + driver_free(ctxt->outstanding_refs); + + driver_free(ctxt); +} + +/** + * Output from Erlang + **/ +static void outputv(ErlDrvData driver_data, ErlIOVec *ev) +{ + driver_context_t *ctxt = (driver_context_t *)driver_data; + int p = 0, q = 1; + char cmd; + + if (! EV_GET_CHAR(ev,&cmd,&p,&q)) { + ErlDrvTermData output[] = { + ERL_DRV_ATOM, a_ose_drv_reply, + ERL_DRV_PORT, driver_mk_port(ctxt->port), + ERL_DRV_ATOM, a_badarg, + ERL_DRV_TUPLE, 3}; + send_response(ctxt->port, output); + return; + } + + /* Command is in the buffer's first byte */ + switch(cmd) { + + case OPEN: { + char *name = driver_alloc(ev->size - 1+1); + struct OS_redir_entry redir[2]; + + redir[0].sig = 1; + redir[0].pid = current_process(); + + iov_memcpy(name,ev,q,p); + name[ev->size-1] = '\0'; + + ctxt->spid = create_process(OS_PHANTOM, name, NULL, 0, + 0, 0, 0, redir, 0, 0); + + DEBUGP("0x%x: open\n",ctxt->spid); + + ctxt->perm_events[1] = + erl_drv_ose_event_alloc(ERTS_SIGNAL_OSE_DRV_ATTACH,(int)ctxt->spid); + driver_select(ctxt->port,ctxt->perm_events[1],ERL_DRV_READ|ERL_DRV_USE,1); + + ctxt->perm_events[0] = + erl_drv_ose_event_alloc(ERTS_SIGNAL_OSE_DRV_HUNT,(int)ctxt->spid); + driver_select(ctxt->port,ctxt->perm_events[0],ERL_DRV_READ|ERL_DRV_USE,1); + + start(ctxt->spid); + + { + ErlDrvTermData output[] = { + ERL_DRV_ATOM, a_ose_drv_reply, + ERL_DRV_PORT, driver_mk_port(ctxt->port), + ERL_DRV_ATOM, a_ok, + ERL_DRV_TUPLE, 3}; + + send_response(ctxt->port, output); + } + + break; + + } + + case ATTACH: + case HUNT: + { + union SIGNAL *sig = alloc(sizeof(union SIGNAL), + cmd == HUNT ? ERTS_SIGNAL_OSE_DRV_HUNT:ERTS_SIGNAL_OSE_DRV_ATTACH); + + sig->async.port = driver_mk_port(ctxt->port); + sig->async.proc = driver_caller(ctxt->port); + sig->async.spid = ctxt->spid; + sig->async.ref = ++ctxt->ref; + + if (add_reference(ctxt,ctxt->ref)) { + ErlDrvTermData output[] = { + ERL_DRV_ATOM, a_ose_drv_reply, + ERL_DRV_PORT, driver_mk_port(ctxt->port), + ERL_DRV_ATOM, a_enomem, + ERL_DRV_TUPLE, 3}; + send_response(ctxt->port, output); + free_buf(&sig); + } else { + ErlDrvTermData output[] = { + ERL_DRV_ATOM, a_ose_drv_reply, + ERL_DRV_PORT, driver_mk_port(ctxt->port), + ERL_DRV_PORT, driver_mk_port(ctxt->port), + ERL_DRV_INT, (ErlDrvUInt)ctxt->ref, + ERL_DRV_TUPLE, 2, + ERL_DRV_TUPLE, 3}; + send_response(ctxt->port, output); + + if (cmd == HUNT) { + char *huntname = driver_alloc(sizeof(char)*((ev->size-1)+1)); + + iov_memcpy(huntname,ev,q,p); + huntname[ev->size-1] = '\0'; + + DEBUGP_HUNT("0x%x: hunt %s -> %u (%u,%u)\n", + ctxt->spid,huntname,ctxt->ref, + ctxt->outstanding_refs_cnt, + ctxt->outstanding_refs_max); + + hunt(huntname, 0, NULL, &sig); + + driver_free(huntname); + } else { + EV_GET_UINT32(ev,&sig->async.target,&p,&q); + DEBUGP_ATTACH("0x%x: attach %u -> %u (%u,%u)\n", + ctxt->spid,sig->async.target, + ctxt->ref, + ctxt->outstanding_refs_cnt, + ctxt->outstanding_refs_max); + + send(&sig,proxy_proc); + } + + } + + break; + } + + case DETACH: + case DEHUNT: + { + + Uint32 ref; + + EV_GET_UINT32(ev,&ref,&p,&q); + if (cmd == DETACH) { + DEBUGP_ATTACH("0x%x: detach %u (%u,%u)\n",ctxt->spid,ref, + ctxt->outstanding_refs_cnt, + ctxt->outstanding_refs_max); + } else { + DEBUGP_HUNT("0x%x: dehunt %u (%u,%u)\n",ctxt->spid,ref, + ctxt->outstanding_refs_cnt, + ctxt->outstanding_refs_max); + } + + if (remove_reference(ctxt,ref)) { + ErlDrvTermData output[] = { + ERL_DRV_ATOM, a_ose_drv_reply, + ERL_DRV_PORT, driver_mk_port(ctxt->port), + ERL_DRV_ATOM, a_error, + ERL_DRV_ATOM, a_enoent, + ERL_DRV_TUPLE, 2, + ERL_DRV_TUPLE, 3}; + + send_response(ctxt->port, output); + } else { + ErlDrvTermData output[] = { + ERL_DRV_ATOM, a_ose_drv_reply, + ERL_DRV_PORT, driver_mk_port(ctxt->port), + ERL_DRV_ATOM, a_ok, + ERL_DRV_TUPLE, 3}; + + send_response(ctxt->port, output); + } + + break; + } + + case SEND: + case SEND_W_S: + { + PROCESS spid; + PROCESS sender; + SIGSELECT signo; + OSBUFSIZE size = ev->size-9; + union SIGNAL *sig; + + EV_GET_UINT32(ev,&spid,&p,&q); + + if (cmd == SEND_W_S) { + EV_GET_UINT32(ev,&sender,&p,&q); + size -= 4; + } else { + sender = ctxt->spid; + } + + EV_GET_UINT32(ev,&signo,&p,&q); + + sig = alloc(size + sizeof(SIGSELECT),signo); + + if (cmd == SEND_W_S) { + DEBUGP_SEND("0x%x: send_w_s(%u,%u,%u)\n",ctxt->spid,spid,signo,sender); + } else { + DEBUGP_SEND("0x%x: send(%u,%u)\n",ctxt->spid,spid,signo); + } + + iov_memcpy(((char *)&sig->signo) + sizeof(SIGSELECT),ev,q,p); + + send_w_s(&sig, sender, spid); + + break; + } + + case LISTEN: + { + int i,j,event_cnt = (ev->size - 1)/4; + ErlDrvEvent *events = NULL; + SIGSELECT signo,tmp_signo; + + if (event_cnt == 0) { + for (i = 0; i < ctxt->event_cnt; i++) + driver_select(ctxt->port,ctxt->events[i],ERL_DRV_READ|ERL_DRV_USE,0); + if (ctxt->events) + driver_free(ctxt->events); + } else { + events = driver_alloc(sizeof(ErlDrvEvent)*event_cnt); + EV_GET_UINT32(ev,&signo,&p,&q); + for (i = 0, j = 0; i < event_cnt || j < ctxt->event_cnt; ) { + + if (ctxt->events) + erl_drv_ose_event_fetch(ctxt->events[j],&tmp_signo,NULL); + + if (signo == tmp_signo) { + events[i++] = ctxt->events[j++]; + EV_GET_UINT32(ev,&signo,&p,&q); + } else if (signo < tmp_signo || !ctxt->events) { + /* New signal to select on */ + events[i] = erl_drv_ose_event_alloc(signo,(int)ctxt->spid); + driver_select(ctxt->port,events[i++],ERL_DRV_READ|ERL_DRV_USE,1); + EV_GET_UINT32(ev,&signo,&p,&q); + } else { + /* Remove old signal to select on */ + driver_select(ctxt->port,ctxt->events[j++],ERL_DRV_READ|ERL_DRV_USE,0); + } + } + if (ctxt->events) + driver_free(ctxt->events); + } + ctxt->events = events; + ctxt->event_cnt = event_cnt; + + { + ErlDrvTermData output[] = { + ERL_DRV_ATOM, a_ose_drv_reply, + ERL_DRV_PORT, driver_mk_port(ctxt->port), + ERL_DRV_ATOM, a_ok, + ERL_DRV_TUPLE, 3}; + send_response(ctxt->port, output); + } + break; + } + + default: + { + DEBUGP("Warning: 'ose_signal_drv' unknown command '%d'\n", cmd); + break; + } + } +} + +/** + * Handler for when OSE signal arrives + **/ +static void ready_input(ErlDrvData driver_data, ErlDrvEvent event) +{ + driver_context_t *ctxt = (driver_context_t *)driver_data; + union SIGNAL *sig = erl_drv_ose_get_input_signal(event); + + while (sig != NULL) { + + switch(sig->signo) + { + /* Remote process is available */ + case ERTS_SIGNAL_OSE_DRV_HUNT: + { + const PROCESS spid = sender(&sig); + + if (remove_reference(ctxt,sig->async.ref)) { + DEBUGP_HUNT("0x%x: Got hunt from 0x%x -> %u (CANCELLED) (%u,%u)\n", + ctxt->spid,spid,sig->async.ref, + ctxt->outstanding_refs_cnt, + ctxt->outstanding_refs_max); + /* Already removed by dehunt */ + } else { + ErlDrvTermData reply[] = { + ERL_DRV_ATOM, a_mailbox_up, + ERL_DRV_PORT, sig->async.port, + ERL_DRV_PORT, sig->async.port, + ERL_DRV_UINT, (ErlDrvUInt)sig->async.ref, + ERL_DRV_TUPLE, 2, + ERL_DRV_UINT, (ErlDrvUInt)spid, + ERL_DRV_TUPLE, 4}; + DEBUGP_HUNT("0x%x: Got hunt from 0x%x -> %u (%u,%u)\n", + ctxt->spid,spid,sig->async.ref, + ctxt->outstanding_refs_cnt, + ctxt->outstanding_refs_max); + erl_drv_send_term(sig->async.port, sig->async.proc, reply, + sizeof(reply) / sizeof(reply[0])); + } + break; + } + + /* Remote process is down */ + case ERTS_SIGNAL_OSE_DRV_ATTACH: + { + PROCESS spid = sig->async.target; + + if (remove_reference(ctxt,sig->async.ref)) { + DEBUGP_ATTACH("0x%x: Got attach from 0x%x -> %u (CANCELLED) (%u,%u)\n", + ctxt->spid,spid,sig->async.ref, + ctxt->outstanding_refs_cnt, + ctxt->outstanding_refs_max); + /* Already removed by detach */ + } else { + ErlDrvTermData reply[] = { + ERL_DRV_ATOM, a_mailbox_down, + ERL_DRV_PORT, sig->async.port, + ERL_DRV_PORT, sig->async.port, + ERL_DRV_UINT, sig->async.ref, + ERL_DRV_TUPLE, 2, + ERL_DRV_UINT, (ErlDrvUInt)spid, + ERL_DRV_TUPLE, 4}; + DEBUGP_ATTACH("0x%x: Got attach from 0x%x -> %u (%u,%u)\n", + ctxt->spid,spid,sig->async.ref, + ctxt->outstanding_refs_cnt, + ctxt->outstanding_refs_max); + erl_drv_send_term(sig->async.port, sig->async.proc, reply, + sizeof(reply) / sizeof(reply[0])); + } + break; + } + + /* Received user defined signal */ + default: + { + const PROCESS spid = sender(&sig); + const OSBUFSIZE size = sigsize(&sig) - sizeof(SIGSELECT); + const char *sig_data = ((char *)&sig->signo) + sizeof(SIGSELECT); + + ErlDrvTermData reply[] = { + ERL_DRV_ATOM, a_message, + ERL_DRV_PORT, driver_mk_port(ctxt->port), + ERL_DRV_UINT, (ErlDrvUInt)spid, + ERL_DRV_UINT, (ErlDrvUInt)ctxt->spid, + ERL_DRV_UINT, (ErlDrvUInt)sig->signo, + ERL_DRV_BUF2BINARY, (ErlDrvTermData)sig_data, (ErlDrvUInt)size, + ERL_DRV_TUPLE, 4, + ERL_DRV_TUPLE, 3}; + + DEBUGP_SEND("0x%x: Got 0x%u\r\n", spid, sig->signo); + + erl_drv_output_term(driver_mk_port(ctxt->port), reply, + sizeof(reply) / sizeof(reply[0])); + break; + } + } + + free_buf(&sig); + sig = erl_drv_ose_get_input_signal(event); + } +} + +/** + * Handler for 'port_control' + **/ +static ErlDrvSSizeT control(ErlDrvData driver_data, unsigned int cmd, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen) +{ + driver_context_t *ctxt = (driver_context_t *)driver_data; + + switch(cmd) + { + case GET_SPID: + { + const PROCESS spid = ctxt->spid; + put_u32(spid, *rbuf); + return sizeof(PROCESS); + } + + case GET_NAME: + { + const PROCESS spid = get_u32(buf); + char *name = (char*)get_pid_info(spid,OSE_PI_NAME); + int n; + if (!name) { + *rbuf = NULL; + return 0; + } + + if (rlen < (n = strlen(name))) { + ErlDrvBinary *bin = driver_alloc_binary(n); + strncpy(bin->orig_bytes,name,n); + *rbuf = (char*)bin; + } else + strncpy(*rbuf,name,n); + free_buf((union SIGNAL**)&name); + + return n; + } + default: + { + /* Unknown command */ + return (ErlDrvSSizeT)ERL_DRV_ERROR_GENERAL; + break; + } + } +} + +static void stop_select(ErlDrvEvent event, void *reserved) +{ + erl_drv_ose_event_free(event); +} + +static int resolve_signal(OseSignal* osig, int *mode) { + union SIGNAL *sig = osig; + if (sig->signo == ERTS_SIGNAL_OSE_DRV_HUNT || + sig->signo == ERTS_SIGNAL_OSE_DRV_ATTACH) { + return sig->async.spid; + } + DEBUGP("%p: Got signal %d sent to %p from 0x%p\n", + current_process(),sig->signo,addressee(&sig),sender(&sig)); + return addressee(&sig); +} + +/** + * Setup the driver entry for the Erlang runtime + **/ +ErlDrvEntry ose_signal_driver_entry = { + .init = drv_init, + .start = drv_start, + .stop = drv_stop, + .outputv = outputv, + .ready_input = ready_input, + .driver_name = DRIVER_NAME, + .control = control, + .extended_marker = ERL_DRV_EXTENDED_MARKER, + .major_version = ERL_DRV_EXTENDED_MAJOR_VERSION, + .minor_version = ERL_DRV_EXTENDED_MINOR_VERSION, + .driver_flags = ERL_DRV_FLAG_USE_PORT_LOCKING, + .stop_select = stop_select, + .resolve_signal = resolve_signal +}; -- cgit v1.2.3 From a6788ea337a2319a2d1a42ee4618553a1c7765bf Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Wed, 30 Oct 2013 17:56:37 +0100 Subject: ose: Fix various build environment issues --- erts/emulator/drivers/ose/ose_signal_drv.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/ose/ose_signal_drv.c b/erts/emulator/drivers/ose/ose_signal_drv.c index acf09f748e..c1d861cc5a 100644 --- a/erts/emulator/drivers/ose/ose_signal_drv.c +++ b/erts/emulator/drivers/ose/ose_signal_drv.c @@ -28,7 +28,10 @@ #include "sys.h" #include "erl_driver.h" #include "ose.h" + +#ifdef HAVE_OSE_SPI_H #include "ose_spi/ose_spi.h" +#endif #define DEBUG_ATTACH 0 #define DEBUG_HUNT 0 @@ -819,6 +822,7 @@ static ErlDrvSSizeT control(ErlDrvData driver_data, unsigned int cmd, return sizeof(PROCESS); } +#ifdef HAVE_OSE_SPI_H case GET_NAME: { const PROCESS spid = get_u32(buf); @@ -839,6 +843,7 @@ static ErlDrvSSizeT control(ErlDrvData driver_data, unsigned int cmd, return n; } +#endif default: { /* Unknown command */ -- cgit v1.2.3 From cbfff8e7148a51a76f31effc6b2486f4bda927f6 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Fri, 1 Nov 2013 18:00:11 +0100 Subject: ose: Handle lseek() with offset beyond EOF in the file driver. --- erts/emulator/drivers/ose/ose_efile.c | 316 +++++++++++++++++++++++++++++++--- 1 file changed, 288 insertions(+), 28 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/ose/ose_efile.c b/erts/emulator/drivers/ose/ose_efile.c index fc255e11ef..897d654e89 100644 --- a/erts/emulator/drivers/ose/ose_efile.c +++ b/erts/emulator/drivers/ose/ose_efile.c @@ -62,11 +62,13 @@ #endif #ifdef __OSE__ +#include "ose.h" #include "unistd.h" #include "sys/stat.h" #include "dirent.h" #include "sys/time.h" #include "time.h" +#include "heapapi.h" #endif /* Find a definition of MAXIOV, that is used in the code later. */ @@ -99,8 +101,142 @@ #define IS_DOT_OR_DOTDOT(s) \ (s[0] == '.' && (s[1] == '\0' || (s[1] == '.' && s[2] == '\0'))) + +/* + * Local file descriptor handling, this is needed for filesystems + * that does not handle seeking outside EOF. + */ + +#define L_FD_EXISTS(fd) \ + ((fdm->is_init == 1) && fdm->fd_array[(fd)] != NULL) + +#define L_FD_INVALIDATE(fd) \ + fdm->fd_array[(fd)]->valid = 0 + +#define L_FD_IS_VALID(fd) \ + (fdm->fd_array[(fd)]->valid == 1) + +#define L_FD_OFFSET_BEYOND_EOF(fd, offset) \ + (fdm->fd_array[(fd)]->size < offset) + +#define L_FD_CUR(fd) \ + (fdm->fd_array[(fd)]->pos) + + +struct fd_meta +{ + int is_init; + uint32_t fd_count; + struct fd_data *fd_array[256]; +}; + +struct fd_data +{ + int pos; + int whence; + int valid; + size_t size; +}; + +static struct fd_meta *fdm; +static int l_init_local_fd(void); +static int l_pad_file(int fd, off_t offset); +static int l_update_local_fd(int fd, off_t offset, int whence); + static int check_error(int result, Efile_error* errInfo); +static int +l_init_local_fd() +{ + fdm = heap_alloc_private(sizeof(struct fd_meta), __FILE__, __LINE__); + fdm->fd_count = 0; + fdm->is_init = 1; + + memset(fdm->fd_array, NULL, sizeof(fdm->fd_array)); + return 1; +} + +static int +l_update_local_fd(int fd, off_t offset, int whence) +{ + errno = 0; + + if (fdm->fd_array[fd] == NULL) + { + fdm->fd_array[fd] = heap_alloc_private(sizeof(struct fd_data), __FILE__, __LINE__); + fdm->fd_count++; + } + + switch (whence) + { + case SEEK_CUR: + fdm->fd_array[fd]->pos = lseek(fd, 0, SEEK_CUR) + offset; + break; + + case SEEK_END: + fdm->fd_array[fd]->pos = lseek(fd, 0, SEEK_END) + offset; + break; + + case SEEK_SET: + fdm->fd_array[fd]->pos = offset; + + default: + errno = ENOSYS; + break; + } + fdm->fd_array[fd]->size = lseek(fd, 0, SEEK_END); + + fdm->fd_array[fd]->whence = whence; + fdm->fd_array[fd]->valid = 1; + + return ((errno != 0) ? -1 : 1); +} + +static int +l_pad_file(int fd, off_t offset) +{ + int size_dif; + char *pad; + char *cursor; + int file_size; + int written = 0; + + if (!L_FD_IS_VALID(fd)) + { + l_update_local_fd(fd, offset, SEEK_END); + } + + if (!L_FD_OFFSET_BEYOND_EOF(fd, offset)) + { + + return -1; + } + + + file_size = lseek(fd, 0, SEEK_END); + size_dif = offset - file_size; + pad = heap_alloc_private(size_dif, __FILE__, __LINE__); + cursor = pad; + memset(pad, '\0', size_dif); + + while (size_dif > 0) + { + written = write(fd, cursor, size_dif); + + if (written < 0) + { + return -1; + } + cursor += written; + size_dif -= written; + } + + L_FD_INVALIDATE(fd); + heap_free_private(pad); + + return ((errno != 0) ? -1 : 1); +} + static int check_error(int result, Efile_error *errInfo) { @@ -111,6 +247,10 @@ check_error(int result, Efile_error *errInfo) return 1; } +/* + * public API + */ + int efile_mkdir(Efile_error* errInfo, /* Where to return error codes. */ char* name) /* Name of directory to create. */ @@ -155,6 +295,15 @@ int efile_delete_file(Efile_error* errInfo, /* Where to return error codes. */ char* name) /* Name of file to delete. */ { + struct stat statbuf; + + /* OSE will accept removal of directories with unlink() */ + if (stat(name, &statbuf) >= 0 && ISDIR(statbuf)) + { + errno = EPERM; + return check_error(-1, errInfo); + } + if (unlink(name) == 0) { return 1; } @@ -202,7 +351,22 @@ efile_rename(Efile_error* errInfo, /* Where to return error codes. */ char* src, /* Original name. */ char* dst) /* New name. */ { - if (rename(src, dst) == 0) { + + /* temporary fix AFM does not recognize ./ + * in destination */ + + char *dot_str; + if (dst != NULL) + { + dot_str = strchr(dst, '.'); + + if (dot_str && dot_str == dst && dot_str[1] == '/') + { + dst = dst+2; + } + } + + if (rename(src, dst) == 0) { return 1; } if (errno == ENOTEMPTY) { @@ -445,7 +609,12 @@ efile_may_openfile(Efile_error* errInfo, char *name) { void efile_closefile(int fd) { - close(fd); + if (L_FD_EXISTS(fd)) + { + free(fdm->fd_array[fd]); + fdm->fd_array[fd] = NULL; + } + close(fd); } int @@ -546,6 +715,10 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, int efile_write_info(Efile_error *errInfo, Efile_info *pInfo, char *name) { +/* FIXME, this will be dificult to get to work right with the tests on ose + * reason being that the info values are sometimes used in different ways, and in + * some times not used at all. */ + #ifndef __OSE__ struct utimbuf tval; #endif @@ -593,16 +766,40 @@ efile_write(Efile_error* errInfo, /* Where to return error codes. */ { ssize_t written; /* Bytes written in last operation. */ - while (count > 0) { - if ((written = write(fd, buf, count)) < 0) { - if (errno != EINTR) - return check_error(-1, errInfo); - else - written = 0; - } - ASSERT(written <= count); - buf += written; - count -= written; + if (L_FD_EXISTS(fd)) + { + off_t off; + off = (L_FD_IS_VALID(fd)) ? L_FD_CUR(fd) : lseek(fd, 0, SEEK_CUR); + + if (L_FD_OFFSET_BEYOND_EOF(fd, off)) + { + l_pad_file(fd, off); + } + + L_FD_INVALIDATE(fd); + } + + while (count > 0) + { + if ((written = write(fd, buf, count)) < 0) + { + if (errno != EINTR) + { + return check_error(-1, errInfo); + } + else + { + written = 0; + } + } + ASSERT(written <= count); + buf += written; + count -= written; + } + + if (L_FD_EXISTS(fd)) + { + L_FD_INVALIDATE(fd); } return 1; } @@ -676,12 +873,38 @@ efile_read(Efile_error* errInfo, /* Where to return error codes. */ bytes read. */ { ssize_t n; + if (L_FD_EXISTS(fd)) + { + off_t off; + off = (L_FD_IS_VALID(fd)) ? L_FD_CUR(fd) : lseek(fd, 0, SEEK_CUR); + if (L_FD_IS_VALID(fd) == 0) + { + l_update_local_fd(fd, off, SEEK_SET); + } - for (;;) { - if ((n = read(fd, buf, count)) >= 0) - break; - else if (errno != EINTR) - return check_error(-1, errInfo); + if (L_FD_OFFSET_BEYOND_EOF(fd, off)) + { + *pBytesRead = 0; + return 1; + } + /* FIXME .. is this needed? */ + lseek(fd, off, SEEK_SET); + } + + for (;;) + { + if ((n = read(fd, buf, count)) >= 0) + { + break; + } + else if (errno != EINTR) + { + return check_error(-1, errInfo); + } + } + if (n != 0 && L_FD_EXISTS(fd)) + { + L_FD_INVALIDATE(fd); } *pBytesRead = (size_t) n; return 1; @@ -789,6 +1012,7 @@ efile_seek(Efile_error* errInfo, /* Where to return error codes. */ Sint64 *new_location) /* Resulting new location in file. */ { off_t off, result; + off = (off_t) offset; switch (origin) { case EFILE_SEEK_SET: origin = SEEK_SET; break; @@ -798,15 +1022,19 @@ efile_seek(Efile_error* errInfo, /* Where to return error codes. */ errno = EINVAL; return check_error(-1, errInfo); } - off = (off_t) offset; if (off != offset) { - errno = EINVAL; - return check_error(-1, errInfo); + errno = EINVAL; + return check_error(-1, errInfo); } errno = 0; result = lseek(fd, off, origin); + if (result >= 0 && L_FD_EXISTS(fd)) + { + L_FD_INVALIDATE(fd); + } + /* * Note that the man page for lseek (on SunOs 5) says: * @@ -815,14 +1043,40 @@ efile_seek(Efile_error* errInfo, /* Where to return error codes. */ * negative." */ - if (result < 0 && errno == 0) - errno = EINVAL; - if (result < 0) - return check_error(-1, errInfo); - if (new_location) { - *new_location = result; - } - return 1; + if (result < 0 && errno == 0) + errno = EINVAL; + if (result < 0) + { + /* Some filesystems on OSE does not handle seeking beyond EOF + * We handle this here, by localy storing offsets. */ + + if ((lseek(fd, 0, SEEK_END) < off) && errno == 78) + { + if (fdm == NULL) /* first time */ + { + if (l_init_local_fd() == -1) + { + errno = EINVAL; + check_error(-1, errInfo); + } + } + l_update_local_fd(fd, off, origin); + result = off; + } + else if (off < 0 && errno == ENOSYS) + { + errno = EINVAL; + return check_error(-1, errInfo); + } + else + { + return check_error(-1, errInfo); + } + } + if (new_location) { + *new_location = result; + } + return 1; } @@ -831,6 +1085,12 @@ efile_truncate_file(Efile_error* errInfo, int *fd, int flags) { #ifndef NO_FTRUNCATE off_t offset; + + if (L_FD_EXISTS(fileno(fd))) + { + L_FD_INVALIDATE(fileno(fd)); + } + return check_error((offset = lseek(*fd, 0, SEEK_CUR)) >= 0 && ftruncate(*fd, offset) == 0 ? 1 : -1, errInfo); #else -- cgit v1.2.3 From a0766a4efeefe0ac035d2be04816274aee5751f3 Mon Sep 17 00:00:00 2001 From: Jonas Karlsson Date: Fri, 8 Nov 2013 14:00:36 +0100 Subject: ose: Bugfixes to filesystem related issues. --- erts/emulator/drivers/ose/ose_efile.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/ose/ose_efile.c b/erts/emulator/drivers/ose/ose_efile.c index 897d654e89..9980b07817 100644 --- a/erts/emulator/drivers/ose/ose_efile.c +++ b/erts/emulator/drivers/ose/ose_efile.c @@ -258,7 +258,11 @@ efile_mkdir(Efile_error* errInfo, /* Where to return error codes. */ #ifdef NO_MKDIR_MODE return check_error(mkdir(name), errInfo); #else - return check_error(mkdir(name, DIR_MODE), errInfo); + int res = mkdir(name, DIR_MODE); + if (res < 0 && errno == EINVAL) { + errno = ENOENT; + } + return check_error(res, errInfo); #endif } -- cgit v1.2.3 From 3d24208d607501207af371098c1466758844e667 Mon Sep 17 00:00:00 2001 From: Jonas Karlsson Date: Fri, 22 Nov 2013 09:45:05 +0100 Subject: ose: efile driver updates. --- erts/emulator/drivers/common/efile_drv.c | 8 +- erts/emulator/drivers/common/erl_efile.h | 2 +- erts/emulator/drivers/ose/ose_efile.c | 1531 +++++++++++++----------------- erts/emulator/drivers/unix/unix_efile.c | 5 + erts/emulator/drivers/win32/win_efile.c | 5 + 5 files changed, 665 insertions(+), 886 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index fbd72c6c1b..7ef985dc41 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -373,9 +373,6 @@ struct erl_drv_entry efile_driver_entry = { #else NULL #endif /* HAVE_SENDFILE */ -#ifdef __OSE__ - ,NULL -#endif }; @@ -768,6 +765,9 @@ file_init(void) : 0); driver_system_info(&sys_info, sizeof(ErlDrvSysInfo)); + /* run initiation of efile_driver if needed */ + efile_init(); + #ifdef USE_VM_PROBES erts_mtx_init(&dt_driver_mutex, "efile_drv dtrace mutex"); pthread_key_create(&dt_driver_key, NULL); @@ -914,6 +914,7 @@ static void reply_Uint_posix_error(file_descriptor *desc, Uint num, driver_output2(desc->port, response, t-response, NULL, 0); } +#ifdef HAVE_SENDFILE static void reply_string_error(file_descriptor *desc, char* str) { char response[256]; /* Response buffer. */ char* s; @@ -924,6 +925,7 @@ static void reply_string_error(file_descriptor *desc, char* str) { *t = tolower(*s); driver_output2(desc->port, response, t-response, NULL, 0); } +#endif static int reply_error(file_descriptor *desc, Efile_error *errInfo) /* The error codes. */ diff --git a/erts/emulator/drivers/common/erl_efile.h b/erts/emulator/drivers/common/erl_efile.h index 95c036db8f..5a8e3bc5db 100644 --- a/erts/emulator/drivers/common/erl_efile.h +++ b/erts/emulator/drivers/common/erl_efile.h @@ -127,7 +127,7 @@ struct t_sendfile_hdtl { /* * Functions. */ - +int efile_init(void); int efile_mkdir(Efile_error* errInfo, char* name); int efile_rmdir(Efile_error* errInfo, char* name); int efile_delete_file(Efile_error* errInfo, char* name); diff --git a/erts/emulator/drivers/ose/ose_efile.c b/erts/emulator/drivers/ose/ose_efile.c index 9980b07817..035ff81a9b 100644 --- a/erts/emulator/drivers/ose/ose_efile.c +++ b/erts/emulator/drivers/ose/ose_efile.c @@ -31,45 +31,16 @@ #include "sys.h" #include "erl_driver.h" #include "erl_efile.h" -/*#include */ -#ifdef HAVE_UNISTD_H -#ifndef __OSE__ -#include -#endif -#endif -#ifdef HAVE_SYS_UIO_H -#include -#include -#endif -#if defined(HAVE_SENDFILE) && (defined(__linux__) || (defined(__sun) && defined(__SVR4))) -#include -#endif - -#if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__) -#define DARWIN 1 -#endif - #if defined(DARWIN) || defined(HAVE_LINUX_FALLOC_H) || defined(HAVE_POSIX_FALLOCATE) -#include -#endif - -#ifdef HAVE_LINUX_FALLOC_H -#include +#include "fcntl.h" #endif - -#ifdef SUNOS4 -# define getcwd(buf, size) getwd(buf) -#endif - -#ifdef __OSE__ #include "ose.h" #include "unistd.h" #include "sys/stat.h" #include "dirent.h" #include "sys/time.h" #include "time.h" -#include "heapapi.h" -#endif +#include "assert.h" /* Find a definition of MAXIOV, that is used in the code later. */ #if defined IOV_MAX @@ -80,7 +51,6 @@ #define MAXIOV 16 #endif - /* * Macros for testing file types. */ @@ -88,7 +58,7 @@ #define ISDIR(st) (((st).st_mode & S_IFMT) == S_IFDIR) #define ISREG(st) (((st).st_mode & S_IFMT) == S_IFREG) #define ISDEV(st) \ - (((st).st_mode&S_IFMT) == S_IFCHR || ((st).st_mode&S_IFMT) == S_IFBLK) + (((st).st_mode&S_IFMT) == S_IFCHR || ((st).st_mode&S_IFMT) == S_IFBLK) #define ISLNK(st) (((st).st_mode & S_IFLNK) == S_IFLNK) #ifdef NO_UMASK #define FILE_MODE 0644 @@ -101,159 +71,261 @@ #define IS_DOT_OR_DOTDOT(s) \ (s[0] == '.' && (s[1] == '\0' || (s[1] == '.' && s[2] == '\0'))) - /* - * Local file descriptor handling, this is needed for filesystems - * that does not handle seeking outside EOF. + * Macros for handling local file descriptors + * and mutexes. + * + * Handling of files like this is necessary because OSE + * does not allow seeking after the end of a file. So + * what we do it emulate this by keeping track of the size + * of the file and where the file's positions is. If a + * write happens after eof then we pad it. + * + * Given time this should be rewritten to get rid of the + * mutex and use the port lock to protect the data. This + * could be done be done by adapting the efile api for some + * calls to allow some meta-data to be associated with the + * open file. */ -#define L_FD_EXISTS(fd) \ - ((fdm->is_init == 1) && fdm->fd_array[(fd)] != NULL) +#define L_FD_IS_VALID(fd_data) ((fd_data)->beyond_eof > 0) +#define L_FD_INVALIDATE(fd_data) (fd_data)->beyond_eof = 0 +#define L_FD_CUR(fd_data) (fd_data)->pos +#define L_FD_OFFS_BEYOND_EOF(fd_data, offs) \ + (((fd_data)->size > offs) ? 0 : 1) + +#define L_FD_FAIL -1 +#define L_FD_SUCCESS 1 +#define L_FD_PAD_SIZE 255 -#define L_FD_INVALIDATE(fd) \ - fdm->fd_array[(fd)]->valid = 0 +struct fd_meta { + ErlDrvMutex *meta_mtx; + struct fd_data *fd_data_list; +}; -#define L_FD_IS_VALID(fd) \ - (fdm->fd_array[(fd)]->valid == 1) +struct fd_data { + int fd; + struct fd_data *next; + struct fd_data *prev; + int pos; + int beyond_eof; + size_t size; +#ifdef DEBUG + PROCESS owner; +#endif +}; -#define L_FD_OFFSET_BEYOND_EOF(fd, offset) \ - (fdm->fd_array[(fd)]->size < offset) +static int l_invalidate_local_fd(int fd); +static int l_pad_file(struct fd_data *fd_data, off_t offset); +static int check_error(int result, Efile_error* errInfo); +static struct fd_data* l_new_fd(void); +static int l_remove_local_fd(int fd); +static struct fd_data* l_find_local_fd(int fd); +static int l_update_local_fd(int fd, int pos, int size); -#define L_FD_CUR(fd) \ - (fdm->fd_array[(fd)]->pos) +static struct fd_meta* fdm = NULL; -struct fd_meta -{ - int is_init; - uint32_t fd_count; - struct fd_data *fd_array[256]; -}; +/***************************************************************************/ -struct fd_data +static int +l_remove_local_fd(int fd) { - int pos; - int whence; - int valid; - size_t size; -}; + struct fd_data *fd_data; + fd_data = l_find_local_fd(fd); + + if (fd_data == NULL) { + return L_FD_FAIL; + } +#ifdef DEBUG + assert(fd_data->owner == current_process()); +#endif + erl_drv_mutex_lock(fdm->meta_mtx); + /* head ? */ + if (fd_data == fdm->fd_data_list) { + if (fd_data->next != NULL) { + /* remove link to head */ + fd_data->next->prev = NULL; + /* set new head */ + fdm->fd_data_list = fd_data->next; + } + else { + /* head is lonely */ + fdm->fd_data_list = NULL; + } + } + else { /* not head */ + if (fd_data->prev == NULL) { + erl_drv_mutex_unlock(fdm->meta_mtx); + return L_FD_FAIL; + } + else { + if (fd_data->next != NULL) { + fd_data->next->prev = fd_data->prev; + fd_data->prev->next = fd_data->next; + } + else { + fd_data->prev->next = NULL; + } + } + } -static struct fd_meta *fdm; -static int l_init_local_fd(void); -static int l_pad_file(int fd, off_t offset); -static int l_update_local_fd(int fd, off_t offset, int whence); + /* scramble values */ + fd_data->beyond_eof = -1; + fd_data->next = NULL; + fd_data->prev = NULL; + fd_data->fd = -1; -static int check_error(int result, Efile_error* errInfo); + /* unlock and clean */ + driver_free(fd_data); + erl_drv_mutex_unlock(fdm->meta_mtx); + + return L_FD_SUCCESS; +} + +/***************************************************************************/ static int -l_init_local_fd() -{ - fdm = heap_alloc_private(sizeof(struct fd_meta), __FILE__, __LINE__); - fdm->fd_count = 0; - fdm->is_init = 1; +l_invalidate_local_fd(int fd) { + struct fd_data *fd_data; + + if ((fd_data = l_find_local_fd(fd)) == NULL) { + return L_FD_FAIL; + } - memset(fdm->fd_array, NULL, sizeof(fdm->fd_array)); - return 1; + fd_data->beyond_eof = 0; + return L_FD_SUCCESS; } -static int -l_update_local_fd(int fd, off_t offset, int whence) -{ - errno = 0; +/****************************************************************************/ - if (fdm->fd_array[fd] == NULL) - { - fdm->fd_array[fd] = heap_alloc_private(sizeof(struct fd_data), __FILE__, __LINE__); - fdm->fd_count++; - } +static struct fd_data* +l_find_local_fd(int fd) { + struct fd_data *fd_data; - switch (whence) - { - case SEEK_CUR: - fdm->fd_array[fd]->pos = lseek(fd, 0, SEEK_CUR) + offset; - break; + fd_data = NULL; + erl_drv_mutex_lock(fdm->meta_mtx); + for (fd_data = fdm->fd_data_list; fd_data != NULL; ) { + if (fd_data->fd == fd) { +#ifdef DEBUG + assert(fd_data->owner == current_process()); +#endif + break; + } + fd_data = fd_data->next; + } + erl_drv_mutex_unlock(fdm->meta_mtx); + return fd_data; +} + +/***************************************************************************/ - case SEEK_END: - fdm->fd_array[fd]->pos = lseek(fd, 0, SEEK_END) + offset; - break; +static struct fd_data* +l_new_fd(void) { + struct fd_data *fd_data; - case SEEK_SET: - fdm->fd_array[fd]->pos = offset; + fd_data = driver_alloc(sizeof(struct fd_data)); + if (fd_data == NULL) { + return NULL; + } + erl_drv_mutex_lock(fdm->meta_mtx); + if (fdm->fd_data_list == NULL) { + fdm->fd_data_list = fd_data; + fdm->fd_data_list->prev = NULL; + fdm->fd_data_list->next = NULL; + } + else { + fd_data->next = fdm->fd_data_list; + fdm->fd_data_list = fd_data; + fdm->fd_data_list->prev = NULL; + } +#ifdef DEBUG + fd_data->owner = current_process(); +#endif + erl_drv_mutex_unlock(fdm->meta_mtx); + return fd_data; +} - default: - errno = ENOSYS; - break; - } - fdm->fd_array[fd]->size = lseek(fd, 0, SEEK_END); +/***************************************************************************/ - fdm->fd_array[fd]->whence = whence; - fdm->fd_array[fd]->valid = 1; +static int +l_update_local_fd(int fd, int pos, int size) { + struct fd_data *fd_data = NULL; + + fd_data = l_find_local_fd(fd); + /* new fd to handle? */ + if (fd_data == NULL) { + fd_data = l_new_fd(); + if (fd_data == NULL) { + /* out of memory */ + return L_FD_FAIL; + } + } + fd_data->size = size; + fd_data->pos = pos; + fd_data->fd = fd; + fd_data->beyond_eof = 1; - return ((errno != 0) ? -1 : 1); + return L_FD_SUCCESS; } +/***************************************************************************/ + static int -l_pad_file(int fd, off_t offset) -{ - int size_dif; - char *pad; - char *cursor; - int file_size; - int written = 0; - - if (!L_FD_IS_VALID(fd)) - { - l_update_local_fd(fd, offset, SEEK_END); - } - - if (!L_FD_OFFSET_BEYOND_EOF(fd, offset)) - { - - return -1; - } - - - file_size = lseek(fd, 0, SEEK_END); - size_dif = offset - file_size; - pad = heap_alloc_private(size_dif, __FILE__, __LINE__); - cursor = pad; - memset(pad, '\0', size_dif); - - while (size_dif > 0) - { - written = write(fd, cursor, size_dif); - - if (written < 0) - { - return -1; - } - cursor += written; - size_dif -= written; - } - - L_FD_INVALIDATE(fd); - heap_free_private(pad); - - return ((errno != 0) ? -1 : 1); +l_pad_file(struct fd_data *fd_data, off_t offset) { + int size_dif; + int written = 0; + int ret_val = L_FD_SUCCESS; + char padding[L_FD_PAD_SIZE]; + + size_dif = (offset - fd_data->size); + memset(&padding, '\0', L_FD_PAD_SIZE); + + while (size_dif > 0) { + written = write(fd_data->fd, padding, + (size_dif < L_FD_PAD_SIZE) ? + size_dif : L_FD_PAD_SIZE); + if (written < 0 && errno != EINTR && errno != EAGAIN) { + ret_val = -1; + break; + } + size_dif -= written; + } + L_FD_INVALIDATE(fd_data); + return ret_val; } +/***************************************************************************/ + static int -check_error(int result, Efile_error *errInfo) -{ +check_error(int result, Efile_error *errInfo) { if (result < 0) { - errInfo->posix_errno = errInfo->os_errno = errno; - return 0; + errInfo->posix_errno = errInfo->os_errno = errno; + return 0; } return 1; } -/* - * public API - */ +/***************************************************************************/ + +int +efile_init() { + fdm = driver_alloc(sizeof(struct fd_meta)); + if (fdm == NULL) { + return L_FD_FAIL; + } + fdm->meta_mtx = erl_drv_mutex_create("ose_efile local fd mutex\n"); + erl_drv_mutex_lock(fdm->meta_mtx); + fdm->fd_data_list = NULL; + erl_drv_mutex_unlock(fdm->meta_mtx); + return L_FD_SUCCESS; +} + +/***************************************************************************/ int -efile_mkdir(Efile_error* errInfo, /* Where to return error codes. */ - char* name) /* Name of directory to create. */ +efile_mkdir(Efile_error* errInfo, /* Where to return error codes. */ + char* name) /* Name of directory to create. */ { #ifdef NO_MKDIR_MODE return check_error(mkdir(name), errInfo); @@ -266,53 +338,69 @@ efile_mkdir(Efile_error* errInfo, /* Where to return error codes. */ #endif } +/***************************************************************************/ + int -efile_rmdir(Efile_error* errInfo, /* Where to return error codes. */ - char* name) /* Name of directory to delete. */ +efile_rmdir(Efile_error* errInfo, /* Where to return error codes. */ + char* name) /* Name of directory to delete. */ { if (rmdir(name) == 0) { - return 1; + return 1; } if (errno == ENOTEMPTY) { - errno = EEXIST; + errno = EEXIST; } - if (errno == EEXIST) { - int saved_errno = errno; - struct stat file_stat; - struct stat cwd_stat; - - /* - * The error code might be wrong if this is the current directory. - */ - - if (stat(name, &file_stat) == 0 && stat(".", &cwd_stat) == 0 && - file_stat.st_ino == cwd_stat.st_ino && - file_stat.st_dev == cwd_stat.st_dev) { - saved_errno = EINVAL; - } - errno = saved_errno; + if (errno == EEXIST || errno == EINVAL) { + int saved_errno = errno; + struct stat file_stat; + struct stat cwd_stat; + + if(stat(name, &file_stat) != 0) { + errno = ENOENT; + return check_error(-1, errInfo); + } + /* + * The error code might be wrong if this is the current directory. + */ + if (stat(name, &file_stat) == 0 && stat(".", &cwd_stat) == 0 && + file_stat.st_ino == cwd_stat.st_ino && + file_stat.st_dev == cwd_stat.st_dev) { + saved_errno = EACCES; + } + errno = saved_errno; } return check_error(-1, errInfo); } +/***************************************************************************/ + int -efile_delete_file(Efile_error* errInfo, /* Where to return error codes. */ - char* name) /* Name of file to delete. */ +efile_delete_file(Efile_error* errInfo, /* Where to return error codes. */ + char* name) /* Name of file to delete. */ { struct stat statbuf; - /* OSE will accept removal of directories with unlink() */ - if (stat(name, &statbuf) >= 0 && ISDIR(statbuf)) - { - errno = EPERM; - return check_error(-1, errInfo); - } + if (stat(name, &statbuf) >= 0) { + /* Do not let unlink() remove directories */ + if (ISDIR(statbuf)) { + errno = EPERM; + return check_error(-1, errInfo); + } - if (unlink(name) == 0) { - return 1; + if (unlink(name) == 0) { + return 1; + } + + if (errno == EISDIR) { + errno = EPERM; + return check_error(-1, errInfo); + } } - if (errno == EISDIR) { /* Linux sets the wrong error code. */ - errno = EPERM; + else { + if (errno == EINVAL) { + errno = ENOENT; + return check_error(-1, errInfo); + } } return check_error(-1, errInfo); } @@ -321,150 +409,107 @@ efile_delete_file(Efile_error* errInfo, /* Where to return error codes. */ *--------------------------------------------------------------------------- * * Changes the name of an existing file or directory, from src to dst. - * If src and dst refer to the same file or directory, does nothing - * and returns success. Otherwise if dst already exists, it will be - * deleted and replaced by src subject to the following conditions: - * If src is a directory, dst may be an empty directory. - * If src is a file, dst may be a file. - * In any other situation where dst already exists, the rename will - * fail. + * If src and dst refer to the same file or directory, does nothing + * and returns success. Otherwise if dst already exists, it will be + * deleted and replaced by src subject to the following conditions: + * If src is a directory, dst may be an empty directory. + * If src is a file, dst may be a file. + * In any other situation where dst already exists, the rename will + * fail. * * Results: - * If the directory was successfully created, returns 1. - * Otherwise the return value is 0 and errno is set to - * indicate the error. Some possible values for errno are: + * If the directory was successfully created, returns 1. + * Otherwise the return value is 0 and errno is set to + * indicate the error. Some possible values for errno are: * - * EACCES: src or dst parent directory can't be read and/or written. - * EEXIST: dst is a non-empty directory. - * EINVAL: src is a root directory or dst is a subdirectory of src. - * EISDIR: dst is a directory, but src is not. - * ENOENT: src doesn't exist, or src or dst is "". - * ENOTDIR: src is a directory, but dst is not. - * EXDEV: src and dst are on different filesystems. + * EACCES: src or dst parent directory can't be read and/or written. + * EEXIST: dst is a non-empty directory. + * EINVAL: src is a root directory or dst is a subdirectory of src. + * EISDIR: dst is a directory, but src is not. + * ENOENT: src doesn't exist, or src or dst is "". + * ENOTDIR: src is a directory, but dst is not. + * EXDEV: src and dst are on different filesystems. * * Side effects: - * The implementation of rename may allow cross-filesystem renames, - * but the caller should be prepared to emulate it with copy and - * delete if errno is EXDEV. + * The implementation of rename may allow cross-filesystem renames, + * but the caller should be prepared to emulate it with copy and + * delete if errno is EXDEV. * *--------------------------------------------------------------------------- */ int -efile_rename(Efile_error* errInfo, /* Where to return error codes. */ - char* src, /* Original name. */ - char* dst) /* New name. */ +efile_rename(Efile_error* errInfo, /* Where to return error codes. */ + char* src, /* Original name. */ + char* dst) /* New name. */ { - /* temporary fix AFM does not recognize ./ - * in destination */ - - char *dot_str; - if (dst != NULL) - { - dot_str = strchr(dst, '.'); + /* temporary fix AFM does not recognize ./ + * in destination remove pending on adaption of AFM fix + */ - if (dot_str && dot_str == dst && dot_str[1] == '/') - { - dst = dst+2; - } - } + char *dot_str; + if (dst != NULL) { + dot_str = strchr(dst, '.'); + if (dot_str && dot_str == dst && dot_str[1] == '/') { + dst = dst+2; + } + } - if (rename(src, dst) == 0) { - return 1; + if (rename(src, dst) == 0) { + return 1; } if (errno == ENOTEMPTY) { - errno = EEXIST; + errno = EEXIST; } -#if defined (sparc) - /* - * SunOS 4.1.4 reports overwriting a non-empty directory with a - * directory as EINVAL instead of EEXIST (first rule out the correct - * EINVAL result code for moving a directory into itself). Must be - * conditionally compiled because realpath() is only defined on SunOS. - */ - if (errno == EINVAL) { - char srcPath[MAXPATHLEN], dstPath[MAXPATHLEN]; - DIR *dirPtr; - struct dirent *dirEntPtr; - -#ifdef PURIFY - memset(srcPath, '\0', sizeof(srcPath)); - memset(dstPath, '\0', sizeof(dstPath)); -#endif + struct stat file_stat; - if ((realpath(src, srcPath) != NULL) - && (realpath(dst, dstPath) != NULL) - && (strncmp(srcPath, dstPath, strlen(srcPath)) != 0)) { - dirPtr = opendir(dst); - if (dirPtr != NULL) { - while ((dirEntPtr = readdir(dirPtr)) != NULL) { - if ((strcmp(dirEntPtr->d_name, ".") != 0) && - (strcmp(dirEntPtr->d_name, "..") != 0)) { - errno = EEXIST; - closedir(dirPtr); - return check_error(-1, errInfo); - } - } - closedir(dirPtr); - } - } - errno = EINVAL; + if (stat(dst, &file_stat)== 0) { + if (ISDIR(file_stat)) { + errno = EISDIR; + } + else if (ISREG(file_stat)) { + errno = ENOTDIR; + } + else { + errno = EINVAL; + } + } + else { + errno = EINVAL; + } } -#endif /* sparc */ if (strcmp(src, "/") == 0) { - /* - * Alpha reports renaming / as EBUSY and Linux reports it as EACCES, - * instead of EINVAL. - */ - - errno = EINVAL; + errno = EINVAL; } - - /* - * DEC Alpha OSF1 V3.0 returns EACCES when attempting to move a - * file across filesystems and the parent directory of that file is - * not writable. Most other systems return EXDEV. Does nothing to - * correct this behavior. - */ - return check_error(-1, errInfo); } +/***************************************************************************/ + int efile_chdir(Efile_error* errInfo, /* Where to return error codes. */ - char* name) /* Name of directory to make current. */ + char* name) /* Name of directory to make current. */ { return check_error(chdir(name), errInfo); } +/***************************************************************************/ int -efile_getdcwd(Efile_error* errInfo, /* Where to return error codes. */ - int drive, /* 0 - current, 1 - A, 2 - B etc. */ - char* buffer, /* Where to return the current - directory. */ - size_t size) /* Size of buffer. */ +efile_getdcwd(Efile_error* errInfo, /* Where to return error codes. */ + int drive, /* 0 - current, 1 - A, 2 - B etc. */ + char* buffer, /* Where to return the current + directory. */ + size_t size) /* Size of buffer. */ { if (drive == 0) { - if (getcwd(buffer, size) == NULL) - return check_error(-1, errInfo); - -#ifdef SIMSPARCSOLARIS - /* We get "host:" prepended to the dirname - remove!. */ - { - int i = 0; - int j = 0; - while ((buffer[i] != ':') && (buffer[i] != '\0')) i++; - if (buffer[i] == ':') { - i++; - while ((buffer[j++] = buffer[i++]) != '\0'); - } - } -#endif - return 1; + if (getcwd(buffer, size) == NULL) + return check_error(-1, errInfo); + + return 1; } /* @@ -475,29 +520,31 @@ efile_getdcwd(Efile_error* errInfo, /* Where to return error codes. */ return check_error(-1, errInfo); } +/***************************************************************************/ + int -efile_readdir(Efile_error* errInfo, /* Where to return error codes. */ - char* name, /* Name of directory to open. */ - EFILE_DIR_HANDLE* p_dir_handle, /* Pointer to directory - handle of - open directory.*/ - char* buffer, /* Pointer to buffer for - one filename. */ - size_t *size) /* in-out Size of buffer, length - of name. */ +efile_readdir(Efile_error* errInfo, /* Where to return error codes. */ + char* name, /* Name of directory to open. */ + EFILE_DIR_HANDLE* p_dir_handle, /* Pointer to directory + handle of + open directory.*/ + char* buffer, /* Pointer to buffer for + one filename. */ + size_t *size) /* in-out Size of buffer, length + of name. */ { - DIR *dp; /* Pointer to directory structure. */ - struct dirent* dirp; /* Pointer to directory entry. */ + DIR *dp; /* Pointer to directory structure. */ + struct dirent* dirp; /* Pointer to directory entry. */ /* * If this is the first call, we must open the directory. */ if (*p_dir_handle == NULL) { - dp = opendir(name); - if (dp == NULL) - return check_error(-1, errInfo); - *p_dir_handle = (EFILE_DIR_HANDLE) dp; + dp = opendir(name); + if (dp == NULL) + return check_error(-1, errInfo); + *p_dir_handle = (EFILE_DIR_HANDLE) dp; } /* @@ -506,165 +553,138 @@ efile_readdir(Efile_error* errInfo, /* Where to return error codes. */ dp = *((DIR **)((void *)p_dir_handle)); for (;;) { - dirp = readdir(dp); - if (dirp == NULL) { - closedir(dp); - return 0; - } - if (IS_DOT_OR_DOTDOT(dirp->d_name)) - continue; - buffer[0] = '\0'; - strncat(buffer, dirp->d_name, (*size)-1); - *size = strlen(dirp->d_name); - return 1; + dirp = readdir(dp); + if (dirp == NULL) { + closedir(dp); + return 0; + } + if (IS_DOT_OR_DOTDOT(dirp->d_name)) + continue; + buffer[0] = '\0'; + strncat(buffer, dirp->d_name, (*size)-1); + *size = strlen(dirp->d_name); + return 1; } } +/***************************************************************************/ + int -efile_openfile(Efile_error* errInfo, /* Where to return error codes. */ - char* name, /* Name of directory to open. */ - int flags, /* Flags to user for opening. */ - int* pfd, /* Where to store the file - descriptor. */ - Sint64 *pSize) /* Where to store the size of the - file. */ +efile_openfile(Efile_error* errInfo, /* Where to return error codes. */ + char* name, /* Name of directory to open. */ + int flags, /* Flags to user for opening. */ + int* pfd, /* Where to store the file + descriptor. */ + Sint64 *pSize) /* Where to store the size of the + file. */ { struct stat statbuf; int fd; - int mode; /* Open mode. */ + int mode; /* Open mode. */ if (stat(name, &statbuf) >= 0 && !ISREG(statbuf)) { - /* - * For UNIX only, here is some ugly code to allow - * /dev/null to be opened as a file. - * - * Assumption: The i-node number for /dev/null cannot be zero. - */ - static ino_t dev_null_ino = 0; - - if (dev_null_ino == 0) { - struct stat nullstatbuf; - - if (stat("/dev/null", &nullstatbuf) >= 0) { - dev_null_ino = nullstatbuf.st_ino; - } - } - if (!(dev_null_ino && statbuf.st_ino == dev_null_ino)) { - errno = EISDIR; - return check_error(-1, errInfo); - } + errno = EISDIR; + return check_error(-1, errInfo); } switch (flags & (EFILE_MODE_READ|EFILE_MODE_WRITE)) { - case EFILE_MODE_READ: - mode = O_RDONLY; - break; - case EFILE_MODE_WRITE: - if (flags & EFILE_NO_TRUNCATE) - mode = O_WRONLY | O_CREAT; - else - mode = O_WRONLY | O_CREAT | O_TRUNC; - break; - case EFILE_MODE_READ_WRITE: - mode = O_RDWR | O_CREAT; - break; - default: - errno = EINVAL; - return check_error(-1, errInfo); + case EFILE_MODE_READ: + mode = O_RDONLY; + break; + case EFILE_MODE_WRITE: + if (flags & EFILE_NO_TRUNCATE) + mode = O_WRONLY | O_CREAT; + else + mode = O_WRONLY | O_CREAT | O_TRUNC; + break; + case EFILE_MODE_READ_WRITE: + mode = O_RDWR | O_CREAT; + break; + default: + errno = EINVAL; + return check_error(-1, errInfo); } if (flags & EFILE_MODE_APPEND) { - mode &= ~O_TRUNC; - mode |= O_APPEND; + mode &= ~O_TRUNC; + mode |= O_APPEND; } if (flags & EFILE_MODE_EXCL) { - mode |= O_EXCL; + mode |= O_EXCL; } fd = open(name, mode, FILE_MODE); if (!check_error(fd, errInfo)) - return 0; + return 0; *pfd = fd; if (pSize) { - *pSize = statbuf.st_size; + *pSize = statbuf.st_size; } return 1; } +/***************************************************************************/ + int efile_may_openfile(Efile_error* errInfo, char *name) { - struct stat statbuf; /* Information about the file */ + struct stat statbuf; /* Information about the file */ int result; result = stat(name, &statbuf); if (!check_error(result, errInfo)) - return 0; + return 0; if (!ISREG(statbuf)) { - errno = EISDIR; - return check_error(-1, errInfo); + errno = EISDIR; + return check_error(-1, errInfo); } return 1; } +/***************************************************************************/ + void efile_closefile(int fd) { - if (L_FD_EXISTS(fd)) - { - free(fdm->fd_array[fd]); - fdm->fd_array[fd] = NULL; - } - close(fd); + if (l_find_local_fd(fd) != NULL) { + l_remove_local_fd(fd); + } + close(fd); } +/***************************************************************************/ + int efile_fdatasync(Efile_error *errInfo, /* Where to return error codes. */ - int fd) /* File descriptor for file to sync data. */ + int fd) /* File descriptor for file to sync data. */ { -#ifdef HAVE_FDATASYNC - return check_error(fdatasync(fd), errInfo); -#else return efile_fsync(errInfo, fd); -#endif } +/***************************************************************************/ + int efile_fsync(Efile_error *errInfo, /* Where to return error codes. */ - int fd) /* File descriptor for file to sync. */ + int fd) /* File descriptor for file to sync. */ { -#ifdef NO_FSYNC - undefined fsync /* XXX: Really? */ -#else -#if defined(DARWIN) && defined(F_FULLFSYNC) - return check_error(fcntl(fd, F_FULLFSYNC), errInfo); -#else return check_error(fsync(fd), errInfo); -#endif /* DARWIN */ -#endif /* NO_FSYNC */ } +/***************************************************************************/ + int efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, - char* name, int info_for_link) + char* name, int info_for_link) { - struct stat statbuf; /* Information about the file */ + struct stat statbuf; /* Information about the file */ int result; - if (info_for_link) { -#ifndef __OSE__ - result = lstat(name, &statbuf); -#else - result = stat(name, &statbuf); -#endif - } else { - result = stat(name, &statbuf); - } + result = stat(name, &statbuf); if (!check_error(result, errInfo)) { - return 0; + return 0; } #if SIZEOF_OFF_T == 4 @@ -682,22 +702,22 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, #else pInfo->access = FA_NONE; if (access(name, R_OK) == 0) - pInfo->access |= FA_READ; + pInfo->access |= FA_READ; if (access(name, W_OK) == 0) - pInfo->access |= FA_WRITE; + pInfo->access |= FA_WRITE; #endif if (ISDEV(statbuf)) - pInfo->type = FT_DEVICE; + pInfo->type = FT_DEVICE; else if (ISDIR(statbuf)) - pInfo->type = FT_DIRECTORY; + pInfo->type = FT_DIRECTORY; else if (ISREG(statbuf)) - pInfo->type = FT_REGULAR; + pInfo->type = FT_REGULAR; else if (ISLNK(statbuf)) - pInfo->type = FT_SYMLINK; + pInfo->type = FT_SYMLINK; else - pInfo->type = FT_OTHER; + pInfo->type = FT_OTHER; pInfo->accessTime = statbuf.st_atime; pInfo->modifyTime = statbuf.st_mtime; @@ -706,9 +726,6 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, pInfo->mode = statbuf.st_mode; pInfo->links = statbuf.st_nlink; pInfo->major_device = statbuf.st_dev; -#ifndef __OSE__ - pInfo->minor_device = statbuf.st_rdev; -#endif pInfo->inode = statbuf.st_ino; pInfo->uid = statbuf.st_uid; pInfo->gid = statbuf.st_gid; @@ -716,205 +733,164 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, return 1; } +/***************************************************************************/ + int efile_write_info(Efile_error *errInfo, Efile_info *pInfo, char *name) { -/* FIXME, this will be dificult to get to work right with the tests on ose - * reason being that the info values are sometimes used in different ways, and in - * some times not used at all. */ - -#ifndef __OSE__ - struct utimbuf tval; -#endif - /* * On some systems chown will always fail for a non-root user unless * POSIX_CHOWN_RESTRICTED is not set. Others will succeed as long as * you don't try to chown a file to someone besides youself. */ -#ifndef __OSE__ - if (chown(name, pInfo->uid, pInfo->gid) && errno != EPERM) { - return check_error(-1, errInfo); - } -#endif - if (pInfo->mode != -1) { - mode_t newMode = pInfo->mode & (S_ISUID | S_ISGID | - S_IRWXU | S_IRWXG | S_IRWXO); - if (chmod(name, newMode)) { - newMode &= ~(S_ISUID | S_ISGID); - if (chmod(name, newMode)) { - return check_error(-1, errInfo); - } - } + mode_t newMode = pInfo->mode & (S_ISUID | S_ISGID | + S_IRWXU | S_IRWXG | S_IRWXO); + if (chmod(name, newMode)) { + newMode &= ~(S_ISUID | S_ISGID); + if (chmod(name, newMode)) { + return check_error(-1, errInfo); + } + } } -#ifndef __OSE__ - tval.actime = pInfo->accessTime; - tval.modtime = pInfo->modifyTime; - - return check_error(utime(name, &tval), errInfo); -#else - return 1; -#endif + return 1; } +/***************************************************************************/ int -efile_write(Efile_error* errInfo, /* Where to return error codes. */ - int flags, /* Flags given when file was - opened. */ - int fd, /* File descriptor to write to. */ - char* buf, /* Buffer to write. */ - size_t count) /* Number of bytes to write. */ +efile_write(Efile_error* errInfo, /* Where to return error codes. */ + int flags, /* Flags given when file was + opened. */ + int fd, /* File descriptor to write to. */ + char* buf, /* Buffer to write. */ + size_t count) /* Number of bytes to write. */ { - ssize_t written; /* Bytes written in last operation. */ - - if (L_FD_EXISTS(fd)) - { - off_t off; - off = (L_FD_IS_VALID(fd)) ? L_FD_CUR(fd) : lseek(fd, 0, SEEK_CUR); - - if (L_FD_OFFSET_BEYOND_EOF(fd, off)) - { - l_pad_file(fd, off); - } - - L_FD_INVALIDATE(fd); - } - - while (count > 0) - { - if ((written = write(fd, buf, count)) < 0) - { - if (errno != EINTR) - { - return check_error(-1, errInfo); - } - else - { - written = 0; - } - } - ASSERT(written <= count); - buf += written; - count -= written; + ssize_t written; /* Bytes written in last operation. */ + struct fd_data *fd_data; + + if ((fd_data = l_find_local_fd(fd)) != NULL) { + if (L_FD_IS_VALID(fd_data)) { + /* we are beyond eof and need to pad*/ + if (l_pad_file(fd_data, L_FD_CUR(fd_data)) < 0) { + return check_error(-1, errInfo); + } + } } - if (L_FD_EXISTS(fd)) - { - L_FD_INVALIDATE(fd); + while (count > 0) { + if ((written = write(fd, buf, count)) < 0) { + if (errno != EINTR) { + return check_error(-1, errInfo); + } + else { + written = 0; + } + } + ASSERT(written <= count); + buf += written; + count -= written; } return 1; } +/***************************************************************************/ + int efile_writev(Efile_error* errInfo, /* Where to return error codes */ - int flags, /* Flags given when file was - * opened */ - int fd, /* File descriptor to write to */ - SysIOVec* iov, /* Vector of buffer structs. - * The structs may be changed i.e. - * due to incomplete writes */ - int iovcnt) /* Number of structs in vector */ + int flags, /* Flags given when file was + * opened */ + int fd, /* File descriptor to write to */ + SysIOVec* iov, /* Vector of buffer structs. + * The structs may be changed i.e. + * due to incomplete writes */ + int iovcnt) /* Number of structs in vector */ { + struct fd_data *fd_data; int cnt = 0; /* Buffers so far written */ ASSERT(iovcnt >= 0); - + if ((fd_data = l_find_local_fd(fd)) != NULL) { + if (L_FD_IS_VALID(fd_data)) { + /* we are beyond eof and need to pad*/ + if (l_pad_file(fd_data, L_FD_CUR(fd_data)) < 0) { + return check_error(-1, errInfo); + } + } + } 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 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); - } 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 || w == -1); - } - 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; - } - } - } - ASSERT(w == 0); - } /* else Non-empty buffer */ + 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 */ + do { + w = write(fd, iov[cnt].iov_base, iov[cnt].iov_len); + } while (w < 0 && errno == EINTR); + + ASSERT(w <= iov[cnt].iov_len || w == -1); + + 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; + } + } + } + ASSERT(w == 0); + } /* else Non-empty buffer */ } /* while (cnt< iovcnt) */ return 1; } +/***************************************************************************/ + int efile_read(Efile_error* errInfo, /* Where to return error codes. */ - int flags, /* Flags given when file was opened. */ - int fd, /* File descriptor to read from. */ - char* buf, /* Buffer to read into. */ - size_t count, /* Number of bytes to read. */ - size_t *pBytesRead) /* Where to return number of - bytes read. */ + int flags, /* Flags given when file was opened. */ + int fd, /* File descriptor to read from. */ + char* buf, /* Buffer to read into. */ + size_t count, /* Number of bytes to read. */ + size_t *pBytesRead) /* Where to return number of + bytes read. */ { ssize_t n; - if (L_FD_EXISTS(fd)) - { - off_t off; - off = (L_FD_IS_VALID(fd)) ? L_FD_CUR(fd) : lseek(fd, 0, SEEK_CUR); - if (L_FD_IS_VALID(fd) == 0) - { - l_update_local_fd(fd, off, SEEK_SET); - } - - if (L_FD_OFFSET_BEYOND_EOF(fd, off)) - { - *pBytesRead = 0; - return 1; - } - /* FIXME .. is this needed? */ - lseek(fd, off, SEEK_SET); - } - - for (;;) - { - if ((n = read(fd, buf, count)) >= 0) - { - break; - } - else if (errno != EINTR) - { - return check_error(-1, errInfo); - } + struct fd_data *fd_data; + + if ((fd_data = l_find_local_fd(fd)) != NULL) { + if (L_FD_IS_VALID(fd_data)) { + *pBytesRead = 0; + return 1; + } } - if (n != 0 && L_FD_EXISTS(fd)) - { - L_FD_INVALIDATE(fd); + for (;;) { + if ((n = read(fd, buf, count)) >= 0) { + break; + } + else if (errno != EINTR) { + return check_error(-1, errInfo); + } + } + if (fd_data != NULL && L_FD_IS_VALID(fd_data)) { + L_FD_INVALIDATE(fd_data); } *pBytesRead = (size_t) n; return 1; } - /* pread() and pwrite() */ /* Some unix systems, notably Solaris has these syscalls */ /* It is especially nice for i.e. the dets module to have support */ @@ -928,198 +904,159 @@ efile_read(Efile_error* errInfo, /* Where to return error codes. */ int efile_pread(Efile_error* errInfo, /* Where to return error codes. */ - int fd, /* File descriptor to read from. */ - Sint64 offset, /* Offset in bytes from BOF. */ - char* buf, /* Buffer to read into. */ - size_t count, /* Number of bytes to read. */ - size_t *pBytesRead) /* Where to return - number of bytes read. */ + int fd, /* File descriptor to read from. */ + Sint64 offset, /* Offset in bytes from BOF. */ + char* buf, /* Buffer to read into. */ + size_t count, /* Number of bytes to read. */ + size_t *pBytesRead) /* Where to return + number of bytes read. */ { -#if defined(HAVE_PREAD) && defined(HAVE_PWRITE) - ssize_t n; - off_t off = (off_t) offset; - if (off != offset) { - errno = EINVAL; - return check_error(-1, errInfo); - } - for (;;) { - if ((n = pread(fd, buf, count, offset)) >= 0) - break; - else if (errno != EINTR) - return check_error(-1, errInfo); - } - *pBytesRead = (size_t) n; - return 1; -#else - { - int res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL); - if (res) { - return efile_read(errInfo, 0, fd, buf, count, pBytesRead); - } else { - return res; - } + int res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL); + if (res) { + return efile_read(errInfo, 0, fd, buf, count, pBytesRead); + } else { + return res; } -#endif } +/***************************************************************************/ int efile_pwrite(Efile_error* errInfo, /* Where to return error codes. */ - int fd, /* File descriptor to write to. */ - char* buf, /* Buffer to write. */ - size_t count, /* Number of bytes to write. */ - Sint64 offset) /* where to write it */ + int fd, /* File descriptor to write to. */ + char* buf, /* Buffer to write. */ + size_t count, /* Number of bytes to write. */ + Sint64 offset) /* where to write it */ { -#if defined(HAVE_PREAD) && defined(HAVE_PWRITE) - ssize_t written; /* Bytes written in last operation. */ - off_t off = (off_t) offset; - if (off != offset) { - errno = EINVAL; - return check_error(-1, errInfo); - } - - while (count > 0) { - if ((written = pwrite(fd, buf, count, offset)) < 0) { - if (errno != EINTR) - return check_error(-1, errInfo); - else - written = 0; - } - ASSERT(written <= count); - buf += written; - count -= written; - offset += written; - } - return 1; -#else /* For unix systems that don't support pread() and pwrite() */ - { - int res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL); + int res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL); - if (res) { - return efile_write(errInfo, 0, fd, buf, count); - } else { - return res; - } + if (res) { + return efile_write(errInfo, 0, fd, buf, count); + } else { + return res; } -#endif } +/***************************************************************************/ int efile_seek(Efile_error* errInfo, /* Where to return error codes. */ - int fd, /* File descriptor to do the seek on. */ - Sint64 offset, /* Offset in bytes from the given - origin. */ - int origin, /* Origin of seek (SEEK_SET, SEEK_CUR, - SEEK_END). */ - Sint64 *new_location) /* Resulting new location in file. */ + int fd, /* File descriptor to do the seek on. */ + Sint64 offset, /* Offset in bytes from the given + origin. */ + int origin, /* Origin of seek (SEEK_SET, SEEK_CUR, + SEEK_END). */ + Sint64 *new_location) /* Resulting new location in file. */ { off_t off, result; off = (off_t) offset; switch (origin) { - case EFILE_SEEK_SET: origin = SEEK_SET; break; - case EFILE_SEEK_CUR: origin = SEEK_CUR; break; - case EFILE_SEEK_END: origin = SEEK_END; break; - default: - errno = EINVAL; - return check_error(-1, errInfo); + case EFILE_SEEK_SET: + origin = SEEK_SET; + break; + case EFILE_SEEK_CUR: + origin = SEEK_CUR; + break; + case EFILE_SEEK_END: + origin = SEEK_END; + break; + default: + errno = EINVAL; + return check_error(-1, errInfo); } + if (off != offset) { - errno = EINVAL; - return check_error(-1, errInfo); + errno = EINVAL; + return check_error(-1, errInfo); } errno = 0; result = lseek(fd, off, origin); - if (result >= 0 && L_FD_EXISTS(fd)) - { - L_FD_INVALIDATE(fd); + if (result >= 0) { + l_invalidate_local_fd(fd); } - /* - * Note that the man page for lseek (on SunOs 5) says: - * - * "if fildes is a remote file descriptor and offset is - * negative, lseek() returns the file pointer even if it is - * negative." - */ + if (result < 0) + { + if (errno == ENOSYS) { + int size, cur_pos; + + if (off < 0) { + errno = EINVAL; + return check_error(-1, errInfo); + } + + cur_pos = lseek(fd, 0, SEEK_CUR); + size = lseek(fd, 0, SEEK_END); + + if (origin == SEEK_SET) { + result = offset; + } + else if (origin == SEEK_CUR) { + result = offset + cur_pos; + } + else if (origin == SEEK_END) { + result = size + offset; + } - if (result < 0 && errno == 0) - errno = EINVAL; - if (result < 0) - { - /* Some filesystems on OSE does not handle seeking beyond EOF - * We handle this here, by localy storing offsets. */ - - if ((lseek(fd, 0, SEEK_END) < off) && errno == 78) - { - if (fdm == NULL) /* first time */ - { - if (l_init_local_fd() == -1) - { - errno = EINVAL; - check_error(-1, errInfo); - } + /* sanity check our result */ + if (size > result) { + return check_error(-1, errInfo); } - l_update_local_fd(fd, off, origin); - result = off; - } - else if (off < 0 && errno == ENOSYS) - { + + /* store the data localy */ + l_update_local_fd(fd, result, size); + + /* reset the original file position */ + if (origin != SEEK_END) { + lseek(fd, cur_pos, SEEK_SET); + } + } + else if (errno == 0) { errno = EINVAL; - return check_error(-1, errInfo); - } - else - { - return check_error(-1, errInfo); - } - } - if (new_location) { - *new_location = result; - } - return 1; + } + } + + if (new_location) { + *new_location = result; + } + + return 1; } +/***************************************************************************/ int efile_truncate_file(Efile_error* errInfo, int *fd, int flags) { -#ifndef NO_FTRUNCATE off_t offset; + struct fd_data *fd_data; - if (L_FD_EXISTS(fileno(fd))) - { - L_FD_INVALIDATE(fileno(fd)); + if ((fd_data = l_find_local_fd(*fd)) != NULL && L_FD_IS_VALID(fd_data)) { + offset = L_FD_CUR(fd_data); + } + else { + offset = lseek(*fd, 0, SEEK_CUR); } - return check_error((offset = lseek(*fd, 0, SEEK_CUR)) >= 0 && - ftruncate(*fd, offset) == 0 ? 1 : -1, errInfo); -#else - return 1; -#endif + return check_error(((offset >= 0) && + (ftruncate(*fd, offset) == 0)) ? 1 : -1, errInfo); } +/***************************************************************************/ + int efile_readlink(Efile_error* errInfo, char* name, char* buffer, size_t size) { -#ifndef __OSE__ - int len; - ASSERT(size > 0); - len = readlink(name, buffer, size-1); - if (len == -1) { - return check_error(-1, errInfo); - } - buffer[len] = '\0'; - return 1; -#else errno = ENOTSUP; return check_error(-1, errInfo); -#endif } +/***************************************************************************/ + int efile_altname(Efile_error* errInfo, char* name, char* buffer, size_t size) { @@ -1127,158 +1064,35 @@ efile_altname(Efile_error* errInfo, char* name, char* buffer, size_t size) return check_error(-1, errInfo); } +/***************************************************************************/ + int efile_link(Efile_error* errInfo, char* old, char* new) { -#ifndef __OSE__ - return check_error(link(old, new), errInfo); -#else errno = ENOTSUP; return check_error(-1, errInfo); -#endif } +/***************************************************************************/ + int efile_symlink(Efile_error* errInfo, char* old, char* new) { -#ifndef __OSE__ - return check_error(symlink(old, new), errInfo); -#else errno = ENOTSUP; return check_error(-1, errInfo); -#endif } +/***************************************************************************/ + int efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset, - Sint64 length, int advise) + Sint64 length, int advise) { -#ifdef HAVE_POSIX_FADVISE return check_error(posix_fadvise(fd, offset, length, advise), errInfo); -#else - 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. - * - * The semantics of the API is this: - * Return value: 1 if all data was sent and the function does not need to - * be called again. 0 if an error occures OR if there is more data which - * has to be sent (EAGAIN or EINTR will be set appropriately) - * - * The amount of data written in a call is returned through nbytes. - * - */ - -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); - if (written != 0) { - /* -1 is not returned by the linux API so we have to simulate it */ - retval = -1; - errno = EAGAIN; - } -#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); - - /* Sometimes sendfilev can return -1 and still send data. - When that happens we just pretend that no error happend. */ - if (retval != -1 || errno == EAGAIN || errno == EINTR || - len != 0) { - *offset += len; - *nbytes -= len; - written += len; - if (errno != EAGAIN && errno != EINTR && len != 0) - retval = len; - } - } while (len == SENDFILE_CHUNK_SIZE); -#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); -#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); -#endif - *nbytes = written; - return check_error(retval, errInfo); -} -#endif /* HAVE_SENDFILE */ +/***************************************************************************/ -#ifdef HAVE_POSIX_FALLOCATE static int call_posix_fallocate(int fd, Sint64 offset, Sint64 length) { @@ -1300,58 +1114,11 @@ call_posix_fallocate(int fd, Sint64 offset, Sint64 length) return ret; } -#endif /* HAVE_POSIX_FALLOCATE */ + +/***************************************************************************/ int efile_fallocate(Efile_error* errInfo, int fd, Sint64 offset, Sint64 length) { -#if defined HAVE_FALLOCATE - /* Linux specific, more efficient than posix_fallocate. */ - int ret; - - do { - ret = fallocate(fd, FALLOC_FL_KEEP_SIZE, (off_t) offset, (off_t) length); - } while (ret != 0 && errno == EINTR); - -#if defined HAVE_POSIX_FALLOCATE - /* Fallback to posix_fallocate if available. */ - if (ret != 0) { - ret = call_posix_fallocate(fd, offset, length); - } -#endif - - return check_error(ret, errInfo); -#elif defined F_PREALLOCATE - /* Mac OS X specific, equivalent to posix_fallocate. */ - int ret; - fstore_t fs; - - memset(&fs, 0, sizeof(fs)); - fs.fst_flags = F_ALLOCATECONTIG; - fs.fst_posmode = F_VOLPOSMODE; - fs.fst_offset = (off_t) offset; - fs.fst_length = (off_t) length; - - ret = fcntl(fd, F_PREALLOCATE, &fs); - - if (-1 == ret) { - fs.fst_flags = F_ALLOCATEALL; - ret = fcntl(fd, F_PREALLOCATE, &fs); - -#if defined HAVE_POSIX_FALLOCATE - /* Fallback to posix_fallocate if available. */ - if (-1 == ret) { - ret = call_posix_fallocate(fd, offset, length); - } -#endif - } - - return check_error(ret, errInfo); -#elif defined HAVE_POSIX_FALLOCATE - /* Other Unixes, use posix_fallocate if available. */ return check_error(call_posix_fallocate(fd, offset, length), errInfo); -#else - errno = ENOTSUP; - return check_error(-1, errInfo); -#endif } diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c index 8ffc05da99..06078858ca 100644 --- a/erts/emulator/drivers/unix/unix_efile.c +++ b/erts/emulator/drivers/unix/unix_efile.c @@ -101,6 +101,11 @@ check_error(int result, Efile_error *errInfo) return 1; } +int +efile_init() { + return 1; +} + int efile_mkdir(Efile_error* errInfo, /* Where to return error codes. */ char* name) /* Name of directory to create. */ diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c index d693d7d593..480ba23239 100644 --- a/erts/emulator/drivers/win32/win_efile.c +++ b/erts/emulator/drivers/win32/win_efile.c @@ -196,6 +196,11 @@ set_error(Efile_error* errInfo) return 0; } +int +efile_init() { + return 1; +} + /* * A writev with Unix semantics, but with Windows arguments */ -- cgit v1.2.3 From 2145db903b665622ea885db175c5e606d9f840a4 Mon Sep 17 00:00:00 2001 From: Jonas Karlsson Date: Fri, 22 Nov 2013 09:50:34 +0100 Subject: ose: OSE port related cleanup and fixes Some OSE cross-chains have problems with system includes being used, so for atleast OSE specific parts we use "" instead of <>. --- erts/emulator/drivers/common/efile_drv.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 7ef985dc41..b62e9a0306 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -99,7 +99,16 @@ #ifdef HAVE_CONFIG_H # include "config.h" #endif + +#ifndef __OSE__ +#include +#include #include +#else +#include "ctype.h" +#include "sys/types.h" +#include "stdlib.h" +#endif /* Need (NON)BLOCKING macros for sendfile */ #ifndef WANT_NONBLOCKING @@ -113,8 +122,7 @@ #include "erl_threads.h" #include "gzio.h" #include "dtrace-wrapper.h" -#include -#include + void erl_exit(int n, char *fmt, ...); -- cgit v1.2.3 From c64851d619fb916362abc8db9c28534eff39f53c Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Fri, 10 Jan 2014 17:17:58 +0100 Subject: ose: Rewrite resolve_signal API for ose drivers This new API has less impact on the check_io code and also removes the callback from ErlDrvEntry. The downside is that you have to give the resolve function when creating each event. Also the mode if the resolve was removed as this mimics the win32 code and decreases complexity. --- erts/emulator/drivers/ose/ose_signal_drv.c | 41 +++++++++++++++++------------- 1 file changed, 23 insertions(+), 18 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/ose/ose_signal_drv.c b/erts/emulator/drivers/ose/ose_signal_drv.c index c1d861cc5a..46890a1503 100644 --- a/erts/emulator/drivers/ose/ose_signal_drv.c +++ b/erts/emulator/drivers/ose/ose_signal_drv.c @@ -392,6 +392,19 @@ static int drv_init(void) { return 0; } +/* Signal resolution callback */ +static ErlDrvOseEventId resolve_signal(union SIGNAL* osig) { + union SIGNAL *sig = osig; + if (sig->signo == ERTS_SIGNAL_OSE_DRV_HUNT || + sig->signo == ERTS_SIGNAL_OSE_DRV_ATTACH) { + return sig->async.spid; + } + DEBUGP("%p: Got signal %d sent to %p from 0x%p\n", + current_process(),sig->signo,addressee(&sig),sender(&sig)); + return addressee(&sig); +} + + /** * Start routine for the driver **/ @@ -488,11 +501,13 @@ static void outputv(ErlDrvData driver_data, ErlIOVec *ev) DEBUGP("0x%x: open\n",ctxt->spid); ctxt->perm_events[1] = - erl_drv_ose_event_alloc(ERTS_SIGNAL_OSE_DRV_ATTACH,(int)ctxt->spid); + erl_drv_ose_event_alloc(ERTS_SIGNAL_OSE_DRV_ATTACH,(int)ctxt->spid, + resolve_signal); driver_select(ctxt->port,ctxt->perm_events[1],ERL_DRV_READ|ERL_DRV_USE,1); ctxt->perm_events[0] = - erl_drv_ose_event_alloc(ERTS_SIGNAL_OSE_DRV_HUNT,(int)ctxt->spid); + erl_drv_ose_event_alloc(ERTS_SIGNAL_OSE_DRV_HUNT,(int)ctxt->spid, + resolve_signal); driver_select(ctxt->port,ctxt->perm_events[0],ERL_DRV_READ|ERL_DRV_USE,1); start(ctxt->spid); @@ -669,7 +684,8 @@ static void outputv(ErlDrvData driver_data, ErlIOVec *ev) EV_GET_UINT32(ev,&signo,&p,&q); } else if (signo < tmp_signo || !ctxt->events) { /* New signal to select on */ - events[i] = erl_drv_ose_event_alloc(signo,(int)ctxt->spid); + events[i] = erl_drv_ose_event_alloc(signo,(int)ctxt->spid, + resolve_signal); driver_select(ctxt->port,events[i++],ERL_DRV_READ|ERL_DRV_USE,1); EV_GET_UINT32(ev,&signo,&p,&q); } else { @@ -708,7 +724,7 @@ static void outputv(ErlDrvData driver_data, ErlIOVec *ev) static void ready_input(ErlDrvData driver_data, ErlDrvEvent event) { driver_context_t *ctxt = (driver_context_t *)driver_data; - union SIGNAL *sig = erl_drv_ose_get_input_signal(event); + union SIGNAL *sig = erl_drv_ose_get_signal(event); while (sig != NULL) { @@ -800,7 +816,7 @@ static void ready_input(ErlDrvData driver_data, ErlDrvEvent event) } free_buf(&sig); - sig = erl_drv_ose_get_input_signal(event); + sig = erl_drv_ose_get_signal(event); } } @@ -858,17 +874,6 @@ static void stop_select(ErlDrvEvent event, void *reserved) erl_drv_ose_event_free(event); } -static int resolve_signal(OseSignal* osig, int *mode) { - union SIGNAL *sig = osig; - if (sig->signo == ERTS_SIGNAL_OSE_DRV_HUNT || - sig->signo == ERTS_SIGNAL_OSE_DRV_ATTACH) { - return sig->async.spid; - } - DEBUGP("%p: Got signal %d sent to %p from 0x%p\n", - current_process(),sig->signo,addressee(&sig),sender(&sig)); - return addressee(&sig); -} - /** * Setup the driver entry for the Erlang runtime **/ @@ -884,6 +889,6 @@ ErlDrvEntry ose_signal_driver_entry = { .major_version = ERL_DRV_EXTENDED_MAJOR_VERSION, .minor_version = ERL_DRV_EXTENDED_MINOR_VERSION, .driver_flags = ERL_DRV_FLAG_USE_PORT_LOCKING, - .stop_select = stop_select, - .resolve_signal = resolve_signal + .stop_select = stop_select }; + -- cgit v1.2.3 From a35d0f5f82f8152f1b953eda039807a7d4f4e9b9 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Sun, 23 Feb 2014 18:26:38 +0100 Subject: ose: Thread priorities configurable from lmconf The pattern used for getting the priority from the lmconf is based on the name of the process created. The pattern is: ERTS_%%PROCESS_NAME%%_PRIO with the %%PROCESS_NAME%% replaced by the prefix of the process the priority applies to. eg: ERTS_SCHEDULER_PRIO=24 applies to processes with name SCHEDULER_1, SCHEDULER_2 etc. --- erts/emulator/drivers/ose/ose_signal_drv.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/ose/ose_signal_drv.c b/erts/emulator/drivers/ose/ose_signal_drv.c index 46890a1503..1335bffe18 100644 --- a/erts/emulator/drivers/ose/ose_signal_drv.c +++ b/erts/emulator/drivers/ose/ose_signal_drv.c @@ -29,6 +29,7 @@ #include "erl_driver.h" #include "ose.h" + #ifdef HAVE_OSE_SPI_H #include "ose_spi/ose_spi.h" #endif @@ -363,6 +364,7 @@ static OS_PROCESS(driver_proxy_process) { } } + /** * Init routine for the driver **/ -- cgit v1.2.3 From 4a6850e522b91eb009ddd0ed9d9f542f1baf1bee Mon Sep 17 00:00:00 2001 From: Jonas Karlsson Date: Fri, 21 Feb 2014 14:01:38 +0100 Subject: ose: Updating event and signal API for OSE --- erts/emulator/drivers/ose/ose_signal_drv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/ose/ose_signal_drv.c b/erts/emulator/drivers/ose/ose_signal_drv.c index 1335bffe18..4929b53856 100644 --- a/erts/emulator/drivers/ose/ose_signal_drv.c +++ b/erts/emulator/drivers/ose/ose_signal_drv.c @@ -504,12 +504,12 @@ static void outputv(ErlDrvData driver_data, ErlIOVec *ev) ctxt->perm_events[1] = erl_drv_ose_event_alloc(ERTS_SIGNAL_OSE_DRV_ATTACH,(int)ctxt->spid, - resolve_signal); + resolve_signal, NULL); driver_select(ctxt->port,ctxt->perm_events[1],ERL_DRV_READ|ERL_DRV_USE,1); ctxt->perm_events[0] = erl_drv_ose_event_alloc(ERTS_SIGNAL_OSE_DRV_HUNT,(int)ctxt->spid, - resolve_signal); + resolve_signal, NULL); driver_select(ctxt->port,ctxt->perm_events[0],ERL_DRV_READ|ERL_DRV_USE,1); start(ctxt->spid); @@ -679,7 +679,7 @@ static void outputv(ErlDrvData driver_data, ErlIOVec *ev) for (i = 0, j = 0; i < event_cnt || j < ctxt->event_cnt; ) { if (ctxt->events) - erl_drv_ose_event_fetch(ctxt->events[j],&tmp_signo,NULL); + erl_drv_ose_event_fetch(ctxt->events[j],&tmp_signo,NULL,NULL); if (signo == tmp_signo) { events[i++] = ctxt->events[j++]; @@ -687,7 +687,7 @@ static void outputv(ErlDrvData driver_data, ErlIOVec *ev) } else if (signo < tmp_signo || !ctxt->events) { /* New signal to select on */ events[i] = erl_drv_ose_event_alloc(signo,(int)ctxt->spid, - resolve_signal); + resolve_signal, NULL); driver_select(ctxt->port,events[i++],ERL_DRV_READ|ERL_DRV_USE,1); EV_GET_UINT32(ev,&signo,&p,&q); } else { -- cgit v1.2.3 From 08910c59fb8dda35ee3c272d84cba450954fcd24 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Fri, 21 Feb 2014 15:19:31 +0100 Subject: ose: Add dummy ttsl driver --- erts/emulator/drivers/ose/ttsl_drv.c | 68 ++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 erts/emulator/drivers/ose/ttsl_drv.c (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/ose/ttsl_drv.c b/erts/emulator/drivers/ose/ttsl_drv.c new file mode 100644 index 0000000000..8af2ce6af3 --- /dev/null +++ b/erts/emulator/drivers/ose/ttsl_drv.c @@ -0,0 +1,68 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1996-2013. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Stub tty driver because group/user depend on this. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "erl_driver.h" + +static int ttysl_init(void); +static ErlDrvData ttysl_start(ErlDrvPort, char*); + +/* Define the driver table entry. */ +struct erl_drv_entry ttsl_driver_entry = { + ttysl_init, + ttysl_start, + NULL, + NULL, + NULL, + NULL, + "tty_sl", + NULL, + NULL, + 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, /* ERL_DRV_FLAGs */ + NULL, + NULL, /* process_exit */ + NULL +}; + + +static int ttysl_init(void) +{ + return 0; +} + +static ErlDrvData ttysl_start(ErlDrvPort port, char* buf) +{ + return ERL_DRV_ERROR_GENERAL; +} -- cgit v1.2.3 From 81abbc48e12317a07a8d2fcc041031c1c1567c8d Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Mon, 24 Feb 2014 09:43:11 +0100 Subject: erts: Fix unix efile assert If writev return an error (eg ENOSPC) we do not want to abort here but instead propagate upwards into erlang. --- erts/emulator/drivers/unix/unix_efile.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c index 06078858ca..42f41c5f3d 100644 --- a/erts/emulator/drivers/unix/unix_efile.c +++ b/erts/emulator/drivers/unix/unix_efile.c @@ -634,7 +634,8 @@ efile_writev(Efile_error* errInfo, /* Where to return error codes */ do { w = write(fd, iov[cnt].iov_base, iov[cnt].iov_len); } while (w < 0 && errno == EINTR); - ASSERT(w <= iov[cnt].iov_len); + ASSERT(w <= iov[cnt].iov_len || + (w == -1 && errno != EINTR)); } if (w < 0) return check_error(-1, errInfo); /* Move forward to next buffer to write */ -- cgit v1.2.3 From fe00fbc345a58ad4313ba34ec303784353ec6039 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 13 Mar 2014 14:30:08 +0100 Subject: erts: Fix file driver to handle long paths on windows --- erts/emulator/drivers/win32/win_efile.c | 752 +++++++++++++++++++++++++------- 1 file changed, 603 insertions(+), 149 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c index d693d7d593..e4a7dac1df 100644 --- a/erts/emulator/drivers/win32/win_efile.c +++ b/erts/emulator/drivers/win32/win_efile.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2013. All Rights Reserved. + * Copyright Ericsson AB 1997-2014. 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 @@ -29,12 +29,27 @@ #include #include "erl_efile.h" +// 1 = file name ops +// 2 = file descr ops +// 4 = errors +// 8 = path name conversion +#define SVERK_TRACE_MASK 0 + +#if !SVERK_TRACE_MASK +# define SVERK_TRACE(M,S) +# define SVERK_TRACE1(M,FMT,A) +# define SVERK_TRACE2(M,FMT,A,B) +#else +# define SVERK_TRACE(M,S) do { if ((M)&SVERK_TRACE_MASK) fwprintf(stderr, L"SVERK TRACE %d: %s\r\n", __LINE__, (WCHAR*)(S)); }while(0) +# define SVERK_TRACE1(M,FMT,A) do { if ((M)&SVERK_TRACE_MASK) fwprintf(stderr, L"SVERK TRACE %d: " L##FMT L"\r\n", __LINE__, (A)); }while(0) +# define SVERK_TRACE2(M,FMT,A,B) do { if ((M)&SVERK_TRACE_MASK) fwprintf(stderr, L"SVERK TRACE %d: " L##FMT L"\r\n", __LINE__, (A), (B)); }while(0) +#endif + /* * Microsoft-specific function to map a WIN32 error code to a Posix errno. */ #define ISSLASH(a) ((a) == L'\\' || (a) == L'/') - #define ISDIR(st) (((st).st_mode&S_IFMT) == S_IFDIR) #define ISREG(st) (((st).st_mode&S_IFMT) == S_IFREG) @@ -69,10 +84,92 @@ static int check_error(int result, Efile_error* errInfo); static int set_error(Efile_error* errInfo); +static int set_os_errno(Efile_error* errInfo, DWORD os_errno); static int is_root_unc_name(const WCHAR *path); static int extract_root(WCHAR *name); static unsigned short dos_to_posix_mode(int attr, const WCHAR *name); + +struct wpath_tmp_buffer { + struct wpath_tmp_buffer* next; + WCHAR buffer[1]; +}; + +typedef struct { + Efile_error* errInfo; + struct wpath_tmp_buffer* buf_list; +}Efile_call_state; + +static void call_state_init(Efile_call_state* state, Efile_error* errInfo) +{ + state->errInfo = errInfo; + state->buf_list = NULL; +} +static WCHAR* wpath_tmp_alloc(Efile_call_state* state, size_t len) +{ + size_t sz = offsetof(struct wpath_tmp_buffer, buffer) + + (len+1)*sizeof(WCHAR); + struct wpath_tmp_buffer* p = driver_alloc(sz); + p->next = state->buf_list; + state->buf_list = p; + return p->buffer; +} +static void call_state_free(Efile_call_state* state) +{ + while(state->buf_list) { + struct wpath_tmp_buffer* next = state->buf_list->next; + driver_free(state->buf_list); + state->buf_list = next; + } +} +static WCHAR* get_cwd_wpath_tmp(Efile_call_state* state) +{ + WCHAR dummy; + DWORD size = GetCurrentDirectoryW(0, &dummy); + WCHAR* ret = NULL; + + if (size) { + ret = wpath_tmp_alloc(state, size); + if (!GetCurrentDirectoryW(size, ret)) { + ret = NULL; + } + } + return ret; +} +static WCHAR* get_full_wpath_tmp(Efile_call_state* state, + const WCHAR* file, + WCHAR** file_part, + DWORD extra) +{ + WCHAR dummy; + DWORD size = GetFullPathNameW(file, 0, &dummy, NULL); + WCHAR* ret = NULL; + + if (size) { + int ok; + ret = wpath_tmp_alloc(state, size + extra); + if (file_part) { + ok = (GetFullPathNameW(file, size, ret, file_part) != 0); + } + else { + ok = (_wfullpath(ret, file, size) != NULL); + } + if (!ok) { + ret = NULL; + } + } + return ret; +} + +static void ensure_wpath_max(Efile_call_state* state, WCHAR** pathp, size_t max); +static int do_rmdir(Efile_call_state*, char* name); +static int do_rename(Efile_call_state*, char* src, char* dst); +static int do_readdir(Efile_call_state*, char* name, EFILE_DIR_HANDLE*, char* buffer, size_t *size); +static int do_fileinfo(Efile_call_state*, Efile_info*, char* orig_name, int info_for_link); +static char* do_readlink(Efile_call_state*, char* name, char* buffer, size_t size); +static int do_altname(Efile_call_state*, char* orig_name, char* buffer, size_t size); + + static int errno_map(DWORD last_error) { switch (last_error) { @@ -176,11 +273,23 @@ check_error(int result, Efile_error* errInfo) if (result < 0) { errInfo->posix_errno = errno; errInfo->os_errno = GetLastError(); + SVERK_TRACE2(4, "ERROR os_error=%d errno=%d @@@@@@@@@@@@@@@@@@@@@@@@@@@@", + errInfo->os_errno, errInfo->posix_errno); return 0; } return 1; } +static void +save_last_error(Efile_error* errInfo) +{ + errInfo->posix_errno = errno; + errInfo->os_errno = GetLastError(); + SVERK_TRACE2(4, "ERROR os_error=%d errno=%d $$$$$$$$$$$$$$$$$$$$$$$$$$$$$", + errInfo->os_errno, errInfo->posix_errno); +} + + /* * Fills the provided error information structure with information * with the error code given by GetLastError() and its corresponding @@ -192,10 +301,21 @@ check_error(int result, Efile_error* errInfo) static int set_error(Efile_error* errInfo) { - errInfo->posix_errno = errno_map(errInfo->os_errno = GetLastError()); + set_os_errno(errInfo, GetLastError()); return 0; } +static int +set_os_errno(Efile_error* errInfo, DWORD os_errno) +{ + errInfo->os_errno = os_errno; + errInfo->posix_errno = errno_map(os_errno); + SVERK_TRACE2(4, "ERROR os_error=%d errno=%d ############################", + errInfo->os_errno, errInfo->posix_errno); + return 0; +} + + /* * A writev with Unix semantics, but with Windows arguments */ @@ -221,21 +341,143 @@ win_writev(Efile_error* errInfo, } +/* Check '*pathp' and convert it if needed to something that windows will accept. + * Typically use UNC path with \\?\ prefix if absolute path is longer than 260. + */ +static void ensure_wpath(Efile_call_state* state, WCHAR** pathp) +{ + ensure_wpath_max(state, pathp, MAX_PATH); +} + +static void ensure_wpath_max(Efile_call_state* state, WCHAR** pathp, size_t max) +{ + WCHAR* path = *pathp; + WCHAR* p; + size_t len = wcslen(path); + int unc_fixup = 0; + + if (path[0] == 0) { + SVERK_TRACE(8,"Let empty path pass through"); + return; + } + + if (path[1] == L':' && ISSLASH(path[2])) { /* absolute path */ + if (len >= max) { + WCHAR *src, *dst; + + *pathp = wpath_tmp_alloc(state, 4+len+1); + dst = *pathp; + wcscpy(dst, L"\\\\?\\"); + for (src=path,dst+=4; *src; src++,dst++) + *dst = (*src == L'/') ? L'\\' : *src; + *dst = 0; + unc_fixup = 1; + } + } + else if (!(ISSLASH(path[0]) && ISSLASH(path[1]))) { /* relative path */ + DWORD cwdLen = GetCurrentDirectoryW(0, NULL); + DWORD absLen = cwdLen + 1 + len; + if (absLen >= max) { + WCHAR *cwd; + + cwd = wpath_tmp_alloc(state, 4+absLen); + wcscpy(cwd, L"\\\\?\\"); + cwdLen = GetCurrentDirectoryW(cwdLen, cwd+4); + if (wcsncmp(cwd+4, L"\\\\?\\", 4) == 0) { + cwd += 4; + cwdLen -= 4; + } + p = cwd + 4 + cwdLen; + if (!ISSLASH(p[-1])) + *p++ = L'\\'; + wcscpy(p, path); + + for (p=cwd; *p; p++) + if (*p == L'/') + *p = L'\\'; + *pathp = cwd; + unc_fixup = 1; + } + } + + if (unc_fixup) { + WCHAR* endp; + + SVERK_TRACE1(8,"IN: %s", path); + + p = *pathp; + len = wcslen(p); + endp = p + len; + if (len > 4) { + p += 4; + while (*p) { + if (p[0] == L'\\' && p[1] == L'.') { + if (p[2] == L'\\' || !p[2]) { /* single dot */ + wmemmove(p, p+2, (&endp[1] - &p[2])); + endp -= 2; + } + else if (p[2] == L'.' && (p[3] == L'\\' || !p[3])) { /* double dot */ + WCHAR* r; + for (r=p-1; *r == L'\\'; --r) + /*skip redundant slashes*/; + for (; *r != L'\\'; --r) + /*find start of prev directory*/; + if (r < *pathp + 6) + break; + wmemmove(r, p+3, (&endp[1] - &p[3])); + p = r; + } + else p += 3; + } + else ++p; + } + } + SVERK_TRACE1(8,"OUT: %s", *pathp); + } +} int efile_mkdir(Efile_error* errInfo, /* Where to return error codes. */ char* name) /* Name of directory to create. */ { - return check_error(_wmkdir((WCHAR *) name), errInfo); + Efile_call_state state; + WCHAR* wname = (WCHAR*)name; + int ret; + + SVERK_TRACE(1, name); + call_state_init(&state, errInfo); + ensure_wpath_max(&state, &wname, 248); /* Yes, 248 limit for normal paths */ + + ret = (int) CreateDirectoryW(wname, NULL); + if (!ret) + set_error(errInfo); + + call_state_free(&state); + return ret; } int efile_rmdir(Efile_error* errInfo, /* Where to return error codes. */ char* name) /* Name of directory to delete. */ +{ + Efile_call_state state; + int ret; + + SVERK_TRACE(1, name); + call_state_init(&state, errInfo); + ret = do_rmdir(&state, name); + call_state_free(&state); + return ret; +} + +static int do_rmdir(Efile_call_state* state, char* name) { OSVERSIONINFO os; DWORD attr; WCHAR *wname = (WCHAR *) name; + WCHAR *buffer = NULL; + + ensure_wpath(state, &wname); if (RemoveDirectoryW(wname) != FALSE) { return 1; @@ -265,10 +507,9 @@ efile_rmdir(Efile_error* errInfo, /* Where to return error codes. */ if (os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { HANDLE handle; WIN32_FIND_DATAW data; - WCHAR buffer[2*MAX_PATH]; - int len; + int len = wcslen(wname); - len = wcslen(wname); + buffer = wpath_tmp_alloc(state, len + 4); wcscpy(buffer, wname); if (buffer[0] && buffer[len-1] != L'\\' && buffer[len-1] != L'/') { wcscat(buffer, L"\\"); @@ -306,16 +547,30 @@ efile_rmdir(Efile_error* errInfo, /* Where to return error codes. */ } end: - return check_error(-1, errInfo); + save_last_error(state->errInfo); + return 0; } int efile_delete_file(Efile_error* errInfo, /* Where to return error codes. */ char* name) /* Name of file to delete. */ +{ + Efile_call_state state; + int ret; + SVERK_TRACE(1, name); + call_state_init(&state, errInfo); + ret = do_delete_file(&state, name); + call_state_free(&state); + return ret; +} + +static int do_delete_file(Efile_call_state* state, char* name) { DWORD attr; WCHAR *wname = (WCHAR *) name; + ensure_wpath(state, &wname); + if (DeleteFileW(wname) != FALSE) { return 1; } @@ -354,7 +609,7 @@ efile_delete_file(Efile_error* errInfo, /* Where to return error codes. */ errno = EACCES; } - return check_error(-1, errInfo); + return check_error(-1, state->errInfo); } /* @@ -388,14 +643,29 @@ efile_delete_file(Efile_error* errInfo, /* Where to return error codes. */ */ int -efile_rename(Efile_error* errInfo, /* Where to return error codes. */ - char* src, /* Original name. */ - char* dst) /* New name. */ +efile_rename(Efile_error* errInfo, char* src, char* dst) +{ + Efile_call_state state; + int ret; + SVERK_TRACE(1, src); + call_state_init(&state, errInfo); + ret = do_rename(&state, src, dst); + call_state_free(&state); + return ret; +} + +static int +do_rename(Efile_call_state* state, + char* src, /* Original name. */ + char* dst) /* New name. */ { DWORD srcAttr, dstAttr; WCHAR *wsrc = (WCHAR *) src; WCHAR *wdst = (WCHAR *) dst; - + + ensure_wpath(state, &wsrc); + ensure_wpath(state, &wdst); + if (MoveFileW(wsrc, wdst) != FALSE) { return 1; } @@ -412,23 +682,27 @@ efile_rename(Efile_error* errInfo, /* Where to return error codes. */ if (errno == EBADF) { errno = EACCES; - return check_error(-1, errInfo); + return check_error(-1, state->errInfo); } if (errno == EACCES) { decode: if (srcAttr & FILE_ATTRIBUTE_DIRECTORY) { - WCHAR srcPath[MAX_PATH], dstPath[MAX_PATH]; + WCHAR *srcPath, *dstPath; WCHAR *srcRest, *dstRest; int size; - size = GetFullPathNameW(wsrc, MAX_PATH, srcPath, &srcRest); - if ((size == 0) || (size > MAX_PATH)) { - return check_error(-1, errInfo); + srcPath = get_full_wpath_tmp(state, wsrc, &srcRest, 0); + if (!srcPath) { + save_last_error(state->errInfo); + return 0; } - size = GetFullPathNameW(wdst, MAX_PATH, dstPath, &dstRest); - if ((size == 0) || (size > MAX_PATH)) { - return check_error(-1, errInfo); + + dstPath = get_full_wpath_tmp(state, wdst, &dstRest, 0); + if (!dstPath) { + save_last_error(state->errInfo); + return 0; } + if (srcRest == NULL) { srcRest = srcPath + wcslen(srcPath); } @@ -533,14 +807,16 @@ efile_rename(Efile_error* errInfo, /* Where to return error codes. */ * put temp file back to old name. */ - WCHAR tempName[MAX_PATH]; - int result, size; + WCHAR *tempName; + int result; WCHAR *rest; - size = GetFullPathNameW(wdst, MAX_PATH, tempName, &rest); - if ((size == 0) || (size > MAX_PATH) || (rest == NULL)) { - return check_error(-1, errInfo); + tempName = get_full_wpath_tmp(state, wdst, &rest, 14); + if (!tempName || !rest) { + save_last_error(state->errInfo); + return 0; } + *rest = L'\0'; result = -1; if (GetTempFileNameW(tempName, L"erlr", 0, tempName) != 0) { @@ -573,7 +849,6 @@ efile_rename(Efile_error* errInfo, /* Where to return error codes. */ /* * Decode the EACCES to a more meaningful error. */ - goto decode; } } @@ -581,17 +856,30 @@ efile_rename(Efile_error* errInfo, /* Where to return error codes. */ } } } - return check_error(-1, errInfo); + return check_error(-1, state->errInfo); } int efile_chdir(Efile_error* errInfo, /* Where to return error codes. */ char* name) /* Name of directory to make current. */ { - int success = check_error(_wchdir((WCHAR *) name), errInfo); - if (!success && errInfo->posix_errno == EINVAL) - /* POSIXification of errno */ - errInfo->posix_errno = ENOENT; + Efile_call_state state; + WCHAR* wname = (WCHAR*)name; + int success; + SVERK_TRACE(1, name); + + call_state_init(&state, errInfo); + ensure_wpath(&state, &wname); + success = (int) SetCurrentDirectoryW(wname); + if (!success) { + set_error(state.errInfo); + if (state.errInfo->posix_errno == EINVAL) { + /* POSIXification of errno */ + errInfo->posix_errno = ENOENT; + } + } + + call_state_free(&state); return success; } @@ -603,28 +891,45 @@ efile_getdcwd(Efile_error* errInfo, /* Where to return error codes. */ { WCHAR *wbuffer = (WCHAR *) buffer; size_t wbuffer_size = size / 2; - if (_wgetdcwd(drive, wbuffer, wbuffer_size) == NULL) + SVERK_TRACE(1, L"#getdcwd#"); + if (_wgetdcwd(drive, wbuffer, wbuffer_size) == NULL) { return check_error(-1, errInfo); + } + SVERK_TRACE1(8, "getdcwd OS=%s", wbuffer); + if (wcsncmp(wbuffer, L"\\\\?\\", 4) == 0) { + wmemmove(wbuffer, wbuffer+4, wcslen(wbuffer+4)+1); + } for ( ; *wbuffer; wbuffer++) if (*wbuffer == L'\\') *wbuffer = L'/'; + SVERK_TRACE1(8, "getdcwd ERLANG=%s", (WCHAR*)buffer); return 1; } int -efile_readdir(Efile_error* errInfo, /* Where to return error codes. */ - char* name, /* Name of directory to list */ - EFILE_DIR_HANDLE* dir_handle, /* Handle of opened directory or NULL */ - char* buffer, /* Buffer to put one filename in */ - size_t *size) /* in-out size of buffer/size of filename excluding zero - termination in bytes*/ +efile_readdir(Efile_error* errInfo, char* name, EFILE_DIR_HANDLE* dir_handle, + char* buffer, size_t *size) +{ + Efile_call_state state; + int ret; + SVERK_TRACE(dir_handle?2:1, name); + call_state_init(&state, errInfo); + ret = do_readdir(&state, name, dir_handle, buffer, size); + call_state_free(&state); + return ret; +} + +static int do_readdir(Efile_call_state* state, + char* name, /* Name of directory to list */ + EFILE_DIR_HANDLE* dir_handle, /* Handle of opened directory or NULL */ + char* buffer, /* Buffer to put one filename in */ + size_t *size) /* in-out size of buffer/size of filename excluding zero + termination in bytes*/ { HANDLE dir; /* Handle to directory. */ - WCHAR wildcard[MAX_PATH]; /* Wildcard to search for. */ WIN32_FIND_DATAW findData; /* Data found by FindFirstFile() or FindNext(). */ /* Alignment is not honored, this works on x86 because of alignment fixup by processor. Not perfect, but faster than alinging by hand (really) */ - WCHAR *wname = (WCHAR *) name; WCHAR *wbuffer = (WCHAR *) buffer; /* @@ -632,13 +937,15 @@ efile_readdir(Efile_error* errInfo, /* Where to return error codes. */ */ if (*dir_handle == NULL) { - int length = wcslen(wname); + WCHAR *wname = (WCHAR *) name; + WCHAR* wildcard; + int length; WCHAR* s; - if (length+3 >= MAX_PATH) { - errno = ENAMETOOLONG; - return check_error(-1, errInfo); - } + ensure_wpath(state, &wname); + length = wcslen(wname); + + wildcard = wpath_tmp_alloc(state, length+3); wcscpy(wildcard, wname); s = wildcard+length-1; @@ -648,8 +955,10 @@ efile_readdir(Efile_error* errInfo, /* Where to return error codes. */ *++s = L'\0'; DEBUGF(("Reading %ws\n", wildcard)); dir = FindFirstFileW(wildcard, &findData); - if (dir == INVALID_HANDLE_VALUE) - return set_error(errInfo); + if (dir == INVALID_HANDLE_VALUE) { + set_error(state->errInfo); + return 0; + } *dir_handle = (EFILE_DIR_HANDLE) dir; if (!IS_DOT_OR_DOTDOT(findData.cFileName)) { @@ -659,7 +968,6 @@ efile_readdir(Efile_error* errInfo, /* Where to return error codes. */ } } - /* * Retrieve the name of the next file using the directory handle. */ @@ -676,24 +984,36 @@ efile_readdir(Efile_error* errInfo, /* Where to return error codes. */ } if (GetLastError() == ERROR_NO_MORE_FILES) { - FindClose(dir); - errInfo->posix_errno = errInfo->os_errno = 0; - return 0; + state->errInfo->posix_errno = state->errInfo->os_errno = 0; + } + else { + set_error(state->errInfo); } - - set_error(errInfo); FindClose(dir); return 0; } } int -efile_openfile(Efile_error* errInfo, /* Where to return error codes. */ - char* name, /* Name of directory to open. */ - int flags, /* Flags to use for opening. */ - int* pfd, /* Where to store the file descriptor. */ - Sint64* pSize) /* Where to store the size of the file. */ +efile_openfile(Efile_error* errInfo, char* name, int flags, int* pfd, Sint64* pSize) +{ + Efile_call_state state; + int ret; + SVERK_TRACE(1, name); + call_state_init(&state, errInfo); + ret = do_openfile(&state, name, flags, pfd, pSize); + call_state_free(&state); + return ret; +} + +static +int do_openfile(Efile_call_state* state, /* Where to return error codes. */ + char* name, /* Name of directory to open. */ + int flags, /* Flags to use for opening. */ + int* pfd, /* Where to store the file descriptor. */ + Sint64* pSize) /* Where to store the size of the file. */ { + Efile_error* errInfo = state->errInfo; BY_HANDLE_FILE_INFORMATION fileInfo; /* File information from a handle. */ HANDLE fd; /* Handle to open file. */ DWORD access; /* Access mode: GENERIC_READ, GENERIC_WRITE. */ @@ -730,6 +1050,7 @@ efile_openfile(Efile_error* errInfo, /* Where to return error codes. */ if (flags & EFILE_MODE_EXCL) { crFlags = CREATE_NEW; } + ensure_wpath(state, &wname); fd = CreateFileW(wname, access, FILE_SHARE_FLAGS, NULL, crFlags, flagsAndAttrs, NULL); @@ -772,26 +1093,35 @@ efile_openfile(Efile_error* errInfo, /* Where to return error codes. */ } int -efile_may_openfile(Efile_error* errInfo, char *name) { +efile_may_openfile(Efile_error* errInfo, char *name) +{ + Efile_call_state state; WCHAR *wname = (WCHAR *) name; DWORD attr; + int ret; + SVERK_TRACE(1, name); + call_state_init(&state, errInfo); + ensure_wpath(&state, &wname); if ((attr = GetFileAttributesW(wname)) == INVALID_FILE_ATTRIBUTES) { errno = ENOENT; - return check_error(-1, errInfo); + ret = check_error(-1, errInfo); } - - if (attr & FILE_ATTRIBUTE_DIRECTORY) { + else if (attr & FILE_ATTRIBUTE_DIRECTORY) { errno = EISDIR; - return check_error(-1, errInfo); + ret = check_error(-1, errInfo); } - return 1; + else ret = 1; + + call_state_free(&state); + return ret; } void efile_closefile(fd) int fd; /* File descriptor for file to close. */ { + SVERK_TRACE(2, L""); CloseHandle((HANDLE) fd); } @@ -800,6 +1130,7 @@ efile_fdatasync(errInfo, fd) Efile_error* errInfo; /* Where to return error codes. */ int fd; /* File descriptor for file to sync. */ { + SVERK_TRACE(2, L""); /* Not available in Windows, just call regular fsync */ return efile_fsync(errInfo, fd); } @@ -809,6 +1140,7 @@ efile_fsync(errInfo, fd) Efile_error* errInfo; /* Where to return error codes. */ int fd; /* File descriptor for file to sync. */ { + SVERK_TRACE(2, L""); if (!FlushFileBuffers((HANDLE) fd)) { return check_error(-1, errInfo); } @@ -819,64 +1151,87 @@ int efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, char* orig_name, int info_for_link) { + Efile_call_state state; + int ret; + SVERK_TRACE(1, L""); + call_state_init(&state, errInfo); + ret = do_fileinfo(&state, pInfo, orig_name, info_for_link); + call_state_free(&state); + return ret; +} + +static int +do_fileinfo(Efile_call_state* state, Efile_info* pInfo, + char* orig_name, int info_for_link) +{ + Efile_error* errInfo = state->errInfo; HANDLE findhandle; /* Handle returned by FindFirstFile(). */ WIN32_FIND_DATAW findbuf; /* Data return by FindFirstFile(). */ - WCHAR name[_MAX_PATH]; + WCHAR* name = NULL; + WCHAR* win_path; int name_len; - WCHAR *path; - WCHAR pathbuf[_MAX_PATH]; int drive; /* Drive for filename (1 = A:, 2 = B: etc). */ - WCHAR *worig_name = (WCHAR *) orig_name; + WCHAR *worig_name = (WCHAR *) orig_name; + ensure_wpath(state, &worig_name); /* Don't allow wildcards to be interpreted by system */ - if (wcspbrk(worig_name, L"?*")) { - enoent: - errInfo->posix_errno = ENOENT; - errInfo->os_errno = ERROR_FILE_NOT_FOUND; - return 0; - } /* * Move the name to a buffer and make sure to remove a trailing * slash, because it causes FindFirstFile() to fail on Win95. */ - if ((name_len = wcslen(worig_name)) >= _MAX_PATH) { - goto enoent; - } else { - wcscpy(name, worig_name); - if (name_len > 2 && ISSLASH(name[name_len-1]) && - name[name_len-2] != L':') { - name[name_len-1] = L'\0'; - } + name_len = wcslen(worig_name); + + name = wpath_tmp_alloc(state, name_len+1); + wcscpy(name, worig_name); + if (name_len > 2 && ISSLASH(name[name_len-1]) && + name[name_len-2] != L':') { + name[name_len-1] = L'\0'; } - + + win_path = name; + if (wcsncmp(name, L"\\\\?\\", 4) == 0) { + win_path += 4; + } + + if (wcspbrk(win_path, L"?*")) { + enoent: + errInfo->posix_errno = ENOENT; + errInfo->os_errno = ERROR_FILE_NOT_FOUND; + return 0; + } + /* Try to get disk from name. If none, get current disk. */ - if (name[1] != L':') { + if (win_path[1] != L':') { + WCHAR* cwd_path = get_cwd_wpath_tmp(state); drive = 0; - if (GetCurrentDirectoryW(_MAX_PATH, pathbuf) && - pathbuf[1] == L':') { - drive = towlower(pathbuf[0]) - L'a' + 1; + if (cwd_path[1] == L':') { + drive = towlower(cwd_path[0]) - L'a' + 1; } - } else if (*name && name[2] == L'\0') { + } else if (*win_path && win_path[2] == L'\0') { /* * X: and nothing more is an error. */ errInfo->posix_errno = ENOENT; errInfo->os_errno = ERROR_FILE_NOT_FOUND; return 0; - } else - drive = towlower(*name) - L'a' + 1; + } else { + drive = towlower(*win_path) - L'a' + 1; + } findhandle = FindFirstFileW(name, &findbuf); if (findhandle == INVALID_HANDLE_VALUE) { + WCHAR* path = NULL; + if (!(wcspbrk(name, L"./\\") && - (path = _wfullpath(pathbuf, name, _MAX_PATH)) && + (path = get_full_wpath_tmp(state, name, NULL, 0)) && /* root dir. ('C:\') or UNC root dir. ('\\server\share\') */ ((wcslen(path) == 3) || is_root_unc_name(path)) && (GetDriveTypeW(path) > 1) ) ) { + errInfo->posix_errno = ENOENT; errInfo->os_errno = ERROR_FILE_NOT_FOUND; return 0; @@ -903,13 +1258,11 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, /* * given that we know this is a symlink, we should be able to find its target */ - WCHAR target_name[_MAX_PATH]; - if (efile_readlink(errInfo, (char *) name, - (char *) target_name, - _MAX_PATH * sizeof(WCHAR)) == 1) { + WCHAR* target_name = (WCHAR*) do_readlink(state, (char *) name, NULL, 0); + if (target_name) { FindClose(findhandle); - return efile_fileinfo(errInfo, pInfo, - (char *) target_name, info_for_link); + return do_fileinfo(state, pInfo, + (char *) target_name, info_for_link); } } @@ -976,6 +1329,20 @@ efile_write_info(Efile_error* errInfo, Efile_info* pInfo, char* name) { + Efile_call_state state; + int ret; + call_state_init(&state, errInfo); + ret = do_write_info(&state, pInfo, name); + call_state_free(&state); + return ret; +} + +static int +do_write_info(Efile_call_state* state, + Efile_info* pInfo, + char* name) +{ + Efile_error* errInfo = state->errInfo; SYSTEMTIME timebuf; FILETIME ModifyFileTime; FILETIME AccessFileTime; @@ -985,6 +1352,10 @@ efile_write_info(Efile_error* errInfo, DWORD tempAttr; WCHAR *wname = (WCHAR *) name; + SVERK_TRACE(1, name); + + ensure_wpath(state, &wname); + /* * Get the attributes for the file. */ @@ -1061,7 +1432,9 @@ char* buf; /* Buffer to write. */ size_t count; /* Number of bytes to write. */ Sint64 offset; /* where to write it */ { - int res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL); + int res; + SVERK_TRACE(2, L""); + res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL); if (res) { return efile_write(errInfo, EFILE_MODE_WRITE, fd, buf, count); } else { @@ -1079,7 +1452,9 @@ char* buf; /* Buffer to read into. */ size_t count; /* Number of bytes to read. */ size_t* pBytesRead; /* Where to return number of bytes read. */ { - int res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL); + int res; + SVERK_TRACE(2, L""); + res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL); if (res) { return efile_read(errInfo, EFILE_MODE_READ, fd, buf, count, pBytesRead); } else { @@ -1101,6 +1476,7 @@ size_t count; /* Number of bytes to write. */ OVERLAPPED overlapped; OVERLAPPED* pOverlapped = NULL; + SVERK_TRACE(2, L""); if (flags & EFILE_MODE_APPEND) { memset(&overlapped, 0, sizeof(overlapped)); overlapped.Offset = 0xffffffff; @@ -1130,6 +1506,7 @@ efile_writev(Efile_error* errInfo, /* Where to return error codes */ OVERLAPPED overlapped; OVERLAPPED* pOverlapped = NULL; + SVERK_TRACE(2, L""); ASSERT(iovcnt >= 0); if (flags & EFILE_MODE_APPEND) { @@ -1166,6 +1543,8 @@ size_t count; /* Number of bytes to read. */ size_t* pBytesRead; /* Where to return number of bytes read. */ { DWORD nbytes = 0; + + SVERK_TRACE(2, L""); if (!ReadFile((HANDLE) fd, buf, count, &nbytes, NULL)) return set_error(errInfo); @@ -1185,6 +1564,7 @@ Sint64* new_location; /* Resulting new location in file. */ { LARGE_INTEGER off, new_loc; + SVERK_TRACE(2, L""); switch (origin) { case EFILE_SEEK_SET: origin = FILE_BEGIN; break; case EFILE_SEEK_CUR: origin = FILE_CURRENT; break; @@ -1216,6 +1596,7 @@ Efile_error* errInfo; /* Where to return error codes. */ int *fd; /* File descriptor for file to truncate. */ int flags; { + SVERK_TRACE(2, L""); if (!SetEndOfFile((HANDLE) (*fd))) return set_error(errInfo); return 1; @@ -1368,8 +1749,23 @@ dos_to_posix_mode(int attr, const WCHAR *name) return uxmode; } + int efile_readlink(Efile_error* errInfo, char* name, char* buffer, size_t size) +{ + Efile_call_state state; + int ret; + SVERK_TRACE(1, name); + call_state_init(&state, errInfo); + ret = !!do_readlink(&state, name, buffer, size); + call_state_free(&state); + return ret; +} + +/* If buffer==0, return buffer allocated by wpath_tmp_allocate +*/ +static char* +do_readlink(Efile_call_state* state, char* name, char* buffer, size_t size) { /* * load dll and see if we have CreateSymbolicLink at runtime: @@ -1378,6 +1774,9 @@ efile_readlink(Efile_error* errInfo, char* name, char* buffer, size_t size) HINSTANCE hModule = NULL; WCHAR *wname = (WCHAR *) name; WCHAR *wbuffer = (WCHAR *) buffer; + DWORD wsize = size / sizeof(WCHAR) - 1; + char* ret = NULL; + if ((hModule = LoadLibrary("kernel32.dll")) != NULL) { typedef DWORD (WINAPI * GETFINALPATHNAMEBYHANDLEPTR)( HANDLE hFile, @@ -1388,58 +1787,84 @@ efile_readlink(Efile_error* errInfo, char* name, char* buffer, size_t size) GETFINALPATHNAMEBYHANDLEPTR pGetFinalPathNameByHandle = (GETFINALPATHNAMEBYHANDLEPTR)GetProcAddress(hModule, "GetFinalPathNameByHandleW"); - if (pGetFinalPathNameByHandle == NULL) { - FreeLibrary(hModule); - } else { + if (pGetFinalPathNameByHandle != NULL) { + DWORD fileAttributes; + ensure_wpath(state, &wname); /* first check if file is a symlink; {error, einval} otherwise */ - DWORD fileAttributes = GetFileAttributesW(wname); + fileAttributes = GetFileAttributesW(wname); if ((fileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { - BOOLEAN success = 0; + DWORD success = 0; HANDLE h = CreateFileW(wname, GENERIC_READ, FILE_SHARE_FLAGS, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); int len; if(h != INVALID_HANDLE_VALUE) { - success = pGetFinalPathNameByHandle(h, wbuffer, size / sizeof(WCHAR),0); - /* GetFinalPathNameByHandle prepends path with "\\?\": */ - len = wcslen(wbuffer); - wmemmove(wbuffer,wbuffer+4,len-3); - if (len - 4 >= 2 && wbuffer[1] == L':' && wbuffer[0] >= L'A' && - wbuffer[0] <= L'Z') { - wbuffer[0] = wbuffer[0] + L'a' - L'A'; + if (!wbuffer) { /* dynamic allocation */ + WCHAR dummy; + wsize = pGetFinalPathNameByHandle(h, &dummy, 0, 0); + if (wsize) { + wbuffer = wpath_tmp_alloc(state, wsize); + wsize--; + } } + if (wbuffer + && (success = pGetFinalPathNameByHandle(h, wbuffer, wsize, 0)) + && success <= wsize) { + + /* GetFinalPathNameByHandle prepends path with "\\?\": */ + len = wcslen(wbuffer); + wmemmove(wbuffer,wbuffer+4,len-3); + if (len - 4 >= 2 && wbuffer[1] == L':' && wbuffer[0] >= L'A' && + wbuffer[0] <= L'Z') { + wbuffer[0] = wbuffer[0] + L'a' - L'A'; + } - for ( ; *wbuffer; wbuffer++) - if (*wbuffer == L'\\') - *wbuffer = L'/'; + for ( ; *wbuffer; wbuffer++) + if (*wbuffer == L'\\') + *wbuffer = L'/'; + } CloseHandle(h); - } - FreeLibrary(hModule); + } if (success) { - return 1; + ret = (char*) wbuffer; } else { - return set_error(errInfo); + set_error(state->errInfo); } } else { - FreeLibrary(hModule); errno = EINVAL; - return check_error(-1, errInfo); + save_last_error(state->errInfo); } + goto done; } } errno = ENOTSUP; - return check_error(-1, errInfo); + save_last_error(state->errInfo); + +done: + if (hModule) + FreeLibrary(hModule); + return ret; } int efile_altname(Efile_error* errInfo, char* orig_name, char* buffer, size_t size) +{ + Efile_call_state state; + int ret; + SVERK_TRACE(1, orig_name); + call_state_init(&state, errInfo); + ret = do_altname(&state, orig_name, buffer, size); + call_state_free(&state); + return ret; +} + +static int +do_altname(Efile_call_state* state, char* orig_name, char* buffer, size_t size) { WIN32_FIND_DATAW wfd; HANDLE fh; - WCHAR name[_MAX_PATH+1]; + WCHAR* name; int name_len; - WCHAR* path; - WCHAR pathbuf[_MAX_PATH+1]; /* Unclear weather GetCurrentDirectory will access one char after - _MAX_PATH */ + WCHAR* full_path = NULL; WCHAR *worig_name = (WCHAR *) orig_name; WCHAR *wbuffer = (WCHAR *) buffer; int drive; /* Drive for filename (1 = A:, 2 = B: etc). */ @@ -1448,8 +1873,8 @@ efile_altname(Efile_error* errInfo, char* orig_name, char* buffer, size_t size) if (wcspbrk(worig_name, L"?*")) { enoent: - errInfo->posix_errno = ENOENT; - errInfo->os_errno = ERROR_FILE_NOT_FOUND; + state->errInfo->posix_errno = ENOENT; + state->errInfo->os_errno = ERROR_FILE_NOT_FOUND; return 0; } @@ -1457,24 +1882,23 @@ efile_altname(Efile_error* errInfo, char* orig_name, char* buffer, size_t size) * Move the name to a buffer and make sure to remove a trailing * slash, because it causes FindFirstFile() to fail on Win95. */ - - if ((name_len = wcslen(worig_name)) >= _MAX_PATH) { - goto enoent; - } else { - wcscpy(name, worig_name); - if (name_len > 2 && ISSLASH(name[name_len-1]) && - name[name_len-2] != L':') { - name[name_len-1] = L'\0'; - } + ensure_wpath(state, &worig_name); + name_len = wcslen(worig_name); + + name = wpath_tmp_alloc(state, name_len + 1); + wcscpy(name, worig_name); + if (name_len > 2 && ISSLASH(name[name_len-1]) && + name[name_len-2] != L':') { + name[name_len-1] = L'\0'; } /* Try to get disk from name. If none, get current disk. */ if (name[1] != L':') { + WCHAR* cwd_path = get_cwd_wpath_tmp(state); drive = 0; - if (GetCurrentDirectoryW(_MAX_PATH, pathbuf) && - pathbuf[1] == L':') { - drive = towlower(pathbuf[0]) - L'a' + 1; + if (cwd_path[1] == L':') { + drive = towlower(cwd_path[0]) - L'a' + 1; } } else if (*name && name[2] == L'\0') { /* @@ -1486,13 +1910,15 @@ efile_altname(Efile_error* errInfo, char* orig_name, char* buffer, size_t size) } fh = FindFirstFileW(name,&wfd); if (fh == INVALID_HANDLE_VALUE) { + DWORD fff_error = GetLastError(); if (!(wcspbrk(name, L"./\\") && - (path = _wfullpath(pathbuf, name, _MAX_PATH)) && + (full_path = get_full_wpath_tmp(state, name, NULL, 0)) && /* root dir. ('C:\') or UNC root dir. ('\\server\share\') */ - ((wcslen(path) == 3) || is_root_unc_name(path)) && - (GetDriveTypeW(path) > 1) ) ) { - errno = errno_map(GetLastError()); - return check_error(-1, errInfo); + ((wcslen(full_path) == 3) || is_root_unc_name(full_path)) && + (GetDriveTypeW(full_path) > 1) ) ) { + + set_os_errno(state->errInfo, fff_error); + return 0; } /* * Root directories (such as C:\ or \\server\share\ are fabricated. @@ -1513,16 +1939,36 @@ efile_altname(Efile_error* errInfo, char* orig_name, char* buffer, size_t size) int efile_link(Efile_error* errInfo, char* old, char* new) { + Efile_call_state state; WCHAR *wold = (WCHAR *) old; WCHAR *wnew = (WCHAR *) new; + int ret; + SVERK_TRACE(1, old); + call_state_init(&state, errInfo); + ensure_wpath(&state, &wold); + ensure_wpath(&state, &wnew); if(!CreateHardLinkW(wnew, wold, NULL)) { - return set_error(errInfo); + ret = set_error(errInfo); } - return 1; + else ret =1; + call_state_free(&state); + return ret; } int efile_symlink(Efile_error* errInfo, char* old, char* new) +{ + Efile_call_state state; + int ret; + SVERK_TRACE(1, old); + call_state_init(&state, errInfo); + ret = do_symlink(&state, old, new); + call_state_free(&state); + return ret; +} + +static int +do_symlink(Efile_call_state* state, char* old, char* new) { /* * Load dll and see if we have CreateSymbolicLink at runtime: @@ -1531,6 +1977,8 @@ efile_symlink(Efile_error* errInfo, char* old, char* new) HINSTANCE hModule = NULL; WCHAR *wold = (WCHAR *) old; WCHAR *wnew = (WCHAR *) new; + + SVERK_TRACE(1, old); if ((hModule = LoadLibrary("kernel32.dll")) != NULL) { typedef BOOLEAN (WINAPI * CREATESYMBOLICLINKFUNCPTR) ( LPCWSTR lpSymlinkFileName, @@ -1542,6 +1990,9 @@ efile_symlink(Efile_error* errInfo, char* old, char* new) "CreateSymbolicLinkW"); /* A for MBCS, W for UNICODE... char* above implies 'W'! */ if (pCreateSymbolicLink != NULL) { + ensure_wpath(state, &wold); + ensure_wpath(state, &wnew); + { DWORD attr = GetFileAttributesW(wold); int flag = (attr != INVALID_FILE_ATTRIBUTES && attr & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0; @@ -1552,19 +2003,21 @@ efile_symlink(Efile_error* errInfo, char* old, char* new) if (success) { return 1; } else { - return set_error(errInfo); + return set_error(state->errInfo); } + } } else FreeLibrary(hModule); } errno = ENOTSUP; - return check_error(-1, errInfo); + return check_error(-1, state->errInfo); } int efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset, Sint64 length, int advise) { + SVERK_TRACE(2, L""); /* posix_fadvise is not available on Windows, do nothing */ errno = ERROR_SUCCESS; return check_error(0, errInfo); @@ -1573,6 +2026,7 @@ efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset, int efile_fallocate(Efile_error* errInfo, int fd, Sint64 offset, Sint64 length) { + SVERK_TRACE(2, L""); /* No file preallocation method available in Windows. */ errno = errno_map(ERROR_NOT_SUPPORTED); SetLastError(ERROR_NOT_SUPPORTED); -- cgit v1.2.3 From eec90640fb8d122dd713d2c892fa2c365c05aae6 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 13 Mar 2014 14:30:38 +0100 Subject: erts: Use GetFullPathNameW to construct abs paths from relative ones --- erts/emulator/drivers/win32/win_efile.c | 42 ++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c index e4a7dac1df..d9bc390d13 100644 --- a/erts/emulator/drivers/win32/win_efile.c +++ b/erts/emulator/drivers/win32/win_efile.c @@ -361,6 +361,8 @@ static void ensure_wpath_max(Efile_call_state* state, WCHAR** pathp, size_t max) return; } + SVERK_TRACE1(8,"IN: %s", path); + if (path[1] == L':' && ISSLASH(path[2])) { /* absolute path */ if (len >= max) { WCHAR *src, *dst; @@ -378,33 +380,31 @@ static void ensure_wpath_max(Efile_call_state* state, WCHAR** pathp, size_t max) DWORD cwdLen = GetCurrentDirectoryW(0, NULL); DWORD absLen = cwdLen + 1 + len; if (absLen >= max) { - WCHAR *cwd; - - cwd = wpath_tmp_alloc(state, 4+absLen); - wcscpy(cwd, L"\\\\?\\"); - cwdLen = GetCurrentDirectoryW(cwdLen, cwd+4); - if (wcsncmp(cwd+4, L"\\\\?\\", 4) == 0) { - cwd += 4; - cwdLen -= 4; + WCHAR *fullPath = wpath_tmp_alloc(state, 4+4+absLen); + DWORD fullLen; + + fullLen = GetFullPathNameW(path, 4 + absLen, fullPath+4, NULL); + if (fullLen >= 4+absLen) { + *pathp = path; + SVERK_TRACE2(8,"ensure_wpath FAILED absLen=%u %s", (int)absLen, path); + return; + } + /* GetFullPathNameW can return paths longer than MAX_PATH without the \\?\ prefix. + * At least seen on Windows 7. Go figure... + */ + if (fullLen >= max && wcsncmp(fullPath+4, L"\\\\?\\", 4) != 0) { + wcsncpy(fullPath, L"\\\\?\\", 4); + *pathp = fullPath; + } + else { + *pathp = fullPath + 4; } - p = cwd + 4 + cwdLen; - if (!ISSLASH(p[-1])) - *p++ = L'\\'; - wcscpy(p, path); - - for (p=cwd; *p; p++) - if (*p == L'/') - *p = L'\\'; - *pathp = cwd; - unc_fixup = 1; } } if (unc_fixup) { WCHAR* endp; - SVERK_TRACE1(8,"IN: %s", path); - p = *pathp; len = wcslen(p); endp = p + len; @@ -432,8 +432,8 @@ static void ensure_wpath_max(Efile_call_state* state, WCHAR** pathp, size_t max) else ++p; } } - SVERK_TRACE1(8,"OUT: %s", *pathp); } + SVERK_TRACE1(8,"OUT: %s", *pathp); } int -- cgit v1.2.3 From 0e9eb5c6586c927e3407f33951596e22c04a0cfe Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 13 Mar 2014 14:30:48 +0100 Subject: erts: Fix long windows paths for compressed files --- erts/emulator/drivers/common/gzio.c | 3 ++- erts/emulator/drivers/win32/win_efile.c | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/gzio.c b/erts/emulator/drivers/common/gzio.c index 653f3954b1..86734452a3 100644 --- a/erts/emulator/drivers/common/gzio.c +++ b/erts/emulator/drivers/common/gzio.c @@ -229,6 +229,7 @@ local ErtsGzFile gz_open (path, mode) errno = 0; #if defined(FILENAMES_16BIT) { + FILE* efile_wfopen(const WCHAR* name, const WCHAR* mode); WCHAR wfmode[80]; int i = 0; int j; @@ -236,7 +237,7 @@ local ErtsGzFile gz_open (path, mode) wfmode[i++] = (WCHAR) fmode[j]; } wfmode[i++] = L'\0'; - s->file = _wfopen((WCHAR *)path, wfmode); + s->file = efile_wfopen((WCHAR *)path, wfmode); if (s->file == NULL) { return s->destroy(s), (ErtsGzFile)Z_NULL; } diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c index d9bc390d13..afb0252724 100644 --- a/erts/emulator/drivers/win32/win_efile.c +++ b/erts/emulator/drivers/win32/win_efile.c @@ -1125,6 +1125,18 @@ int fd; /* File descriptor for file to close. */ CloseHandle((HANDLE) fd); } +FILE* efile_wfopen(const WCHAR* name, const WCHAR* mode) +{ + Efile_call_state state; + Efile_error dummy; + FILE* f; + call_state_init(&state, &dummy); + ensure_wpath(&state, &name); + f = _wfopen(name, mode); + call_state_free(&state); + return f; +} + int efile_fdatasync(errInfo, fd) Efile_error* errInfo; /* Where to return error codes. */ -- cgit v1.2.3 From 189e2f0313eb6cc96e92d2c7efb790cb4d9849a4 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 12 Mar 2014 16:39:29 +0100 Subject: erts: Ignore reduntant slashes in windows paths --- erts/emulator/drivers/win32/win_efile.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c index afb0252724..c25fb34637 100644 --- a/erts/emulator/drivers/win32/win_efile.c +++ b/erts/emulator/drivers/win32/win_efile.c @@ -370,8 +370,16 @@ static void ensure_wpath_max(Efile_call_state* state, WCHAR** pathp, size_t max) *pathp = wpath_tmp_alloc(state, 4+len+1); dst = *pathp; wcscpy(dst, L"\\\\?\\"); - for (src=path,dst+=4; *src; src++,dst++) - *dst = (*src == L'/') ? L'\\' : *src; + for (src=path,dst+=4; *src; src++) { + if (*src == L'/') { + if (dst[-1] != L'\\') { + *dst++ = L'\\'; + } + /*else ignore redundant slashes */ + } + else + *dst++ = *src; + } *dst = 0; unc_fixup = 1; } -- cgit v1.2.3 From cb748a7989ed79cdac9454fe25a6b93b3b6f8393 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 12 Mar 2014 16:49:50 +0100 Subject: erts: Revert file:set_cwd impl for windows No need to even try as CWD can not bee a long path anyway. --- erts/emulator/drivers/win32/win_efile.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c index c25fb34637..3236da8a98 100644 --- a/erts/emulator/drivers/win32/win_efile.c +++ b/erts/emulator/drivers/win32/win_efile.c @@ -870,24 +870,15 @@ do_rename(Efile_call_state* state, int efile_chdir(Efile_error* errInfo, /* Where to return error codes. */ char* name) /* Name of directory to make current. */ -{ - Efile_call_state state; - WCHAR* wname = (WCHAR*)name; - int success; - SVERK_TRACE(1, name); - - call_state_init(&state, errInfo); - ensure_wpath(&state, &wname); - success = (int) SetCurrentDirectoryW(wname); - if (!success) { - set_error(state.errInfo); - if (state.errInfo->posix_errno == EINVAL) { - /* POSIXification of errno */ - errInfo->posix_errno = ENOENT; - } - } - - call_state_free(&state); +{ + /* We don't even try to handle long paths here + * as current working directory is always limited to MAX_PATH + * even if we use UNC paths and SetCurrentDirectoryW() + */ + int success = check_error(_wchdir((WCHAR *) name), errInfo); + if (!success && errInfo->posix_errno == EINVAL) + /* POSIXification of errno */ + errInfo->posix_errno = ENOENT; return success; } -- cgit v1.2.3 From 6e318949a19c7603d23da64f312b96ecf950ee30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 20 Mar 2014 16:50:53 +0100 Subject: zlib: Fix adler32_combine/4 and crc32_combine/4 Since our config.h is included in each source file in the zlib directory, we must make sure that config.h is also included every time zlib functions are called to ensure that definitions of types are consistent. zlib_drv.c did not include config.h, which caused problems on a MacOS X Leopard system. What happened was that HAVE_UNISTD_H was not defined when zlib.h was included. When unistd.h is not known to exist, the type z_off_t will be set to a long (32 bits on this platform). But when the zlib source files were compiled, HAVE_UNISTD_H was defined, unistd.h would be included, and z_off_t would be set to off_t (64 bits; defined in unistd.h). As a result of the mismatch, calls to the adler32_combine() and crc32_combine() would pass only 32 bits in the len2 argument when 64 bits were expected. --- erts/emulator/drivers/common/zlib_drv.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/zlib_drv.c b/erts/emulator/drivers/common/zlib_drv.c index 3fe5d282dc..3143e4511d 100644 --- a/erts/emulator/drivers/common/zlib_drv.c +++ b/erts/emulator/drivers/common/zlib_drv.c @@ -21,6 +21,9 @@ * ZLib interface for erlang * */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif #include #include #include -- cgit v1.2.3 From 2d2ce325546bc93178d1343e2a53911b890cc259 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 12 Mar 2014 17:07:16 +0100 Subject: erts: Make file:make_symlink/2 return {error,eperm} on Windows if the user has not the privilege SE_CREATE_SYMBOLIC_LINK_NAME --- erts/emulator/drivers/win32/win_efile.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c index 3236da8a98..3d3a5bcb84 100644 --- a/erts/emulator/drivers/win32/win_efile.c +++ b/erts/emulator/drivers/win32/win_efile.c @@ -251,6 +251,8 @@ static int errno_map(DWORD last_error) { return EAGAIN; case ERROR_CANT_RESOLVE_FILENAME: return EMLINK; + case ERROR_PRIVILEGE_NOT_HELD: + return EPERM; case ERROR_ARENA_TRASHED: case ERROR_INVALID_BLOCK: case ERROR_BAD_ENVIRONMENT: -- cgit v1.2.3 From 2be50d2eb4690b0f849f86170ad176928443de30 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 12 Mar 2014 17:14:04 +0100 Subject: erts: Fix compiler warning in win_efile.c and some improved debug tracing --- erts/emulator/drivers/win32/win_efile.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c index 3d3a5bcb84..4176f137c1 100644 --- a/erts/emulator/drivers/win32/win_efile.c +++ b/erts/emulator/drivers/win32/win_efile.c @@ -1000,7 +1000,7 @@ efile_openfile(Efile_error* errInfo, char* name, int flags, int* pfd, Sint64* pS { Efile_call_state state; int ret; - SVERK_TRACE(1, name); + SVERK_TRACE1(1, "openfile(%s)", name); call_state_init(&state, errInfo); ret = do_openfile(&state, name, flags, pfd, pSize); call_state_free(&state); @@ -1132,7 +1132,7 @@ FILE* efile_wfopen(const WCHAR* name, const WCHAR* mode) Efile_error dummy; FILE* f; call_state_init(&state, &dummy); - ensure_wpath(&state, &name); + ensure_wpath(&state, (WCHAR**)&name); f = _wfopen(name, mode); call_state_free(&state); return f; @@ -1973,7 +1973,7 @@ efile_symlink(Efile_error* errInfo, char* old, char* new) { Efile_call_state state; int ret; - SVERK_TRACE(1, old); + SVERK_TRACE2(1, "symlink(%s <- %s)", old, new); call_state_init(&state, errInfo); ret = do_symlink(&state, old, new); call_state_free(&state); -- cgit v1.2.3 From 3700d457197ae91ba75248d19716005c4013c177 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 18 Mar 2014 16:00:44 +0100 Subject: erts: Fix bug in efile_readlink for long win paths --- erts/emulator/drivers/win32/win_efile.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c index 4176f137c1..9621fcca45 100644 --- a/erts/emulator/drivers/win32/win_efile.c +++ b/erts/emulator/drivers/win32/win_efile.c @@ -1787,7 +1787,7 @@ do_readlink(Efile_call_state* state, char* name, char* buffer, size_t size) HINSTANCE hModule = NULL; WCHAR *wname = (WCHAR *) name; WCHAR *wbuffer = (WCHAR *) buffer; - DWORD wsize = size / sizeof(WCHAR) - 1; + DWORD wsize = size / sizeof(WCHAR); char* ret = NULL; if ((hModule = LoadLibrary("kernel32.dll")) != NULL) { @@ -1815,12 +1815,12 @@ do_readlink(Efile_call_state* state, char* name, char* buffer, size_t size) wsize = pGetFinalPathNameByHandle(h, &dummy, 0, 0); if (wsize) { wbuffer = wpath_tmp_alloc(state, wsize); - wsize--; } } if (wbuffer && (success = pGetFinalPathNameByHandle(h, wbuffer, wsize, 0)) - && success <= wsize) { + && success < wsize) { + WCHAR* wp; /* GetFinalPathNameByHandle prepends path with "\\?\": */ len = wcslen(wbuffer); @@ -1830,9 +1830,9 @@ do_readlink(Efile_call_state* state, char* name, char* buffer, size_t size) wbuffer[0] = wbuffer[0] + L'a' - L'A'; } - for ( ; *wbuffer; wbuffer++) - if (*wbuffer == L'\\') - *wbuffer = L'/'; + for (wp=wbuffer ; *wp; wp++) + if (*wp == L'\\') + *wp = L'/'; } CloseHandle(h); } -- cgit v1.2.3 From 921c6c64cd8168956f0c5f09c20d1fa0a4753edf Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 20 Mar 2014 15:00:09 +0100 Subject: erts: Fix file:list_dir for windows paths 258 or 259 chars long Appending wildcard "\*" made the path too long (>= 260 chars). --- erts/emulator/drivers/win32/win_efile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c index 9621fcca45..fb746f1f54 100644 --- a/erts/emulator/drivers/win32/win_efile.c +++ b/erts/emulator/drivers/win32/win_efile.c @@ -943,7 +943,7 @@ static int do_readdir(Efile_call_state* state, int length; WCHAR* s; - ensure_wpath(state, &wname); + ensure_wpath_max(state, &wname, MAX_PATH-2); length = wcslen(wname); wildcard = wpath_tmp_alloc(state, length+3); -- cgit v1.2.3 From 293543db1ca5fc17a24e7dc2562d376ea186b009 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 20 Mar 2014 15:16:06 +0100 Subject: erts: Cleanup debug tracing in win_efile.c --- erts/emulator/drivers/win32/win_efile.c | 98 ++++++++++++++++----------------- 1 file changed, 49 insertions(+), 49 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c index fb746f1f54..7ab0e09072 100644 --- a/erts/emulator/drivers/win32/win_efile.c +++ b/erts/emulator/drivers/win32/win_efile.c @@ -29,20 +29,20 @@ #include #include "erl_efile.h" -// 1 = file name ops -// 2 = file descr ops -// 4 = errors -// 8 = path name conversion -#define SVERK_TRACE_MASK 0 - -#if !SVERK_TRACE_MASK -# define SVERK_TRACE(M,S) -# define SVERK_TRACE1(M,FMT,A) -# define SVERK_TRACE2(M,FMT,A,B) +#define DBG_TRACE_MASK 0 +/* 1 = file name ops + * 2 = file descr ops + * 4 = errors + * 8 = path name conversion + */ +#if !DBG_TRACE_MASK +# define DBG_TRACE(M,S) +# define DBG_TRACE1(M,FMT,A) +# define DBG_TRACE2(M,FMT,A,B) #else -# define SVERK_TRACE(M,S) do { if ((M)&SVERK_TRACE_MASK) fwprintf(stderr, L"SVERK TRACE %d: %s\r\n", __LINE__, (WCHAR*)(S)); }while(0) -# define SVERK_TRACE1(M,FMT,A) do { if ((M)&SVERK_TRACE_MASK) fwprintf(stderr, L"SVERK TRACE %d: " L##FMT L"\r\n", __LINE__, (A)); }while(0) -# define SVERK_TRACE2(M,FMT,A,B) do { if ((M)&SVERK_TRACE_MASK) fwprintf(stderr, L"SVERK TRACE %d: " L##FMT L"\r\n", __LINE__, (A), (B)); }while(0) +# define DBG_TRACE(M,S) do { if ((M)&DBG_TRACE_MASK) fwprintf(stderr, L"DBG_TRACE %d: %s\r\n", __LINE__, (WCHAR*)(S)); }while(0) +# define DBG_TRACE1(M,FMT,A) do { if ((M)&DBG_TRACE_MASK) fwprintf(stderr, L"DBG_TRACE %d: " L##FMT L"\r\n", __LINE__, (A)); }while(0) +# define DBG_TRACE2(M,FMT,A,B) do { if ((M)&DBG_TRACE_MASK) fwprintf(stderr, L"DBG_TRACE %d: " L##FMT L"\r\n", __LINE__, (A), (B)); }while(0) #endif /* @@ -275,7 +275,7 @@ check_error(int result, Efile_error* errInfo) if (result < 0) { errInfo->posix_errno = errno; errInfo->os_errno = GetLastError(); - SVERK_TRACE2(4, "ERROR os_error=%d errno=%d @@@@@@@@@@@@@@@@@@@@@@@@@@@@", + DBG_TRACE2(4, "ERROR os_error=%d errno=%d @@@@@@@@@@@@@@@@@@@@@@@@@@@@", errInfo->os_errno, errInfo->posix_errno); return 0; } @@ -287,7 +287,7 @@ save_last_error(Efile_error* errInfo) { errInfo->posix_errno = errno; errInfo->os_errno = GetLastError(); - SVERK_TRACE2(4, "ERROR os_error=%d errno=%d $$$$$$$$$$$$$$$$$$$$$$$$$$$$$", + DBG_TRACE2(4, "ERROR os_error=%d errno=%d $$$$$$$$$$$$$$$$$$$$$$$$$$$$$", errInfo->os_errno, errInfo->posix_errno); } @@ -312,7 +312,7 @@ set_os_errno(Efile_error* errInfo, DWORD os_errno) { errInfo->os_errno = os_errno; errInfo->posix_errno = errno_map(os_errno); - SVERK_TRACE2(4, "ERROR os_error=%d errno=%d ############################", + DBG_TRACE2(4, "ERROR os_error=%d errno=%d ############################", errInfo->os_errno, errInfo->posix_errno); return 0; } @@ -359,11 +359,11 @@ static void ensure_wpath_max(Efile_call_state* state, WCHAR** pathp, size_t max) int unc_fixup = 0; if (path[0] == 0) { - SVERK_TRACE(8,"Let empty path pass through"); + DBG_TRACE(8, L"Let empty path pass through"); return; } - SVERK_TRACE1(8,"IN: %s", path); + DBG_TRACE1(8,"IN: %s", path); if (path[1] == L':' && ISSLASH(path[2])) { /* absolute path */ if (len >= max) { @@ -396,7 +396,7 @@ static void ensure_wpath_max(Efile_call_state* state, WCHAR** pathp, size_t max) fullLen = GetFullPathNameW(path, 4 + absLen, fullPath+4, NULL); if (fullLen >= 4+absLen) { *pathp = path; - SVERK_TRACE2(8,"ensure_wpath FAILED absLen=%u %s", (int)absLen, path); + DBG_TRACE2(8,"ensure_wpath FAILED absLen=%u %s", (int)absLen, path); return; } /* GetFullPathNameW can return paths longer than MAX_PATH without the \\?\ prefix. @@ -443,7 +443,7 @@ static void ensure_wpath_max(Efile_call_state* state, WCHAR** pathp, size_t max) } } } - SVERK_TRACE1(8,"OUT: %s", *pathp); + DBG_TRACE1(8,"OUT: %s", *pathp); } int @@ -454,7 +454,7 @@ efile_mkdir(Efile_error* errInfo, /* Where to return error codes. */ WCHAR* wname = (WCHAR*)name; int ret; - SVERK_TRACE(1, name); + DBG_TRACE(1, name); call_state_init(&state, errInfo); ensure_wpath_max(&state, &wname, 248); /* Yes, 248 limit for normal paths */ @@ -473,7 +473,7 @@ efile_rmdir(Efile_error* errInfo, /* Where to return error codes. */ Efile_call_state state; int ret; - SVERK_TRACE(1, name); + DBG_TRACE(1, name); call_state_init(&state, errInfo); ret = do_rmdir(&state, name); call_state_free(&state); @@ -567,7 +567,7 @@ efile_delete_file(Efile_error* errInfo, /* Where to return error codes. */ { Efile_call_state state; int ret; - SVERK_TRACE(1, name); + DBG_TRACE(1, name); call_state_init(&state, errInfo); ret = do_delete_file(&state, name); call_state_free(&state); @@ -657,7 +657,7 @@ efile_rename(Efile_error* errInfo, char* src, char* dst) { Efile_call_state state; int ret; - SVERK_TRACE(1, src); + DBG_TRACE(1, src); call_state_init(&state, errInfo); ret = do_rename(&state, src, dst); call_state_free(&state); @@ -892,18 +892,18 @@ efile_getdcwd(Efile_error* errInfo, /* Where to return error codes. */ { WCHAR *wbuffer = (WCHAR *) buffer; size_t wbuffer_size = size / 2; - SVERK_TRACE(1, L"#getdcwd#"); + DBG_TRACE(1, L"#getdcwd#"); if (_wgetdcwd(drive, wbuffer, wbuffer_size) == NULL) { return check_error(-1, errInfo); } - SVERK_TRACE1(8, "getdcwd OS=%s", wbuffer); + DBG_TRACE1(8, "getdcwd OS=%s", wbuffer); if (wcsncmp(wbuffer, L"\\\\?\\", 4) == 0) { wmemmove(wbuffer, wbuffer+4, wcslen(wbuffer+4)+1); } for ( ; *wbuffer; wbuffer++) if (*wbuffer == L'\\') *wbuffer = L'/'; - SVERK_TRACE1(8, "getdcwd ERLANG=%s", (WCHAR*)buffer); + DBG_TRACE1(8, "getdcwd ERLANG=%s", (WCHAR*)buffer); return 1; } @@ -913,7 +913,7 @@ efile_readdir(Efile_error* errInfo, char* name, EFILE_DIR_HANDLE* dir_handle, { Efile_call_state state; int ret; - SVERK_TRACE(dir_handle?2:1, name); + DBG_TRACE(dir_handle?2:1, name); call_state_init(&state, errInfo); ret = do_readdir(&state, name, dir_handle, buffer, size); call_state_free(&state); @@ -1000,7 +1000,7 @@ efile_openfile(Efile_error* errInfo, char* name, int flags, int* pfd, Sint64* pS { Efile_call_state state; int ret; - SVERK_TRACE1(1, "openfile(%s)", name); + DBG_TRACE1(1, "openfile(%s)", name); call_state_init(&state, errInfo); ret = do_openfile(&state, name, flags, pfd, pSize); call_state_free(&state); @@ -1101,7 +1101,7 @@ efile_may_openfile(Efile_error* errInfo, char *name) DWORD attr; int ret; - SVERK_TRACE(1, name); + DBG_TRACE(1, name); call_state_init(&state, errInfo); ensure_wpath(&state, &wname); if ((attr = GetFileAttributesW(wname)) == INVALID_FILE_ATTRIBUTES) { @@ -1122,7 +1122,7 @@ void efile_closefile(fd) int fd; /* File descriptor for file to close. */ { - SVERK_TRACE(2, L""); + DBG_TRACE(2, L""); CloseHandle((HANDLE) fd); } @@ -1143,7 +1143,7 @@ efile_fdatasync(errInfo, fd) Efile_error* errInfo; /* Where to return error codes. */ int fd; /* File descriptor for file to sync. */ { - SVERK_TRACE(2, L""); + DBG_TRACE(2, L""); /* Not available in Windows, just call regular fsync */ return efile_fsync(errInfo, fd); } @@ -1153,7 +1153,7 @@ efile_fsync(errInfo, fd) Efile_error* errInfo; /* Where to return error codes. */ int fd; /* File descriptor for file to sync. */ { - SVERK_TRACE(2, L""); + DBG_TRACE(2, L""); if (!FlushFileBuffers((HANDLE) fd)) { return check_error(-1, errInfo); } @@ -1166,7 +1166,7 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, { Efile_call_state state; int ret; - SVERK_TRACE(1, L""); + DBG_TRACE(1, L""); call_state_init(&state, errInfo); ret = do_fileinfo(&state, pInfo, orig_name, info_for_link); call_state_free(&state); @@ -1365,7 +1365,7 @@ do_write_info(Efile_call_state* state, DWORD tempAttr; WCHAR *wname = (WCHAR *) name; - SVERK_TRACE(1, name); + DBG_TRACE(1, name); ensure_wpath(state, &wname); @@ -1446,7 +1446,7 @@ size_t count; /* Number of bytes to write. */ Sint64 offset; /* where to write it */ { int res; - SVERK_TRACE(2, L""); + DBG_TRACE(2, L""); res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL); if (res) { return efile_write(errInfo, EFILE_MODE_WRITE, fd, buf, count); @@ -1466,7 +1466,7 @@ size_t count; /* Number of bytes to read. */ size_t* pBytesRead; /* Where to return number of bytes read. */ { int res; - SVERK_TRACE(2, L""); + DBG_TRACE(2, L""); res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL); if (res) { return efile_read(errInfo, EFILE_MODE_READ, fd, buf, count, pBytesRead); @@ -1489,7 +1489,7 @@ size_t count; /* Number of bytes to write. */ OVERLAPPED overlapped; OVERLAPPED* pOverlapped = NULL; - SVERK_TRACE(2, L""); + DBG_TRACE(2, L""); if (flags & EFILE_MODE_APPEND) { memset(&overlapped, 0, sizeof(overlapped)); overlapped.Offset = 0xffffffff; @@ -1519,7 +1519,7 @@ efile_writev(Efile_error* errInfo, /* Where to return error codes */ OVERLAPPED overlapped; OVERLAPPED* pOverlapped = NULL; - SVERK_TRACE(2, L""); + DBG_TRACE(2, L""); ASSERT(iovcnt >= 0); if (flags & EFILE_MODE_APPEND) { @@ -1557,7 +1557,7 @@ size_t* pBytesRead; /* Where to return number of bytes read. */ { DWORD nbytes = 0; - SVERK_TRACE(2, L""); + DBG_TRACE(2, L""); if (!ReadFile((HANDLE) fd, buf, count, &nbytes, NULL)) return set_error(errInfo); @@ -1577,7 +1577,7 @@ Sint64* new_location; /* Resulting new location in file. */ { LARGE_INTEGER off, new_loc; - SVERK_TRACE(2, L""); + DBG_TRACE(2, L""); switch (origin) { case EFILE_SEEK_SET: origin = FILE_BEGIN; break; case EFILE_SEEK_CUR: origin = FILE_CURRENT; break; @@ -1609,7 +1609,7 @@ Efile_error* errInfo; /* Where to return error codes. */ int *fd; /* File descriptor for file to truncate. */ int flags; { - SVERK_TRACE(2, L""); + DBG_TRACE(2, L""); if (!SetEndOfFile((HANDLE) (*fd))) return set_error(errInfo); return 1; @@ -1768,7 +1768,7 @@ efile_readlink(Efile_error* errInfo, char* name, char* buffer, size_t size) { Efile_call_state state; int ret; - SVERK_TRACE(1, name); + DBG_TRACE(1, name); call_state_init(&state, errInfo); ret = !!do_readlink(&state, name, buffer, size); call_state_free(&state); @@ -1863,7 +1863,7 @@ efile_altname(Efile_error* errInfo, char* orig_name, char* buffer, size_t size) { Efile_call_state state; int ret; - SVERK_TRACE(1, orig_name); + DBG_TRACE(1, orig_name); call_state_init(&state, errInfo); ret = do_altname(&state, orig_name, buffer, size); call_state_free(&state); @@ -1956,7 +1956,7 @@ efile_link(Efile_error* errInfo, char* old, char* new) WCHAR *wold = (WCHAR *) old; WCHAR *wnew = (WCHAR *) new; int ret; - SVERK_TRACE(1, old); + DBG_TRACE(1, old); call_state_init(&state, errInfo); ensure_wpath(&state, &wold); ensure_wpath(&state, &wnew); @@ -1973,7 +1973,7 @@ efile_symlink(Efile_error* errInfo, char* old, char* new) { Efile_call_state state; int ret; - SVERK_TRACE2(1, "symlink(%s <- %s)", old, new); + DBG_TRACE2(1, "symlink(%s <- %s)", old, new); call_state_init(&state, errInfo); ret = do_symlink(&state, old, new); call_state_free(&state); @@ -1991,7 +1991,7 @@ do_symlink(Efile_call_state* state, char* old, char* new) WCHAR *wold = (WCHAR *) old; WCHAR *wnew = (WCHAR *) new; - SVERK_TRACE(1, old); + DBG_TRACE(1, old); if ((hModule = LoadLibrary("kernel32.dll")) != NULL) { typedef BOOLEAN (WINAPI * CREATESYMBOLICLINKFUNCPTR) ( LPCWSTR lpSymlinkFileName, @@ -2030,7 +2030,7 @@ int efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset, Sint64 length, int advise) { - SVERK_TRACE(2, L""); + DBG_TRACE(2, L""); /* posix_fadvise is not available on Windows, do nothing */ errno = ERROR_SUCCESS; return check_error(0, errInfo); @@ -2039,7 +2039,7 @@ efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset, int efile_fallocate(Efile_error* errInfo, int fd, Sint64 offset, Sint64 length) { - SVERK_TRACE(2, L""); + DBG_TRACE(2, L""); /* No file preallocation method available in Windows. */ errno = errno_map(ERROR_NOT_SUPPORTED); SetLastError(ERROR_NOT_SUPPORTED); -- cgit v1.2.3 From 68c1740b8b2a23ea8caf46b024fc339e10f375f0 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Sun, 23 Mar 2014 22:20:36 +0100 Subject: ose: Add ifdefs for HAVE_UDP --- erts/emulator/drivers/common/inet_drv.c | 45 ++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 6 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 357a4b7bcb..a846df9bf3 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -200,6 +200,7 @@ typedef unsigned long long llu_t; #define HAVE_MULTICAST_SUPPORT +#define HAVE_UDP #define ERRNO_BLOCK WSAEWOULDBLOCK @@ -438,6 +439,8 @@ typedef unsigned long u_long; #include #endif +#define HAVE_UDP + /* SCTP support -- currently for UNIX platforms only: */ #undef HAVE_SCTP #if defined(HAVE_SCTP_H) @@ -1181,6 +1184,7 @@ static struct erl_drv_entry tcp_inet_driver_entry = +#ifdef HAVE_UDP static int packet_inet_init(void); static void packet_inet_stop(ErlDrvData); static void packet_inet_command(ErlDrvData, char*, ErlDrvSizeT); @@ -1230,6 +1234,7 @@ static struct erl_drv_entry udp_inet_driver_entry = NULL, inet_stop_select }; +#endif #ifdef HAVE_SCTP static struct erl_drv_entry sctp_inet_driver_entry = @@ -1293,6 +1298,7 @@ static int tcp_deliver(tcp_descriptor* desc, int len); static int tcp_inet_output(tcp_descriptor* desc, HANDLE event); static int tcp_inet_input(tcp_descriptor* desc, HANDLE event); +#ifdef HAVE_UDP typedef struct { inet_descriptor inet; /* common data structure (DON'T MOVE) */ int read_packets; /* Number of packets to read per invocation */ @@ -1304,6 +1310,7 @@ typedef struct { static int packet_inet_input(udp_descriptor* udesc, HANDLE event); static int packet_inet_output(udp_descriptor* udesc, HANDLE event); +#endif /* convert descriptor poiner to inet_descriptor pointer */ #define INETP(d) (&(d)->inet) @@ -1324,7 +1331,6 @@ static int async_ref = 0; /* async reference id generator */ static ErlDrvTermData am_ok; static ErlDrvTermData am_tcp; -static ErlDrvTermData am_udp; static ErlDrvTermData am_error; static ErlDrvTermData am_einval; static ErlDrvTermData am_inet_async; @@ -1334,10 +1340,13 @@ static ErlDrvTermData am_closed; static ErlDrvTermData am_tcp_passive; static ErlDrvTermData am_tcp_closed; static ErlDrvTermData am_tcp_error; -static ErlDrvTermData am_udp_passive; -static ErlDrvTermData am_udp_error; static ErlDrvTermData am_empty_out_q; static ErlDrvTermData am_ssl_tls; +#ifdef HAVE_UDP +static ErlDrvTermData am_udp; +static ErlDrvTermData am_udp_passive; +static ErlDrvTermData am_udp_error; +#endif #ifdef HAVE_SCTP static ErlDrvTermData am_sctp; static ErlDrvTermData am_sctp_passive; @@ -1545,6 +1554,7 @@ static void *realloc_wrapper(void *current, ErlDrvSizeT size){ # define SCTP_ANC_BUFF_SIZE INET_DEF_BUFFER/2 /* XXX: not very good... */ #endif +#ifdef HAVE_UDP static int load_ip_port(ErlDrvTermData* spec, int i, char* buf) { spec[i++] = ERL_DRV_INT; @@ -1579,6 +1589,7 @@ static int load_ip_address(ErlDrvTermData* spec, int i, int family, char* buf) } return i; } +#endif #ifdef HAVE_SCTP @@ -1745,10 +1756,12 @@ static void release_buffer(ErlDrvBinary* buf) } } +#ifdef HAVE_UDP static ErlDrvBinary* realloc_buffer(ErlDrvBinary* buf, ErlDrvSizeT newsz) { return driver_realloc_binary(buf, newsz); } +#endif /* use a TRICK, access the refc field to see if any one else has * a ref to this buffer then call driver_free_binary else @@ -3409,6 +3422,7 @@ static int tcp_error_message(tcp_descriptor* desc, int err) return erl_drv_output_term(desc->inet.dport, spec, i); } +#ifdef HAVE_UDP /* ** active mode message: ** {udp, S, IP, Port, [H1,...Hsz | Data]} or @@ -3499,6 +3513,7 @@ static int packet_binary_message ASSERT(i <= PACKET_ERL_DRV_TERM_DATA_LEN); return erl_drv_output_term(desc->dport, spec, i); } +#endif /* ** active mode message: send active-to-passive transition message @@ -3528,6 +3543,7 @@ static int packet_binary_message return erl_drv_output_term(desc->dport, spec, i); } +#ifdef HAVE_UDP /* ** send active message {udp_error|sctp_error, S, Error} */ @@ -3554,7 +3570,7 @@ static int packet_error_message(udp_descriptor* udesc, int err) ASSERT(i == sizeof(spec)/sizeof(*spec)); return erl_drv_output_term(desc->dport, spec, i); } - +#endif /* ** active=TRUE: @@ -3619,7 +3635,7 @@ tcp_reply_binary_data(tcp_descriptor* desc, ErlDrvBinary* bin, int offs, int len return code; } - +#ifdef HAVE_UDP static int packet_reply_binary_data(inet_descriptor* desc, unsigned int hsz, ErlDrvBinary * bin, int offs, int len, @@ -3642,6 +3658,7 @@ packet_reply_binary_data(inet_descriptor* desc, unsigned int hsz, return code; } } +#endif /* ---------------------------------------------------------------------------- @@ -3817,7 +3834,9 @@ static int inet_init() INIT_ATOM(ok); INIT_ATOM(tcp); +#ifdef HAVE_UDP INIT_ATOM(udp); +#endif INIT_ATOM(error); INIT_ATOM(einval); INIT_ATOM(inet_async); @@ -3827,8 +3846,10 @@ static int inet_init() INIT_ATOM(tcp_passive); INIT_ATOM(tcp_closed); INIT_ATOM(tcp_error); +#ifdef HAVE_UDP INIT_ATOM(udp_passive); INIT_ATOM(udp_error); +#endif INIT_ATOM(empty_out_q); INIT_ATOM(ssl_tls); @@ -3847,7 +3868,10 @@ static int inet_init() /* add TCP, UDP and SCTP drivers */ add_driver_entry(&tcp_inet_driver_entry); +#ifdef HAVE_UDP add_driver_entry(&udp_inet_driver_entry); +#endif + #ifdef HAVE_SCTP /* Check the size of SCTP AssocID -- currently both this driver and the Erlang part require 32 bit: */ @@ -5929,6 +5953,7 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) } continue; +#ifdef HAVE_UDP case INET_LOPT_UDP_READ_PACKETS: if (desc->stype == SOCK_DGRAM) { udp_descriptor* udesc = (udp_descriptor*) desc; @@ -5936,6 +5961,7 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) udesc->read_packets = ival; } continue; +#endif #ifdef HAVE_SETNS case INET_LOPT_NETNS: @@ -6902,6 +6928,7 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc, } continue; +#ifdef HAVE_UDP case INET_LOPT_UDP_READ_PACKETS: if (desc->stype == SOCK_DGRAM) { *ptr++ = opt; @@ -6911,6 +6938,7 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc, TRUNCATE_TO(0,ptr); } continue; +#endif #ifdef HAVE_SETNS case INET_LOPT_NETNS: @@ -10499,6 +10527,7 @@ static udp_descriptor* sctp_inet_copy(udp_descriptor* desc, SOCKET s, int* err) +#ifdef HAVE_UDP static int packet_inet_init() { return 0; @@ -10529,6 +10558,7 @@ static ErlDrvData udp_inet_start(ErlDrvPort port, char *args) set_default_msgq_limits(port); return data; } +#endif #ifdef HAVE_SCTP static ErlDrvData sctp_inet_start(ErlDrvPort port, char *args) @@ -10539,6 +10569,7 @@ static ErlDrvData sctp_inet_start(ErlDrvPort port, char *args) } #endif +#ifdef HAVE_UDP static void packet_inet_stop(ErlDrvData e) { /* There should *never* be any "empty out q" subscribers on @@ -11049,7 +11080,7 @@ static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len) else inet_reply_ok(desc); } - +#endif #ifdef __WIN32__ static void packet_inet_event(ErlDrvData e, ErlDrvEvent event) @@ -11071,6 +11102,7 @@ static void packet_inet_event(ErlDrvData e, ErlDrvEvent event) #endif +#ifdef HAVE_UDP static void packet_inet_drv_input(ErlDrvData e, ErlDrvEvent event) { (void) packet_inet_input((udp_descriptor*)e, (HANDLE)event); @@ -11327,6 +11359,7 @@ static int packet_inet_output(udp_descriptor* udesc, HANDLE event) DEBUGF(("packet_inet_output(%ld) }\r\n", (long)desc->port)); return ret; } +#endif /*---------------------------------------------------------------------------*/ -- cgit v1.2.3 From 38db84be84daefe80806e6a4c06d3ed8c6c8db31 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Sun, 23 Mar 2014 22:21:38 +0100 Subject: ose: Implement tcp inet driver for OSE The inet driver for OSE has to handle signals instead of selects and thus the wrappers for ready_input/output are a little bit different. However the majority of the inet code remains the same. --- erts/emulator/drivers/common/inet_drv.c | 548 +++++++++++++++++++++++++++++--- 1 file changed, 503 insertions(+), 45 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index a846df9bf3..e33594b026 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -93,6 +93,10 @@ typedef unsigned long long llu_t; #define INT16_MAX (32767) #endif +#ifdef __OSE__ +#include "inet.h" +#endif + #ifdef __WIN32__ #define STRNCASECMP strncasecmp @@ -121,10 +125,6 @@ typedef unsigned long long llu_t; #undef WANT_NONBLOCKING #include "sys.h" -#ifdef __OSE__ -#include "inet.h" -#endif - #undef EWOULDBLOCK #undef ETIMEDOUT @@ -295,29 +295,55 @@ static unsigned long zero_value = 0; static unsigned long one_value = 1; #elif defined (__OSE__) + +/* + * Some notes about how inet (currently only tcp) works on OSE. + * The driver uses OSE signals to communicate with the one_inet + * process. Because of the difference in how signals and file descriptors + * work the whole select/deselect mechanic is very different. + * In ose when a sock_select is done a function is called. That function + * notes the changes that the driver want to do, but does not act on it. + * later when the function returns the new desired state is compared + * to the previous state and the apprioriate actions are taken. The action + * is usually to either request more data from the stack or stop requesting + * data. + * + * One thing to note is that the driver never does select/deselect. It always + * listens for the signals. Flow of data is regulated by sending or not sending + * signals to the ose inet process. + * + * The interesting functions to look at are: + * * inet_driver_select : called when sock_select is called + * * tcp_inet_ose_dispatch_signal : checks state changes and sends new signals + * * tcp_inet_drv_output_ose : ready output callback, reads signals and calls + * dispatch_signal + * * tcp_inet_drv_input_ose : ready input callback. + */ + +#include "efs.h" #include "sys/socket.h" #include "sys/uio.h" #include "sfk/sys/sfk_uio.h" #include "netinet/in.h" #include "netinet/tcp.h" #include "netdb.h" +#include "ose_spi/socket.sig" -ssize_t writev(int fd, const struct iovec *iov, int iovcnt) -{ - return 0; -} + +static ssize_t writev_fallback(int fd, const struct iovec *iov, int iovcnt, int max_sz); #define INVALID_SOCKET -1 #define INVALID_EVENT -1 #define SOCKET_ERROR -1 #define SOCKET int -#define HANDLE long int -#define FD_READ ERL_DRV_READ -#define FD_WRITE ERL_DRV_WRITE -#define FD_CLOSE 0 -#define FD_CONNECT ERL_DRV_WRITE -#define FD_ACCEPT ERL_DRV_READ +#define HANDLE int +#define FD_READ ERL_DRV_READ +#define FD_WRITE ERL_DRV_WRITE +#define FD_CLOSE 0 +#define FD_CONNECT (1<<4) +#define FD_ACCEPT (1<<5) +#define SOCK_FD_ERROR (1<<6) #define sock_connect(s, addr, len) connect((s), (addr), (len)) #define sock_listen(s, b) listen((s), (b)) @@ -336,11 +362,12 @@ ssize_t writev(int fd, const struct iovec *iov, int iovcnt) #define sock_sendto(s,buf,blen,flag,addr,alen) \ sendto((s),(buf),(blen),(flag),(addr),(alen)) #define sock_sendv(s, vec, size, np, flag) \ - (*(np) = writev((s), (struct iovec*)(vec), (size))) + (*(np) = writev_fallback((s), (struct iovec*)(vec), (size), (*(np)))) #define sock_sendmsg(s,msghdr,flag) sendmsg((s),(msghdr),(flag)) #define sock_open(af, type, proto) socket((af), (type), (proto)) #define sock_close(s) close((s)) +#define sock_dup(s) dup((s)) #define sock_shutdown(s, how) shutdown((s), (how)) #define sock_hostname(buf, len) gethostname((buf), (len)) @@ -356,19 +383,6 @@ ssize_t writev(int fd, const struct iovec *iov, int iovcnt) #define sock_create_event(d) ((d)->s) /* return file descriptor */ #define sock_close_event(e) /* do nothing */ -#define inet_driver_select(port, e, mode, on) \ - 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)); \ - DEBUGF(("sock_select(%ld): flags=%02X, onoff=%d, event_mask=%02lX\r\n", \ - (long) (d)->port, (flags), (onoff), (unsigned long) (d)->event_mask)); \ - inet_driver_select((d)->port, (ErlDrvEvent)(long)(d)->event, (flags), (onoff)); \ - } while(0) - #ifndef WANT_NONBLOCKING #define WANT_NONBLOCKING #endif @@ -398,6 +412,16 @@ typedef unsigned long u_long; #define IN_EXPERIMENTAL(a) ((((in_addr_t)(a)) & 0xe0000000) == 0xe0000000) #define IN_BADCLASS(a) ((((in_addr_t)(a)) & 0xf0000000) == 0xf0000000) +#define sock_select(d, flags, onoff) do { \ + ASSERT(!(d)->is_ignored); \ + (d)->event_mask = (onoff) ? \ + ((d)->event_mask | (flags)) : \ + ((d)->event_mask & ~(flags)); \ + DEBUGF(("(%s / %d) sock_select(%ld): flags=%02X, onoff=%d, event_mask=%02lX, s=%d\r\n", \ + __FILE__, __LINE__, (long) (d)->port, (flags), (onoff), (unsigned long) (d)->event_mask, (d)->s)); \ + inet_driver_select((d), (flags), (onoff)); \ + } while(0) + #else /* !__OSE__ && !__WIN32__ */ #include @@ -663,13 +687,13 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) (d)->event_mask = (onoff) ? \ ((d)->event_mask | (flags)) : \ ((d)->event_mask & ~(flags)); \ - DEBUGF(("sock_select(%ld): flags=%02X, onoff=%d, event_mask=%02lX\r\n", \ - (long) (d)->port, (flags), (onoff), (unsigned long) (d)->event_mask)); \ + DEBUGF(("(%s / %d) sock_select(%ld): flags=%02X, onoff=%d, event_mask=%02lX\r\n", \ + __FILE__, __LINE__, (long) (d)->port, (flags), (onoff), (unsigned long) (d)->event_mask)); \ inet_driver_select((d)->port, (ErlDrvEvent)(long)(d)->event, (flags), (onoff)); \ } while(0) -#endif /* #ifdef __WIN32__ #else */ +#endif /* !__WIN32__ && !__OSE__ */ #ifdef HAVE_SOCKLEN_T # define SOCKLEN_T socklen_t @@ -1122,6 +1146,13 @@ typedef struct { char *netns; /* Socket network namespace name as full file path */ #endif +#ifdef __OSE__ + int select_state; /* state to keep track of whether we + should trigger another read/write + request at end of ready_input/output */ + ErlDrvEvent events[6]; +#endif + } inet_descriptor; @@ -1137,8 +1168,10 @@ static void tcp_inet_stop(ErlDrvData); static void tcp_inet_command(ErlDrvData, char*, ErlDrvSizeT); static void tcp_inet_commandv(ErlDrvData, ErlIOVec*); static void tcp_inet_flush(ErlDrvData drv_data); +#ifndef __OSE__ static void tcp_inet_drv_input(ErlDrvData, ErlDrvEvent); static void tcp_inet_drv_output(ErlDrvData data, ErlDrvEvent event); +#endif static ErlDrvData tcp_inet_start(ErlDrvPort, char* command); static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData, unsigned int, char*, ErlDrvSizeT, char**, ErlDrvSizeT); @@ -1150,7 +1183,72 @@ static void tcp_inet_event(ErlDrvData, ErlDrvEvent); static void find_dynamic_functions(void); #endif -static struct erl_drv_entry tcp_inet_driver_entry = +#ifdef __OSE__ +/* The structure of the signal used for requesting asynchronous + * notification from the stack. Under normal circumstances the network stack + * shouldn't overwrite the value set in the fd field by the sender + * of the request */ +struct OseAsyncSig { + struct FmEvent event; + int fd; +}; + +union SIGNAL { + SIGSELECT signo; + struct OseAsyncSig async; +}; + +static ErlDrvSSizeT tcp_inet_ctl_ose(ErlDrvData e, unsigned int cmd, + char* buf, ErlDrvSizeT len, + char** rbuf, ErlDrvSizeT rsize); +static void tcp_inet_commandv_ose(ErlDrvData e, ErlIOVec* ev); +static void tcp_inet_drv_output_ose(ErlDrvData data, ErlDrvEvent event); +static void tcp_inet_drv_input_ose(ErlDrvData data, ErlDrvEvent event); +static ErlDrvOseEventId inet_resolve_signal(union SIGNAL *sig); + +#ifdef INET_DRV_DEBUG + +static char *read_req = "SO_EVENT_READ_REQUEST"; +static char *read_rep = "SO_EVENT_READ_REPLY"; +static char *write_req = "SO_EVENT_WRITE_REQUEST"; +static char *write_rep = "SO_EVENT_WRITE_REPLY"; +static char *eof_req = "SO_EVENT_EOF_REQUEST"; +static char *eof_rep = "SO_EVENT_EOF_REPLY"; +static char *accept_req = "SO_EVENT_ACCEPT_REQUEST"; +static char *accept_rep = "SO_EVENT_ACCEPT_REPLY"; +static char *connect_req = "SO_EVENT_CONNECT_REQUEST"; +static char *connect_rep = "SO_EVENT_CONNECT_REPLY"; +static char *error_req = "SO_EVENT_ERROR_REQUEST"; +static char *error_rep = "SO_EVENT_ERROR_REPLY"; +static char signo_tmp[32]; + +static char *signo_to_string(SIGSELECT signo) { + switch (signo) { + case SO_EVENT_READ_REQUEST: { return read_req; } + case SO_EVENT_READ_REPLY: { return read_rep; } + case SO_EVENT_WRITE_REQUEST: { return write_req; } + case SO_EVENT_WRITE_REPLY: { return write_rep; } + case SO_EVENT_EOF_REQUEST: { return eof_req; } + case SO_EVENT_EOF_REPLY: { return eof_rep; } + case SO_EVENT_ACCEPT_REQUEST: { return accept_req; } + case SO_EVENT_ACCEPT_REPLY: { return accept_rep; } + case SO_EVENT_CONNECT_REQUEST: { return connect_req; } + case SO_EVENT_CONNECT_REPLY: { return connect_rep; } + case SO_EVENT_ERROR_REQUEST: { return error_req; } + case SO_EVENT_ERROR_REPLY: { return error_rep; } + } + + snprintf(signo_tmp,32,"0x%x",signo); + + return signo_tmp; +} + +#endif + +#endif /* __OSE__ */ + + +static struct erl_drv_entry tcp_inet_driver_entry = { tcp_inet_init, /* inet_init will add this driver !! */ tcp_inet_start, @@ -1159,6 +1257,9 @@ static struct erl_drv_entry tcp_inet_driver_entry = #ifdef __WIN32__ tcp_inet_event, NULL, +#elif defined(__OSE__) + tcp_inet_drv_input_ose, /*ready_input*/ + tcp_inet_drv_output_ose, /*ready_output*/ #else tcp_inet_drv_input, tcp_inet_drv_output, @@ -1166,9 +1267,17 @@ static struct erl_drv_entry tcp_inet_driver_entry = "tcp_inet", NULL, NULL, +#ifdef __OSE__ + tcp_inet_ctl_ose, +#else tcp_inet_ctl, +#endif tcp_inet_timeout, +#ifdef __OSE__ + tcp_inet_commandv_ose, +#else tcp_inet_commandv, +#endif NULL, tcp_inet_flush, NULL, @@ -1315,6 +1424,14 @@ static int packet_inet_output(udp_descriptor* udesc, HANDLE event); /* convert descriptor poiner to inet_descriptor pointer */ #define INETP(d) (&(d)->inet) +#ifdef __OSE__ +static void inet_driver_select(inet_descriptor* desc, + int flags, int onoff); +static void tcp_inet_ose_dispatch_signals(tcp_descriptor *desc, + int prev_select_state, + union SIGNAL *sig); +#endif + static int async_ref = 0; /* async reference id generator */ #define NEW_ASYNC_ID() ((async_ref++) & 0xffff) @@ -3528,6 +3645,9 @@ static int packet_binary_message DEBUGF(("packet_passive_message(%ld):\r\n", (long)desc->port)); +#if !defined(HAVE_UDP) && !defined(HAVE_SCTP) + i = LOAD_ATOM(spec, i, am_tcp_passive); +#else if (desc->sprotocol == IPPROTO_TCP) i = LOAD_ATOM(spec, i, am_tcp_passive); else { @@ -3537,6 +3657,7 @@ static int packet_binary_message i = LOAD_ATOM(spec, i, am_udp_passive); #endif } +#endif i = LOAD_PORT(spec, i, desc->dport); i = LOAD_TUPLE(spec, i, 2); ASSERT(i <= 6); @@ -4200,6 +4321,16 @@ static void desc_close(inet_descriptor* desc) desc->forced_events = 0; desc->send_would_block = 0; #endif +#ifdef __OSE__ + if (desc->events[0]) { + driver_select(desc->port,desc->events[0],FD_READ|FD_WRITE|ERL_DRV_USE,0); + driver_select(desc->port,desc->events[1],FD_READ|FD_WRITE|ERL_DRV_USE,0); + driver_select(desc->port,desc->events[2],FD_READ|FD_WRITE|ERL_DRV_USE,0); + driver_select(desc->port,desc->events[3],FD_READ|FD_WRITE|ERL_DRV_USE,0); + driver_select(desc->port,desc->events[4],FD_READ|FD_WRITE|ERL_DRV_USE,0); + driver_select(desc->port,desc->events[5],FD_READ|FD_WRITE|ERL_DRV_USE,0); + } +#else /* * We should close the fd here, but the other driver might still * be selecting on it. @@ -4209,6 +4340,7 @@ static void desc_close(inet_descriptor* desc) ERL_DRV_USE, 0); else inet_stop_select((ErlDrvEvent)(long)desc->event,NULL); +#endif desc->event = INVALID_EVENT; /* closed by stop_select callback */ desc->s = INVALID_SOCKET; desc->event_mask = 0; @@ -4250,6 +4382,64 @@ static int erl_inet_close(inet_descriptor* desc) return 0; } +#ifdef __OSE__ +static void inet_select_init(inet_descriptor* desc) +{ + desc->events[0] = + erl_drv_ose_event_alloc(SO_EVENT_READ_REPLY, + desc->s, + inet_resolve_signal, + NULL); + driver_select(desc->port, desc->events[0], + ERL_DRV_READ|ERL_DRV_USE, 1); + + desc->events[1] = + erl_drv_ose_event_alloc(SO_EVENT_EOF_REPLY, + desc->s, + inet_resolve_signal, + NULL); + driver_select(desc->port, desc->events[1], + ERL_DRV_READ|ERL_DRV_USE, 1); + + desc->events[2] = + erl_drv_ose_event_alloc(SO_EVENT_ACCEPT_REPLY, + desc->s, + inet_resolve_signal, + NULL); + driver_select(desc->port, desc->events[2], + ERL_DRV_READ|ERL_DRV_USE, 1); + + /* trigger tcp_inet_input */ + desc->events[3] = + erl_drv_ose_event_alloc(SO_EVENT_WRITE_REPLY, + desc->s, + inet_resolve_signal, + NULL); + driver_select(desc->port, desc->events[3], + ERL_DRV_WRITE|ERL_DRV_USE, 1); + + desc->events[4] = + erl_drv_ose_event_alloc(SO_EVENT_CONNECT_REPLY, + desc->s, + inet_resolve_signal, + NULL); + driver_select(desc->port, desc->events[4], + ERL_DRV_WRITE|ERL_DRV_USE, 1); + + desc->events[5] = + erl_drv_ose_event_alloc(SO_EVENT_ERROR_REPLY, + desc->s, + inet_resolve_signal, + NULL); + driver_select(desc->port, desc->events[5], + ERL_DRV_WRITE|ERL_DRV_USE, 1); + + /* Issue a select on error event before any other select to be sure we are + prepared to receive error notifications from the stack, even in the + situations when select isn't issued */ + sock_select(desc, SOCK_FD_ERROR, 1); +} +#endif static ErlDrvSSizeT inet_ctl_open(inet_descriptor* desc, int domain, int type, char** rbuf, ErlDrvSizeT rsize) @@ -4333,6 +4523,10 @@ static ErlDrvSSizeT inet_ctl_open(inet_descriptor* desc, int domain, int type, #ifdef __WIN32__ driver_select(desc->port, desc->event, ERL_DRV_READ, 1); #endif +#ifdef __OSE__ + inet_select_init(desc); +#endif + desc->state = INET_STATE_OPEN; desc->stype = type; desc->sfamily = domain; @@ -4352,7 +4546,14 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type, return ctl_error(sock_errno(), rbuf, rsize); if (name.sa.sa_family != domain) return ctl_error(EINVAL, rbuf, rsize); +#ifdef __OSE__ + /* for fdopen duplicating the sd will allow to uniquely identify + the signal from OSE with erlang port */ + desc->s = sock_dup(s); +#else desc->s = s; +#endif + if ((desc->event = sock_create_event(desc)) == INVALID_EVENT) return ctl_error(sock_errno(), rbuf, rsize); SET_NONBLOCKING(desc->s); @@ -4362,8 +4563,15 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type, desc->state = INET_STATE_BOUND; /* assume bound */ if (type == SOCK_STREAM) { /* check if connected */ sz = sizeof(name); - if (!IS_SOCKET_ERROR(sock_peer(s, (struct sockaddr*) &name, &sz))) + if (!IS_SOCKET_ERROR(sock_peer(s, (struct sockaddr*) &name, &sz))) { desc->state = INET_STATE_CONNECTED; +#ifdef __OSE__ + /* since we are dealing with different descriptors (i.e. inet and + socket) the select part should be initialized with the right + values */ + inet_select_init(desc); +#endif + } } desc->prebound = 1; /* used to prevent a real close since @@ -4389,8 +4597,7 @@ struct addr_if { #ifndef SIOCGIFNETMASK -static struct in_addr net_mask(in) -struct in_addr in; +static struct in_addr net_mask(struct in_addr in) { register u_long i = sock_ntohl(in.s_addr); @@ -8069,6 +8276,15 @@ static ErlDrvData inet_start(ErlDrvPort port, int size, int protocol) #ifdef HAVE_SETNS desc->netns = NULL; #endif +#ifdef __OSE__ + desc->select_state = 0; + desc->events[0] = NULL; + desc->events[1] = NULL; + desc->events[2] = NULL; + desc->events[3] = NULL; + desc->events[4] = NULL; + desc->events[5] = NULL; +#endif return (ErlDrvData)desc; } @@ -8789,6 +9005,11 @@ static tcp_descriptor* tcp_inet_copy(tcp_descriptor* desc,SOCKET s, copy_desc->inet.port = port; copy_desc->inet.dport = driver_mk_port(port); + +#ifdef __OSE__ + inet_select_init(©_desc->inet); +#endif + *err = 0; return copy_desc; } @@ -8850,8 +9071,22 @@ static void tcp_inet_stop(ErlDrvData e) inet_stop(INETP(desc)); } +#ifdef __OSE__ - +static ErlDrvSSizeT tcp_inet_ctl_ose(ErlDrvData e, unsigned int cmd, + char* buf, ErlDrvSizeT len, + char** rbuf, ErlDrvSizeT rsize) { + + tcp_descriptor* desc = (tcp_descriptor*)e; + int prev_select_state = INETP(desc)->select_state; + + ErlDrvSSizeT res = tcp_inet_ctl(e,cmd,buf,len,rbuf,rsize); + + tcp_inet_ose_dispatch_signals((tcp_descriptor*)e,prev_select_state,NULL); + + return res; +} +#endif /* TCP requests from Erlang */ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, @@ -9067,7 +9302,7 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, ErlDrvTermData caller = driver_caller(desc->inet.port); tcp_descriptor* accept_desc; int err; - + if ((accept_desc = tcp_inet_copy(desc,s,caller,&err)) == NULL) { sock_close(s); return ctl_error(err, rbuf, rsize); @@ -9101,7 +9336,8 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, char tbuf[2]; int n; - DEBUGF(("tcp_inet_ctl(%ld): RECV\r\n", (long)desc->inet.port)); + DEBUGF(("tcp_inet_ctl(%ld): RECV (s=%d)\r\n", + (long)desc->inet.port, desc->inet.s)); /* INPUT: Timeout(4), Length(4) */ if (!IS_CONNECTED(INETP(desc))) { if (desc->tcp_add_flags & TCP_ADDF_DELAYED_CLOSE_RECV) { @@ -9273,6 +9509,16 @@ static void tcp_inet_command(ErlDrvData e, char *buf, ErlDrvSizeT len) DEBUGF(("tcp_inet_command(%ld) }\r\n", (long)desc->inet.port)); } +#ifdef __OSE__ + +static void tcp_inet_commandv_ose(ErlDrvData e, ErlIOVec* ev) { + int prev_select_state = INETP((tcp_descriptor*)e)->select_state; + tcp_inet_commandv(e, ev); + tcp_inet_ose_dispatch_signals((tcp_descriptor*)e,prev_select_state,NULL); +} + +#endif + static void tcp_inet_commandv(ErlDrvData e, ErlIOVec* ev) { @@ -9336,6 +9582,22 @@ static void inet_stop_select(ErlDrvEvent event, void* _) { #ifdef __WIN32__ WSACloseEvent((HANDLE)event); +#elif defined(__OSE__) + ErlDrvOseEventId id; + union SIGNAL *sig; + erl_drv_ose_event_fetch(event, NULL, &id,NULL); + DEBUGF(("inet_stop_select(?#?) {s=%d\n",id)); + sock_close((int)id); + /* On socket close all the signals waiting to be processed as part of the + select should be deallocated */ + while((sig = erl_drv_ose_get_signal(event))) { + DEBUGF(("inet_stop_select(?#?): Freeing signal %s\n", + signo_to_string(sig->signo))); + free_buf(&sig); + } + erl_drv_ose_event_free(event); + DEBUGF(("inet_stop_select(?#?) }\n")); + #else sock_close((SOCKET)(long)event); #endif @@ -9455,12 +9717,13 @@ static int tcp_remain(tcp_descriptor* desc, int* len) int n = desc->i_ptr - ptr; /* number of bytes read */ int tlen; - DEBUGF(("tcp_remain(%ld): s=%d, n=%d, nfill=%d nsz=%d\r\n", - (long)desc->inet.port, desc->inet.s, n, nfill, nsz)); + DEBUGF(("tcp_remain(%ld): s=%d, n=%d, nfill=%d nsz=%d, tlen %d\r\n", + (long)desc->inet.port, desc->inet.s, n, nfill, nsz, tlen)); tlen = packet_get_length(desc->inet.htype, ptr, n, desc->inet.psize, desc->i_bufsz, &desc->http_state); + if (tlen > 0) { if (tlen <= n) { /* got a packet */ *len = tlen; @@ -9868,7 +10131,146 @@ static void tcp_inet_event(ErlDrvData e, ErlDrvEvent event) return; } -#endif /* WIN32 */ +#elif defined(__OSE__) /* !__WIN32__ */ +/* The specific resolve signal function. It will return the socket descriptor + for which the select was issued */ +static ErlDrvOseEventId inet_resolve_signal(union SIGNAL *sig) { + DEBUGF(("%s(?#?): s=%d got signal %s, status = %d, extra = %d, sender = 0x%x\n", + __FUNCTION__,sig->async.fd,signo_to_string(sig->signo), + sig->async.event.status, + sig->async.event.extra,sender(&sig))); + if (sig->signo == SO_EVENT_READ_REPLY || + sig->signo == SO_EVENT_ACCEPT_REPLY || + sig->signo == SO_EVENT_EOF_REPLY || + sig->signo == SO_EVENT_WRITE_REPLY || + sig->signo == SO_EVENT_ERROR_REPLY || + sig->signo == SO_EVENT_CONNECT_REPLY ) { + return sig->async.fd; + } + + return -1; +} + +static void inet_driver_select(inet_descriptor* desc, + int flags, int onoff) { + ASSERT(!desc->is_ignored); + + if(onoff) { + desc->select_state |= flags; + } else { + desc->select_state &= ~flags; + } +} + +static ssize_t writev_fallback(int fd, const struct iovec *iov, int iovcnt, int max_sz) +{ + size_t data_len = 0; + size_t sent = 0; + ssize_t n; + int i; + + for(i = 0; i < iovcnt; i++) + { + data_len = iov[i].iov_len; +tryagain: + n = sock_send(fd, iov[i].iov_base, data_len, 0); + if (IS_SOCKET_ERROR(n)) { + /* If buffer length is greater than the amount stack is able to + * send out then try to send at least max_sz (this comes with + * SO_EVENT_WRITE_REPLY signal*/ + if ((errno == EMSGSIZE) && (max_sz > 0) && (data_len > max_sz)) { + data_len = max_sz; + goto tryagain; + } + break; + } + sent += n; + } + return sent; +} + +#define OSE_EVENT_REQ(TCP_DESC,EVENT) do { \ + union SIGNAL *sig = alloc(sizeof(struct OseAsyncSig), EVENT); \ + sig->async.fd = INETP(TCP_DESC)->s; \ + ose_request_event(INETP(TCP_DESC)->s, &sig, 1); \ + DEBUGF(("%s(%ld): s=%d sent %s\r\n",__FUNCTION__, \ + INETP(TCP_DESC)->port,INETP(TCP_DESC)->s,signo_to_string(EVENT))); \ + } while(0) + +static void tcp_inet_ose_dispatch_signals(tcp_descriptor *desc, + int prev_select_state, + union SIGNAL *sig) { + if (sig) { + DEBUGF(("tcp_inet_ose_dispatch_signals(%ld) {s=%d resend\r\n", + (long)INETP(desc)->port,INETP(desc)->s)); + /* We are reacting to a signal, which means that if + the select_state for that signal is still activated + we should send a new signal */ + switch (sig->signo) { + case SO_EVENT_READ_REPLY: { + if (INETP(desc)->select_state & FD_READ) + OSE_EVENT_REQ(desc,SO_EVENT_READ_REQUEST); + break; + } + case SO_EVENT_WRITE_REPLY: { + if (INETP(desc)->select_state & FD_WRITE) + OSE_EVENT_REQ(desc,SO_EVENT_WRITE_REQUEST); + break; + } + case SO_EVENT_CONNECT_REPLY: { + if (INETP(desc)->select_state & FD_CONNECT) + OSE_EVENT_REQ(desc,SO_EVENT_CONNECT_REQUEST); + break; + } + case SO_EVENT_ACCEPT_REPLY: { + if (INETP(desc)->select_state & FD_ACCEPT) + OSE_EVENT_REQ(desc,SO_EVENT_ACCEPT_REQUEST); + break; + } + case SO_EVENT_ERROR_REPLY: { + if (INETP(desc)->select_state & SOCK_FD_ERROR) + OSE_EVENT_REQ(desc,SO_EVENT_ERROR_REQUEST); + break; + } + + } + DEBUGF(("tcp_inet_ose_dispatch_signals(%ld) }\r\n", + (long)INETP(desc)->port)); + } + + if (INETP(desc)->select_state != prev_select_state) { + /* If the select state has changed we have to issue signals for + the state parts that have changed. */ + int xor_select_state = INETP(desc)->select_state ^ prev_select_state; + DEBUGF(("tcp_inet_ose_dispatch_signals(%ld) {s=%d select change\r\n", + (long)INETP(desc)->port,INETP(desc)->s)); + if ((xor_select_state & FD_READ) && + (INETP(desc)->select_state & FD_READ)) { + OSE_EVENT_REQ(desc,SO_EVENT_READ_REQUEST); + } + if ((xor_select_state & FD_WRITE) && + (INETP(desc)->select_state & FD_WRITE)) { + OSE_EVENT_REQ(desc,SO_EVENT_WRITE_REQUEST); + } + if ((xor_select_state & FD_CONNECT) && + (INETP(desc)->select_state & FD_CONNECT)) { + OSE_EVENT_REQ(desc,SO_EVENT_CONNECT_REQUEST); + } + if ((xor_select_state & FD_ACCEPT) && + (INETP(desc)->select_state & FD_ACCEPT)) { + OSE_EVENT_REQ(desc,SO_EVENT_ACCEPT_REQUEST); + } + if ((xor_select_state & SOCK_FD_ERROR) && + (INETP(desc)->select_state & SOCK_FD_ERROR)) { + OSE_EVENT_REQ(desc,SO_EVENT_ERROR_REQUEST); + } + + DEBUGF(("tcp_inet_ose_dispatch_signals(%ld) }\r\n", + (long)INETP(desc)->port)); + } +} + +#endif /* __OSE__ */ /* socket has input: @@ -9889,7 +10291,7 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event) unsigned int len; inet_address remote; inet_async_op *this_op = desc->inet.opt; - + len = sizeof(desc->inet.remote); s = sock_accept(desc->inet.s, (struct sockaddr*) &remote, &len); if (s == INVALID_SOCKET && sock_errno() == ERRNO_BLOCK) { @@ -9958,7 +10360,6 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event) while (desc->inet.state == INET_STATE_MULTI_ACCEPTING) { len = sizeof(desc->inet.remote); s = sock_accept(desc->inet.s, (struct sockaddr*) &remote, &len); - if (s == INVALID_SOCKET && sock_errno() == ERRNO_BLOCK) { /* Just try again, no real error, keep the last return code */ goto done; @@ -10284,6 +10685,49 @@ static int tcp_send(tcp_descriptor* desc, char* ptr, ErlDrvSizeT len) return 0; } +#ifdef __OSE__ + +static void tcp_inet_drv_output_ose(ErlDrvData data, ErlDrvEvent event) +{ + union SIGNAL *event_sig = erl_drv_ose_get_signal(event); + + while (event_sig) { + int prev_select_state = INETP((tcp_descriptor*)data)->select_state; + int res = tcp_inet_output((tcp_descriptor*)data, (HANDLE)event_sig); + if (res != -1) { + tcp_inet_ose_dispatch_signals((tcp_descriptor*)data, + prev_select_state,event_sig); + free_buf(&event_sig); + event_sig = erl_drv_ose_get_signal(event); + } else { + /* NOTE: here the event object could have been deallocated!!!! + inet_stop_select is called when doing driver_select(ERL_DRV_USE,0) + */ + free_buf(&event_sig); + return; + } + } +} + +static void tcp_inet_drv_input_ose(ErlDrvData data, ErlDrvEvent event) +{ + union SIGNAL *event_sig = erl_drv_ose_get_signal(event); + + while (event_sig) { + int prev_select_state = INETP((tcp_descriptor*)data)->select_state; + int res = tcp_inet_input((tcp_descriptor*)data, (HANDLE)event); + if (res != -1) { + tcp_inet_ose_dispatch_signals((tcp_descriptor*)data, prev_select_state, + event_sig); + free_buf(&event_sig); + event_sig = erl_drv_ose_get_signal(event); + } else { + free_buf(&event_sig); + return; + } + } +} +#else static void tcp_inet_drv_output(ErlDrvData data, ErlDrvEvent event) { (void)tcp_inet_output((tcp_descriptor*)data, (HANDLE)event); @@ -10293,6 +10737,7 @@ static void tcp_inet_drv_input(ErlDrvData data, ErlDrvEvent event) { (void)tcp_inet_input((tcp_descriptor*)data, (HANDLE)event); } +#endif /* socket ready for ouput: ** 1. INET_STATE_CONNECTING => non block connect ? @@ -10358,6 +10803,13 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event) ssize_t n; SysIOVec* iov; +#ifdef __OSE__ + /* For large size buffers case the amount of data that the stack is + able to send out (received in the .extra field) should be passed + down to writev_fallback */ + n = event ? ((union SIGNAL*)event)->async.event.extra : 0; +#endif + if ((iov = driver_peekq(ix, &vsize)) == NULL) { sock_select(INETP(desc), FD_WRITE, 0); send_empty_out_q_msgs(INETP(desc)); @@ -10369,8 +10821,8 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event) if (IS_SOCKET_ERROR(sock_sendv(desc->inet.s, iov, vsize, &n, 0))) { write_error: if ((sock_errno() != ERRNO_BLOCK) && (sock_errno() != EINTR)) { - DEBUGF(("tcp_inet_output(%ld): sock_sendv(%d) errno = %d\r\n", - (long)desc->inet.port, vsize, sock_errno())); + DEBUGF(("tcp_inet_output(%ld): sock_sendv(%d) errno = %d (errno %d)\r\n", + (long)desc->inet.port, vsize, sock_errno(), errno)); ret = tcp_send_error(desc, sock_errno()); goto done; } @@ -10383,6 +10835,12 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event) sizes > (max 32 bit signed int) */ size_t howmuch = 0x7FFFFFFF; /* max signed 32 bit */ int x; +#ifdef __OSE__ + /* For EWOULDBLOCK sock_sendv returns 0 so we have to be sure it + wasn't the case */ + if(sock_errno() == ERRNO_BLOCK) + goto done; +#endif for(x = 0; x < vsize && iov[x].iov_len == 0; ++x) ; if (x < vsize) { -- cgit v1.2.3 From 547aa83f94c6614757e9033849c0c13563930300 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Fri, 28 Mar 2014 09:56:29 +0100 Subject: erts: Move debug printout to eliminate gcc warning --- erts/emulator/drivers/common/inet_drv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index e33594b026..09bada457d 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -9717,13 +9717,13 @@ static int tcp_remain(tcp_descriptor* desc, int* len) int n = desc->i_ptr - ptr; /* number of bytes read */ int tlen; - DEBUGF(("tcp_remain(%ld): s=%d, n=%d, nfill=%d nsz=%d, tlen %d\r\n", - (long)desc->inet.port, desc->inet.s, n, nfill, nsz, tlen)); - tlen = packet_get_length(desc->inet.htype, ptr, n, desc->inet.psize, desc->i_bufsz, &desc->http_state); + DEBUGF(("tcp_remain(%ld): s=%d, n=%d, nfill=%d nsz=%d, tlen %d\r\n", + (long)desc->inet.port, desc->inet.s, n, nfill, nsz, tlen)); + if (tlen > 0) { if (tlen <= n) { /* got a packet */ *len = tlen; -- cgit v1.2.3 From 78540afe8d4a15fe3d6c42208b82bde546e4c0c8 Mon Sep 17 00:00:00 2001 From: Mikael Pettersson Date: Wed, 14 May 2014 16:23:02 +0200 Subject: Fix efile_openfile() to handle stat() failure If the initial stat() fails then efile_openfile() will still proceed to open() the file. If that succeeds and the caller passed a non-NULL pSize, then it will copy bogus data from the statbuf into *pSize. This has been observed to cause file:read_file/1 to return truncated file data with no error indication. The use case involved a large file system mounted via NFS, with some directories containing large number of files, and NFS mount options that allow the NFS client to return EIO if the NFS server does not respond quickly enough. Depending on the caching state of the client and server machines, a few stat() calls (fewer than 1 per 10 million) would take long enough to trigger EIO errors, but subsequent open() calls would succeed, and read_file/1 would return truncated data. This sequence of events has been observed via "strace" on beam.smp. Signed-off-by: Mikael Pettersson --- erts/emulator/drivers/unix/unix_efile.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c index 42f41c5f3d..878beb055b 100644 --- a/erts/emulator/drivers/unix/unix_efile.c +++ b/erts/emulator/drivers/unix/unix_efile.c @@ -360,7 +360,12 @@ efile_openfile(Efile_error* errInfo, /* Where to return error codes. */ int fd; int mode; /* Open mode. */ - if (stat(name, &statbuf) >= 0 && !ISREG(statbuf)) { + if (stat(name, &statbuf) < 0) { + /* statbuf is undefined: if the caller depends on it, + i.e. invoke_read_file(), fail the call immediately */ + if (pSize && flags == EFILE_MODE_READ) + return check_error(-1, errInfo); + } else if (!ISREG(statbuf)) { /* * For UNIX only, here is some ugly code to allow * /dev/null to be opened as a file. -- cgit v1.2.3 From 8a6390613225ec3f3e2d5bbf537d2e0737342e87 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Fri, 11 Jul 2014 10:46:37 +0200 Subject: kernel: When doing an fdopen we now also bind the fd to the specified addr/port --- erts/emulator/drivers/common/inet_drv.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 45fac69303..4f0bf1167e 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -4155,7 +4155,8 @@ static ErlDrvSSizeT 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 ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type, - SOCKET s, char** rbuf, ErlDrvSizeT rsize) + SOCKET s, Uint32 bound, + char** rbuf, ErlDrvSizeT rsize) { inet_address name; unsigned int sz = sizeof(name); @@ -4172,7 +4173,12 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type, #ifdef __WIN32__ driver_select(desc->port, desc->event, ERL_DRV_READ, 1); #endif - desc->state = INET_STATE_BOUND; /* assume bound */ + + if (bound) + desc->state = INET_STATE_BOUND; + else + desc->state = INET_STATE_OPEN; + if (type == SOCK_STREAM) { /* check if connected */ sz = sizeof(name); if (!IS_SOCKET_ERROR(sock_peer(s, (struct sockaddr*) &name, &sz))) @@ -8642,10 +8648,11 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, break; } - case INET_REQ_FDOPEN: { /* pass in an open socket */ + case INET_REQ_FDOPEN: { /* pass in an open (and optionally bound) socket */ int domain; + int bound; DEBUGF(("tcp_inet_ctl(%ld): FDOPEN\r\n", (long)desc->inet.port)); - if (len != 6) return ctl_error(EINVAL, rbuf, rsize); + if (len != 6 && len != 10) return ctl_error(EINVAL, rbuf, rsize); switch(buf[0]) { case INET_AF_INET: domain = AF_INET; @@ -8663,8 +8670,13 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, return ctl_error(EINVAL, rbuf, rsize); } if (buf[1] != INET_TYPE_STREAM) return ctl_error(EINVAL, rbuf, rsize); + + if (len == 6) bound = 1; + else bound = get_int32(buf+2+4); + return inet_ctl_fdopen(INETP(desc), domain, SOCK_STREAM, - (SOCKET) get_int32(buf+2), rbuf, rsize); + (SOCKET) get_int32(buf+2), + bound, rbuf, rsize); break; } @@ -10409,10 +10421,11 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, return replen; - case INET_REQ_FDOPEN: { /* pass in an open (and bound) socket */ + case INET_REQ_FDOPEN: { /* pass in an open (and optionally bound) socket */ SOCKET s; + int bound; DEBUGF(("packet inet_ctl(%ld): FDOPEN\r\n", (long)desc->port)); - if (len != 6) { + if (len != 6 && len != 10) { return ctl_error(EINVAL, rbuf, rsize); } switch (buf[0]) { @@ -10437,7 +10450,11 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, return ctl_error(EINVAL, rbuf, rsize); } s = (SOCKET)get_int32(buf+2); - replen = inet_ctl_fdopen(desc, af, type, s, rbuf, rsize); + + if (len == 6) bound = 1; + else bound = get_int32(buf+2+4); + + replen = inet_ctl_fdopen(desc, af, type, s, bound, rbuf, rsize); if ((*rbuf)[0] != INET_REP_ERROR) { if (desc->active) -- cgit v1.2.3 From 03a1fcf5346233f76c8dc50844e132f4760154d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Mon, 26 May 2014 19:33:24 +0200 Subject: erts: Fix inet close on prebound fds Inet close must remove fd from select/poll without closing the fd. --- erts/emulator/drivers/common/inet_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 4f0bf1167e..4cc31c1344 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -4053,7 +4053,7 @@ static int erl_inet_close(inet_descriptor* desc) desc_close(desc); desc->state = INET_STATE_CLOSED; } else if (desc->prebound && (desc->s != INVALID_SOCKET)) { - sock_select(desc, FD_READ | FD_WRITE | FD_CLOSE, 0); + sock_select(desc, FD_READ | FD_WRITE | FD_CLOSE | ERL_DRV_USE_NO_CALLBACK, 0); desc->event_mask = 0; #ifdef __WIN32__ desc->forced_events = 0; -- cgit v1.2.3 From 63d7fbe5cdf2b714500467b771a237e9ec11aaa8 Mon Sep 17 00:00:00 2001 From: Tuncer Ayaz Date: Sun, 24 Aug 2014 19:05:02 +0200 Subject: Fix misspellings of 'another' --- erts/emulator/drivers/common/inet_drv.c | 2 +- erts/emulator/drivers/unix/multi_drv.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 09d90f4984..891589d1c5 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -5778,7 +5778,7 @@ done: ia_p->Ipv6IfIndex && ia_p->Ipv6IfIndex != index) { - /* Oops, there was an other interface for IPv6. Possible? XXX */ + /* Oops, there was another interface for IPv6. Possible? XXX */ index = ia_p->Ipv6IfIndex; goto index; } diff --git a/erts/emulator/drivers/unix/multi_drv.c b/erts/emulator/drivers/unix/multi_drv.c index 822c96730c..724d325ed5 100644 --- a/erts/emulator/drivers/unix/multi_drv.c +++ b/erts/emulator/drivers/unix/multi_drv.c @@ -20,7 +20,7 @@ /* Purpose: Multidriver interface This is an example of a driver which allows multiple instances of itself. I.e have one erlang process execute open_port(multi......) and - at the same time have an other erlang process open an other port + at the same time have another erlang process open another port running multi there as well. */ -- cgit v1.2.3 From a5bfb0a58783c472887ce0ad2060e4a395aa941d Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Fri, 12 Sep 2014 12:06:34 +0200 Subject: erts: getsockname is not allowed on non-bound sockets This only produces an error on win32, but should not really be called on *nix either. --- erts/emulator/drivers/common/inet_drv.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 891589d1c5..db8a251fdd 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -4542,11 +4542,13 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type, inet_address name; unsigned int sz = sizeof(name); - /* check that it is a socket and that the socket is bound */ - if (IS_SOCKET_ERROR(sock_name(s, (struct sockaddr*) &name, &sz))) - return ctl_error(sock_errno(), rbuf, rsize); - if (name.sa.sa_family != domain) - return ctl_error(EINVAL, rbuf, rsize); + if (bound) { + /* check that it is a socket and that the socket is bound */ + if (IS_SOCKET_ERROR(sock_name(s, (struct sockaddr*) &name, &sz))) + return ctl_error(sock_errno(), rbuf, rsize); + if (name.sa.sa_family != domain) + return ctl_error(EINVAL, rbuf, rsize); + } #ifdef __OSE__ /* for fdopen duplicating the sd will allow to uniquely identify the signal from OSE with erlang port */ -- cgit v1.2.3 From b4f191993631630ee14cd48e0e792bb3dee1ed5c Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Mon, 22 Sep 2014 11:11:40 +0200 Subject: erts: Initialize links when reading file info --- erts/emulator/drivers/win32/win_efile.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c index a321bb9641..7e4043fc1b 100644 --- a/erts/emulator/drivers/win32/win_efile.c +++ b/erts/emulator/drivers/win32/win_efile.c @@ -1288,6 +1288,10 @@ do_fileinfo(Efile_call_state* state, Efile_info* pInfo, { HANDLE handle; /* Handle returned by CreateFile() */ BY_HANDLE_FILE_INFORMATION fileInfo; /* from CreateFile() */ + + /* We initialise nNumberOfLinks as GetFileInformationByHandle + does not always initialise this field */ + fileInfo.nNumberOfLinks = 1; if (handle = CreateFileW(name, GENERIC_READ, FILE_SHARE_FLAGS, NULL, OPEN_EXISTING, 0, NULL)) { GetFileInformationByHandle(handle, &fileInfo); -- cgit v1.2.3 From 2e84a2ab5e0f0c82c2d79f69cd2f4bff762762a4 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Thu, 26 Jun 2014 18:50:51 +0200 Subject: erts: Make tty driver non-blocking Instead of using blocking call to fwrite, the tty driver now uses non-blocking calls to writev and queues any output data that cannot be written into the driver queue. Without this change an stdout write could block an entire scheduler if for some reason the pseudo tty on the other side does not consume the output of the Erlang shell. OTP-12239 --- erts/emulator/drivers/unix/ttsl_drv.c | 130 ++++++++++++++++++++++++++++++---- 1 file changed, 117 insertions(+), 13 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/unix/ttsl_drv.c b/erts/emulator/drivers/unix/ttsl_drv.c index 491e0a090e..73ce27c6ec 100644 --- a/erts/emulator/drivers/unix/ttsl_drv.c +++ b/erts/emulator/drivers/unix/ttsl_drv.c @@ -32,6 +32,10 @@ static ErlDrvData ttysl_start(ErlDrvPort, char*); #ifdef HAVE_TERMCAP /* else make an empty driver that can not be opened */ +#ifndef WANT_NONBLOCKING +#define WANT_NONBLOCKING +#endif + #include "sys.h" #include #include @@ -39,6 +43,7 @@ static ErlDrvData ttysl_start(ErlDrvPort, char*); #include #include #include +#include #include #include #include @@ -57,6 +62,14 @@ static ErlDrvData ttysl_start(ErlDrvPort, char*); #include #endif +#if defined IOV_MAX +#define MAXIOV IOV_MAX +#elif defined UIO_MAXIOV +#define MAXIOV UIO_MAXIOV +#else +#define MAXIOV 16 +#endif + #define TRUE 1 #define FALSE 0 @@ -85,7 +98,9 @@ static volatile int cols_needs_update = FALSE; #define CTRL_OP_GET_UNICODE_STATE 101 #define CTRL_OP_SET_UNICODE_STATE 102 - +/* We use 1024 as the buf size as that was the default buf size of FILE streams + on all platforms that I checked. */ +#define TTY_BUFFSIZE 1024 static int lbuf_size = BUFSIZ; static Uint32 *lbuf; /* The current line buffer */ @@ -113,13 +128,18 @@ 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*, ErlDrvSizeT); +static void ttysl_to_tty(ErlDrvData, ErlDrvEvent); +static void ttysl_flush_tty(ErlDrvData); static void ttysl_from_tty(ErlDrvData, ErlDrvEvent); static void ttysl_stop_select(ErlDrvEvent, void*); static Sint16 get_sint16(char*); static ErlDrvPort ttysl_port; static int ttysl_fd; -static FILE *ttysl_out; +static int ttysl_terminate = 0; +static ErlDrvBinary *putcbuf; +static int putcpos; +static int putclen; /* Functions that work on the line buffer. */ static int start_lbuf(void); @@ -201,22 +221,22 @@ struct erl_drv_entry ttsl_driver_entry = { IF_IMPL(ttysl_stop), IF_IMPL(ttysl_from_erlang), IF_IMPL(ttysl_from_tty), - NULL, - "tty_sl", - NULL, - NULL, + IF_IMPL(ttysl_to_tty), + "tty_sl", /* driver_name */ + NULL, /* finish */ + NULL, /* handle */ IF_IMPL(ttysl_control), NULL, /* timeout */ NULL, /* outputv */ NULL, /* ready_async */ - NULL, /* flush */ + IF_IMPL(ttysl_flush_tty), NULL, /* call */ NULL, /* event */ ERL_DRV_EXTENDED_MARKER, ERL_DRV_EXTENDED_MAJOR_VERSION, ERL_DRV_EXTENDED_MINOR_VERSION, 0, /* ERL_DRV_FLAGs */ - NULL, + NULL, /* handle2 */ NULL, /* process_exit */ IF_IMPL(ttysl_stop_select) }; @@ -296,8 +316,7 @@ static ErlDrvData ttysl_start(ErlDrvPort port, char* buf) return ERL_DRV_ERROR_GENERAL; } - /* Open the terminal and set the terminal */ - ttysl_out = fdopen(ttysl_fd, "w"); + SET_NONBLOCKING(ttysl_fd); #ifdef PRIMITIVE_UTF8_CHECK setlocale(LC_CTYPE, ""); /* Set international environment, @@ -400,12 +419,14 @@ static void ttysl_stop(ErlDrvData ttysl_data) stop_lbuf(); stop_termcap(); tty_reset(ttysl_fd); - driver_select(ttysl_port, (ErlDrvEvent)(UWord)ttysl_fd, ERL_DRV_READ|ERL_DRV_USE, 0); + driver_select(ttysl_port, (ErlDrvEvent)(UWord)ttysl_fd, + ERL_DRV_WRITE|ERL_DRV_READ|ERL_DRV_USE, 0); sys_sigset(SIGCONT, SIG_DFL); sys_sigset(SIGWINCH, SIG_DFL); } ttysl_port = (ErlDrvPort)-1; ttysl_fd = -1; + ttysl_terminate = 0; /* return TRUE; */ } @@ -650,6 +671,14 @@ static int check_buf_size(byte *s, int n) static void ttysl_from_erlang(ErlDrvData ttysl_data, char* buf, ErlDrvSizeT count) { + ErlDrvSizeT sz; + + sz = driver_sizeq(ttysl_port); + + putclen = count > TTY_BUFFSIZE ? TTY_BUFFSIZE : count; + putcbuf = driver_alloc_binary(putclen); + putcpos = 0; + if (lpos > MAXSIZE) put_chars((byte*)"\n", 1); @@ -678,10 +707,78 @@ static void ttysl_from_erlang(ErlDrvData ttysl_data, char* buf, ErlDrvSizeT coun /* Unknown op, just ignore. */ break; } - fflush(ttysl_out); + + driver_enq_bin(ttysl_port,putcbuf,0,putcpos); + + if (sz == 0) { + for (;;) { + int written, qlen; + SysIOVec *iov; + + iov = driver_peekq(ttysl_port,&qlen); + if (iov) + written = writev(ttysl_fd, iov, qlen > MAXIOV ? MAXIOV : qlen); + else + written = 0; + if (written < 0) { + if (errno == EAGAIN) { + driver_select(ttysl_port,(ErlDrvEvent)(long)ttysl_fd, + ERL_DRV_USE|ERL_DRV_WRITE,1); + break; + } else { + /* we ignore all other errors */ + break; + } + } else { + if (driver_deq(ttysl_port, written) == 0) + break; + } + } + } + return; /* TRUE; */ } +static void ttysl_to_tty(ErlDrvData ttysl_data, ErlDrvEvent fd) { + for (;;) { + int written, qlen; + SysIOVec *iov; + ErlDrvSizeT sz; + + iov = driver_peekq(ttysl_port,&qlen); + if (iov) + written = writev(ttysl_fd, iov, qlen > MAXIOV ? MAXIOV : qlen); + else + written = 0; + if (written < 0) { + if (errno == EAGAIN) { + break; + } else { + /* we ignore all other errors */ + } + } else { + sz = driver_deq(ttysl_port, written); + if (sz == 0) { + driver_select(ttysl_port,(ErlDrvEvent)(long)ttysl_fd, + ERL_DRV_WRITE,0); + if (ttysl_terminate) + /* flush has been called, which means we should terminate + when queue is empty. This will not send any exit + message */ + driver_failure_atom(ttysl_port, "normal"); + break; + } + } + } + + return; +} + +static void ttysl_flush_tty(ErlDrvData ttysl_data) { + ttysl_terminate = 1; + return; +} + static void ttysl_from_tty(ErlDrvData ttysl_data, ErlDrvEvent fd) { byte b[1024]; @@ -1070,7 +1167,14 @@ static int write_buf(Uint32 *s, int n) /* The basic procedure for outputting one character. */ static int outc(int c) { - return (int)putc(c, ttysl_out); + putcbuf->orig_bytes[putcpos++] = c; + if (putcpos == putclen) { + driver_enq_bin(ttysl_port,putcbuf,0,putclen); + putcpos = 0; + putclen = TTY_BUFFSIZE; + putcbuf = driver_alloc_binary(BUFSIZ); + } + return 1; } static int move_cursor(int from, int to) -- cgit v1.2.3 From 48083e54b502afb2768066394074d29423162dc8 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Thu, 26 Jun 2014 18:55:47 +0200 Subject: kernel,ssh: Add synchronous user_drv protocol Added a put_chars_sync to the protocol that can be used to talk to user_drv and made group use it. This is needed in order to guarantee that bytes has been pushed to the tty port when doing something like this: io:format("halting\n"),erlang:halt(0). Before this change the halting message could be lost in the message queue of the user_drv process, this is no longer possible. This commit also fixes ssh_cli as that plugs itself in as a user_drv process. OTP-12240 --- erts/emulator/drivers/unix/ttsl_drv.c | 36 ++++++++++++++++++++++++++++++++++ erts/emulator/drivers/win32/ttsl_drv.c | 16 +++++++++++++++ 2 files changed, 52 insertions(+) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/unix/ttsl_drv.c b/erts/emulator/drivers/unix/ttsl_drv.c index 73ce27c6ec..be2fee1f25 100644 --- a/erts/emulator/drivers/unix/ttsl_drv.c +++ b/erts/emulator/drivers/unix/ttsl_drv.c @@ -93,6 +93,7 @@ static volatile int cols_needs_update = FALSE; #define OP_INSC 2 #define OP_DELC 3 #define OP_BEEP 4 +#define OP_PUTC_SYNC 5 /* Control op */ #define CTRL_OP_GET_WINSIZE 100 #define CTRL_OP_GET_UNICODE_STATE 101 @@ -137,6 +138,7 @@ static Sint16 get_sint16(char*); static ErlDrvPort ttysl_port; static int ttysl_fd; static int ttysl_terminate = 0; +static int ttysl_send_ok = 0; static ErlDrvBinary *putcbuf; static int putcpos; static int putclen; @@ -683,6 +685,14 @@ static void ttysl_from_erlang(ErlDrvData ttysl_data, char* buf, ErlDrvSizeT coun put_chars((byte*)"\n", 1); switch (buf[0]) { + case OP_PUTC_SYNC: + /* Using sync means that we have to send an ok to the + controlling process for each command call. We delay + sending ok if the driver queue exceeds a certain size. + We do not set ourselves as a busy port, as this + could be very bad for user_drv, if it gets blocked on + the port_command. */ + /* fall through */ case OP_PUTC: DEBUGLOG(("OP: Putc(%lu)",(unsigned long) count-1)); if (check_buf_size((byte*)buf+1, count-1) == 0) @@ -736,6 +746,22 @@ static void ttysl_from_erlang(ErlDrvData ttysl_data, char* buf, ErlDrvSizeT coun } } + if (buf[0] == OP_PUTC_SYNC) { + if (driver_sizeq(ttysl_port) > TTY_BUFFSIZE && !ttysl_terminate) { + /* We delay sending the ack until the buffer has been consumed */ + ttysl_send_ok = 1; + } else { + ErlDrvTermData spec[] = { + ERL_DRV_PORT, driver_mk_port(ttysl_port), + ERL_DRV_ATOM, driver_mk_atom("ok"), + ERL_DRV_TUPLE, 2 + }; + ASSERT(ttysl_send_ok == 0); + erl_drv_output_term(driver_mk_port(ttysl_port), spec, + sizeof(spec) / sizeof(spec[0])); + } + } + return; /* TRUE; */ } @@ -758,6 +784,16 @@ static void ttysl_to_tty(ErlDrvData ttysl_data, ErlDrvEvent fd) { } } else { sz = driver_deq(ttysl_port, written); + if (sz < TTY_BUFFSIZE && ttysl_send_ok) { + ErlDrvTermData spec[] = { + ERL_DRV_PORT, driver_mk_port(ttysl_port), + ERL_DRV_ATOM, driver_mk_atom("ok"), + ERL_DRV_TUPLE, 2 + }; + ttysl_send_ok = 0; + erl_drv_output_term(driver_mk_port(ttysl_port), spec, + sizeof(spec) / sizeof(spec[0])); + } if (sz == 0) { driver_select(ttysl_port,(ErlDrvEvent)(long)ttysl_fd, ERL_DRV_WRITE,0); diff --git a/erts/emulator/drivers/win32/ttsl_drv.c b/erts/emulator/drivers/win32/ttsl_drv.c index 502cb58dfa..851c336a11 100644 --- a/erts/emulator/drivers/win32/ttsl_drv.c +++ b/erts/emulator/drivers/win32/ttsl_drv.c @@ -46,6 +46,7 @@ static int rows; /* Number of rows available. */ #define OP_INSC 2 #define OP_DELC 3 #define OP_BEEP 4 +#define OP_PUTC_SYNC 5 /* Control op */ #define CTRL_OP_GET_WINSIZE 100 @@ -458,6 +459,7 @@ static void ttysl_from_erlang(ErlDrvData ttysl_data, char* buf, ErlDrvSizeT coun switch (buf[0]) { case OP_PUTC: + case OP_PUTC_SYNC: DEBUGLOG(("OP: Putc(%I64u)",(unsigned long long)count-1)); if (check_buf_size((byte*)buf+1, count-1) == 0) return; @@ -481,6 +483,20 @@ static void ttysl_from_erlang(ErlDrvData ttysl_data, char* buf, ErlDrvSizeT coun /* Unknown op, just ignore. */ break; } + + if (buf[0] == OP_PUTC_SYNC) { + /* On windows we do a blocking write to the tty so we just + send the ack immidiately. If at some point in the future + someone has a problem with tty output being blocking + this has to be changed. */ + ErlDrvTermData spec[] = { + ERL_DRV_PORT, driver_mk_port(ttysl_port), + ERL_DRV_ATOM, driver_mk_atom("ok"), + ERL_DRV_TUPLE, 2 + }; + erl_drv_output_term(driver_mk_port(ttysl_port), spec, + sizeof(spec) / sizeof(spec[0])); + } return; } -- cgit v1.2.3 From b3e52c026ce4920e1a4e36ef98e5de94666e91ef Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 2 Dec 2014 17:37:13 +0100 Subject: erts: Add compile time assert ERTS_CT_ASSERT and usage --- erts/emulator/drivers/common/inet_drv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index db8a251fdd..c8b69b0a94 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -3948,9 +3948,9 @@ static int inet_init() if (0 != erl_drv_tsd_key_create("inet_buffer_stack_key", &buffer_stack_key)) goto error; - ASSERT(sizeof(struct in_addr) == 4); + ERTS_CT_ASSERT(sizeof(struct in_addr) == 4); # if defined(HAVE_IN6) && defined(AF_INET6) - ASSERT(sizeof(struct in6_addr) == 16); + ERTS_CT_ASSERT(sizeof(struct in6_addr) == 16); # endif INIT_ATOM(ok); @@ -3996,7 +3996,7 @@ static int inet_init() #ifdef HAVE_SCTP /* 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); + ERTS_CT_ASSERT(sizeof(sctp_assoc_t)==ASSOC_ID_LEN); # if defined(HAVE_SCTP_BINDX) p_sctp_bindx = sctp_bindx; # if defined(HAVE_SCTP_PEELOFF) -- cgit v1.2.3 From 6d49fd3d4d66237924912cc6e6ab3d2512fce728 Mon Sep 17 00:00:00 2001 From: Simon Cornish Date: Tue, 2 Dec 2014 13:01:54 -0800 Subject: Fix inet:getopts involving #sctp_paddrinfo{} Handle peer addresses that are unconfirmed (i.e. in state SCTP_UNCONFIRMED). Handle unknown states instead of using ASSERT --- erts/emulator/drivers/common/inet_drv.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index db8a251fdd..3fe5dac813 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -2890,6 +2890,9 @@ static ErlDrvTermData am_sctp_rtoinfo, /* Option names */ /* For #sctp_paddrinfo{}: */ am_active, am_inactive, +# if HAVE_DECL_SCTP_UNCONFIRMED + am_unconfirmed, +# endif /* For #sctp_status{}: */ # if HAVE_DECL_SCTP_EMPTY @@ -3919,7 +3922,10 @@ static void inet_init_sctp(void) { /* For #sctp_paddrinfo{}: */ INIT_ATOM(active); INIT_ATOM(inactive); - +# if HAVE_DECL_SCTP_UNCONFIRMED + INIT_ATOM(unconfirmed); +# endif + /* For #sctp_status{}: */ # if HAVE_DECL_SCTP_EMPTY INIT_ATOM(empty); @@ -7338,8 +7344,13 @@ static int load_paddrinfo (ErlDrvTermData * spec, int i, case SCTP_INACTIVE: i = LOAD_ATOM (spec, i, am_inactive); break; +# if HAVE_DECL_SCTP_UNCONFIRMED + case SCTP_UNCONFIRMED: + i = LOAD_ATOM (spec, i, am_unconfirmed); + break; +# endif default: - ASSERT(0); /* NB: SCTP_UNCONFIRMED modifier not yet supported */ + i = LOAD_ATOM (spec, i, am_undefined); } i = LOAD_INT (spec, i, pai->spinfo_cwnd); i = LOAD_INT (spec, i, pai->spinfo_srtt); -- cgit v1.2.3 From e2a600341324d2ce3689119f8fd61b248702d79f Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Fri, 5 Dec 2014 10:14:51 +0100 Subject: erts: Rename sys_sigset to sys_signal Also removed old legacy fallback that is no longer used --- erts/emulator/drivers/unix/ttsl_drv.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/unix/ttsl_drv.c b/erts/emulator/drivers/unix/ttsl_drv.c index be2fee1f25..a5960716f2 100644 --- a/erts/emulator/drivers/unix/ttsl_drv.c +++ b/erts/emulator/drivers/unix/ttsl_drv.c @@ -338,8 +338,8 @@ static ErlDrvData ttysl_start(ErlDrvPort port, char* buf) } #endif DEBUGLOG(("utf8_mode is %s\n",(utf8_mode) ? "on" : "off")); - sys_sigset(SIGCONT, cont); - sys_sigset(SIGWINCH, winch); + sys_signal(SIGCONT, cont); + sys_signal(SIGWINCH, winch); driver_select(port, (ErlDrvEvent)(UWord)ttysl_fd, ERL_DRV_READ|ERL_DRV_USE, 1); ttysl_port = port; @@ -423,8 +423,8 @@ static void ttysl_stop(ErlDrvData ttysl_data) tty_reset(ttysl_fd); driver_select(ttysl_port, (ErlDrvEvent)(UWord)ttysl_fd, ERL_DRV_WRITE|ERL_DRV_READ|ERL_DRV_USE, 0); - sys_sigset(SIGCONT, SIG_DFL); - sys_sigset(SIGWINCH, SIG_DFL); + sys_signal(SIGCONT, SIG_DFL); + sys_signal(SIGWINCH, SIG_DFL); } ttysl_port = (ErlDrvPort)-1; ttysl_fd = -1; @@ -1458,11 +1458,11 @@ static RETSIGTYPE suspend(int sig) exit(1); } - sys_sigset(sig, SIG_DFL); /* Set signal handler to default */ + sys_signal(sig, SIG_DFL); /* Set signal handler to default */ sys_sigrelease(sig); /* Allow 'sig' to come through */ kill(getpid(), sig); /* Send ourselves the signal */ sys_sigblock(sig); /* Reset to old mask */ - sys_sigset(sig, suspend); /* Reset signal handler */ + sys_signal(sig, suspend); /* Reset signal handler */ if (tty_set(ttysl_fd) < 0) { fprintf(stderr,"Can't set tty raw \n"); -- cgit v1.2.3 From d373dc49ae4c8a2d27dde23564bcaf2642cc46e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Mon, 12 Jan 2015 17:30:45 +0100 Subject: erts: Extend driver interface with emergency_close The intention of this callback is to close all sockets associated to a port. It is closed only on crashdumps. This will currently only be used for the epmd port. --- erts/emulator/drivers/common/inet_drv.c | 36 ++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 10 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index db8a251fdd..be02a4b243 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -268,14 +268,13 @@ static BOOL (WINAPI *fpSetHandleInformation)(HANDLE,DWORD,DWORD); #define sock_htonl(x) htonl((x)) #define sock_send(s,buf,len,flag) send((s),(buf),(len),(flag)) #define sock_sendv(s, vec, size, np, flag) \ - WSASend((s),(WSABUF*)(vec),\ - (size),(np),(flag),NULL,NULL) + WSASend((s),(WSABUF*)(vec),(size),(np),(flag),NULL,NULL) #define sock_recv(s,buf,len,flag) recv((s),(buf),(len),(flag)) #define sock_recvfrom(s,buf,blen,flag,addr,alen) \ - recvfrom((s),(buf),(blen),(flag),(addr),(alen)) + recvfrom((s),(buf),(blen),(flag),(addr),(alen)) #define sock_sendto(s,buf,blen,flag,addr,alen) \ - sendto((s),(buf),(blen),(flag),(addr),(alen)) + sendto((s),(buf),(blen),(flag),(addr),(alen)) #define sock_hostname(buf, len) gethostname((buf), (len)) #define sock_getservbyname(name,proto) getservbyname((name),(proto)) @@ -360,9 +359,9 @@ static ssize_t writev_fallback(int fd, const struct iovec *iov, int iovcnt, int #define sock_accept(s, addr, len) accept((s), (addr), (len)) #define sock_send(s,buf,len,flag) inet_send((s),(buf),(len),(flag)) #define sock_sendto(s,buf,blen,flag,addr,alen) \ - sendto((s),(buf),(blen),(flag),(addr),(alen)) + sendto((s),(buf),(blen),(flag),(addr),(alen)) #define sock_sendv(s, vec, size, np, flag) \ - (*(np) = writev_fallback((s), (struct iovec*)(vec), (size), (*(np)))) + (*(np) = writev_fallback((s), (struct iovec*)(vec), (size), (*(np)))) #define sock_sendmsg(s,msghdr,flag) sendmsg((s),(msghdr),(flag)) #define sock_open(af, type, proto) socket((af), (type), (proto)) @@ -1178,6 +1177,7 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData, unsigned int, static void tcp_inet_timeout(ErlDrvData); static void tcp_inet_process_exit(ErlDrvData, ErlDrvMonitor *); static void inet_stop_select(ErlDrvEvent, void*); +static void inet_emergency_close(ErlDrvData); #ifdef __WIN32__ static void tcp_inet_event(ErlDrvData, ErlDrvEvent); static void find_dynamic_functions(void); @@ -1288,7 +1288,8 @@ static struct erl_drv_entry tcp_inet_driver_entry = ERL_DRV_FLAG_USE_PORT_LOCKING|ERL_DRV_FLAG_SOFT_BUSY, NULL, tcp_inet_process_exit, - inet_stop_select + inet_stop_select, + inet_emergency_close }; @@ -1341,7 +1342,8 @@ static struct erl_drv_entry udp_inet_driver_entry = ERL_DRV_FLAG_USE_PORT_LOCKING, NULL, NULL, - inet_stop_select + inet_stop_select, + inet_emergency_close }; #endif @@ -1375,7 +1377,8 @@ static struct erl_drv_entry sctp_inet_driver_entry = ERL_DRV_FLAG_USE_PORT_LOCKING, NULL, NULL, /* process_exit */ - inet_stop_select + inet_stop_select, + inet_emergency_close }; #endif @@ -1421,7 +1424,7 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event); static int packet_inet_output(udp_descriptor* udesc, HANDLE event); #endif -/* convert descriptor poiner to inet_descriptor pointer */ +/* convert descriptor pointer to inet_descriptor pointer */ #define INETP(d) (&(d)->inet) #ifdef __OSE__ @@ -8204,6 +8207,19 @@ static void inet_stop(inet_descriptor* desc) FREE(desc); } +static void inet_emergency_close(ErlDrvData data) +{ + /* valid for any (UDP, TCP or SCTP) descriptor */ + tcp_descriptor* tcp_desc = (tcp_descriptor*)data; + inet_descriptor* desc = INETP(tcp_desc); + DEBUGF(("inet_emergency_close(%ld) {s=%d\r\n", + (long)desc->inet.port, desc->inet.s)); + if (desc->s != INVALID_SOCKET) { + sock_close(desc->s); + } +} + + static void set_default_msgq_limits(ErlDrvPort port) { ErlDrvSizeT q_high = INET_HIGH_MSGQ_WATERMARK; -- cgit v1.2.3 From 86d605807356f79f3484c36cba632ff88d4e2417 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Tue, 13 Jan 2015 12:13:43 +0100 Subject: erts: Use emergency close to close epmd Closes all open socket before writing crashdump to file. --- erts/emulator/drivers/common/inet_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index be02a4b243..33d37f8a6a 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -8213,7 +8213,7 @@ static void inet_emergency_close(ErlDrvData data) tcp_descriptor* tcp_desc = (tcp_descriptor*)data; inet_descriptor* desc = INETP(tcp_desc); DEBUGF(("inet_emergency_close(%ld) {s=%d\r\n", - (long)desc->inet.port, desc->inet.s)); + (long)desc->port, desc->s)); if (desc->s != INVALID_SOCKET) { sock_close(desc->s); } -- cgit v1.2.3 From 4d960f16d89c880507c951e1c74ac17e349f5dd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Thu, 29 Jan 2015 16:04:46 +0100 Subject: erts: Fix getifaddrs realloc ptr mismatch When a buffer was exhausted and subsequently a realloc, we could get an invalid pointer. For this to occur we would need to have a realloc to lower adresses. The symptom would be garbage returned from erlang:port_control(Port, 25, []) (prim_inet:getifaddrs(Port) resulting in a badarg) or a segmentation fault. --- erts/emulator/drivers/common/inet_drv.c | 53 ++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 8 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index db8a251fdd..ff155cc07c 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -4721,6 +4721,36 @@ static char* sockaddr_to_buf(struct sockaddr* addr, char* ptr, char* end) return NULL; } +/* sockaddr_bufsz_need + * Returns the number of bytes needed to store the information + * through sockaddr_to_buf + */ + +static size_t sockaddr_bufsz_need(struct sockaddr* addr) +{ + if (addr->sa_family == AF_INET || addr->sa_family == 0) { + return 1 + sizeof(struct in_addr); + } +#if defined(HAVE_IN6) && defined(AF_INET6) + else if (addr->sa_family == AF_INET6) { + return 1 + sizeof(struct in6_addr); + } +#endif +#if defined(AF_LINK) + if (addr->sa_family == AF_LINK) { + struct sockaddr_dl *sdl_p = (struct sockaddr_dl*) addr; + return 2 + sdl_p->sdl_alen; + } +#endif +#if defined(AF_PACKET) && defined(HAVE_NETPACKET_PACKET_H) + else if(addr->sa_family == AF_PACKET) { + struct sockaddr_ll *sll_p = (struct sockaddr_ll*) addr; + return 2 + sll_p->sll_halen; + } +#endif + return 0; +} + static char* buf_to_sockaddr(char* ptr, char* end, struct sockaddr* addr) { buf_check(ptr,end,1); @@ -5799,6 +5829,11 @@ done: } #elif defined(HAVE_GETIFADDRS) +#ifdef DEBUG +#define GETIFADDRS_BUFSZ (1) +#else +#define GETIFADDRS_BUFSZ (512) +#endif static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p, char **rbuf_pp, ErlDrvSizeT rsize) @@ -5809,15 +5844,15 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p, char *buf_p; char *buf_alloc_p; - buf_size = 512; - buf_alloc_p = ALLOC(buf_size); + buf_size = GETIFADDRS_BUFSZ; + buf_alloc_p = ALLOC(GETIFADDRS_BUFSZ); buf_p = buf_alloc_p; # define BUF_ENSURE(Size) \ do { \ int NEED_, GOT_ = buf_p - buf_alloc_p; \ NEED_ = GOT_ + (Size); \ if (NEED_ > buf_size) { \ - buf_size = NEED_ + 512; \ + buf_size = NEED_ + GETIFADDRS_BUFSZ; \ buf_alloc_p = REALLOC(buf_alloc_p, buf_size); \ buf_p = buf_alloc_p + GOT_; \ } \ @@ -5830,7 +5865,7 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p, while (! (P_ = sockaddr_to_buf((sa), buf_p, \ buf_alloc_p+buf_size))) { \ int GOT_ = buf_p - buf_alloc_p; \ - buf_size += 512; \ + buf_size += GETIFADDRS_BUFSZ; \ buf_alloc_p = REALLOC(buf_alloc_p, buf_size); \ buf_p = buf_alloc_p + GOT_; \ } \ @@ -5887,10 +5922,11 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p, || ifa_p->ifa_addr->sa_family == AF_PACKET #endif ) { - char *bp = buf_p; - BUF_ENSURE(1); - SOCKADDR_TO_BUF(INET_IFOPT_HWADDR, ifa_p->ifa_addr); - if (buf_p - bp < 4) buf_p = bp; /* Empty hwaddr */ + size_t need = sockaddr_bufsz_need(ifa_p->ifa_addr); + if (need > 3) { + BUF_ENSURE(1 + need); + SOCKADDR_TO_BUF(INET_IFOPT_HWADDR, ifa_p->ifa_addr); + } } #endif } @@ -5905,6 +5941,7 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p, return buf_size; # undef BUF_ENSURE } +#undef GETIFADDRS_BUFSZ #else -- cgit v1.2.3 From b24651c3bb6fef59c0e92c24e69151d1a92c4b08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=B5=D1=80=D0=B3=D0=B5=D0=B9=20=D0=9F=D1=80=D0=BE?= =?UTF-8?q?=D1=85=D0=BE=D1=80=D0=BE=D0=B2?= Date: Mon, 19 Jan 2015 05:06:53 +0300 Subject: Add zlib limited output buffer size functionality This functionality may be useful for compressed streams with high compression ratio (in case of gzip it may be up to x1000), when small amount of compressed data will produce large amount of uncompressed output. This may lead to DoS attacks, because server easily goes out of memory. Example of such high compression ratio stream: ``` dd if=/dev/zero of=sparse.bin bs=1MB count=100 # 100mb of zeroes gzip sparse.bin # 95kb sparse.bin.gz $ erl > {ok, Compressed} = file:read_file("sparse.bin.gz"), > 97082 = size(Compressed), > Uncompressed = zlib:gunzip(Compressed), > 100000000 = iolist_size(Uncompressed). ``` --- erts/emulator/drivers/common/zlib_drv.c | 73 +++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/zlib_drv.c b/erts/emulator/drivers/common/zlib_drv.c index 3143e4511d..f7b2d91d23 100644 --- a/erts/emulator/drivers/common/zlib_drv.c +++ b/erts/emulator/drivers/common/zlib_drv.c @@ -62,8 +62,17 @@ #define CRC32_COMBINE 23 #define ADLER32_COMBINE 24 +#define INFLATE_CHUNK 25 + + #define DEFAULT_BUFSZ 4000 +/* This flag is used in the same places, where zlib return codes + * (Z_OK, Z_STREAM_END, Z_NEED_DICT) are. So, we need to set it to + * relatively large value to avoid possible value clashes in future. + * */ +#define INFLATE_HAS_MORE 100 + static int zlib_init(void); static ErlDrvData zlib_start(ErlDrvPort port, char* buf); static void zlib_stop(ErlDrvData e); @@ -295,6 +304,58 @@ static int zlib_inflate(ZLibData* d, int flush) return res; } +static int zlib_inflate_chunk(ZLibData* d) +{ + int res = Z_OK; + + if ((d->bin == NULL) && (zlib_output_init(d) < 0)) { + errno = ENOMEM; + return Z_ERRNO; + } + + while ((driver_sizeq(d->port) > 0) && (d->s.avail_out > 0) && + (res != Z_STREAM_END)) { + int vlen; + SysIOVec* iov = driver_peekq(d->port, &vlen); + int len; + + d->s.next_in = iov[0].iov_base; + d->s.avail_in = iov[0].iov_len; + while((d->s.avail_in > 0) && (d->s.avail_out > 0) && (res != Z_STREAM_END)) { + res = inflate(&d->s, Z_NO_FLUSH); + if (res == Z_NEED_DICT) { + /* Essential to eat the header bytes that zlib has looked at */ + len = iov[0].iov_len - d->s.avail_in; + driver_deq(d->port, len); + return res; + } + if (res == Z_BUF_ERROR) { + /* Was possible more output, but actually not */ + res = Z_OK; + } + else if (res < 0) { + return res; + } + } + len = iov[0].iov_len - d->s.avail_in; + driver_deq(d->port, len); + } + + /* We are here because all input was consumed or EOS reached or output + * buffer is full */ + if (d->want_crc) { + d->crc = crc32(d->crc, (unsigned char*) d->bin->orig_bytes, + d->binsz - d->s.avail_out); + } + zlib_output(d); + if ((res == Z_OK) && (d->s.avail_in > 0)) + res = INFLATE_HAS_MORE; + else if (res == Z_STREAM_END) { + d->inflate_eos_seen = 1; + } + return res; +} + static int zlib_deflate(ZLibData* d, int flush) { int res = Z_OK; @@ -568,6 +629,18 @@ static ErlDrvSSizeT zlib_ctl(ErlDrvData drv_data, unsigned int command, char *bu return zlib_return(res, rbuf, rlen); } + case INFLATE_CHUNK: + if (d->state != ST_INFLATE) goto badarg; + if (len != 0) goto badarg; + res = zlib_inflate_chunk(d); + if (res == INFLATE_HAS_MORE) { + return zlib_value2(4, 0, rbuf, rlen); + } else if (res == Z_NEED_DICT) { + return zlib_value2(3, d->s.adler, rbuf, rlen); + } else { + return zlib_return(res, rbuf, rlen); + } + case GET_QSIZE: return zlib_value(driver_sizeq(d->port), rbuf, rlen); -- cgit v1.2.3 From 0989fd90d50ff95d291971f62ed4dde7f5fba911 Mon Sep 17 00:00:00 2001 From: Nick Mills Date: Sat, 14 Mar 2015 00:30:17 -0400 Subject: Remove unused time macros from efile_drv All uses of these macros were removed in commit c3a615aa2da09bc3a0575e973959f800460a63de. --- erts/emulator/drivers/common/efile_drv.c | 17 ----------------- 1 file changed, 17 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index b62e9a0306..3b8e7acb6e 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -264,23 +264,6 @@ dt_private *get_dt_private(int); -#define GET_TIME(i, b) \ - (i).year = get_int32((b) + 0 * 4); \ - (i).month = get_int32((b) + 1 * 4); \ - (i).day = get_int32((b) + 2 * 4); \ - (i).hour = get_int32((b) + 3 * 4); \ - (i).minute = get_int32((b) + 4 * 4); \ - (i).second = get_int32((b) + 5 * 4) - -#define PUT_TIME(i, b) \ - put_int32((i).year, (b) + 0 * 4); \ - put_int32((i).month, (b) + 1 * 4); \ - put_int32((i).day, (b) + 2 * 4); \ - put_int32((i).hour, (b) + 3 * 4); \ - put_int32((i).minute,(b) + 4 * 4); \ - put_int32((i).second,(b) + 5 * 4) - - #if ALWAYS_READ_LINE_AHEAD #define DEFAULT_LINEBUF_SIZE 2048 #else -- cgit v1.2.3 From 641003f0dd87c0f50b06c022a1d162fc04e96795 Mon Sep 17 00:00:00 2001 From: Nick Mills Date: Mon, 16 Mar 2015 14:43:46 -0400 Subject: Use the correct union member inside efile_drv The `invoke_pwritev()` function was in some places using the union member intended for the `invoke_writev()` function. --- erts/emulator/drivers/common/efile_drv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 3b8e7acb6e..8d4992c3f0 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -1695,9 +1695,9 @@ static void invoke_pwritev(void *data) { d->result_ok = 0; d->again = 0; deq_error: - MUTEX_LOCK(d->c.writev.q_mtx); + MUTEX_LOCK(d->c.pwritev.q_mtx); driver_deq(d->c.pwritev.port, c->size); - MUTEX_UNLOCK(d->c.writev.q_mtx); + MUTEX_UNLOCK(d->c.pwritev.q_mtx); goto done; } else { @@ -1708,9 +1708,9 @@ static void invoke_pwritev(void *data) { ASSERT(written >= FILE_SEGMENT_WRITE); } - MUTEX_LOCK(d->c.writev.q_mtx); + MUTEX_LOCK(d->c.pwritev.q_mtx); driver_deq(d->c.pwritev.port, written); - MUTEX_UNLOCK(d->c.writev.q_mtx); + MUTEX_UNLOCK(d->c.pwritev.q_mtx); done: EF_FREE(iov); /* Free our copy of the vector, nothing to restore */ -- cgit v1.2.3 From 7f6e9ab38d14cba1386cb91307258302702617b8 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 10 Apr 2015 17:12:56 +0200 Subject: erts: Cleanup code in invoke_pwritev --- erts/emulator/drivers/common/efile_drv.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 8d4992c3f0..518646649d 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -1616,12 +1616,12 @@ static void invoke_altname(void *data) } static void invoke_pwritev(void *data) { - struct t_data *d = (struct t_data *) data; + struct t_data* const d = (struct t_data *) data; + struct t_pwritev * const c = &d->c.pwritev; SysIOVec *iov0; SysIOVec *iov; int iovlen; int iovcnt; - struct t_pwritev *c = &d->c.pwritev; size_t p; int segment; size_t size, write_size, written; @@ -1695,9 +1695,9 @@ static void invoke_pwritev(void *data) { d->result_ok = 0; d->again = 0; deq_error: - MUTEX_LOCK(d->c.pwritev.q_mtx); - driver_deq(d->c.pwritev.port, c->size); - MUTEX_UNLOCK(d->c.pwritev.q_mtx); + MUTEX_LOCK(c->q_mtx); + driver_deq(c->port, c->size); + MUTEX_UNLOCK(c->q_mtx); goto done; } else { @@ -1708,9 +1708,9 @@ static void invoke_pwritev(void *data) { ASSERT(written >= FILE_SEGMENT_WRITE); } - MUTEX_LOCK(d->c.pwritev.q_mtx); - driver_deq(d->c.pwritev.port, written); - MUTEX_UNLOCK(d->c.pwritev.q_mtx); + MUTEX_LOCK(c->q_mtx); + driver_deq(c->port, written); + MUTEX_UNLOCK(c->q_mtx); done: EF_FREE(iov); /* Free our copy of the vector, nothing to restore */ -- cgit v1.2.3 From daaefc2fa63eb0c3fc8f6183ec1169733c2f2ea8 Mon Sep 17 00:00:00 2001 From: Stefan Grundmann Date: Thu, 23 Apr 2015 17:40:51 +0000 Subject: Fix FreeBSD sendfile check (nbytes == 0 && d->c.sendfile.nbytes == 0) when efile_sendfile returns 0 and has EAGAIN set. FreeBSD sendfile(2) man page: When using a socket marked for non-blocking I/O, sendfile() may send fewer bytes than requested. In this case, the number of bytes successfully written is returned in *sbytes (if specified), and the error EAGAIN is returned. The number of bytes successfully written can be 0. If this happens and in a request handling either file:sendfile/2 or file:sendfile/5 with Bytes=0, the sendfile loop will stop prematurely and file:sendfile will return {ok, BytesSent} where BytesSent < DataAfterOffset, effectively breaking sendfile support on FreeBSD. --- erts/emulator/drivers/common/efile_drv.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 518646649d..b2cfe70f94 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -1938,6 +1938,8 @@ static void invoke_sendfile(void *data) d->result_ok = 1; if (d->c.sendfile.nbytes != 0) d->c.sendfile.nbytes -= nbytes; + } else if (nbytes == 0 && d->c.sendfile.nbytes == 0) { + d->result_ok = 1; } else d->result_ok = 0; } else { -- cgit v1.2.3 From 25bd6312491fc9153a16f74b5d1d39609426ae60 Mon Sep 17 00:00:00 2001 From: Rory Byrne Date: Wed, 15 Apr 2015 17:28:09 +0100 Subject: Fix gen_tcp:shutdown/2 by making it asynchronous If the driver queue is empty, or the user is requesting a 'read' shutdown, then the shutdown() syscall is performed synchronously, as per the old version of shutdown/2. However, if the user is requesting a 'write' or 'read_write' shutdown, and there is data in the driver queue for the socket, then the shutdown() syscall is delayed and handled asynchronously when the driver queue is written out. This version of shutdown solves a number of issues with the old version. The two main solutions it offers are: * It doesn't block when the TCP peer is idle or slow. This is the expected behaviour when shutdown() is called: the caller needs to be able to continue reading from the socket, not be prevented from doing so. * It doesn't truncate the output. The current version of gen_tcp:shutdown/2 will truncate any outbound data in the driver queue after about 10 seconds if the TCP peer is idle of slow. Worse yet, it doesn't even inform anyone that the data has been truncated: 'ok' is returned to the caller; and a FIN rather than an RST is sent to the TCP peer. For a detailed description of all the problems with the old version of shutdown, please see the EEP Light that was written to justify this patch. --- erts/emulator/drivers/common/inet_drv.c | 58 +++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 3 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 5196eb51c6..e001f31932 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -293,6 +293,10 @@ static BOOL (WINAPI *fpSetHandleInformation)(HANDLE,DWORD,DWORD); static unsigned long zero_value = 0; static unsigned long one_value = 1; +#define TCP_SHUT_WR SD_SEND +#define TCP_SHUT_RD SD_RECEIVE +#define TCP_SHUT_RDWR SD_BOTH + #elif defined (__OSE__) /* @@ -421,6 +425,10 @@ typedef unsigned long u_long; inet_driver_select((d), (flags), (onoff)); \ } while(0) +#define TCP_SHUT_WR SHUT_WR +#define TCP_SHUT_RD SHUT_RD +#define TCP_SHUT_RDWR SHUT_RDWR + #else /* !__OSE__ && !__WIN32__ */ #include @@ -691,6 +699,9 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) inet_driver_select((d)->port, (ErlDrvEvent)(long)(d)->event, (flags), (onoff)); \ } while(0) +#define TCP_SHUT_WR SHUT_WR +#define TCP_SHUT_RD SHUT_RD +#define TCP_SHUT_RDWR SHUT_RDWR #endif /* !__WIN32__ && !__OSE__ */ @@ -820,6 +831,10 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #define TCP_ADDF_CLOSE_SENT 2 /* Close sent (active mode only) */ #define TCP_ADDF_DELAYED_CLOSE_RECV 4 /* If receive fails, report {error,closed} (passive mode) */ #define TCP_ADDF_DELAYED_CLOSE_SEND 8 /* If send fails, report {error,closed} (passive mode) */ +#define TCP_ADDF_PENDING_SHUT_WR 16 /* Call shutdown(sock, SHUT_WR) when queue empties */ +#define TCP_ADDF_PENDING_SHUT_RDWR 32 /* Call shutdown(sock, SHUT_RDWR) when queue empties */ +#define TCP_ADDF_PENDING_SHUTDOWN \ + (TCP_ADDF_PENDING_SHUT_WR | TCP_ADDF_PENDING_SHUT_RDWR) /* *_REQ_* replies */ #define INET_REP_ERROR 0 @@ -1407,6 +1422,8 @@ 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); +static int tcp_shutdown_error(tcp_descriptor* desc, int err); + static int tcp_inet_output(tcp_descriptor* desc, HANDLE event); static int tcp_inet_input(tcp_descriptor* desc, HANDLE event); @@ -9473,10 +9490,18 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, return ctl_error(EINVAL, rbuf, rsize); } how = buf[0]; - if (sock_shutdown(INETP(desc)->s, how) == 0) { + if (how != TCP_SHUT_RD && driver_sizeq(desc->inet.port) > 0) { + if (how == TCP_SHUT_WR) { + desc->tcp_add_flags |= TCP_ADDF_PENDING_SHUT_WR; + } else if (how == TCP_SHUT_RDWR) { + desc->tcp_add_flags |= TCP_ADDF_PENDING_SHUT_RDWR; + } return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); - } else { + } + if (IS_SOCKET_ERROR(sock_shutdown(INETP(desc)->s, how))) { return ctl_error(sock_errno(), rbuf, rsize); + } else { + return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); } } default: @@ -9613,6 +9638,8 @@ static void tcp_inet_commandv(ErlDrvData e, ErlIOVec* ev) else inet_reply_error(INETP(desc), ENOTCONN); } + else if (desc->tcp_add_flags & TCP_ADDF_PENDING_SHUTDOWN) + tcp_shutdown_error(desc, EPIPE); else if (tcp_sendv(desc, ev) == 0) inet_reply_ok(INETP(desc)); DEBUGF(("tcp_inet_commandv(%ld) }\r\n", (long)desc->inet.port)); @@ -10506,7 +10533,7 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event) return ret; } -static int tcp_send_error(tcp_descriptor* desc, int err) +static int tcp_send_or_shutdown_error(tcp_descriptor* desc, int err) { /* * If the port is busy, we must do some clean-up before proceeding. @@ -10563,6 +10590,16 @@ static int tcp_send_error(tcp_descriptor* desc, int err) return -1; } +static int tcp_send_error(tcp_descriptor* desc, int err) +{ + return tcp_send_or_shutdown_error(desc, err); +} + +static int tcp_shutdown_error(tcp_descriptor* desc, int err) +{ + return tcp_send_or_shutdown_error(desc, err); +} + /* ** Send non-blocking vector data */ @@ -10763,6 +10800,19 @@ static int tcp_send(tcp_descriptor* desc, char* ptr, ErlDrvSizeT len) return 0; } +/* shutdown on the socket: +** Assume caller has confirmed TCP_ADDF_PENDING_SHUTDOWN is set. +*/ +static void tcp_shutdown_async(tcp_descriptor* desc) +{ + int how; + + how = (desc->tcp_add_flags & TCP_ADDF_PENDING_SHUT_WR) ? + TCP_SHUT_WR : TCP_SHUT_RDWR; + if (IS_SOCKET_ERROR(sock_shutdown(INETP(desc)->s, how))) + tcp_shutdown_error(desc, sock_errno()); +} + #ifdef __OSE__ static void tcp_inet_drv_output_ose(ErlDrvData data, ErlDrvEvent event) @@ -10891,6 +10941,8 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event) if ((iov = driver_peekq(ix, &vsize)) == NULL) { sock_select(INETP(desc), FD_WRITE, 0); send_empty_out_q_msgs(INETP(desc)); + if (desc->tcp_add_flags & TCP_ADDF_PENDING_SHUTDOWN) + tcp_shutdown_async(desc); goto done; } vsize = vsize > MAX_VSIZE ? MAX_VSIZE : vsize; -- cgit v1.2.3 From 34b858c3e329918d530da882b594d2db727d3856 Mon Sep 17 00:00:00 2001 From: Rory Byrne Date: Thu, 14 May 2015 20:07:39 +0100 Subject: Fix add_multi_timer() in inet_drv Fix the sorting logic in add_multi_timer() and expand the test case coverage around this area. --- erts/emulator/drivers/common/inet_drv.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index e001f31932..10ef20fc82 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -12172,6 +12172,8 @@ static MultiTimerData *add_multi_timer(MultiTimerData **first, ErlDrvPort port, void (*timeout_fun)(ErlDrvData drv_data, ErlDrvTermData caller)) { +#define eq_mega(a, b) ((a)->when.megasecs == (b)->when.megasecs) +#define eq_sec(a, b) ((a)->when.secs == (b)->when.secs) MultiTimerData *mtd, *p, *s; mtd = ALLOC(sizeof(MultiTimerData)); absolute_timeout(timeout, &(mtd->when)); @@ -12183,23 +12185,17 @@ static MultiTimerData *add_multi_timer(MultiTimerData **first, ErlDrvPort port, break; } } - if (!p || p->when.megasecs > mtd->when.megasecs) { - goto found; - } - for (; p!= NULL; s = p, p = p->next) { + for (; p!= NULL && eq_mega(p, mtd); s = p, p = p->next) { if (p->when.secs >= mtd->when.secs) { break; } } - if (!p || p->when.secs > mtd->when.secs) { - goto found; - } - for (; p!= NULL; s = p, p = p->next) { + for (; p!= NULL && eq_mega(p, mtd) && eq_sec(p, mtd); s = p, p = p->next) { if (p->when.microsecs >= mtd->when.microsecs) { break; } } - found: + if (!p) { if (!s) { *first = mtd; @@ -12225,6 +12221,8 @@ static MultiTimerData *add_multi_timer(MultiTimerData **first, ErlDrvPort port, } return mtd; } +#undef eq_mega +#undef eq_sec -- cgit v1.2.3 From 4f63e427f1345b40b484ef16f6ff5e922bf14dac Mon Sep 17 00:00:00 2001 From: Rory Byrne Date: Mon, 20 Apr 2015 10:57:53 +0100 Subject: Add 'show_econnreset' TCP socket option An ECONNRESET is a socket error which tells us that a TCP peer has sent an RST. The RST indicates that they have aborted the connection and that the payload we have received should not be considered complete. Up until now, the implementation of TCP in inet_drv.c has hidden the receipt of the RST from the user, treating it as though it was just a FIN terminating the read side of the socket. There are many cases where user code needs to be able to distinguish between a socket that was closed normally and one that was aborted. Setting the option {show_econnreset, true} enables the user to receive ECONNRESET errors on both active and passive sockets. A connected socket returned from gen_tcp:accept/1 will inherit the show_econnreset setting of the listening socket. By default this option is set to {show_econnreset, false}. Note that this patch only enables the reporting of ECONNRESET when the socket is being read from. It does not report ECONNRESET (or EPIPE) when the user tries to write to a connection when an RST has already been received. Currently the TCP implementation in inet_drv.c hides all such send errors from the user in favour of returning {error, close}. A separate patch will be needed to enable the reporting of such errors. --- erts/emulator/drivers/common/inet_drv.c | 47 +++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index e001f31932..b5903f0c07 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -835,6 +835,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #define TCP_ADDF_PENDING_SHUT_RDWR 32 /* Call shutdown(sock, SHUT_RDWR) when queue empties */ #define TCP_ADDF_PENDING_SHUTDOWN \ (TCP_ADDF_PENDING_SHUT_WR | TCP_ADDF_PENDING_SHUT_RDWR) +#define TCP_ADDF_SHOW_ECONNRESET 64 /* Tell user about incoming RST */ /* *_REQ_* replies */ #define INET_REP_ERROR 0 @@ -879,6 +880,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #define INET_LOPT_MSGQ_HIWTRMRK 36 /* set local msgq high watermark */ #define INET_LOPT_MSGQ_LOWTRMRK 37 /* set local msgq low watermark */ #define INET_LOPT_NETNS 38 /* Network namespace pathname */ +#define INET_LOPT_TCP_SHOW_ECONNRESET 39 /* tell user about incoming RST */ /* SCTP options: a separate range, from 100: */ #define SCTP_OPT_RTOINFO 100 #define SCTP_OPT_ASSOCINFO 101 @@ -6255,6 +6257,16 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) continue; #endif + case INET_LOPT_TCP_SHOW_ECONNRESET: + if (desc->sprotocol == IPPROTO_TCP) { + tcp_descriptor* tdesc = (tcp_descriptor*) desc; + if (ival) + tdesc->tcp_add_flags |= TCP_ADDF_SHOW_ECONNRESET; + else + tdesc->tcp_add_flags &= ~TCP_ADDF_SHOW_ECONNRESET; + } + continue; + case INET_OPT_REUSEADDR: #ifdef __WIN32__ continue; /* Bjorn says */ @@ -7234,6 +7246,17 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc, continue; #endif + case INET_LOPT_TCP_SHOW_ECONNRESET: + if (desc->sprotocol == IPPROTO_TCP) { + tcp_descriptor* tdesc = (tcp_descriptor*) desc; + *ptr++ = opt; + ival = !!(tdesc->tcp_add_flags & TCP_ADDF_SHOW_ECONNRESET); + put_int32(ival, ptr); + } else { + TRUNCATE_TO(0,ptr); + } + continue; + case INET_OPT_PRIORITY: #ifdef SO_PRIORITY type = SO_PRIORITY; @@ -9077,6 +9100,11 @@ static tcp_descriptor* tcp_inet_copy(tcp_descriptor* desc,SOCKET s, copy_desc->low = desc->low; copy_desc->send_timeout = desc->send_timeout; copy_desc->send_timeout_close = desc->send_timeout_close; + + if (desc->tcp_add_flags & TCP_ADDF_SHOW_ECONNRESET) + copy_desc->tcp_add_flags |= TCP_ADDF_SHOW_ECONNRESET; + else + copy_desc->tcp_add_flags &= ~TCP_ADDF_SHOW_ECONNRESET; /* The new port will be linked and connected to the original caller */ port = driver_create_port(port, owner, "tcp_inet", (ErlDrvData) copy_desc); @@ -10014,7 +10042,10 @@ static int tcp_recv(tcp_descriptor* desc, int request_len) int err = sock_errno(); if (err == ECONNRESET) { DEBUGF((" => detected close (connreset)\r\n")); - return tcp_recv_closed(desc); + if (desc->tcp_add_flags & TCP_ADDF_SHOW_ECONNRESET) + return tcp_recv_error(desc, err); + else + return tcp_recv_closed(desc); } if (err == ERRNO_BLOCK) { DEBUGF((" => would block\r\n")); @@ -10226,7 +10257,19 @@ static void tcp_inet_event(ErlDrvData e, ErlDrvEvent event) if (netEv.lNetworkEvents & FD_CLOSE) { /* error in err = netEv.iErrorCode[FD_CLOSE_BIT] */ DEBUGF(("Detected close in %s, line %d\r\n", __FILE__, __LINE__)); - tcp_recv_closed(desc); + if (desc->tcp_add_flags & TCP_ADDF_SHOW_ECONNRESET) { + err = netEv.iErrorCode[FD_CLOSE_BIT]; + if (err == ECONNRESET) + tcp_recv_error(desc, err); + else if (err == ECONNABORTED && IS_CONNECTED(INETP(desc))) { + /* translate this error to ECONNRESET */ + tcp_recv_error(desc, ECONNRESET); + } + else + tcp_recv_closed(desc); + } + else + tcp_recv_closed(desc); } DEBUGF(("tcp_inet_event(%ld) }\r\n", (long)desc->inet.port)); return; -- cgit v1.2.3 From 0098eed847516cc6760d961421c83527816e35ae Mon Sep 17 00:00:00 2001 From: Rory Byrne Date: Sat, 2 May 2015 20:34:24 +0100 Subject: Apply 'show_econnreset' socket option to send errors as well Up till now all send errors have been translated into a generic {error, closed}. This patch allows {error, econnreset} to be returned on send errors when it is detected that the TCP peer has sent an RST. --- erts/emulator/drivers/common/inet_drv.c | 84 +++++++++++++++++++++++++++++---- 1 file changed, 76 insertions(+), 8 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index b5903f0c07..a8c58a8149 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -836,6 +836,8 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #define TCP_ADDF_PENDING_SHUTDOWN \ (TCP_ADDF_PENDING_SHUT_WR | TCP_ADDF_PENDING_SHUT_RDWR) #define TCP_ADDF_SHOW_ECONNRESET 64 /* Tell user about incoming RST */ +#define TCP_ADDF_DELAYED_ECONNRESET 128 /* An ECONNRESET error occured on send or shutdown */ +#define TCP_ADDF_SHUTDOWN_WR_DONE 256 /* A shutdown(sock, SHUT_WR) or SHUT_RDWR was made */ /* *_REQ_* replies */ #define INET_REP_ERROR 0 @@ -6140,7 +6142,12 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) desc->active_count = 0; if ((desc->stype == SOCK_STREAM) && (desc->active != INET_PASSIVE) && (desc->state == INET_STATE_CLOSED)) { - tcp_closed_message((tcp_descriptor *) desc); + tcp_descriptor *tdesc = (tcp_descriptor *) desc; + if (tdesc->tcp_add_flags & TCP_ADDF_DELAYED_ECONNRESET) { + tdesc->tcp_add_flags &= ~TCP_ADDF_DELAYED_ECONNRESET; + tcp_error_message(tdesc, ECONNRESET); + } + tcp_closed_message(tdesc); if (desc->exitf) { driver_exit(desc->port, 0); return 0; /* Give up on this socket, descriptor lost */ @@ -9466,7 +9473,11 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, if (desc->tcp_add_flags & TCP_ADDF_DELAYED_CLOSE_RECV) { desc->tcp_add_flags &= ~(TCP_ADDF_DELAYED_CLOSE_RECV| TCP_ADDF_DELAYED_CLOSE_SEND); - return ctl_reply(INET_REP_ERROR, "closed", 6, rbuf, rsize); + if (desc->tcp_add_flags & TCP_ADDF_DELAYED_ECONNRESET) { + desc->tcp_add_flags &= ~TCP_ADDF_DELAYED_ECONNRESET; + return ctl_reply(INET_REP_ERROR, "econnreset", 10, rbuf, rsize); + } else + return ctl_reply(INET_REP_ERROR, "closed", 6, rbuf, rsize); } return ctl_error(ENOTCONN, rbuf, rsize); } @@ -9527,6 +9538,8 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); } if (IS_SOCKET_ERROR(sock_shutdown(INETP(desc)->s, how))) { + if (how != TCP_SHUT_RD) + desc->tcp_add_flags |= TCP_ADDF_SHUTDOWN_WR_DONE; return ctl_error(sock_errno(), rbuf, rsize); } else { return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); @@ -9661,7 +9674,13 @@ static void tcp_inet_commandv(ErlDrvData e, ErlIOVec* ev) if (!IS_CONNECTED(INETP(desc))) { if (desc->tcp_add_flags & TCP_ADDF_DELAYED_CLOSE_SEND) { desc->tcp_add_flags &= ~TCP_ADDF_DELAYED_CLOSE_SEND; - inet_reply_error_am(INETP(desc), am_closed); + if (desc->tcp_add_flags & TCP_ADDF_DELAYED_ECONNRESET) { + /* Don't clear flag. Leave it enabled for the next receive + * operation. + */ + inet_reply_error(INETP(desc), ECONNRESET); + } else + inet_reply_error_am(INETP(desc), am_closed); } else inet_reply_error(INETP(desc), ENOTCONN); @@ -10578,6 +10597,9 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event) static int tcp_send_or_shutdown_error(tcp_descriptor* desc, int err) { + int show_econnreset = (err == ECONNRESET + && desc->tcp_add_flags & TCP_ADDF_SHOW_ECONNRESET); + /* * If the port is busy, we must do some clean-up before proceeding. */ @@ -10593,14 +10615,21 @@ static int tcp_send_or_shutdown_error(tcp_descriptor* desc, int err) /* * We used to handle "expected errors" differently from unexpected ones. - * Now we handle all errors in the same way. We just have to distinguish - * between passive and active sockets. + * Now we handle all errors in the same way (unless the show_econnreset + * socket option is enabled). We just have to distinguish between passive + * and active sockets. */ DEBUGF(("driver_failure_eof(%ld) in %s, line %d\r\n", (long)desc->inet.port, __FILE__, __LINE__)); if (desc->inet.active) { - tcp_closed_message(desc); - inet_reply_error_am(INETP(desc), am_closed); + if (show_econnreset) { + tcp_error_message(desc, err); + tcp_closed_message(desc); + inet_reply_error(INETP(desc), err); + } else { + tcp_closed_message(desc); + inet_reply_error_am(INETP(desc), am_closed); + } if (desc->inet.exitf) driver_exit(desc->inet.port, 0); else @@ -10612,7 +10641,10 @@ static int tcp_send_or_shutdown_error(tcp_descriptor* desc, int err) erl_inet_close(INETP(desc)); if (desc->inet.caller) { - inet_reply_error_am(INETP(desc), am_closed); + if (show_econnreset) + inet_reply_error(INETP(desc), err); + else + inet_reply_error_am(INETP(desc), am_closed); } else { /* No blocking send op to reply to right now. @@ -10629,12 +10661,46 @@ static int tcp_send_or_shutdown_error(tcp_descriptor* desc, int err) * in the receive operation. */ desc->tcp_add_flags |= TCP_ADDF_DELAYED_CLOSE_RECV; + + if (show_econnreset) { + /* Return {error, econnreset} instead of {error, closed} + * on send or receive operations. + */ + desc->tcp_add_flags |= TCP_ADDF_DELAYED_ECONNRESET; + } } return -1; } static int tcp_send_error(tcp_descriptor* desc, int err) { + /* EPIPE errors usually occur in one of three ways: + * 1. We write to a socket when we've already shutdown() the write side. On + * Windows the error returned for this is ESHUTDOWN rather than EPIPE. + * 2. The TCP peer sends us an RST through no fault of our own (perhaps + * by aborting the connection using SO_LINGER) and we then attempt + * to write to the socket. On Linux and Windows we would actually + * receive an ECONNRESET error for this, but on the BSDs, Darwin, + * Illumos and presumably Solaris, it's an EPIPE. + * 3. We cause the TCP peer to send us an RST by writing to a socket + * after we receive a FIN from them. Our first write will be + * successful, but if the they have closed the connection (rather + * than just shutting down the write side of it) this will cause their + * OS to send us an RST. Then, when we attempt to write to the socket + * a second time, we will get an EPIPE error. On Windows we get an + * ECONNABORTED. + * + * What we are going to do here is to treat all EPIPE messages that aren't + * of type 1 as ECONNRESET errors. This will allow users who have the + * show_econnreset socket option enabled to receive {error, econnreset} on + * both send and recv operations to indicate that an RST has been received. + */ +#ifdef __WIN_32__ + if (err == ECONNABORTED) + err = ECONNRESET; +#endif + if (err == EPIPE && !(desc->tcp_add_flags & TCP_ADDF_SHUTDOWN_WR_DONE)) + err = ECONNRESET; return tcp_send_or_shutdown_error(desc, err); } @@ -10854,6 +10920,8 @@ static void tcp_shutdown_async(tcp_descriptor* desc) TCP_SHUT_WR : TCP_SHUT_RDWR; if (IS_SOCKET_ERROR(sock_shutdown(INETP(desc)->s, how))) tcp_shutdown_error(desc, sock_errno()); + else + desc->tcp_add_flags |= TCP_ADDF_SHUTDOWN_WR_DONE; } #ifdef __OSE__ -- cgit v1.2.3 From eed21b4fd99c8ab71dcefd3802104186af1cb6b0 Mon Sep 17 00:00:00 2001 From: Rory Byrne Date: Thu, 16 Apr 2015 18:01:23 +0100 Subject: Fix socket option {linger, {true, 0}} to abort TCP connections Up until now, if {linger, {true, 0}} is set on the socket and there is data in the port driver queue, the connection is not aborted until the port queue is empty and close() is called on the underlying file descriptor. This bug allows an idle TCP client to prevent a server from terminating the connection and freeing resources. This patch fixes the problem by discarding the port queue if the socket is closed when {linger, {true, 0}} is set. --- erts/emulator/drivers/common/inet_drv.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index a8c58a8149..80cb705896 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -838,6 +838,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #define TCP_ADDF_SHOW_ECONNRESET 64 /* Tell user about incoming RST */ #define TCP_ADDF_DELAYED_ECONNRESET 128 /* An ECONNRESET error occured on send or shutdown */ #define TCP_ADDF_SHUTDOWN_WR_DONE 256 /* A shutdown(sock, SHUT_WR) or SHUT_RDWR was made */ +#define TCP_ADDF_LINGER_ZERO 512 /* Discard driver queue on port close */ /* *_REQ_* replies */ #define INET_REP_ERROR 0 @@ -6318,6 +6319,13 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) arg_sz = sizeof(li_val); DEBUGF(("inet_set_opts(%ld): s=%d, SO_LINGER=%d,%d", (long)desc->port, desc->s, li_val.l_onoff,li_val.l_linger)); + if (desc->sprotocol == IPPROTO_TCP) { + tcp_descriptor* tdesc = (tcp_descriptor*) desc; + if (li_val.l_onoff && li_val.l_linger == 0) + tdesc->tcp_add_flags |= TCP_ADDF_LINGER_ZERO; + else + tdesc->tcp_add_flags &= ~TCP_ADDF_LINGER_ZERO; + } break; case INET_OPT_PRIORITY: @@ -9699,6 +9707,8 @@ static void tcp_inet_flush(ErlDrvData e) /* Discard send queue to avoid hanging port (OTP-7615) */ tcp_clear_output(desc); } + if (desc->tcp_add_flags & TCP_ADDF_LINGER_ZERO) + tcp_clear_output(desc); } static void tcp_inet_process_exit(ErlDrvData e, ErlDrvMonitor *monitorp) -- cgit v1.2.3 From 738c34d4bb8f1a3811acd00af8c6c12107f8315b Mon Sep 17 00:00:00 2001 From: Bruce Yinhe Date: Thu, 18 Jun 2015 11:31:02 +0200 Subject: Change license text to APLv2 --- erts/emulator/drivers/common/efile_drv.c | 19 ++++++++++--------- erts/emulator/drivers/common/erl_efile.h | 19 ++++++++++--------- erts/emulator/drivers/common/gzio.h | 21 +++++++++++---------- erts/emulator/drivers/common/gzio_zutil.h | 21 +++++++++++---------- erts/emulator/drivers/common/inet_drv.c | 19 ++++++++++--------- erts/emulator/drivers/common/ram_file_drv.c | 19 ++++++++++--------- erts/emulator/drivers/common/zlib_drv.c | 19 ++++++++++--------- erts/emulator/drivers/ose/ose_efile.c | 19 ++++++++++--------- erts/emulator/drivers/ose/ose_signal_drv.c | 19 ++++++++++--------- erts/emulator/drivers/ose/ttsl_drv.c | 19 ++++++++++--------- erts/emulator/drivers/unix/bin_drv.c | 21 +++++++++++---------- erts/emulator/drivers/unix/multi_drv.c | 21 +++++++++++---------- erts/emulator/drivers/unix/sig_drv.c | 21 +++++++++++---------- erts/emulator/drivers/unix/ttsl_drv.c | 19 ++++++++++--------- erts/emulator/drivers/unix/unix_efile.c | 19 ++++++++++--------- erts/emulator/drivers/vxworks/vxworks_resolv.c | 21 +++++++++++---------- erts/emulator/drivers/win32/registry_drv.c | 21 +++++++++++---------- erts/emulator/drivers/win32/ttsl_drv.c | 21 +++++++++++---------- erts/emulator/drivers/win32/win_con.c | 21 +++++++++++---------- erts/emulator/drivers/win32/win_con.h | 21 +++++++++++---------- erts/emulator/drivers/win32/win_efile.c | 19 ++++++++++--------- 21 files changed, 220 insertions(+), 199 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index b2cfe70f94..8aff6c1865 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -3,16 +3,17 @@ * * Copyright Ericsson AB 1996-2013. All Rights Reserved. * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * * %CopyrightEnd% */ diff --git a/erts/emulator/drivers/common/erl_efile.h b/erts/emulator/drivers/common/erl_efile.h index 5a8e3bc5db..be5a891486 100644 --- a/erts/emulator/drivers/common/erl_efile.h +++ b/erts/emulator/drivers/common/erl_efile.h @@ -3,16 +3,17 @@ * * Copyright Ericsson AB 1997-2013. All Rights Reserved. * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * * %CopyrightEnd% */ diff --git a/erts/emulator/drivers/common/gzio.h b/erts/emulator/drivers/common/gzio.h index ea50d922ec..a6fe2fb6f5 100644 --- a/erts/emulator/drivers/common/gzio.h +++ b/erts/emulator/drivers/common/gzio.h @@ -3,16 +3,17 @@ * * Copyright Ericsson AB 1999-2009. All Rights Reserved. * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * * %CopyrightEnd% */ diff --git a/erts/emulator/drivers/common/gzio_zutil.h b/erts/emulator/drivers/common/gzio_zutil.h index 854205cc2c..9eefb86637 100644 --- a/erts/emulator/drivers/common/gzio_zutil.h +++ b/erts/emulator/drivers/common/gzio_zutil.h @@ -3,16 +3,17 @@ * * Copyright Ericsson AB 2009. All Rights Reserved. * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * * %CopyrightEnd% */ diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 119d6c097d..549de6503c 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -3,16 +3,17 @@ * * Copyright Ericsson AB 1997-2013. All Rights Reserved. * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * * %CopyrightEnd% */ diff --git a/erts/emulator/drivers/common/ram_file_drv.c b/erts/emulator/drivers/common/ram_file_drv.c index 7f7cd7cd91..9cb44d0b7e 100644 --- a/erts/emulator/drivers/common/ram_file_drv.c +++ b/erts/emulator/drivers/common/ram_file_drv.c @@ -3,16 +3,17 @@ * * 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 - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * * %CopyrightEnd% */ diff --git a/erts/emulator/drivers/common/zlib_drv.c b/erts/emulator/drivers/common/zlib_drv.c index f7b2d91d23..364048174c 100644 --- a/erts/emulator/drivers/common/zlib_drv.c +++ b/erts/emulator/drivers/common/zlib_drv.c @@ -3,16 +3,17 @@ * * Copyright Ericsson AB 2003-2013. All Rights Reserved. * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * * %CopyrightEnd% */ diff --git a/erts/emulator/drivers/ose/ose_efile.c b/erts/emulator/drivers/ose/ose_efile.c index 035ff81a9b..c8337a95d5 100644 --- a/erts/emulator/drivers/ose/ose_efile.c +++ b/erts/emulator/drivers/ose/ose_efile.c @@ -3,16 +3,17 @@ * * Copyright Ericsson AB 1997-2012. All Rights Reserved. * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * * %CopyrightEnd% */ diff --git a/erts/emulator/drivers/ose/ose_signal_drv.c b/erts/emulator/drivers/ose/ose_signal_drv.c index 4929b53856..2be9462a47 100644 --- a/erts/emulator/drivers/ose/ose_signal_drv.c +++ b/erts/emulator/drivers/ose/ose_signal_drv.c @@ -3,16 +3,17 @@ * * Copyright Ericsson AB 2013-2013. All Rights Reserved. * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * * %CopyrightEnd% */ diff --git a/erts/emulator/drivers/ose/ttsl_drv.c b/erts/emulator/drivers/ose/ttsl_drv.c index 8af2ce6af3..f759b47984 100644 --- a/erts/emulator/drivers/ose/ttsl_drv.c +++ b/erts/emulator/drivers/ose/ttsl_drv.c @@ -3,16 +3,17 @@ * * Copyright Ericsson AB 1996-2013. All Rights Reserved. * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * * %CopyrightEnd% */ diff --git a/erts/emulator/drivers/unix/bin_drv.c b/erts/emulator/drivers/unix/bin_drv.c index 1827187d57..21fb398907 100644 --- a/erts/emulator/drivers/unix/bin_drv.c +++ b/erts/emulator/drivers/unix/bin_drv.c @@ -3,16 +3,17 @@ * * Copyright Ericsson AB 1996-2009. All Rights Reserved. * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * * %CopyrightEnd% */ diff --git a/erts/emulator/drivers/unix/multi_drv.c b/erts/emulator/drivers/unix/multi_drv.c index 724d325ed5..7f8c2d9a0d 100644 --- a/erts/emulator/drivers/unix/multi_drv.c +++ b/erts/emulator/drivers/unix/multi_drv.c @@ -3,16 +3,17 @@ * * Copyright Ericsson AB 1996-2009. All Rights Reserved. * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * * %CopyrightEnd% */ diff --git a/erts/emulator/drivers/unix/sig_drv.c b/erts/emulator/drivers/unix/sig_drv.c index aab5d63a40..e6f2ecc494 100644 --- a/erts/emulator/drivers/unix/sig_drv.c +++ b/erts/emulator/drivers/unix/sig_drv.c @@ -3,16 +3,17 @@ * * Copyright Ericsson AB 1996-2009. All Rights Reserved. * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * * %CopyrightEnd% */ diff --git a/erts/emulator/drivers/unix/ttsl_drv.c b/erts/emulator/drivers/unix/ttsl_drv.c index a5960716f2..0f773b69fb 100644 --- a/erts/emulator/drivers/unix/ttsl_drv.c +++ b/erts/emulator/drivers/unix/ttsl_drv.c @@ -3,16 +3,17 @@ * * Copyright Ericsson AB 1996-2013. All Rights Reserved. * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * * %CopyrightEnd% */ diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c index 878beb055b..06ba986044 100644 --- a/erts/emulator/drivers/unix/unix_efile.c +++ b/erts/emulator/drivers/unix/unix_efile.c @@ -3,16 +3,17 @@ * * Copyright Ericsson AB 1997-2013. All Rights Reserved. * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * * %CopyrightEnd% */ diff --git a/erts/emulator/drivers/vxworks/vxworks_resolv.c b/erts/emulator/drivers/vxworks/vxworks_resolv.c index 8fcbb736f7..a7de53c692 100644 --- a/erts/emulator/drivers/vxworks/vxworks_resolv.c +++ b/erts/emulator/drivers/vxworks/vxworks_resolv.c @@ -3,16 +3,17 @@ * * Copyright Ericsson AB 1997-2009. All Rights Reserved. * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * * %CopyrightEnd% */ diff --git a/erts/emulator/drivers/win32/registry_drv.c b/erts/emulator/drivers/win32/registry_drv.c index e908c956ae..4e396aa8d9 100644 --- a/erts/emulator/drivers/win32/registry_drv.c +++ b/erts/emulator/drivers/win32/registry_drv.c @@ -3,16 +3,17 @@ * * Copyright Ericsson AB 1997-2013. All Rights Reserved. * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * * %CopyrightEnd% */ diff --git a/erts/emulator/drivers/win32/ttsl_drv.c b/erts/emulator/drivers/win32/ttsl_drv.c index 851c336a11..4bd766a8a8 100644 --- a/erts/emulator/drivers/win32/ttsl_drv.c +++ b/erts/emulator/drivers/win32/ttsl_drv.c @@ -3,16 +3,17 @@ * * Copyright Ericsson AB 1996-2013. All Rights Reserved. * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * * %CopyrightEnd% */ diff --git a/erts/emulator/drivers/win32/win_con.c b/erts/emulator/drivers/win32/win_con.c index 7b9cadd32b..0d63d46698 100644 --- a/erts/emulator/drivers/win32/win_con.c +++ b/erts/emulator/drivers/win32/win_con.c @@ -3,16 +3,17 @@ * * Copyright Ericsson AB 1997-2012. All Rights Reserved. * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * * %CopyrightEnd% */ diff --git a/erts/emulator/drivers/win32/win_con.h b/erts/emulator/drivers/win32/win_con.h index d46af86ca5..3f4e89a195 100644 --- a/erts/emulator/drivers/win32/win_con.h +++ b/erts/emulator/drivers/win32/win_con.h @@ -3,16 +3,17 @@ * * Copyright Ericsson AB 2007-2009. All Rights Reserved. * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * * %CopyrightEnd% */ diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c index 7e4043fc1b..d95f29f49d 100644 --- a/erts/emulator/drivers/win32/win_efile.c +++ b/erts/emulator/drivers/win32/win_efile.c @@ -3,16 +3,17 @@ * * Copyright Ericsson AB 1997-2014. All Rights Reserved. * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * * %CopyrightEnd% */ -- cgit v1.2.3 From 1c86a620d74f4f9383c4956dafd3e2486300dc0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Wed, 17 Jun 2015 17:33:29 +0200 Subject: erts: Remove HALFWORD_HEAP definition --- erts/emulator/drivers/common/efile_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 8aff6c1865..0317a95e8b 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -895,7 +895,7 @@ static void reply_Uint_posix_error(file_descriptor *desc, Uint num, TRACE_C('N'); response[0] = FILE_RESP_NUMERR; -#if SIZEOF_VOID_P == 4 || HALFWORD_HEAP +#if SIZEOF_VOID_P == 4 put_int32(0, response+1); #else put_int32(num>>32, response+1); @@ -964,7 +964,7 @@ static int reply_Uint(file_descriptor *desc, Uint result) { TRACE_C('R'); tmp[0] = FILE_RESP_NUMBER; -#if SIZEOF_VOID_P == 4 || HALFWORD_HEAP +#if SIZEOF_VOID_P == 4 put_int32(0, tmp+1); #else put_int32(result>>32, tmp+1); -- cgit v1.2.3 From c431a065ba515d27830f01c852f70940efb3003b Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Thu, 2 Jul 2015 11:13:32 +0200 Subject: ose: Remove all code related to the OSE port The OSE port is no longer supported and this commit removed it and any changes related to it. The things that were general improvements have been left in the code. --- erts/emulator/drivers/common/efile_drv.c | 6 - erts/emulator/drivers/common/inet_drv.c | 573 +------------- erts/emulator/drivers/ose/ose_efile.c | 1125 ---------------------------- erts/emulator/drivers/ose/ose_signal_drv.c | 897 ---------------------- erts/emulator/drivers/ose/ttsl_drv.c | 69 -- 5 files changed, 3 insertions(+), 2667 deletions(-) delete mode 100644 erts/emulator/drivers/ose/ose_efile.c delete mode 100644 erts/emulator/drivers/ose/ose_signal_drv.c delete mode 100644 erts/emulator/drivers/ose/ttsl_drv.c (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 0317a95e8b..2cb4662fc3 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -101,15 +101,9 @@ # include "config.h" #endif -#ifndef __OSE__ #include #include #include -#else -#include "ctype.h" -#include "sys/types.h" -#include "stdlib.h" -#endif /* Need (NON)BLOCKING macros for sendfile */ #ifndef WANT_NONBLOCKING diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 549de6503c..31b4b22081 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -94,10 +94,6 @@ typedef unsigned long long llu_t; #define INT16_MAX (32767) #endif -#ifdef __OSE__ -#include "inet.h" -#endif - #ifdef __WIN32__ #define STRNCASECMP strncasecmp @@ -298,139 +294,7 @@ static unsigned long one_value = 1; #define TCP_SHUT_RD SD_RECEIVE #define TCP_SHUT_RDWR SD_BOTH -#elif defined (__OSE__) - -/* - * Some notes about how inet (currently only tcp) works on OSE. - * The driver uses OSE signals to communicate with the one_inet - * process. Because of the difference in how signals and file descriptors - * work the whole select/deselect mechanic is very different. - * In ose when a sock_select is done a function is called. That function - * notes the changes that the driver want to do, but does not act on it. - * later when the function returns the new desired state is compared - * to the previous state and the apprioriate actions are taken. The action - * is usually to either request more data from the stack or stop requesting - * data. - * - * One thing to note is that the driver never does select/deselect. It always - * listens for the signals. Flow of data is regulated by sending or not sending - * signals to the ose inet process. - * - * The interesting functions to look at are: - * * inet_driver_select : called when sock_select is called - * * tcp_inet_ose_dispatch_signal : checks state changes and sends new signals - * * tcp_inet_drv_output_ose : ready output callback, reads signals and calls - * dispatch_signal - * * tcp_inet_drv_input_ose : ready input callback. - */ - -#include "efs.h" -#include "sys/socket.h" -#include "sys/uio.h" -#include "sfk/sys/sfk_uio.h" -#include "netinet/in.h" -#include "netinet/tcp.h" -#include "netdb.h" -#include "ose_spi/socket.sig" - - -static ssize_t writev_fallback(int fd, const struct iovec *iov, int iovcnt, int max_sz); - -#define INVALID_SOCKET -1 -#define INVALID_EVENT -1 -#define SOCKET_ERROR -1 - -#define SOCKET int -#define HANDLE int -#define FD_READ ERL_DRV_READ -#define FD_WRITE ERL_DRV_WRITE -#define FD_CLOSE 0 -#define FD_CONNECT (1<<4) -#define FD_ACCEPT (1<<5) -#define SOCK_FD_ERROR (1<<6) - -#define sock_connect(s, addr, len) connect((s), (addr), (len)) -#define sock_listen(s, b) listen((s), (b)) -#define sock_bind(s, addr, len) bind((s), (addr), (len)) -#define sock_getopt(s,t,n,v,l) getsockopt((s),(t),(n),(v),(l)) -#define sock_setopt(s,t,n,v,l) setsockopt((s),(t),(n),(v),(l)) -#define sock_name(s, addr, len) getsockname((s), (addr), (len)) -#define sock_peer(s, addr, len) getpeername((s), (addr), (len)) -#define sock_ntohs(x) ntohs((x)) -#define sock_ntohl(x) ntohl((x)) -#define sock_htons(x) htons((x)) -#define sock_htonl(x) htonl((x)) - -#define sock_accept(s, addr, len) accept((s), (addr), (len)) -#define sock_send(s,buf,len,flag) inet_send((s),(buf),(len),(flag)) -#define sock_sendto(s,buf,blen,flag,addr,alen) \ - sendto((s),(buf),(blen),(flag),(addr),(alen)) -#define sock_sendv(s, vec, size, np, flag) \ - (*(np) = writev_fallback((s), (struct iovec*)(vec), (size), (*(np)))) -#define sock_sendmsg(s,msghdr,flag) sendmsg((s),(msghdr),(flag)) - -#define sock_open(af, type, proto) socket((af), (type), (proto)) -#define sock_close(s) close((s)) -#define sock_dup(s) dup((s)) -#define sock_shutdown(s, how) shutdown((s), (how)) - -#define sock_hostname(buf, len) gethostname((buf), (len)) -#define sock_getservbyname(name,proto) getservbyname((name), (proto)) -#define sock_getservbyport(port,proto) getservbyport((port), (proto)) - -#define sock_recv(s,buf,len,flag) recv((s),(buf),(len),(flag)) -#define sock_recvfrom(s,buf,blen,flag,addr,alen) \ - recvfrom((s),(buf),(blen),(flag),(addr),(alen)) -#define sock_recvmsg(s,msghdr,flag) recvmsg((s),(msghdr),(flag)) - -#define sock_errno() errno -#define sock_create_event(d) ((d)->s) /* return file descriptor */ -#define sock_close_event(e) /* do nothing */ - -#ifndef WANT_NONBLOCKING -#define WANT_NONBLOCKING -#endif -#include "sys.h" - -typedef unsigned long u_long; -#define IN_CLASSA(a) ((((in_addr_t)(a)) & 0x80000000) == 0) -#define IN_CLASSA_NET 0xff000000 -#define IN_CLASSA_NSHIFT 24 -#define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET) -#define IN_CLASSA_MAX 128 - -#define IN_CLASSB(a) ((((in_addr_t)(a)) & 0xc0000000) == 0x80000000) -#define IN_CLASSB_NET 0xffff0000 -#define IN_CLASSB_NSHIFT 16 -#define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET) -#define IN_CLASSB_MAX 65536 - -#define IN_CLASSC(a) ((((in_addr_t)(a)) & 0xe0000000) == 0xc0000000) -#define IN_CLASSC_NET 0xffffff00 -#define IN_CLASSC_NSHIFT 8 -#define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET) - -#define IN_CLASSD(a) ((((in_addr_t)(a)) & 0xf0000000) == 0xe0000000) -#define IN_MULTICAST(a) IN_CLASSD(a) - -#define IN_EXPERIMENTAL(a) ((((in_addr_t)(a)) & 0xe0000000) == 0xe0000000) -#define IN_BADCLASS(a) ((((in_addr_t)(a)) & 0xf0000000) == 0xf0000000) - -#define sock_select(d, flags, onoff) do { \ - ASSERT(!(d)->is_ignored); \ - (d)->event_mask = (onoff) ? \ - ((d)->event_mask | (flags)) : \ - ((d)->event_mask & ~(flags)); \ - DEBUGF(("(%s / %d) sock_select(%ld): flags=%02X, onoff=%d, event_mask=%02lX, s=%d\r\n", \ - __FILE__, __LINE__, (long) (d)->port, (flags), (onoff), (unsigned long) (d)->event_mask, (d)->s)); \ - inet_driver_select((d), (flags), (onoff)); \ - } while(0) - -#define TCP_SHUT_WR SHUT_WR -#define TCP_SHUT_RD SHUT_RD -#define TCP_SHUT_RDWR SHUT_RDWR - -#else /* !__OSE__ && !__WIN32__ */ +#else /* !__WIN32__ */ #include #ifdef NETDB_H_NEEDS_IN_H @@ -704,7 +568,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #define TCP_SHUT_RD SHUT_RD #define TCP_SHUT_RDWR SHUT_RDWR -#endif /* !__WIN32__ && !__OSE__ */ +#endif /* !__WIN32__ */ #ifdef HAVE_SOCKLEN_T # define SOCKLEN_T socklen_t @@ -1166,13 +1030,6 @@ typedef struct { char *netns; /* Socket network namespace name as full file path */ #endif -#ifdef __OSE__ - int select_state; /* state to keep track of whether we - should trigger another read/write - request at end of ready_input/output */ - ErlDrvEvent events[6]; -#endif - } inet_descriptor; @@ -1188,10 +1045,8 @@ static void tcp_inet_stop(ErlDrvData); static void tcp_inet_command(ErlDrvData, char*, ErlDrvSizeT); static void tcp_inet_commandv(ErlDrvData, ErlIOVec*); static void tcp_inet_flush(ErlDrvData drv_data); -#ifndef __OSE__ static void tcp_inet_drv_input(ErlDrvData, ErlDrvEvent); static void tcp_inet_drv_output(ErlDrvData data, ErlDrvEvent event); -#endif static ErlDrvData tcp_inet_start(ErlDrvPort, char* command); static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData, unsigned int, char*, ErlDrvSizeT, char**, ErlDrvSizeT); @@ -1204,71 +1059,6 @@ static void tcp_inet_event(ErlDrvData, ErlDrvEvent); static void find_dynamic_functions(void); #endif -#ifdef __OSE__ -/* The structure of the signal used for requesting asynchronous - * notification from the stack. Under normal circumstances the network stack - * shouldn't overwrite the value set in the fd field by the sender - * of the request */ -struct OseAsyncSig { - struct FmEvent event; - int fd; -}; - -union SIGNAL { - SIGSELECT signo; - struct OseAsyncSig async; -}; - -static ErlDrvSSizeT tcp_inet_ctl_ose(ErlDrvData e, unsigned int cmd, - char* buf, ErlDrvSizeT len, - char** rbuf, ErlDrvSizeT rsize); -static void tcp_inet_commandv_ose(ErlDrvData e, ErlIOVec* ev); -static void tcp_inet_drv_output_ose(ErlDrvData data, ErlDrvEvent event); -static void tcp_inet_drv_input_ose(ErlDrvData data, ErlDrvEvent event); -static ErlDrvOseEventId inet_resolve_signal(union SIGNAL *sig); - -#ifdef INET_DRV_DEBUG - -static char *read_req = "SO_EVENT_READ_REQUEST"; -static char *read_rep = "SO_EVENT_READ_REPLY"; -static char *write_req = "SO_EVENT_WRITE_REQUEST"; -static char *write_rep = "SO_EVENT_WRITE_REPLY"; -static char *eof_req = "SO_EVENT_EOF_REQUEST"; -static char *eof_rep = "SO_EVENT_EOF_REPLY"; -static char *accept_req = "SO_EVENT_ACCEPT_REQUEST"; -static char *accept_rep = "SO_EVENT_ACCEPT_REPLY"; -static char *connect_req = "SO_EVENT_CONNECT_REQUEST"; -static char *connect_rep = "SO_EVENT_CONNECT_REPLY"; -static char *error_req = "SO_EVENT_ERROR_REQUEST"; -static char *error_rep = "SO_EVENT_ERROR_REPLY"; -static char signo_tmp[32]; - -static char *signo_to_string(SIGSELECT signo) { - switch (signo) { - case SO_EVENT_READ_REQUEST: { return read_req; } - case SO_EVENT_READ_REPLY: { return read_rep; } - case SO_EVENT_WRITE_REQUEST: { return write_req; } - case SO_EVENT_WRITE_REPLY: { return write_rep; } - case SO_EVENT_EOF_REQUEST: { return eof_req; } - case SO_EVENT_EOF_REPLY: { return eof_rep; } - case SO_EVENT_ACCEPT_REQUEST: { return accept_req; } - case SO_EVENT_ACCEPT_REPLY: { return accept_rep; } - case SO_EVENT_CONNECT_REQUEST: { return connect_req; } - case SO_EVENT_CONNECT_REPLY: { return connect_rep; } - case SO_EVENT_ERROR_REQUEST: { return error_req; } - case SO_EVENT_ERROR_REPLY: { return error_rep; } - } - - snprintf(signo_tmp,32,"0x%x",signo); - - return signo_tmp; -} - -#endif - -#endif /* __OSE__ */ - - static struct erl_drv_entry tcp_inet_driver_entry = { tcp_inet_init, /* inet_init will add this driver !! */ @@ -1278,9 +1068,6 @@ static struct erl_drv_entry tcp_inet_driver_entry = #ifdef __WIN32__ tcp_inet_event, NULL, -#elif defined(__OSE__) - tcp_inet_drv_input_ose, /*ready_input*/ - tcp_inet_drv_output_ose, /*ready_output*/ #else tcp_inet_drv_input, tcp_inet_drv_output, @@ -1288,17 +1075,9 @@ static struct erl_drv_entry tcp_inet_driver_entry = "tcp_inet", NULL, NULL, -#ifdef __OSE__ - tcp_inet_ctl_ose, -#else tcp_inet_ctl, -#endif tcp_inet_timeout, -#ifdef __OSE__ - tcp_inet_commandv_ose, -#else tcp_inet_commandv, -#endif NULL, tcp_inet_flush, NULL, @@ -1450,14 +1229,6 @@ static int packet_inet_output(udp_descriptor* udesc, HANDLE event); /* convert descriptor pointer to inet_descriptor pointer */ #define INETP(d) (&(d)->inet) -#ifdef __OSE__ -static void inet_driver_select(inet_descriptor* desc, - int flags, int onoff); -static void tcp_inet_ose_dispatch_signals(tcp_descriptor *desc, - int prev_select_state, - union SIGNAL *sig); -#endif - static int async_ref = 0; /* async reference id generator */ #define NEW_ASYNC_ID() ((async_ref++) & 0xffff) @@ -4353,16 +4124,6 @@ static void desc_close(inet_descriptor* desc) desc->forced_events = 0; desc->send_would_block = 0; #endif -#ifdef __OSE__ - if (desc->events[0]) { - driver_select(desc->port,desc->events[0],FD_READ|FD_WRITE|ERL_DRV_USE,0); - driver_select(desc->port,desc->events[1],FD_READ|FD_WRITE|ERL_DRV_USE,0); - driver_select(desc->port,desc->events[2],FD_READ|FD_WRITE|ERL_DRV_USE,0); - driver_select(desc->port,desc->events[3],FD_READ|FD_WRITE|ERL_DRV_USE,0); - driver_select(desc->port,desc->events[4],FD_READ|FD_WRITE|ERL_DRV_USE,0); - driver_select(desc->port,desc->events[5],FD_READ|FD_WRITE|ERL_DRV_USE,0); - } -#else /* * We should close the fd here, but the other driver might still * be selecting on it. @@ -4372,7 +4133,6 @@ static void desc_close(inet_descriptor* desc) ERL_DRV_USE, 0); else inet_stop_select((ErlDrvEvent)(long)desc->event,NULL); -#endif desc->event = INVALID_EVENT; /* closed by stop_select callback */ desc->s = INVALID_SOCKET; desc->event_mask = 0; @@ -4414,65 +4174,6 @@ static int erl_inet_close(inet_descriptor* desc) return 0; } -#ifdef __OSE__ -static void inet_select_init(inet_descriptor* desc) -{ - desc->events[0] = - erl_drv_ose_event_alloc(SO_EVENT_READ_REPLY, - desc->s, - inet_resolve_signal, - NULL); - driver_select(desc->port, desc->events[0], - ERL_DRV_READ|ERL_DRV_USE, 1); - - desc->events[1] = - erl_drv_ose_event_alloc(SO_EVENT_EOF_REPLY, - desc->s, - inet_resolve_signal, - NULL); - driver_select(desc->port, desc->events[1], - ERL_DRV_READ|ERL_DRV_USE, 1); - - desc->events[2] = - erl_drv_ose_event_alloc(SO_EVENT_ACCEPT_REPLY, - desc->s, - inet_resolve_signal, - NULL); - driver_select(desc->port, desc->events[2], - ERL_DRV_READ|ERL_DRV_USE, 1); - - /* trigger tcp_inet_input */ - desc->events[3] = - erl_drv_ose_event_alloc(SO_EVENT_WRITE_REPLY, - desc->s, - inet_resolve_signal, - NULL); - driver_select(desc->port, desc->events[3], - ERL_DRV_WRITE|ERL_DRV_USE, 1); - - desc->events[4] = - erl_drv_ose_event_alloc(SO_EVENT_CONNECT_REPLY, - desc->s, - inet_resolve_signal, - NULL); - driver_select(desc->port, desc->events[4], - ERL_DRV_WRITE|ERL_DRV_USE, 1); - - desc->events[5] = - erl_drv_ose_event_alloc(SO_EVENT_ERROR_REPLY, - desc->s, - inet_resolve_signal, - NULL); - driver_select(desc->port, desc->events[5], - ERL_DRV_WRITE|ERL_DRV_USE, 1); - - /* Issue a select on error event before any other select to be sure we are - prepared to receive error notifications from the stack, even in the - situations when select isn't issued */ - sock_select(desc, SOCK_FD_ERROR, 1); -} -#endif - static ErlDrvSSizeT inet_ctl_open(inet_descriptor* desc, int domain, int type, char** rbuf, ErlDrvSizeT rsize) { @@ -4555,9 +4256,6 @@ static ErlDrvSSizeT inet_ctl_open(inet_descriptor* desc, int domain, int type, #ifdef __WIN32__ driver_select(desc->port, desc->event, ERL_DRV_READ, 1); #endif -#ifdef __OSE__ - inet_select_init(desc); -#endif desc->state = INET_STATE_OPEN; desc->stype = type; @@ -4581,13 +4279,7 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type, if (name.sa.sa_family != domain) return ctl_error(EINVAL, rbuf, rsize); } -#ifdef __OSE__ - /* for fdopen duplicating the sd will allow to uniquely identify - the signal from OSE with erlang port */ - desc->s = sock_dup(s); -#else desc->s = s; -#endif if ((desc->event = sock_create_event(desc)) == INVALID_EVENT) return ctl_error(sock_errno(), rbuf, rsize); @@ -4605,12 +4297,6 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type, sz = sizeof(name); if (!IS_SOCKET_ERROR(sock_peer(s, (struct sockaddr*) &name, &sz))) { desc->state = INET_STATE_CONNECTED; -#ifdef __OSE__ - /* since we are dealing with different descriptors (i.e. inet and - socket) the select part should be initialized with the right - values */ - inet_select_init(desc); -#endif } } @@ -8404,15 +8090,6 @@ static ErlDrvData inet_start(ErlDrvPort port, int size, int protocol) #ifdef HAVE_SETNS desc->netns = NULL; #endif -#ifdef __OSE__ - desc->select_state = 0; - desc->events[0] = NULL; - desc->events[1] = NULL; - desc->events[2] = NULL; - desc->events[3] = NULL; - desc->events[4] = NULL; - desc->events[5] = NULL; -#endif return (ErlDrvData)desc; } @@ -9139,10 +8816,6 @@ static tcp_descriptor* tcp_inet_copy(tcp_descriptor* desc,SOCKET s, copy_desc->inet.port = port; copy_desc->inet.dport = driver_mk_port(port); -#ifdef __OSE__ - inet_select_init(©_desc->inet); -#endif - *err = 0; return copy_desc; } @@ -9204,23 +8877,6 @@ static void tcp_inet_stop(ErlDrvData e) inet_stop(INETP(desc)); } -#ifdef __OSE__ - -static ErlDrvSSizeT tcp_inet_ctl_ose(ErlDrvData e, unsigned int cmd, - char* buf, ErlDrvSizeT len, - char** rbuf, ErlDrvSizeT rsize) { - - tcp_descriptor* desc = (tcp_descriptor*)e; - int prev_select_state = INETP(desc)->select_state; - - ErlDrvSSizeT res = tcp_inet_ctl(e,cmd,buf,len,rbuf,rsize); - - tcp_inet_ose_dispatch_signals((tcp_descriptor*)e,prev_select_state,NULL); - - return res; -} -#endif - /* TCP requests from Erlang */ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, ErlDrvSizeT len, @@ -9662,17 +9318,6 @@ static void tcp_inet_command(ErlDrvData e, char *buf, ErlDrvSizeT len) DEBUGF(("tcp_inet_command(%ld) }\r\n", (long)desc->inet.port)); } -#ifdef __OSE__ - -static void tcp_inet_commandv_ose(ErlDrvData e, ErlIOVec* ev) { - int prev_select_state = INETP((tcp_descriptor*)e)->select_state; - tcp_inet_commandv(e, ev); - tcp_inet_ose_dispatch_signals((tcp_descriptor*)e,prev_select_state,NULL); -} - -#endif - - static void tcp_inet_commandv(ErlDrvData e, ErlIOVec* ev) { tcp_descriptor* desc = (tcp_descriptor*)e; @@ -9745,22 +9390,6 @@ static void inet_stop_select(ErlDrvEvent event, void* _) { #ifdef __WIN32__ WSACloseEvent((HANDLE)event); -#elif defined(__OSE__) - ErlDrvOseEventId id; - union SIGNAL *sig; - erl_drv_ose_event_fetch(event, NULL, &id,NULL); - DEBUGF(("inet_stop_select(?#?) {s=%d\n",id)); - sock_close((int)id); - /* On socket close all the signals waiting to be processed as part of the - select should be deallocated */ - while((sig = erl_drv_ose_get_signal(event))) { - DEBUGF(("inet_stop_select(?#?): Freeing signal %s\n", - signo_to_string(sig->signo))); - free_buf(&sig); - } - erl_drv_ose_event_free(event); - DEBUGF(("inet_stop_select(?#?) }\n")); - #else sock_close((SOCKET)(long)event); #endif @@ -10309,146 +9938,7 @@ static void tcp_inet_event(ErlDrvData e, ErlDrvEvent event) return; } -#elif defined(__OSE__) /* !__WIN32__ */ -/* The specific resolve signal function. It will return the socket descriptor - for which the select was issued */ -static ErlDrvOseEventId inet_resolve_signal(union SIGNAL *sig) { - DEBUGF(("%s(?#?): s=%d got signal %s, status = %d, extra = %d, sender = 0x%x\n", - __FUNCTION__,sig->async.fd,signo_to_string(sig->signo), - sig->async.event.status, - sig->async.event.extra,sender(&sig))); - if (sig->signo == SO_EVENT_READ_REPLY || - sig->signo == SO_EVENT_ACCEPT_REPLY || - sig->signo == SO_EVENT_EOF_REPLY || - sig->signo == SO_EVENT_WRITE_REPLY || - sig->signo == SO_EVENT_ERROR_REPLY || - sig->signo == SO_EVENT_CONNECT_REPLY ) { - return sig->async.fd; - } - - return -1; -} - -static void inet_driver_select(inet_descriptor* desc, - int flags, int onoff) { - ASSERT(!desc->is_ignored); - - if(onoff) { - desc->select_state |= flags; - } else { - desc->select_state &= ~flags; - } -} - -static ssize_t writev_fallback(int fd, const struct iovec *iov, int iovcnt, int max_sz) -{ - size_t data_len = 0; - size_t sent = 0; - ssize_t n; - int i; - - for(i = 0; i < iovcnt; i++) - { - data_len = iov[i].iov_len; -tryagain: - n = sock_send(fd, iov[i].iov_base, data_len, 0); - if (IS_SOCKET_ERROR(n)) { - /* If buffer length is greater than the amount stack is able to - * send out then try to send at least max_sz (this comes with - * SO_EVENT_WRITE_REPLY signal*/ - if ((errno == EMSGSIZE) && (max_sz > 0) && (data_len > max_sz)) { - data_len = max_sz; - goto tryagain; - } - break; - } - sent += n; - } - return sent; -} - -#define OSE_EVENT_REQ(TCP_DESC,EVENT) do { \ - union SIGNAL *sig = alloc(sizeof(struct OseAsyncSig), EVENT); \ - sig->async.fd = INETP(TCP_DESC)->s; \ - ose_request_event(INETP(TCP_DESC)->s, &sig, 1); \ - DEBUGF(("%s(%ld): s=%d sent %s\r\n",__FUNCTION__, \ - INETP(TCP_DESC)->port,INETP(TCP_DESC)->s,signo_to_string(EVENT))); \ - } while(0) - -static void tcp_inet_ose_dispatch_signals(tcp_descriptor *desc, - int prev_select_state, - union SIGNAL *sig) { - if (sig) { - DEBUGF(("tcp_inet_ose_dispatch_signals(%ld) {s=%d resend\r\n", - (long)INETP(desc)->port,INETP(desc)->s)); - /* We are reacting to a signal, which means that if - the select_state for that signal is still activated - we should send a new signal */ - switch (sig->signo) { - case SO_EVENT_READ_REPLY: { - if (INETP(desc)->select_state & FD_READ) - OSE_EVENT_REQ(desc,SO_EVENT_READ_REQUEST); - break; - } - case SO_EVENT_WRITE_REPLY: { - if (INETP(desc)->select_state & FD_WRITE) - OSE_EVENT_REQ(desc,SO_EVENT_WRITE_REQUEST); - break; - } - case SO_EVENT_CONNECT_REPLY: { - if (INETP(desc)->select_state & FD_CONNECT) - OSE_EVENT_REQ(desc,SO_EVENT_CONNECT_REQUEST); - break; - } - case SO_EVENT_ACCEPT_REPLY: { - if (INETP(desc)->select_state & FD_ACCEPT) - OSE_EVENT_REQ(desc,SO_EVENT_ACCEPT_REQUEST); - break; - } - case SO_EVENT_ERROR_REPLY: { - if (INETP(desc)->select_state & SOCK_FD_ERROR) - OSE_EVENT_REQ(desc,SO_EVENT_ERROR_REQUEST); - break; - } - - } - DEBUGF(("tcp_inet_ose_dispatch_signals(%ld) }\r\n", - (long)INETP(desc)->port)); - } - - if (INETP(desc)->select_state != prev_select_state) { - /* If the select state has changed we have to issue signals for - the state parts that have changed. */ - int xor_select_state = INETP(desc)->select_state ^ prev_select_state; - DEBUGF(("tcp_inet_ose_dispatch_signals(%ld) {s=%d select change\r\n", - (long)INETP(desc)->port,INETP(desc)->s)); - if ((xor_select_state & FD_READ) && - (INETP(desc)->select_state & FD_READ)) { - OSE_EVENT_REQ(desc,SO_EVENT_READ_REQUEST); - } - if ((xor_select_state & FD_WRITE) && - (INETP(desc)->select_state & FD_WRITE)) { - OSE_EVENT_REQ(desc,SO_EVENT_WRITE_REQUEST); - } - if ((xor_select_state & FD_CONNECT) && - (INETP(desc)->select_state & FD_CONNECT)) { - OSE_EVENT_REQ(desc,SO_EVENT_CONNECT_REQUEST); - } - if ((xor_select_state & FD_ACCEPT) && - (INETP(desc)->select_state & FD_ACCEPT)) { - OSE_EVENT_REQ(desc,SO_EVENT_ACCEPT_REQUEST); - } - if ((xor_select_state & SOCK_FD_ERROR) && - (INETP(desc)->select_state & SOCK_FD_ERROR)) { - OSE_EVENT_REQ(desc,SO_EVENT_ERROR_REQUEST); - } - - DEBUGF(("tcp_inet_ose_dispatch_signals(%ld) }\r\n", - (long)INETP(desc)->port)); - } -} - -#endif /* __OSE__ */ +#endif /* __WIN32__ */ /* socket has input: @@ -10935,49 +10425,6 @@ static void tcp_shutdown_async(tcp_descriptor* desc) desc->tcp_add_flags |= TCP_ADDF_SHUTDOWN_WR_DONE; } -#ifdef __OSE__ - -static void tcp_inet_drv_output_ose(ErlDrvData data, ErlDrvEvent event) -{ - union SIGNAL *event_sig = erl_drv_ose_get_signal(event); - - while (event_sig) { - int prev_select_state = INETP((tcp_descriptor*)data)->select_state; - int res = tcp_inet_output((tcp_descriptor*)data, (HANDLE)event_sig); - if (res != -1) { - tcp_inet_ose_dispatch_signals((tcp_descriptor*)data, - prev_select_state,event_sig); - free_buf(&event_sig); - event_sig = erl_drv_ose_get_signal(event); - } else { - /* NOTE: here the event object could have been deallocated!!!! - inet_stop_select is called when doing driver_select(ERL_DRV_USE,0) - */ - free_buf(&event_sig); - return; - } - } -} - -static void tcp_inet_drv_input_ose(ErlDrvData data, ErlDrvEvent event) -{ - union SIGNAL *event_sig = erl_drv_ose_get_signal(event); - - while (event_sig) { - int prev_select_state = INETP((tcp_descriptor*)data)->select_state; - int res = tcp_inet_input((tcp_descriptor*)data, (HANDLE)event); - if (res != -1) { - tcp_inet_ose_dispatch_signals((tcp_descriptor*)data, prev_select_state, - event_sig); - free_buf(&event_sig); - event_sig = erl_drv_ose_get_signal(event); - } else { - free_buf(&event_sig); - return; - } - } -} -#else static void tcp_inet_drv_output(ErlDrvData data, ErlDrvEvent event) { (void)tcp_inet_output((tcp_descriptor*)data, (HANDLE)event); @@ -10987,7 +10434,6 @@ static void tcp_inet_drv_input(ErlDrvData data, ErlDrvEvent event) { (void)tcp_inet_input((tcp_descriptor*)data, (HANDLE)event); } -#endif /* socket ready for ouput: ** 1. INET_STATE_CONNECTING => non block connect ? @@ -11053,13 +10499,6 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event) ssize_t n; SysIOVec* iov; -#ifdef __OSE__ - /* For large size buffers case the amount of data that the stack is - able to send out (received in the .extra field) should be passed - down to writev_fallback */ - n = event ? ((union SIGNAL*)event)->async.event.extra : 0; -#endif - if ((iov = driver_peekq(ix, &vsize)) == NULL) { sock_select(INETP(desc), FD_WRITE, 0); send_empty_out_q_msgs(INETP(desc)); @@ -11087,12 +10526,6 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event) sizes > (max 32 bit signed int) */ size_t howmuch = 0x7FFFFFFF; /* max signed 32 bit */ int x; -#ifdef __OSE__ - /* For EWOULDBLOCK sock_sendv returns 0 so we have to be sure it - wasn't the case */ - if(sock_errno() == ERRNO_BLOCK) - goto done; -#endif for(x = 0; x < vsize && iov[x].iov_len == 0; ++x) ; if (x < vsize) { diff --git a/erts/emulator/drivers/ose/ose_efile.c b/erts/emulator/drivers/ose/ose_efile.c deleted file mode 100644 index c8337a95d5..0000000000 --- a/erts/emulator/drivers/ose/ose_efile.c +++ /dev/null @@ -1,1125 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1997-2012. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * %CopyrightEnd% - */ -/* - * Purpose: Provides file and directory operations for OSE. - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif -#if defined(HAVE_POSIX_FALLOCATE) && !defined(__sun) && !defined(__sun__) -#define _XOPEN_SOURCE 600 -#endif -#if !defined(_GNU_SOURCE) && defined(HAVE_LINUX_FALLOC_H) -#define _GNU_SOURCE -#endif -#include "sys.h" -#include "erl_driver.h" -#include "erl_efile.h" -#if defined(DARWIN) || defined(HAVE_LINUX_FALLOC_H) || defined(HAVE_POSIX_FALLOCATE) -#include "fcntl.h" -#endif -#include "ose.h" -#include "unistd.h" -#include "sys/stat.h" -#include "dirent.h" -#include "sys/time.h" -#include "time.h" -#include "assert.h" - -/* Find a definition of MAXIOV, that is used in the code later. */ -#if defined IOV_MAX -#define MAXIOV IOV_MAX -#elif defined UIO_MAXIOV -#define MAXIOV UIO_MAXIOV -#else -#define MAXIOV 16 -#endif - -/* - * Macros for testing file types. - */ - -#define ISDIR(st) (((st).st_mode & S_IFMT) == S_IFDIR) -#define ISREG(st) (((st).st_mode & S_IFMT) == S_IFREG) -#define ISDEV(st) \ - (((st).st_mode&S_IFMT) == S_IFCHR || ((st).st_mode&S_IFMT) == S_IFBLK) -#define ISLNK(st) (((st).st_mode & S_IFLNK) == S_IFLNK) -#ifdef NO_UMASK -#define FILE_MODE 0644 -#define DIR_MODE 0755 -#else -#define FILE_MODE 0666 -#define DIR_MODE 0777 -#endif - -#define IS_DOT_OR_DOTDOT(s) \ - (s[0] == '.' && (s[1] == '\0' || (s[1] == '.' && s[2] == '\0'))) - -/* - * Macros for handling local file descriptors - * and mutexes. - * - * Handling of files like this is necessary because OSE - * does not allow seeking after the end of a file. So - * what we do it emulate this by keeping track of the size - * of the file and where the file's positions is. If a - * write happens after eof then we pad it. - * - * Given time this should be rewritten to get rid of the - * mutex and use the port lock to protect the data. This - * could be done be done by adapting the efile api for some - * calls to allow some meta-data to be associated with the - * open file. - */ - -#define L_FD_IS_VALID(fd_data) ((fd_data)->beyond_eof > 0) -#define L_FD_INVALIDATE(fd_data) (fd_data)->beyond_eof = 0 -#define L_FD_CUR(fd_data) (fd_data)->pos -#define L_FD_OFFS_BEYOND_EOF(fd_data, offs) \ - (((fd_data)->size > offs) ? 0 : 1) - -#define L_FD_FAIL -1 -#define L_FD_SUCCESS 1 -#define L_FD_PAD_SIZE 255 - -struct fd_meta { - ErlDrvMutex *meta_mtx; - struct fd_data *fd_data_list; -}; - -struct fd_data { - int fd; - struct fd_data *next; - struct fd_data *prev; - int pos; - int beyond_eof; - size_t size; -#ifdef DEBUG - PROCESS owner; -#endif -}; - -static int l_invalidate_local_fd(int fd); -static int l_pad_file(struct fd_data *fd_data, off_t offset); -static int check_error(int result, Efile_error* errInfo); -static struct fd_data* l_new_fd(void); -static int l_remove_local_fd(int fd); -static struct fd_data* l_find_local_fd(int fd); -static int l_update_local_fd(int fd, int pos, int size); - -static struct fd_meta* fdm = NULL; - - -/***************************************************************************/ - -static int -l_remove_local_fd(int fd) -{ - struct fd_data *fd_data; - fd_data = l_find_local_fd(fd); - - if (fd_data == NULL) { - return L_FD_FAIL; - } -#ifdef DEBUG - assert(fd_data->owner == current_process()); -#endif - erl_drv_mutex_lock(fdm->meta_mtx); - /* head ? */ - if (fd_data == fdm->fd_data_list) { - if (fd_data->next != NULL) { - /* remove link to head */ - fd_data->next->prev = NULL; - /* set new head */ - fdm->fd_data_list = fd_data->next; - } - else { - /* head is lonely */ - fdm->fd_data_list = NULL; - } - } - else { /* not head */ - if (fd_data->prev == NULL) { - erl_drv_mutex_unlock(fdm->meta_mtx); - return L_FD_FAIL; - } - else { - if (fd_data->next != NULL) { - fd_data->next->prev = fd_data->prev; - fd_data->prev->next = fd_data->next; - } - else { - fd_data->prev->next = NULL; - } - } - } - - /* scramble values */ - fd_data->beyond_eof = -1; - fd_data->next = NULL; - fd_data->prev = NULL; - fd_data->fd = -1; - - /* unlock and clean */ - driver_free(fd_data); - erl_drv_mutex_unlock(fdm->meta_mtx); - - return L_FD_SUCCESS; -} - -/***************************************************************************/ - -static int -l_invalidate_local_fd(int fd) { - struct fd_data *fd_data; - - if ((fd_data = l_find_local_fd(fd)) == NULL) { - return L_FD_FAIL; - } - - fd_data->beyond_eof = 0; - return L_FD_SUCCESS; -} - -/****************************************************************************/ - -static struct fd_data* -l_find_local_fd(int fd) { - struct fd_data *fd_data; - - fd_data = NULL; - erl_drv_mutex_lock(fdm->meta_mtx); - for (fd_data = fdm->fd_data_list; fd_data != NULL; ) { - if (fd_data->fd == fd) { -#ifdef DEBUG - assert(fd_data->owner == current_process()); -#endif - break; - } - fd_data = fd_data->next; - } - erl_drv_mutex_unlock(fdm->meta_mtx); - return fd_data; -} - -/***************************************************************************/ - -static struct fd_data* -l_new_fd(void) { - struct fd_data *fd_data; - - fd_data = driver_alloc(sizeof(struct fd_data)); - if (fd_data == NULL) { - return NULL; - } - erl_drv_mutex_lock(fdm->meta_mtx); - if (fdm->fd_data_list == NULL) { - fdm->fd_data_list = fd_data; - fdm->fd_data_list->prev = NULL; - fdm->fd_data_list->next = NULL; - } - else { - fd_data->next = fdm->fd_data_list; - fdm->fd_data_list = fd_data; - fdm->fd_data_list->prev = NULL; - } -#ifdef DEBUG - fd_data->owner = current_process(); -#endif - erl_drv_mutex_unlock(fdm->meta_mtx); - return fd_data; -} - -/***************************************************************************/ - -static int -l_update_local_fd(int fd, int pos, int size) { - struct fd_data *fd_data = NULL; - - fd_data = l_find_local_fd(fd); - /* new fd to handle? */ - if (fd_data == NULL) { - fd_data = l_new_fd(); - if (fd_data == NULL) { - /* out of memory */ - return L_FD_FAIL; - } - } - fd_data->size = size; - fd_data->pos = pos; - fd_data->fd = fd; - fd_data->beyond_eof = 1; - - return L_FD_SUCCESS; -} - -/***************************************************************************/ - -static int -l_pad_file(struct fd_data *fd_data, off_t offset) { - int size_dif; - int written = 0; - int ret_val = L_FD_SUCCESS; - char padding[L_FD_PAD_SIZE]; - - size_dif = (offset - fd_data->size); - memset(&padding, '\0', L_FD_PAD_SIZE); - - while (size_dif > 0) { - written = write(fd_data->fd, padding, - (size_dif < L_FD_PAD_SIZE) ? - size_dif : L_FD_PAD_SIZE); - if (written < 0 && errno != EINTR && errno != EAGAIN) { - ret_val = -1; - break; - } - size_dif -= written; - } - L_FD_INVALIDATE(fd_data); - return ret_val; -} - -/***************************************************************************/ - -static int -check_error(int result, Efile_error *errInfo) { - if (result < 0) { - errInfo->posix_errno = errInfo->os_errno = errno; - return 0; - } - return 1; -} - -/***************************************************************************/ - -int -efile_init() { - fdm = driver_alloc(sizeof(struct fd_meta)); - if (fdm == NULL) { - return L_FD_FAIL; - } - fdm->meta_mtx = erl_drv_mutex_create("ose_efile local fd mutex\n"); - erl_drv_mutex_lock(fdm->meta_mtx); - fdm->fd_data_list = NULL; - erl_drv_mutex_unlock(fdm->meta_mtx); - return L_FD_SUCCESS; -} - -/***************************************************************************/ - -int -efile_mkdir(Efile_error* errInfo, /* Where to return error codes. */ - char* name) /* Name of directory to create. */ -{ -#ifdef NO_MKDIR_MODE - return check_error(mkdir(name), errInfo); -#else - int res = mkdir(name, DIR_MODE); - if (res < 0 && errno == EINVAL) { - errno = ENOENT; - } - return check_error(res, errInfo); -#endif -} - -/***************************************************************************/ - -int -efile_rmdir(Efile_error* errInfo, /* Where to return error codes. */ - char* name) /* Name of directory to delete. */ -{ - if (rmdir(name) == 0) { - return 1; - } - if (errno == ENOTEMPTY) { - errno = EEXIST; - } - if (errno == EEXIST || errno == EINVAL) { - int saved_errno = errno; - struct stat file_stat; - struct stat cwd_stat; - - if(stat(name, &file_stat) != 0) { - errno = ENOENT; - return check_error(-1, errInfo); - } - /* - * The error code might be wrong if this is the current directory. - */ - if (stat(name, &file_stat) == 0 && stat(".", &cwd_stat) == 0 && - file_stat.st_ino == cwd_stat.st_ino && - file_stat.st_dev == cwd_stat.st_dev) { - saved_errno = EACCES; - } - errno = saved_errno; - } - return check_error(-1, errInfo); -} - -/***************************************************************************/ - -int -efile_delete_file(Efile_error* errInfo, /* Where to return error codes. */ - char* name) /* Name of file to delete. */ -{ - struct stat statbuf; - - if (stat(name, &statbuf) >= 0) { - /* Do not let unlink() remove directories */ - if (ISDIR(statbuf)) { - errno = EPERM; - return check_error(-1, errInfo); - } - - if (unlink(name) == 0) { - return 1; - } - - if (errno == EISDIR) { - errno = EPERM; - return check_error(-1, errInfo); - } - } - else { - if (errno == EINVAL) { - errno = ENOENT; - return check_error(-1, errInfo); - } - } - return check_error(-1, errInfo); -} - -/* - *--------------------------------------------------------------------------- - * - * Changes the name of an existing file or directory, from src to dst. - * If src and dst refer to the same file or directory, does nothing - * and returns success. Otherwise if dst already exists, it will be - * deleted and replaced by src subject to the following conditions: - * If src is a directory, dst may be an empty directory. - * If src is a file, dst may be a file. - * In any other situation where dst already exists, the rename will - * fail. - * - * Results: - * If the directory was successfully created, returns 1. - * Otherwise the return value is 0 and errno is set to - * indicate the error. Some possible values for errno are: - * - * EACCES: src or dst parent directory can't be read and/or written. - * EEXIST: dst is a non-empty directory. - * EINVAL: src is a root directory or dst is a subdirectory of src. - * EISDIR: dst is a directory, but src is not. - * ENOENT: src doesn't exist, or src or dst is "". - * ENOTDIR: src is a directory, but dst is not. - * EXDEV: src and dst are on different filesystems. - * - * Side effects: - * The implementation of rename may allow cross-filesystem renames, - * but the caller should be prepared to emulate it with copy and - * delete if errno is EXDEV. - * - *--------------------------------------------------------------------------- - */ - -int -efile_rename(Efile_error* errInfo, /* Where to return error codes. */ - char* src, /* Original name. */ - char* dst) /* New name. */ -{ - - /* temporary fix AFM does not recognize ./ - * in destination remove pending on adaption of AFM fix - */ - - char *dot_str; - if (dst != NULL) { - dot_str = strchr(dst, '.'); - if (dot_str && dot_str == dst && dot_str[1] == '/') { - dst = dst+2; - } - } - - if (rename(src, dst) == 0) { - return 1; - } - if (errno == ENOTEMPTY) { - errno = EEXIST; - } - if (errno == EINVAL) { - struct stat file_stat; - - if (stat(dst, &file_stat)== 0) { - if (ISDIR(file_stat)) { - errno = EISDIR; - } - else if (ISREG(file_stat)) { - errno = ENOTDIR; - } - else { - errno = EINVAL; - } - } - else { - errno = EINVAL; - } - } - - if (strcmp(src, "/") == 0) { - errno = EINVAL; - } - return check_error(-1, errInfo); -} - -/***************************************************************************/ - -int -efile_chdir(Efile_error* errInfo, /* Where to return error codes. */ - char* name) /* Name of directory to make current. */ -{ - return check_error(chdir(name), errInfo); -} - -/***************************************************************************/ - -int -efile_getdcwd(Efile_error* errInfo, /* Where to return error codes. */ - int drive, /* 0 - current, 1 - A, 2 - B etc. */ - char* buffer, /* Where to return the current - directory. */ - size_t size) /* Size of buffer. */ -{ - if (drive == 0) { - if (getcwd(buffer, size) == NULL) - return check_error(-1, errInfo); - - return 1; - } - - /* - * Drives other than 0 is not supported on Unix. - */ - - errno = ENOTSUP; - return check_error(-1, errInfo); -} - -/***************************************************************************/ - -int -efile_readdir(Efile_error* errInfo, /* Where to return error codes. */ - char* name, /* Name of directory to open. */ - EFILE_DIR_HANDLE* p_dir_handle, /* Pointer to directory - handle of - open directory.*/ - char* buffer, /* Pointer to buffer for - one filename. */ - size_t *size) /* in-out Size of buffer, length - of name. */ -{ - DIR *dp; /* Pointer to directory structure. */ - struct dirent* dirp; /* Pointer to directory entry. */ - - /* - * If this is the first call, we must open the directory. - */ - - if (*p_dir_handle == NULL) { - dp = opendir(name); - if (dp == NULL) - return check_error(-1, errInfo); - *p_dir_handle = (EFILE_DIR_HANDLE) dp; - } - - /* - * Retrieve the name of the next file using the directory handle. - */ - - dp = *((DIR **)((void *)p_dir_handle)); - for (;;) { - dirp = readdir(dp); - if (dirp == NULL) { - closedir(dp); - return 0; - } - if (IS_DOT_OR_DOTDOT(dirp->d_name)) - continue; - buffer[0] = '\0'; - strncat(buffer, dirp->d_name, (*size)-1); - *size = strlen(dirp->d_name); - return 1; - } -} - -/***************************************************************************/ - -int -efile_openfile(Efile_error* errInfo, /* Where to return error codes. */ - char* name, /* Name of directory to open. */ - int flags, /* Flags to user for opening. */ - int* pfd, /* Where to store the file - descriptor. */ - Sint64 *pSize) /* Where to store the size of the - file. */ -{ - struct stat statbuf; - int fd; - int mode; /* Open mode. */ - - if (stat(name, &statbuf) >= 0 && !ISREG(statbuf)) { - errno = EISDIR; - return check_error(-1, errInfo); - } - - switch (flags & (EFILE_MODE_READ|EFILE_MODE_WRITE)) { - case EFILE_MODE_READ: - mode = O_RDONLY; - break; - case EFILE_MODE_WRITE: - if (flags & EFILE_NO_TRUNCATE) - mode = O_WRONLY | O_CREAT; - else - mode = O_WRONLY | O_CREAT | O_TRUNC; - break; - case EFILE_MODE_READ_WRITE: - mode = O_RDWR | O_CREAT; - break; - default: - errno = EINVAL; - return check_error(-1, errInfo); - } - - - if (flags & EFILE_MODE_APPEND) { - mode &= ~O_TRUNC; - mode |= O_APPEND; - } - - if (flags & EFILE_MODE_EXCL) { - mode |= O_EXCL; - } - - fd = open(name, mode, FILE_MODE); - - if (!check_error(fd, errInfo)) - return 0; - - *pfd = fd; - if (pSize) { - *pSize = statbuf.st_size; - } - return 1; -} - -/***************************************************************************/ - -int -efile_may_openfile(Efile_error* errInfo, char *name) { - struct stat statbuf; /* Information about the file */ - int result; - - result = stat(name, &statbuf); - if (!check_error(result, errInfo)) - return 0; - if (!ISREG(statbuf)) { - errno = EISDIR; - return check_error(-1, errInfo); - } - return 1; -} - -/***************************************************************************/ - -void -efile_closefile(int fd) -{ - if (l_find_local_fd(fd) != NULL) { - l_remove_local_fd(fd); - } - close(fd); -} - -/***************************************************************************/ - -int -efile_fdatasync(Efile_error *errInfo, /* Where to return error codes. */ - int fd) /* File descriptor for file to sync data. */ -{ - return efile_fsync(errInfo, fd); -} - -/***************************************************************************/ - -int -efile_fsync(Efile_error *errInfo, /* Where to return error codes. */ - int fd) /* File descriptor for file to sync. */ -{ - return check_error(fsync(fd), errInfo); -} - -/***************************************************************************/ - -int -efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, - char* name, int info_for_link) -{ - struct stat statbuf; /* Information about the file */ - int result; - - result = stat(name, &statbuf); - if (!check_error(result, errInfo)) { - return 0; - } - -#if SIZEOF_OFF_T == 4 - pInfo->size_high = 0; -#else - pInfo->size_high = (Uint32)(statbuf.st_size >> 32); -#endif - pInfo->size_low = (Uint32)statbuf.st_size; - -#ifdef NO_ACCESS - /* Just look at read/write access for owner. */ - - pInfo->access = ((statbuf.st_mode >> 6) & 07) >> 1; - -#else - pInfo->access = FA_NONE; - if (access(name, R_OK) == 0) - pInfo->access |= FA_READ; - if (access(name, W_OK) == 0) - pInfo->access |= FA_WRITE; - -#endif - - if (ISDEV(statbuf)) - pInfo->type = FT_DEVICE; - else if (ISDIR(statbuf)) - pInfo->type = FT_DIRECTORY; - else if (ISREG(statbuf)) - pInfo->type = FT_REGULAR; - else if (ISLNK(statbuf)) - pInfo->type = FT_SYMLINK; - else - pInfo->type = FT_OTHER; - - pInfo->accessTime = statbuf.st_atime; - pInfo->modifyTime = statbuf.st_mtime; - pInfo->cTime = statbuf.st_ctime; - - pInfo->mode = statbuf.st_mode; - pInfo->links = statbuf.st_nlink; - pInfo->major_device = statbuf.st_dev; - pInfo->inode = statbuf.st_ino; - pInfo->uid = statbuf.st_uid; - pInfo->gid = statbuf.st_gid; - - return 1; -} - -/***************************************************************************/ - -int -efile_write_info(Efile_error *errInfo, Efile_info *pInfo, char *name) -{ - /* - * On some systems chown will always fail for a non-root user unless - * POSIX_CHOWN_RESTRICTED is not set. Others will succeed as long as - * you don't try to chown a file to someone besides youself. - */ - if (pInfo->mode != -1) { - mode_t newMode = pInfo->mode & (S_ISUID | S_ISGID | - S_IRWXU | S_IRWXG | S_IRWXO); - if (chmod(name, newMode)) { - newMode &= ~(S_ISUID | S_ISGID); - if (chmod(name, newMode)) { - return check_error(-1, errInfo); - } - } - } - - return 1; -} - -/***************************************************************************/ - -int -efile_write(Efile_error* errInfo, /* Where to return error codes. */ - int flags, /* Flags given when file was - opened. */ - int fd, /* File descriptor to write to. */ - char* buf, /* Buffer to write. */ - size_t count) /* Number of bytes to write. */ -{ - ssize_t written; /* Bytes written in last operation. */ - struct fd_data *fd_data; - - if ((fd_data = l_find_local_fd(fd)) != NULL) { - if (L_FD_IS_VALID(fd_data)) { - /* we are beyond eof and need to pad*/ - if (l_pad_file(fd_data, L_FD_CUR(fd_data)) < 0) { - return check_error(-1, errInfo); - } - } - } - - while (count > 0) { - if ((written = write(fd, buf, count)) < 0) { - if (errno != EINTR) { - return check_error(-1, errInfo); - } - else { - written = 0; - } - } - ASSERT(written <= count); - buf += written; - count -= written; - } - return 1; -} - -/***************************************************************************/ - -int -efile_writev(Efile_error* errInfo, /* Where to return error codes */ - int flags, /* Flags given when file was - * opened */ - int fd, /* File descriptor to write to */ - SysIOVec* iov, /* Vector of buffer structs. - * The structs may be changed i.e. - * due to incomplete writes */ - int iovcnt) /* Number of structs in vector */ -{ - struct fd_data *fd_data; - int cnt = 0; /* Buffers so far written */ - - ASSERT(iovcnt >= 0); - if ((fd_data = l_find_local_fd(fd)) != NULL) { - if (L_FD_IS_VALID(fd_data)) { - /* we are beyond eof and need to pad*/ - if (l_pad_file(fd_data, L_FD_CUR(fd_data)) < 0) { - return check_error(-1, errInfo); - } - } - } - 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 */ - do { - w = write(fd, iov[cnt].iov_base, iov[cnt].iov_len); - } while (w < 0 && errno == EINTR); - - ASSERT(w <= iov[cnt].iov_len || w == -1); - - 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; - } - } - } - ASSERT(w == 0); - } /* else Non-empty buffer */ - } /* while (cnt< iovcnt) */ - return 1; -} - -/***************************************************************************/ - -int -efile_read(Efile_error* errInfo, /* Where to return error codes. */ - int flags, /* Flags given when file was opened. */ - int fd, /* File descriptor to read from. */ - char* buf, /* Buffer to read into. */ - size_t count, /* Number of bytes to read. */ - size_t *pBytesRead) /* Where to return number of - bytes read. */ -{ - ssize_t n; - struct fd_data *fd_data; - - if ((fd_data = l_find_local_fd(fd)) != NULL) { - if (L_FD_IS_VALID(fd_data)) { - *pBytesRead = 0; - return 1; - } - } - for (;;) { - if ((n = read(fd, buf, count)) >= 0) { - break; - } - else if (errno != EINTR) { - return check_error(-1, errInfo); - } - } - if (fd_data != NULL && L_FD_IS_VALID(fd_data)) { - L_FD_INVALIDATE(fd_data); - } - *pBytesRead = (size_t) n; - return 1; -} - -/* pread() and pwrite() */ -/* Some unix systems, notably Solaris has these syscalls */ -/* It is especially nice for i.e. the dets module to have support */ -/* for this, even if the underlying OS dosn't support it, it is */ -/* reasonably easy to work around by first calling seek, and then */ -/* calling read(). */ -/* This later strategy however changes the file pointer, which pread() */ -/* does not do. We choose to ignore this and say that the location */ -/* of the file pointer is undefined after a call to any of the p functions*/ - - -int -efile_pread(Efile_error* errInfo, /* Where to return error codes. */ - int fd, /* File descriptor to read from. */ - Sint64 offset, /* Offset in bytes from BOF. */ - char* buf, /* Buffer to read into. */ - size_t count, /* Number of bytes to read. */ - size_t *pBytesRead) /* Where to return - number of bytes read. */ -{ - int res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL); - if (res) { - return efile_read(errInfo, 0, fd, buf, count, pBytesRead); - } else { - return res; - } -} - - -/***************************************************************************/ - -int -efile_pwrite(Efile_error* errInfo, /* Where to return error codes. */ - int fd, /* File descriptor to write to. */ - char* buf, /* Buffer to write. */ - size_t count, /* Number of bytes to write. */ - Sint64 offset) /* where to write it */ -{ - int res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL); - - if (res) { - return efile_write(errInfo, 0, fd, buf, count); - } else { - return res; - } -} - -/***************************************************************************/ - -int -efile_seek(Efile_error* errInfo, /* Where to return error codes. */ - int fd, /* File descriptor to do the seek on. */ - Sint64 offset, /* Offset in bytes from the given - origin. */ - int origin, /* Origin of seek (SEEK_SET, SEEK_CUR, - SEEK_END). */ - Sint64 *new_location) /* Resulting new location in file. */ -{ - off_t off, result; - off = (off_t) offset; - - switch (origin) { - case EFILE_SEEK_SET: - origin = SEEK_SET; - break; - case EFILE_SEEK_CUR: - origin = SEEK_CUR; - break; - case EFILE_SEEK_END: - origin = SEEK_END; - break; - default: - errno = EINVAL; - return check_error(-1, errInfo); - } - - if (off != offset) { - errno = EINVAL; - return check_error(-1, errInfo); - } - - errno = 0; - result = lseek(fd, off, origin); - - if (result >= 0) { - l_invalidate_local_fd(fd); - } - - if (result < 0) - { - if (errno == ENOSYS) { - int size, cur_pos; - - if (off < 0) { - errno = EINVAL; - return check_error(-1, errInfo); - } - - cur_pos = lseek(fd, 0, SEEK_CUR); - size = lseek(fd, 0, SEEK_END); - - if (origin == SEEK_SET) { - result = offset; - } - else if (origin == SEEK_CUR) { - result = offset + cur_pos; - } - else if (origin == SEEK_END) { - result = size + offset; - } - - /* sanity check our result */ - if (size > result) { - return check_error(-1, errInfo); - } - - /* store the data localy */ - l_update_local_fd(fd, result, size); - - /* reset the original file position */ - if (origin != SEEK_END) { - lseek(fd, cur_pos, SEEK_SET); - } - } - else if (errno == 0) { - errno = EINVAL; - } - } - - if (new_location) { - *new_location = result; - } - - return 1; -} - -/***************************************************************************/ - -int -efile_truncate_file(Efile_error* errInfo, int *fd, int flags) -{ - off_t offset; - struct fd_data *fd_data; - - if ((fd_data = l_find_local_fd(*fd)) != NULL && L_FD_IS_VALID(fd_data)) { - offset = L_FD_CUR(fd_data); - } - else { - offset = lseek(*fd, 0, SEEK_CUR); - } - - return check_error(((offset >= 0) && - (ftruncate(*fd, offset) == 0)) ? 1 : -1, errInfo); -} - -/***************************************************************************/ - -int -efile_readlink(Efile_error* errInfo, char* name, char* buffer, size_t size) -{ - errno = ENOTSUP; - return check_error(-1, errInfo); -} - -/***************************************************************************/ - -int -efile_altname(Efile_error* errInfo, char* name, char* buffer, size_t size) -{ - errno = ENOTSUP; - return check_error(-1, errInfo); -} - -/***************************************************************************/ - -int -efile_link(Efile_error* errInfo, char* old, char* new) -{ - errno = ENOTSUP; - return check_error(-1, errInfo); -} - -/***************************************************************************/ - -int -efile_symlink(Efile_error* errInfo, char* old, char* new) -{ - errno = ENOTSUP; - return check_error(-1, errInfo); -} - -/***************************************************************************/ - -int -efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset, - Sint64 length, int advise) -{ - return check_error(posix_fadvise(fd, offset, length, advise), errInfo); -} - -/***************************************************************************/ - -static int -call_posix_fallocate(int fd, Sint64 offset, Sint64 length) -{ - int ret; - - /* - * On Linux and Solaris for example, posix_fallocate() returns - * a positive error number on error and it does not set errno. - * On FreeBSD however (9.0 at least), it returns -1 on error - * and it sets errno. - */ - do { - ret = posix_fallocate(fd, (off_t) offset, (off_t) length); - if (ret > 0) { - errno = ret; - ret = -1; - } - } while (ret != 0 && errno == EINTR); - - return ret; -} - -/***************************************************************************/ - -int -efile_fallocate(Efile_error* errInfo, int fd, Sint64 offset, Sint64 length) -{ - return check_error(call_posix_fallocate(fd, offset, length), errInfo); -} diff --git a/erts/emulator/drivers/ose/ose_signal_drv.c b/erts/emulator/drivers/ose/ose_signal_drv.c deleted file mode 100644 index 2be9462a47..0000000000 --- a/erts/emulator/drivers/ose/ose_signal_drv.c +++ /dev/null @@ -1,897 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2013-2013. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * %CopyrightEnd% - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "errno.h" -#include "stdio.h" -#include "string.h" -#include "stddef.h" - -#include "sys.h" -#include "erl_driver.h" -#include "ose.h" - - -#ifdef HAVE_OSE_SPI_H -#include "ose_spi/ose_spi.h" -#endif - -#define DEBUG_ATTACH 0 -#define DEBUG_HUNT 0 -#define DEBUG_SEND 0 -#define DEBUG_LISTEN 0 - -#if 0 -#define DEBUGP(FMT,...) printf(FMT, __VA_ARGS__) -#else -#define DEBUGP(FMT,...) -#endif - -#if DEBUG_ATTACH -#define DEBUGP_ATTACH(...) DEBUGP( __VA_ARGS__) -#else -#define DEBUGP_ATTACH(...) -#endif - -#if DEBUG_HUNT -#define DEBUGP_HUNT(...) DEBUGP( __VA_ARGS__) -#else -#define DEBUGP_HUNT(...) -#endif - -#if DEBUG_LISTEN -#define DEBUGP_LISTEN(...) DEBUGP( __VA_ARGS__) -#else -#define DEBUGP_LISTEN(...) -#endif - -#if DEBUG_SEND -#define DEBUGP_SEND(...) DEBUGP( __VA_ARGS__) -#else -#define DEBUGP_SEND(...) -#endif - - -#define DRIVER_NAME "ose_signal_drv" -#define GET_SPID 1 -#define GET_NAME 2 -#define HUNT 100 -#define DEHUNT 101 -#define ATTACH 102 -#define DETACH 103 -#define SEND 104 -#define SEND_W_S 105 -#define LISTEN 106 -#define OPEN 200 - -#define REF_SEGMENT_SIZE 8 - -struct async { - SIGSELECT signo; - ErlDrvTermData port; - ErlDrvTermData proc; - PROCESS spid; - PROCESS target; - Uint32 ref; -}; - -/** - * OSE signals - **/ -union SIGNAL { - SIGSELECT signo; - struct async async; -}; - -/** - * The driver's context - **/ -typedef struct _driver_context { - ErlDrvPort port; - PROCESS spid; - ErlDrvEvent perm_events[2]; - ErlDrvEvent *events; - Uint32 event_cnt; - Uint32 ref; - Uint32 *outstanding_refs; - Uint32 outstanding_refs_max; - Uint32 outstanding_refs_cnt; -} driver_context_t; - -/** - * Global variables - **/ -static ErlDrvTermData a_ok; -static ErlDrvTermData a_error; -static ErlDrvTermData a_enomem; -static ErlDrvTermData a_enoent; -static ErlDrvTermData a_badarg; -static ErlDrvTermData a_mailbox_up; -static ErlDrvTermData a_mailbox_down; -static ErlDrvTermData a_ose_drv_reply; -static ErlDrvTermData a_message; -static PROCESS proxy_proc; - - -/** - * Serialize/unserialize unsigned 32-bit values - **/ -static char *put_u32(unsigned int value, char *ptr) { - *ptr++ = (value & 0xff000000) >> 24; - *ptr++ = (value & 0x00ff0000) >> 16; - *ptr++ = (value & 0x0000ff00) >> 8; - *ptr++ = (value & 0xff); - - return ptr; -} - -static unsigned int get_u32(char *ptr) { - unsigned int result = 0; - result += (ptr[0] & 0xff) << 24; - result += (ptr[1] & 0xff) << 16; - result += (ptr[2] & 0xff) << 8; - result += (ptr[3] & 0xff); - - return result; -} - - -/* Stolen from efile_drv.c */ - -/* char EV_CHAR_P(ErlIOVec *ev, int p, int q) */ -#define EV_CHAR_P(ev, p, q) \ - (((char *)(ev)->iov[(q)].iov_base) + (p)) - -/* int EV_GET_CHAR(ErlIOVec *ev, char *p, int *pp, int *qp) */ -#define EV_GET_CHAR(ev, p, pp, qp) ev_get_char(ev, p ,pp, qp) -static int -ev_get_char(ErlIOVec *ev, char *p, int *pp, int *qp) { - if (*(pp)+1 <= (ev)->iov[*(qp)].iov_len) { - *(p) = *EV_CHAR_P(ev, *(pp), *(qp)); - if (*(pp)+1 < (ev)->iov[*(qp)].iov_len) - *(pp) = *(pp)+1; - else { - (*(qp))++; - *pp = 0; - } - return !0; - } - return 0; -} - -/* Uint32 EV_UINT32(ErlIOVec *ev, int p, int q)*/ -#define EV_UINT32(ev, p, q) \ - ((Uint32) *(((unsigned char *)(ev)->iov[(q)].iov_base) + (p))) - -/* int EV_GET_UINT32(ErlIOVec *ev, Uint32 *p, int *pp, int *qp) */ -#define EV_GET_UINT32(ev, p, pp, qp) ev_get_uint32(ev,(Uint32*)(p),pp,qp) -static int -ev_get_uint32(ErlIOVec *ev, Uint32 *p, int *pp, int *qp) { - if (*(pp)+4 <= (ev)->iov[*(qp)].iov_len) { - *(p) = (EV_UINT32(ev, *(pp), *(qp)) << 24) - | (EV_UINT32(ev, *(pp)+1, *(qp)) << 16) - | (EV_UINT32(ev, *(pp)+2, *(qp)) << 8) - | (EV_UINT32(ev, *(pp)+3, *(qp))); - if (*(pp)+4 < (ev)->iov[*(qp)].iov_len) - *(pp) = *(pp)+4; - else { - (*(qp))++; - *pp = 0; - } - return !0; - } - return 0; -} - -/** - * Convinience macros - **/ -#define send_response(port,output) erl_drv_send_term(driver_mk_port(port),\ - driver_caller(port), output, sizeof(output) / sizeof(output[0])); - -void iov_memcpy(void *dest,ErlIOVec *ev,int ind,int off); -void iov_memcpy(void *dest,ErlIOVec *ev,int ind,int off) { - int i; - memcpy(dest,ev->iov[ind].iov_base+off,ev->iov[ind].iov_len-off); - for (i = ind+1; i < ev->vsize; i++) - memcpy(dest,ev->iov[i].iov_base,ev->iov[i].iov_len); -} - -/** - * Reference handling - **/ - -static int add_reference(driver_context_t *ctxt, Uint32 ref) { - - /* - * Premature optimizations may be evil, but they sure are fun. - */ - - if (ctxt->outstanding_refs == NULL) { - /* First ref to be ignored */ - ctxt->outstanding_refs = driver_alloc(REF_SEGMENT_SIZE*sizeof(Uint32)); - if (!ctxt->outstanding_refs) - return 1; - - memset(ctxt->outstanding_refs,0,REF_SEGMENT_SIZE*sizeof(Uint32)); - ctxt->outstanding_refs_max += REF_SEGMENT_SIZE; - ctxt->outstanding_refs[ctxt->outstanding_refs_cnt++] = ref; - } else if (ctxt->outstanding_refs_cnt == ctxt->outstanding_refs_max) { - /* Expand ref array */ - Uint32 *new_array; - ctxt->outstanding_refs_max += REF_SEGMENT_SIZE; - new_array = driver_realloc(ctxt->outstanding_refs, - ctxt->outstanding_refs_max*sizeof(Uint32)); - - if (!new_array) { - ctxt->outstanding_refs_max -= REF_SEGMENT_SIZE; - return 1; - } - - ctxt->outstanding_refs = new_array; - - memset(ctxt->outstanding_refs+ctxt->outstanding_refs_cnt,0, - REF_SEGMENT_SIZE*sizeof(Uint32)); - ctxt->outstanding_refs[ctxt->outstanding_refs_cnt++] = ref; - - } else { - /* Find an empty slot: - * First we try current index, - * then we scan for a slot. - */ - if (!ctxt->outstanding_refs[ctxt->outstanding_refs_cnt]) { - ctxt->outstanding_refs[ctxt->outstanding_refs_cnt++] = ref; - } else { - int i; - ASSERT(ctxt->outstanding_refs_cnt < ctxt->outstanding_refs_max); - for (i = 0; i < ctxt->outstanding_refs_max; i++) - if (!ctxt->outstanding_refs[i]) - break; - ASSERT(ctxt->outstanding_refs[i] == 0); - ctxt->outstanding_refs[i] = ref; - ctxt->outstanding_refs_cnt++; - } - } - return 0; -} - -/* Return 0 if removed, 1 if does not exist, */ -static int remove_reference(driver_context_t *ctxt, Uint32 ref) { - int i,j; - - if (ctxt->outstanding_refs_max == 0 && ctxt->outstanding_refs_cnt == 0) { - ASSERT(ctxt->outstanding_refs == NULL); - return 1; - } - - for (i = 0; i < ctxt->outstanding_refs_max; i++) { - if (ctxt->outstanding_refs[i] == ref) { - ctxt->outstanding_refs[i] = 0; - ctxt->outstanding_refs_cnt--; - i = -1; - break; - } - } - - if (i != -1) - return 1; - - if (ctxt->outstanding_refs_cnt == 0) { - driver_free(ctxt->outstanding_refs); - ctxt->outstanding_refs = NULL; - ctxt->outstanding_refs_max = 0; - } else if (ctxt->outstanding_refs_cnt == (ctxt->outstanding_refs_max - REF_SEGMENT_SIZE)) { - Uint32 *new_array; - for (i = 0, j = 0; i < ctxt->outstanding_refs_cnt; i++) { - if (ctxt->outstanding_refs[i] == 0) { - for (j = i+1; j < ctxt->outstanding_refs_max; j++) - if (ctxt->outstanding_refs[j]) { - ctxt->outstanding_refs[i] = ctxt->outstanding_refs[j]; - ctxt->outstanding_refs[j] = 0; - break; - } - } - } - ctxt->outstanding_refs_max -= REF_SEGMENT_SIZE; - new_array = driver_realloc(ctxt->outstanding_refs, - ctxt->outstanding_refs_max*sizeof(Uint32)); - if (!new_array) { - ctxt->outstanding_refs_max += REF_SEGMENT_SIZE; - return 2; - } - - ctxt->outstanding_refs = new_array; - - } - - return 0; -} - -/** - * The OSE proxy process. This only handles ERTS_SIGNAL_OSE_DRV_ATTACH. - * The process is needed because signals triggered by attach ignore - * redir tables. - * - * We have one global proxy process to save memory. An attempt to make each - * port phantom into a proxy was made, but that used way to much memory. - */ -static OS_PROCESS(driver_proxy_process) { - SIGSELECT sigs[] = {1,ERTS_SIGNAL_OSE_DRV_ATTACH}; - PROCESS master = 0; - - while (1) { - union SIGNAL *sig = receive(sigs); - - if (sig->signo == ERTS_SIGNAL_OSE_DRV_ATTACH) { - - /* The first message is used to determine who to send messages to. */ - if (master == 0) - master = sender(&sig); - - if (sig->async.target == 0) { - PROCESS from = sender(&sig); - restore(sig); - DEBUGP_ATTACH("0x%x: got attach 0x%x, sending to 0x%x\n", - current_process(),from,master); - sig->async.target = from; - send(&sig,master); - } else { - PROCESS target = sig->async.target; - restore(sig); - sig->async.target = 0; - DEBUGP_ATTACH("0x%x: doing attach on 0x%x\n",current_process(),target); - attach(&sig,target); - } - } - } -} - - -/** - * Init routine for the driver - **/ -static int drv_init(void) { - - a_ok = driver_mk_atom("ok"); - a_error = driver_mk_atom("error"); - a_enomem = driver_mk_atom("enomem"); - a_enoent = driver_mk_atom("enoent"); - a_badarg = driver_mk_atom("badarg"); - a_mailbox_up = driver_mk_atom("mailbox_up"); - a_mailbox_down = driver_mk_atom("mailbox_down"); - a_ose_drv_reply = driver_mk_atom("ose_drv_reply"); - a_message = driver_mk_atom("message"); - - proxy_proc = create_process(get_ptype(current_process()), - "ose_signal_driver_proxy", - driver_proxy_process, 10000, - get_pri(current_process()), - 0, 0, NULL, 0, 0); - -#ifdef DEBUG - efs_clone(proxy_proc); -#endif - start(proxy_proc); - - return 0; -} - -/* Signal resolution callback */ -static ErlDrvOseEventId resolve_signal(union SIGNAL* osig) { - union SIGNAL *sig = osig; - if (sig->signo == ERTS_SIGNAL_OSE_DRV_HUNT || - sig->signo == ERTS_SIGNAL_OSE_DRV_ATTACH) { - return sig->async.spid; - } - DEBUGP("%p: Got signal %d sent to %p from 0x%p\n", - current_process(),sig->signo,addressee(&sig),sender(&sig)); - return addressee(&sig); -} - - -/** - * Start routine for the driver - **/ -static ErlDrvData drv_start(ErlDrvPort port, char *command) -{ - driver_context_t *ctxt = driver_alloc(sizeof(driver_context_t)); - - ctxt->perm_events[0] = NULL; - ctxt->perm_events[1] = NULL; - - ctxt->spid = 0; - ctxt->port = port; - ctxt->event_cnt = 0; - ctxt->events = NULL; - ctxt->ref = 0; - ctxt->outstanding_refs = NULL; - ctxt->outstanding_refs_max = 0; - ctxt->outstanding_refs_cnt = 0; - - - /* Set the communication protocol to Erlang to be binary */ - set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY); - - /* Everything ok */ - return (ErlDrvData)ctxt; -} - -/** - * Stop routine for the driver - **/ -static void drv_stop(ErlDrvData driver_data) -{ - driver_context_t *ctxt = (driver_context_t *)driver_data; - int i; - - /* HUNT + ATTACH */ - if (ctxt->perm_events[0]) - driver_select(ctxt->port, ctxt->perm_events[0], - ERL_DRV_USE|ERL_DRV_READ, 0); - if (ctxt->perm_events[1]) - driver_select(ctxt->port, ctxt->perm_events[1], - ERL_DRV_USE|ERL_DRV_READ, 0); - - for (i = 0; i < ctxt->event_cnt; i++) { - driver_select(ctxt->port, ctxt->events[i], ERL_DRV_USE|ERL_DRV_READ, 0); - } - - if (ctxt->spid != 0) - kill_proc(ctxt->spid); - DEBUGP("0x%x: stopped\n",ctxt->spid); - if (ctxt->events) - driver_free(ctxt->events); - if (ctxt->outstanding_refs) - driver_free(ctxt->outstanding_refs); - - driver_free(ctxt); -} - -/** - * Output from Erlang - **/ -static void outputv(ErlDrvData driver_data, ErlIOVec *ev) -{ - driver_context_t *ctxt = (driver_context_t *)driver_data; - int p = 0, q = 1; - char cmd; - - if (! EV_GET_CHAR(ev,&cmd,&p,&q)) { - ErlDrvTermData output[] = { - ERL_DRV_ATOM, a_ose_drv_reply, - ERL_DRV_PORT, driver_mk_port(ctxt->port), - ERL_DRV_ATOM, a_badarg, - ERL_DRV_TUPLE, 3}; - send_response(ctxt->port, output); - return; - } - - /* Command is in the buffer's first byte */ - switch(cmd) { - - case OPEN: { - char *name = driver_alloc(ev->size - 1+1); - struct OS_redir_entry redir[2]; - - redir[0].sig = 1; - redir[0].pid = current_process(); - - iov_memcpy(name,ev,q,p); - name[ev->size-1] = '\0'; - - ctxt->spid = create_process(OS_PHANTOM, name, NULL, 0, - 0, 0, 0, redir, 0, 0); - - DEBUGP("0x%x: open\n",ctxt->spid); - - ctxt->perm_events[1] = - erl_drv_ose_event_alloc(ERTS_SIGNAL_OSE_DRV_ATTACH,(int)ctxt->spid, - resolve_signal, NULL); - driver_select(ctxt->port,ctxt->perm_events[1],ERL_DRV_READ|ERL_DRV_USE,1); - - ctxt->perm_events[0] = - erl_drv_ose_event_alloc(ERTS_SIGNAL_OSE_DRV_HUNT,(int)ctxt->spid, - resolve_signal, NULL); - driver_select(ctxt->port,ctxt->perm_events[0],ERL_DRV_READ|ERL_DRV_USE,1); - - start(ctxt->spid); - - { - ErlDrvTermData output[] = { - ERL_DRV_ATOM, a_ose_drv_reply, - ERL_DRV_PORT, driver_mk_port(ctxt->port), - ERL_DRV_ATOM, a_ok, - ERL_DRV_TUPLE, 3}; - - send_response(ctxt->port, output); - } - - break; - - } - - case ATTACH: - case HUNT: - { - union SIGNAL *sig = alloc(sizeof(union SIGNAL), - cmd == HUNT ? ERTS_SIGNAL_OSE_DRV_HUNT:ERTS_SIGNAL_OSE_DRV_ATTACH); - - sig->async.port = driver_mk_port(ctxt->port); - sig->async.proc = driver_caller(ctxt->port); - sig->async.spid = ctxt->spid; - sig->async.ref = ++ctxt->ref; - - if (add_reference(ctxt,ctxt->ref)) { - ErlDrvTermData output[] = { - ERL_DRV_ATOM, a_ose_drv_reply, - ERL_DRV_PORT, driver_mk_port(ctxt->port), - ERL_DRV_ATOM, a_enomem, - ERL_DRV_TUPLE, 3}; - send_response(ctxt->port, output); - free_buf(&sig); - } else { - ErlDrvTermData output[] = { - ERL_DRV_ATOM, a_ose_drv_reply, - ERL_DRV_PORT, driver_mk_port(ctxt->port), - ERL_DRV_PORT, driver_mk_port(ctxt->port), - ERL_DRV_INT, (ErlDrvUInt)ctxt->ref, - ERL_DRV_TUPLE, 2, - ERL_DRV_TUPLE, 3}; - send_response(ctxt->port, output); - - if (cmd == HUNT) { - char *huntname = driver_alloc(sizeof(char)*((ev->size-1)+1)); - - iov_memcpy(huntname,ev,q,p); - huntname[ev->size-1] = '\0'; - - DEBUGP_HUNT("0x%x: hunt %s -> %u (%u,%u)\n", - ctxt->spid,huntname,ctxt->ref, - ctxt->outstanding_refs_cnt, - ctxt->outstanding_refs_max); - - hunt(huntname, 0, NULL, &sig); - - driver_free(huntname); - } else { - EV_GET_UINT32(ev,&sig->async.target,&p,&q); - DEBUGP_ATTACH("0x%x: attach %u -> %u (%u,%u)\n", - ctxt->spid,sig->async.target, - ctxt->ref, - ctxt->outstanding_refs_cnt, - ctxt->outstanding_refs_max); - - send(&sig,proxy_proc); - } - - } - - break; - } - - case DETACH: - case DEHUNT: - { - - Uint32 ref; - - EV_GET_UINT32(ev,&ref,&p,&q); - if (cmd == DETACH) { - DEBUGP_ATTACH("0x%x: detach %u (%u,%u)\n",ctxt->spid,ref, - ctxt->outstanding_refs_cnt, - ctxt->outstanding_refs_max); - } else { - DEBUGP_HUNT("0x%x: dehunt %u (%u,%u)\n",ctxt->spid,ref, - ctxt->outstanding_refs_cnt, - ctxt->outstanding_refs_max); - } - - if (remove_reference(ctxt,ref)) { - ErlDrvTermData output[] = { - ERL_DRV_ATOM, a_ose_drv_reply, - ERL_DRV_PORT, driver_mk_port(ctxt->port), - ERL_DRV_ATOM, a_error, - ERL_DRV_ATOM, a_enoent, - ERL_DRV_TUPLE, 2, - ERL_DRV_TUPLE, 3}; - - send_response(ctxt->port, output); - } else { - ErlDrvTermData output[] = { - ERL_DRV_ATOM, a_ose_drv_reply, - ERL_DRV_PORT, driver_mk_port(ctxt->port), - ERL_DRV_ATOM, a_ok, - ERL_DRV_TUPLE, 3}; - - send_response(ctxt->port, output); - } - - break; - } - - case SEND: - case SEND_W_S: - { - PROCESS spid; - PROCESS sender; - SIGSELECT signo; - OSBUFSIZE size = ev->size-9; - union SIGNAL *sig; - - EV_GET_UINT32(ev,&spid,&p,&q); - - if (cmd == SEND_W_S) { - EV_GET_UINT32(ev,&sender,&p,&q); - size -= 4; - } else { - sender = ctxt->spid; - } - - EV_GET_UINT32(ev,&signo,&p,&q); - - sig = alloc(size + sizeof(SIGSELECT),signo); - - if (cmd == SEND_W_S) { - DEBUGP_SEND("0x%x: send_w_s(%u,%u,%u)\n",ctxt->spid,spid,signo,sender); - } else { - DEBUGP_SEND("0x%x: send(%u,%u)\n",ctxt->spid,spid,signo); - } - - iov_memcpy(((char *)&sig->signo) + sizeof(SIGSELECT),ev,q,p); - - send_w_s(&sig, sender, spid); - - break; - } - - case LISTEN: - { - int i,j,event_cnt = (ev->size - 1)/4; - ErlDrvEvent *events = NULL; - SIGSELECT signo,tmp_signo; - - if (event_cnt == 0) { - for (i = 0; i < ctxt->event_cnt; i++) - driver_select(ctxt->port,ctxt->events[i],ERL_DRV_READ|ERL_DRV_USE,0); - if (ctxt->events) - driver_free(ctxt->events); - } else { - events = driver_alloc(sizeof(ErlDrvEvent)*event_cnt); - EV_GET_UINT32(ev,&signo,&p,&q); - for (i = 0, j = 0; i < event_cnt || j < ctxt->event_cnt; ) { - - if (ctxt->events) - erl_drv_ose_event_fetch(ctxt->events[j],&tmp_signo,NULL,NULL); - - if (signo == tmp_signo) { - events[i++] = ctxt->events[j++]; - EV_GET_UINT32(ev,&signo,&p,&q); - } else if (signo < tmp_signo || !ctxt->events) { - /* New signal to select on */ - events[i] = erl_drv_ose_event_alloc(signo,(int)ctxt->spid, - resolve_signal, NULL); - driver_select(ctxt->port,events[i++],ERL_DRV_READ|ERL_DRV_USE,1); - EV_GET_UINT32(ev,&signo,&p,&q); - } else { - /* Remove old signal to select on */ - driver_select(ctxt->port,ctxt->events[j++],ERL_DRV_READ|ERL_DRV_USE,0); - } - } - if (ctxt->events) - driver_free(ctxt->events); - } - ctxt->events = events; - ctxt->event_cnt = event_cnt; - - { - ErlDrvTermData output[] = { - ERL_DRV_ATOM, a_ose_drv_reply, - ERL_DRV_PORT, driver_mk_port(ctxt->port), - ERL_DRV_ATOM, a_ok, - ERL_DRV_TUPLE, 3}; - send_response(ctxt->port, output); - } - break; - } - - default: - { - DEBUGP("Warning: 'ose_signal_drv' unknown command '%d'\n", cmd); - break; - } - } -} - -/** - * Handler for when OSE signal arrives - **/ -static void ready_input(ErlDrvData driver_data, ErlDrvEvent event) -{ - driver_context_t *ctxt = (driver_context_t *)driver_data; - union SIGNAL *sig = erl_drv_ose_get_signal(event); - - while (sig != NULL) { - - switch(sig->signo) - { - /* Remote process is available */ - case ERTS_SIGNAL_OSE_DRV_HUNT: - { - const PROCESS spid = sender(&sig); - - if (remove_reference(ctxt,sig->async.ref)) { - DEBUGP_HUNT("0x%x: Got hunt from 0x%x -> %u (CANCELLED) (%u,%u)\n", - ctxt->spid,spid,sig->async.ref, - ctxt->outstanding_refs_cnt, - ctxt->outstanding_refs_max); - /* Already removed by dehunt */ - } else { - ErlDrvTermData reply[] = { - ERL_DRV_ATOM, a_mailbox_up, - ERL_DRV_PORT, sig->async.port, - ERL_DRV_PORT, sig->async.port, - ERL_DRV_UINT, (ErlDrvUInt)sig->async.ref, - ERL_DRV_TUPLE, 2, - ERL_DRV_UINT, (ErlDrvUInt)spid, - ERL_DRV_TUPLE, 4}; - DEBUGP_HUNT("0x%x: Got hunt from 0x%x -> %u (%u,%u)\n", - ctxt->spid,spid,sig->async.ref, - ctxt->outstanding_refs_cnt, - ctxt->outstanding_refs_max); - erl_drv_send_term(sig->async.port, sig->async.proc, reply, - sizeof(reply) / sizeof(reply[0])); - } - break; - } - - /* Remote process is down */ - case ERTS_SIGNAL_OSE_DRV_ATTACH: - { - PROCESS spid = sig->async.target; - - if (remove_reference(ctxt,sig->async.ref)) { - DEBUGP_ATTACH("0x%x: Got attach from 0x%x -> %u (CANCELLED) (%u,%u)\n", - ctxt->spid,spid,sig->async.ref, - ctxt->outstanding_refs_cnt, - ctxt->outstanding_refs_max); - /* Already removed by detach */ - } else { - ErlDrvTermData reply[] = { - ERL_DRV_ATOM, a_mailbox_down, - ERL_DRV_PORT, sig->async.port, - ERL_DRV_PORT, sig->async.port, - ERL_DRV_UINT, sig->async.ref, - ERL_DRV_TUPLE, 2, - ERL_DRV_UINT, (ErlDrvUInt)spid, - ERL_DRV_TUPLE, 4}; - DEBUGP_ATTACH("0x%x: Got attach from 0x%x -> %u (%u,%u)\n", - ctxt->spid,spid,sig->async.ref, - ctxt->outstanding_refs_cnt, - ctxt->outstanding_refs_max); - erl_drv_send_term(sig->async.port, sig->async.proc, reply, - sizeof(reply) / sizeof(reply[0])); - } - break; - } - - /* Received user defined signal */ - default: - { - const PROCESS spid = sender(&sig); - const OSBUFSIZE size = sigsize(&sig) - sizeof(SIGSELECT); - const char *sig_data = ((char *)&sig->signo) + sizeof(SIGSELECT); - - ErlDrvTermData reply[] = { - ERL_DRV_ATOM, a_message, - ERL_DRV_PORT, driver_mk_port(ctxt->port), - ERL_DRV_UINT, (ErlDrvUInt)spid, - ERL_DRV_UINT, (ErlDrvUInt)ctxt->spid, - ERL_DRV_UINT, (ErlDrvUInt)sig->signo, - ERL_DRV_BUF2BINARY, (ErlDrvTermData)sig_data, (ErlDrvUInt)size, - ERL_DRV_TUPLE, 4, - ERL_DRV_TUPLE, 3}; - - DEBUGP_SEND("0x%x: Got 0x%u\r\n", spid, sig->signo); - - erl_drv_output_term(driver_mk_port(ctxt->port), reply, - sizeof(reply) / sizeof(reply[0])); - break; - } - } - - free_buf(&sig); - sig = erl_drv_ose_get_signal(event); - } -} - -/** - * Handler for 'port_control' - **/ -static ErlDrvSSizeT control(ErlDrvData driver_data, unsigned int cmd, - char *buf, ErlDrvSizeT len, - char **rbuf, ErlDrvSizeT rlen) -{ - driver_context_t *ctxt = (driver_context_t *)driver_data; - - switch(cmd) - { - case GET_SPID: - { - const PROCESS spid = ctxt->spid; - put_u32(spid, *rbuf); - return sizeof(PROCESS); - } - -#ifdef HAVE_OSE_SPI_H - case GET_NAME: - { - const PROCESS spid = get_u32(buf); - char *name = (char*)get_pid_info(spid,OSE_PI_NAME); - int n; - if (!name) { - *rbuf = NULL; - return 0; - } - - if (rlen < (n = strlen(name))) { - ErlDrvBinary *bin = driver_alloc_binary(n); - strncpy(bin->orig_bytes,name,n); - *rbuf = (char*)bin; - } else - strncpy(*rbuf,name,n); - free_buf((union SIGNAL**)&name); - - return n; - } -#endif - default: - { - /* Unknown command */ - return (ErlDrvSSizeT)ERL_DRV_ERROR_GENERAL; - break; - } - } -} - -static void stop_select(ErlDrvEvent event, void *reserved) -{ - erl_drv_ose_event_free(event); -} - -/** - * Setup the driver entry for the Erlang runtime - **/ -ErlDrvEntry ose_signal_driver_entry = { - .init = drv_init, - .start = drv_start, - .stop = drv_stop, - .outputv = outputv, - .ready_input = ready_input, - .driver_name = DRIVER_NAME, - .control = control, - .extended_marker = ERL_DRV_EXTENDED_MARKER, - .major_version = ERL_DRV_EXTENDED_MAJOR_VERSION, - .minor_version = ERL_DRV_EXTENDED_MINOR_VERSION, - .driver_flags = ERL_DRV_FLAG_USE_PORT_LOCKING, - .stop_select = stop_select -}; - diff --git a/erts/emulator/drivers/ose/ttsl_drv.c b/erts/emulator/drivers/ose/ttsl_drv.c deleted file mode 100644 index f759b47984..0000000000 --- a/erts/emulator/drivers/ose/ttsl_drv.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1996-2013. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * %CopyrightEnd% - */ -/* - * Stub tty driver because group/user depend on this. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "erl_driver.h" - -static int ttysl_init(void); -static ErlDrvData ttysl_start(ErlDrvPort, char*); - -/* Define the driver table entry. */ -struct erl_drv_entry ttsl_driver_entry = { - ttysl_init, - ttysl_start, - NULL, - NULL, - NULL, - NULL, - "tty_sl", - NULL, - NULL, - 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, /* ERL_DRV_FLAGs */ - NULL, - NULL, /* process_exit */ - NULL -}; - - -static int ttysl_init(void) -{ - return 0; -} - -static ErlDrvData ttysl_start(ErlDrvPort port, char* buf) -{ - return ERL_DRV_ERROR_GENERAL; -} -- cgit v1.2.3 From d2bb1ca56dcd0ab8e5b43c4368409317c3ddd4db Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Tue, 18 Aug 2015 16:18:42 +0200 Subject: erts: Fix binary memory leak in ttsl driver --- erts/emulator/drivers/unix/ttsl_drv.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/unix/ttsl_drv.c b/erts/emulator/drivers/unix/ttsl_drv.c index 0f773b69fb..53146e71f0 100644 --- a/erts/emulator/drivers/unix/ttsl_drv.c +++ b/erts/emulator/drivers/unix/ttsl_drv.c @@ -720,6 +720,7 @@ static void ttysl_from_erlang(ErlDrvData ttysl_data, char* buf, ErlDrvSizeT coun } driver_enq_bin(ttysl_port,putcbuf,0,putcpos); + driver_free_binary(putcbuf); if (sz == 0) { for (;;) { @@ -1207,6 +1208,7 @@ static int outc(int c) putcbuf->orig_bytes[putcpos++] = c; if (putcpos == putclen) { driver_enq_bin(ttysl_port,putcbuf,0,putclen); + driver_free_binary(putcbuf); putcpos = 0; putclen = TTY_BUFFSIZE; putcbuf = driver_alloc_binary(BUFSIZ); -- cgit v1.2.3 From 5a02ed2f3505f5ed3282c6b43963e19e63e49905 Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Tue, 25 Aug 2015 15:47:29 +0200 Subject: Fix ethread events with timeout Lots of pthread platforms unnecessarily falled back on the pipe/select solution. This since we tried to use the same monotonic clock source for pthread_cond_timedwait() as used by OS monotonic time. This has been fixed on most platforms by using another clock source. Darwin can however not use pthread_cond_timedwait() with monotonic clock source and has to use the pipe/select solution. On darwin we now use select with _DARWIN_UNLIMITED_SELECT in order to be able to handle a large amount of file descriptors. --- erts/emulator/drivers/unix/unix_efile.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c index 06ba986044..46eccc6568 100644 --- a/erts/emulator/drivers/unix/unix_efile.c +++ b/erts/emulator/drivers/unix/unix_efile.c @@ -45,10 +45,10 @@ #endif #if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__) -#define DARWIN 1 +#define __DARWIN__ 1 #endif -#if defined(DARWIN) || defined(HAVE_LINUX_FALLOC_H) || defined(HAVE_POSIX_FALLOCATE) +#if defined(__DARWIN__) || defined(HAVE_LINUX_FALLOC_H) || defined(HAVE_POSIX_FALLOCATE) #include #endif @@ -476,11 +476,11 @@ efile_fsync(Efile_error *errInfo, /* Where to return error codes. */ #ifdef NO_FSYNC undefined fsync /* XXX: Really? */ #else -#if defined(DARWIN) && defined(F_FULLFSYNC) +#if defined(__DARWIN__) && defined(F_FULLFSYNC) return check_error(fcntl(fd, F_FULLFSYNC), errInfo); #else return check_error(fsync(fd), errInfo); -#endif /* DARWIN */ +#endif /* __DARWIN__ */ #endif /* NO_FSYNC */ } @@ -962,7 +962,7 @@ efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd, retval = len; } } while (len == SENDFILE_CHUNK_SIZE); -#elif defined(DARWIN) +#elif defined(__DARWIN__) int retval; off_t len; do { -- cgit v1.2.3 From efa86bac1cdac245213183574eca5f4662e80c7f Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Mon, 7 Sep 2015 16:33:09 +0200 Subject: erts: Fix inet packet mode ssl_tls for passive mode Caused stack corruption leading to VM crash on windows. {packet,ssl_tls} is undocumented by the way. --- erts/emulator/drivers/common/inet_drv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 549de6503c..89b71aa66a 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -2749,7 +2749,7 @@ int ssl_tls_inetdrv(void* arg, unsigned type, unsigned major, unsigned minor, { tcp_descriptor* desc = (tcp_descriptor*) arg; int i = 0; - ErlDrvTermData spec[28]; + ErlDrvTermData spec[30]; ErlDrvTermData caller = ERL_DRV_NIL; ErlDrvBinary* bin; int ret; @@ -2790,11 +2790,11 @@ int ssl_tls_inetdrv(void* arg, unsigned type, unsigned major, unsigned minor, if (desc->inet.active == INET_PASSIVE) { i = LOAD_TUPLE(spec, i, 2); i = LOAD_TUPLE(spec, i, 4); - ASSERT(i <= 28); + ASSERT(i <= sizeof(spec)/sizeof(*spec)); ret = erl_drv_send_term(desc->inet.dport, caller, spec, i); } else { - ASSERT(i <= 28); + ASSERT(i <= sizeof(spec)/sizeof(*spec)); ret = erl_drv_output_term(desc->inet.dport, spec, i); } done: -- cgit v1.2.3 From 11cf60809a26155c7904771974739f4a51911c93 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Tue, 15 Sep 2015 15:23:56 +0200 Subject: erts: Make sure to deal with EINTR write failures --- erts/emulator/drivers/unix/ttsl_drv.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/unix/ttsl_drv.c b/erts/emulator/drivers/unix/ttsl_drv.c index 53146e71f0..25cad37e25 100644 --- a/erts/emulator/drivers/unix/ttsl_drv.c +++ b/erts/emulator/drivers/unix/ttsl_drv.c @@ -733,13 +733,13 @@ static void ttysl_from_erlang(ErlDrvData ttysl_data, char* buf, ErlDrvSizeT coun else written = 0; if (written < 0) { - if (errno == EAGAIN) { + if (errno == ERRNO_BLOCK || errno == EINTR) { driver_select(ttysl_port,(ErlDrvEvent)(long)ttysl_fd, ERL_DRV_USE|ERL_DRV_WRITE,1); break; } else { - /* we ignore all other errors */ - break; + driver_failure_posix(ttysl_port, errno); + return; } } else { if (driver_deq(ttysl_port, written) == 0) @@ -779,11 +779,12 @@ static void ttysl_to_tty(ErlDrvData ttysl_data, ErlDrvEvent fd) { else written = 0; if (written < 0) { - if (errno == EAGAIN) { - break; - } else { - /* we ignore all other errors */ + if (errno == EINTR) { + continue; + } else if (errno != ERRNO_BLOCK){ + driver_failure_posix(ttysl_port, errno); } + break; } else { sz = driver_deq(ttysl_port, written); if (sz < TTY_BUFFSIZE && ttysl_send_ok) { -- cgit v1.2.3 From 285b4fa13914dc4748c1020213a9c65cad3d2738 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 2 Jun 2015 08:44:23 -0400 Subject: erts: Add {line_delimiter, byte()} option to inet:setopts/2 A new {line_delimiter, byte()} option allows line-oriented TCP-based protocols to use a custom line delimiting character. It is to be used in conjunction with {packet, line}. This option also works with erlang:decode_packet/3 when its first argument is 'line'. --- erts/emulator/drivers/common/inet_drv.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 89b71aa66a..a829599fe5 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -885,6 +885,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #define INET_LOPT_MSGQ_LOWTRMRK 37 /* set local msgq low watermark */ #define INET_LOPT_NETNS 38 /* Network namespace pathname */ #define INET_LOPT_TCP_SHOW_ECONNRESET 39 /* tell user about incoming RST */ +#define INET_LOPT_LINE_DELIM 40 /* Line delimiting char */ /* SCTP options: a separate range, from 100: */ #define SCTP_OPT_RTOINFO 100 #define SCTP_OPT_ASSOCINFO 101 @@ -1154,6 +1155,7 @@ typedef struct { #else Uint32 send_oct[2]; /* number of octets sent, 64 bits */ #endif + char delimiter; /* Line delimiting character (def: '\n') */ unsigned long send_cnt; /* number of packets sent */ unsigned long send_max; /* maximum packet send */ double send_avg; /* average packet size sent */ @@ -6276,6 +6278,12 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) } continue; + case INET_LOPT_LINE_DELIM: + DEBUGF(("inet_set_opts(%ld): s=%d, LINE_DELIM=%d\r\n", + (long)desc->port, desc->s, ival)); + desc->delimiter = (char)ival; + continue; + case INET_OPT_REUSEADDR: #ifdef __WIN32__ continue; /* Bjorn says */ @@ -8371,6 +8379,7 @@ static ErlDrvData inet_start(ErlDrvPort port, int size, int protocol) desc->deliver = INET_DELIVER_TERM; /* standard term format */ desc->active = INET_PASSIVE; /* start passive */ desc->active_count = 0; + desc->delimiter = '\n'; /* line delimiting char */ desc->oph = NULL; desc->opt = NULL; @@ -9882,7 +9891,7 @@ static int tcp_remain(tcp_descriptor* desc, int* len) tlen = packet_get_length(desc->inet.htype, ptr, n, desc->inet.psize, desc->i_bufsz, - &desc->http_state); + desc->inet.delimiter, &desc->http_state); DEBUGF(("tcp_remain(%ld): s=%d, n=%d, nfill=%d nsz=%d, tlen %d\r\n", (long)desc->inet.port, desc->inet.s, n, nfill, nsz, tlen)); -- cgit v1.2.3 From afac3c7136c48d8630bd400c5454e146915e634f Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Mon, 26 Oct 2015 14:46:54 +0100 Subject: erts: Add {line_delimiter, byte()} option to inet:setopts/2 A new {line_delimiter, byte()} option allows line-oriented TCP-based protocols to use a custom line delimiting character. It is to be used in conjunction with {packet, line}. This option also works with erlang:decode_packet/3 when its first argument is 'line'. --- erts/emulator/drivers/common/inet_drv.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 89b71aa66a..a829599fe5 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -885,6 +885,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #define INET_LOPT_MSGQ_LOWTRMRK 37 /* set local msgq low watermark */ #define INET_LOPT_NETNS 38 /* Network namespace pathname */ #define INET_LOPT_TCP_SHOW_ECONNRESET 39 /* tell user about incoming RST */ +#define INET_LOPT_LINE_DELIM 40 /* Line delimiting char */ /* SCTP options: a separate range, from 100: */ #define SCTP_OPT_RTOINFO 100 #define SCTP_OPT_ASSOCINFO 101 @@ -1154,6 +1155,7 @@ typedef struct { #else Uint32 send_oct[2]; /* number of octets sent, 64 bits */ #endif + char delimiter; /* Line delimiting character (def: '\n') */ unsigned long send_cnt; /* number of packets sent */ unsigned long send_max; /* maximum packet send */ double send_avg; /* average packet size sent */ @@ -6276,6 +6278,12 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) } continue; + case INET_LOPT_LINE_DELIM: + DEBUGF(("inet_set_opts(%ld): s=%d, LINE_DELIM=%d\r\n", + (long)desc->port, desc->s, ival)); + desc->delimiter = (char)ival; + continue; + case INET_OPT_REUSEADDR: #ifdef __WIN32__ continue; /* Bjorn says */ @@ -8371,6 +8379,7 @@ static ErlDrvData inet_start(ErlDrvPort port, int size, int protocol) desc->deliver = INET_DELIVER_TERM; /* standard term format */ desc->active = INET_PASSIVE; /* start passive */ desc->active_count = 0; + desc->delimiter = '\n'; /* line delimiting char */ desc->oph = NULL; desc->opt = NULL; @@ -9882,7 +9891,7 @@ static int tcp_remain(tcp_descriptor* desc, int* len) tlen = packet_get_length(desc->inet.htype, ptr, n, desc->inet.psize, desc->i_bufsz, - &desc->http_state); + desc->inet.delimiter, &desc->http_state); DEBUGF(("tcp_remain(%ld): s=%d, n=%d, nfill=%d nsz=%d, tlen %d\r\n", (long)desc->inet.port, desc->inet.s, n, nfill, nsz, tlen)); -- cgit v1.2.3 From 4580ee5b133f680cf808ea12ebc0c930e97643b2 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Thu, 19 Nov 2015 12:24:48 +0100 Subject: Fix error propagate from setopts --- erts/emulator/drivers/common/inet_drv.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 3c6922eb8e..6fff863fa6 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2013. All Rights Reserved. + * Copyright Ericsson AB 1997-2015. 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 @@ -6051,9 +6051,9 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) int arg_sz; enum PacketParseType old_htype = desc->htype; int old_active = desc->active; - int propagate = 0; /* Set to 1 if failure to set this option - should be propagated to erlang (not all - errors can be propagated for BC reasons) */ + int propagate; /* Set to 1 if failure to set this option + should be propagated to erlang (not all + errors can be propagated for BC reasons) */ int res; #ifdef HAVE_SCTP /* SCTP sockets are treated completely separately: */ @@ -6070,6 +6070,7 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) arg_ptr = (char*) &ival; arg_sz = sizeof(ival); proto = SOL_SOCKET; + propagate = 0; switch(opt) { case INET_LOPT_HEADER: -- cgit v1.2.3 From bb1869148129c8ad30167e74aa6b4d7f16798116 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 22 Sep 2015 15:29:30 +0200 Subject: erts: Remove double free in efile_drv That double free is probably very seldom invoked as the port is already gone leading to free_data being called instead of file_async_ready. --- erts/emulator/drivers/common/efile_drv.c | 1 - 1 file changed, 1 deletion(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 8aff6c1865..3b6abec25e 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -2581,7 +2581,6 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data) case FILE_CLOSE_ON_PORT_EXIT: /* See file_stop. However this is never invoked after the port is killed. */ free_data(data); - EF_FREE(desc); desc = NULL; /* This is it for this port, so just send dtrace and return, avoid doing anything to the freed data */ DTRACE6(efile_drv_return, sched_i1, sched_i2, sched_utag, -- cgit v1.2.3 From fe72df791e7857fa72f6ac2b7ba476212a0c2edd Mon Sep 17 00:00:00 2001 From: Mikael Pettersson Date: Sun, 20 Dec 2015 17:02:15 +0100 Subject: efile_drv: logic error in compressed file write Compiling OTP 18.2.1 with gcc-5.3 shows the following warning: drivers/common/efile_drv.c:1538:23: warning: logical not is only applied to the left hand side of comparison [-Wlogical-not-parentheses] The code in question is: if (! (status = erts_gzwrite((ErtsGzFile)d->fd, iov[i].iov_base, iov[i].iov_len)) == iov[i].iov_len) { d->errInfo.posix_errno = d->errInfo.os_errno = errno; /* XXX Correct? */ break; } If we hoist the assignment out of the if for clarity, it becomes: status = erts_gzwrite(..., iov[i].iov_len); if (! status == iov[i].iov_len) { ...; break; } iov_len is > 0 here, and status will equal iov_len if erts_gzwrite succeeded, but will be less than iov_len if an error occurred. "! status" is 0 or 1, which can only equal iov_len if iov_len is 1 and erts_gzwrite detected an error and returned 0. The effect of this mistake is that any error when iov_len >= 2 will skip the conditional code and break statement. In particular, partial writes (0 < status && status < iov_len) will not be flagged as errors. All releases since OTP R8B-0 are affected. The variable "status" is really a boolean, which is to be set to zero on error. The fix is to set status to 1 if erts_gzwrite() returned iov_len and 0 otherwise, and to change the condition to "if (! status) ...". I'm also hoisting the assignment out of the condition since it obscures the code while providing not benefit (the condition in a while or for loop would be a different matter). --- erts/emulator/drivers/common/efile_drv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 3b6abec25e..a5a5dfb7f8 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -1532,10 +1532,10 @@ static void invoke_writev(void *data) { * with errno. */ errno = EINVAL; - if (! (status = - erts_gzwrite((ErtsGzFile)d->fd, - iov[i].iov_base, - iov[i].iov_len)) == iov[i].iov_len) { + status = erts_gzwrite((ErtsGzFile)d->fd, + iov[i].iov_base, + iov[i].iov_len) == iov[i].iov_len; + if (! status) { d->errInfo.posix_errno = d->errInfo.os_errno = errno; /* XXX Correct? */ break; -- cgit v1.2.3 From e293ad1b08b2f937555a102e6f3b4336574773c8 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 30 Dec 2015 13:29:34 -0500 Subject: Assign externally open fd to gen_tcp (UDS support) When a AF_LOCAL file descriptor is created externally (e.g. Unix Domain Socket) and passed to `gen_tcp:listen(0, [{fd, FD}])`, the implementation incorrectly assigned the address family to be equal to `inet`, which in the inet_drv driver translated to AF_INET instead of AF_LOCAL (or AF_UNIX), and an `einval` error code was returned. This patch fixes this problem such that the file descriptors of the `local` address family are supported in the inet:fdopen/5, gen_tcp:connect/3, gen_tcp:listen/2, gen_udp:open/2 calls --- erts/emulator/drivers/common/inet_drv.c | 161 +++++++++++++++++++++++++++++--- 1 file changed, 148 insertions(+), 13 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 89011d89ad..bd4543f831 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -58,6 +58,9 @@ #ifdef HAVE_NETPACKET_PACKET_H #include #endif +#ifdef HAVE_SYS_UN_H +#include +#endif /* All platforms fail on malloc errors. */ #define FATAL_MALLOC @@ -747,6 +750,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #define INET_AF_INET6 2 #define INET_AF_ANY 3 /* INADDR_ANY or IN6ADDR_ANY_INIT */ #define INET_AF_LOOPBACK 4 /* INADDR_LOOPBACK or IN6ADDR_LOOPBACK_INIT */ +#define INET_AF_LOCAL 5 /* open and INET_REQ_GETTYPE enumeration */ #define INET_TYPE_STREAM 1 @@ -1032,19 +1036,29 @@ typedef union { #ifdef HAVE_IN6 struct sockaddr_in6 sai6; #endif +#ifdef HAVE_SYS_UN_H + struct sockaddr_un sal; +#endif } inet_address; /* for AF_INET & AF_INET6 */ #define inet_address_port(x) ((x)->sai.sin_port) +#ifdef HAVE_SYS_UN_H +#define localaddrlen(family, data) \ + ((family == AF_LOCAL) ? *(unsigned char*)(data) : 0) +#else + 0 +#endif + #if defined(HAVE_IN6) && defined(AF_INET6) -#define addrlen(family) \ +#define addrlen(family, data) \ ((family == AF_INET) ? sizeof(struct in_addr) : \ - ((family == AF_INET6) ? sizeof(struct in6_addr) : 0)) + ((family == AF_INET6) ? sizeof(struct in6_addr) : localaddrlen(family, data))) #else -#define addrlen(family) \ - ((family == AF_INET) ? sizeof(struct in_addr) : 0) +#define addrlen(family, data) \ + ((family == AF_INET) ? sizeof(struct in_addr) : localaddrlen(family, data)) #endif typedef struct _multi_timer_data { @@ -1727,6 +1741,12 @@ static int load_ip_address(ErlDrvTermData* spec, int i, int family, char* buf) spec[i++] = ERL_DRV_TUPLE; spec[i++] = 8; } +#endif +#ifdef HAVE_SYS_UN_H + else if (family == AF_LOCAL) { + int len = *(unsigned char*)buf++; + i = LOAD_STRING(spec, i, buf, len); + } #endif else { spec[i++] = ERL_DRV_TUPLE; @@ -3573,10 +3593,11 @@ static int tcp_error_message(tcp_descriptor* desc, int err) #ifdef HAVE_UDP /* ** active mode message: -** {udp, S, IP, Port, [H1,...Hsz | Data]} or -** {sctp, S, IP, Port, {[AncilData], Event_or_Data}} +** {udp, S, IP, Port, [H1,...Hsz | Data]} or +** {sctp, S, IP, Port, {[AncilData], Event_or_Data}} ** where ** [H1,...,HSz] are msg headers (without IP/Port, UDP only), +** [AddrLen, H2,...,HSz] are msg headers for UDP AF_LOCAL only ** Data : List() | Binary() */ static int packet_binary_message @@ -3586,6 +3607,7 @@ static int packet_binary_message ErlDrvTermData spec [PACKET_ERL_DRV_TERM_DATA_LEN]; int i = 0; int alen; + char* data = bin->orig_bytes+offs; DEBUGF(("packet_binary_message(%ld): len = %d\r\n", (long)desc->port, len)); @@ -3596,10 +3618,15 @@ static int packet_binary_message # endif i = LOAD_PORT(spec, i, desc->dport); /* S */ - alen = addrlen(desc->sfamily); - i = load_ip_address(spec, i, desc->sfamily, bin->orig_bytes+offs+3); - i = load_ip_port(spec, i, bin->orig_bytes+offs+1); /* IP, Port */ + alen = addrlen(desc->sfamily, data+3); + i = load_ip_address(spec, i, desc->sfamily, data+3); + i = load_ip_port(spec, i, data+1); /* IP, Port */ +# ifdef HAVE_SYS_UN_H + /* AF_LOCAL addresses have a prefix byte containing address length */ + if (desc->sfamily == AF_LOCAL) + alen++; +# endif offs += (alen + 3); len -= (alen + 3); @@ -4151,6 +4178,16 @@ static char* inet_set_address(int family, inet_address* dst, *len = sizeof(struct sockaddr_in6); return src + 2+16; } +#endif +#ifdef HAVE_SYS_UN_H + else if ((family == AF_LOCAL) && (*len >= 3+sizeof(struct sockaddr_un))) { + int n = *((unsigned char*)src+2); + dst->sal.sun_family = family; + sys_memcpy(dst->sal.sun_path, src+3, n); + dst->sal.sun_path[n-1] = '\0'; + *len = n; + return src + 3 + n; + } #endif return NULL; } @@ -4160,7 +4197,7 @@ static char* inet_set_address(int family, inet_address* dst, ** or from argument if source data specifies constant address. ** ** src = [TAG,P1,P0] when TAG = INET_AF_ANY | INET_AF_LOOPBACK -** src = [TAG,P1,P0,X1,X2,...] when TAG = INET_AF_INET | INET_AF_INET6 +** src = [TAG,P1,P0,X1,X2,...] when TAG = INET_AF_INET | INET_AF_INET6 | INET_AF_LOCAL */ static char *inet_set_faddress(int family, inet_address* dst, char *src, ErlDrvSizeT* len) { @@ -4177,6 +4214,21 @@ static char *inet_set_faddress(int family, inet_address* dst, case INET_AF_INET6: family = AF_INET6; break; +# endif +# ifdef HAVE_SYS_UN_H + case INET_AF_LOCAL: { + int n; + if (*len || *len < 3) return NULL; + family = AF_LOCAL; + /* Next two bytes are the length of the local path (< 256) */ + src++; + n = *(unsigned char*)src++; + if (n+3 > *len) return NULL; + dst->sal.sun_family = family; + sys_memcpy(dst->sal.sun_path, src, n); + *len = n; + break; + } # endif case INET_AF_ANY: case INET_AF_LOOPBACK: { @@ -4241,7 +4293,6 @@ static char *inet_set_faddress(int family, inet_address* dst, return inet_set_address(family, dst, src, len); } - /* Get a inaddr structure ** src = inaddr structure ** *len is the lenght of structure @@ -4273,10 +4324,55 @@ static int inet_get_address(char* dst, inet_address* src, unsigned int* len) *len = 3 + sizeof(struct in6_addr); return 0; } +#endif +#ifdef HAVE_SYS_UN_H + else if ((family == AF_LOCAL) && *len > 0) { + int n = *len - 4; + dst[0] = INET_AF_LOCAL; + put_int16(0, dst+1); + if (n == 0 || n >= sizeof(src->sal.sun_path)) { + *(dst+3) = 0; + *len = 3+1; + } else { + *(dst+3) = n; + sys_memcpy(dst+4, src->sal.sun_path, n); + *len = 3+1+n; + } + return 0; + } #endif return -1; } +static int inet_family_get_address(inet_descriptor* desc, char* dst, inet_address* src, unsigned int* len) +{ +#ifdef HAVE_SYS_UN_H + if (desc->sfamily == AF_LOCAL) { + int n = *len - 4; + dst[0] = INET_AF_LOCAL; + put_int16(0, dst+1); + if (n <= 0 || n >= sizeof(src->sal.sun_path)) { + if (desc->name_ptr) { + char* p = desc->name_ptr->sal.sun_path; + n = strlen(p); + *(dst+3) = n; + sys_memcpy(dst+4, p, n); + *len = 3+1+n; + } else { + *(dst+3) = 0; + *len = 3+1; + } + } else { + *(dst+3) = n; + sys_memcpy(dst+4, src->sal.sun_path, n); + *len = 3+1+n; + } + return 0; + } +#endif + return inet_get_address(dst, src, len); +} + /* Same as the above, but take family from the address structure, ** and advance the address pointer to the next address ** according to the size of the current, @@ -4306,6 +4402,19 @@ static int inet_address_to_erlang(char *dst, inet_address **src) { } (*src) = (inet_address *) (&(*src)->sai6 + 1); return 1 + 2 + 16; +#endif +#ifdef HAVE_SYS_UN_H + case AF_LOCAL: { + int n = strlen((*src)->sal.sun_path); + if (dst) { + dst[0] = INET_AF_LOCAL; + put_int16(0, dst+1); + *(dst+3) = n; + sys_memcpy(dst+1+2+1, (*src)->sal.sun_path, n); + } + (*src) = (inet_address *) (&(*src)->sal + 1); + return 1+2+1+n; + } #endif default: return -1; @@ -4402,7 +4511,8 @@ static void desc_close_read(inet_descriptor* desc) static int erl_inet_close(inet_descriptor* desc) { free_subscribers(&desc->empty_out_q_subs); - if ((desc->prebound == 0) && (desc->state & INET_F_OPEN)) { + if ((desc->prebound == 0 || desc->sfamily == AF_LOCAL) && + (desc->state & INET_F_OPEN)) { desc_close(desc); desc->state = INET_STATE_CLOSED; } else if (desc->prebound && (desc->s != INVALID_SOCKET)) { @@ -4582,6 +4692,13 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type, return ctl_error(sock_errno(), rbuf, rsize); if (name.sa.sa_family != domain) return ctl_error(EINVAL, rbuf, rsize); +#ifdef HAVE_SYS_UN_H + if (domain == AF_LOCAL) { + sys_memcpy(&desc->name_addr, &name, sizeof(desc->name_addr)); + if (desc->name_ptr == NULL) + desc->name_ptr = &desc->name_addr; + } +#endif } #ifdef __OSE__ /* for fdopen duplicating the sd will allow to uniquely identify @@ -8570,6 +8687,11 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, else if (desc->sfamily == AF_INET6) { put_int32(INET_AF_INET6, &tbuf[0]); } +#endif +#ifdef HAVE_SYS_UN_H + else if (desc->sfamily == AF_LOCAL) { + put_int32(INET_AF_LOCAL, &tbuf[0]); + } #endif else return ctl_error(EINVAL, rbuf, rsize); @@ -9255,6 +9377,11 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, case INET_AF_INET6: return ctl_xerror("eafnosupport", rbuf, rsize); break; +#endif +#ifdef HAVE_SYS_UN_H + case INET_AF_LOCAL: + domain = AF_LOCAL; + break; #endif default: return ctl_error(EINVAL, rbuf, rsize); @@ -9281,6 +9408,11 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, case INET_AF_INET6: return ctl_xerror("eafnosupport", rbuf, rsize); break; +#endif +#ifdef HAVE_SYS_UN_H + case INET_AF_LOCAL: + domain = AF_LOCAL; + break; #endif default: return ctl_error(EINVAL, rbuf, rsize); @@ -11343,6 +11475,9 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, case INET_AF_INET6: return ctl_xerror("eafnosupport", rbuf, rsize); break; +#endif +#ifdef HAVE_SYS_UN_H + case INET_AF_LOCAL: af = AF_LOCAL; break; #endif default: return ctl_error(EINVAL, rbuf, rsize); @@ -11955,7 +12090,7 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event) inet_input_count(desc, n); udesc->i_ptr += n; - inet_get_address(abuf, &other, &len); + inet_family_get_address(desc, 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, -- cgit v1.2.3 From da89d3fa551d80c0b16cfd6d46580274cd644ace Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Tue, 19 Jan 2016 17:06:30 +0100 Subject: Fix inet driver multi timers using new time API --- erts/emulator/drivers/common/inet_drv.c | 139 +++----------------------------- 1 file changed, 13 insertions(+), 126 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 89011d89ad..43cb15a25f 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -1048,7 +1048,7 @@ typedef union { #endif typedef struct _multi_timer_data { - ErlDrvNowData when; + ErlDrvTime when; ErlDrvTermData caller; void (*timeout_function)(ErlDrvData drv_data, ErlDrvTermData caller); struct _multi_timer_data *next; @@ -12144,115 +12144,18 @@ make_noninheritable_handle(SOCKET s) * Multi-timers */ -static void absolute_timeout(unsigned millis, ErlDrvNowData *out) -{ - unsigned rest; - unsigned long millipart; - unsigned long secpart; - unsigned long megasecpart; - unsigned tmo_secs = (millis / 1000U); - unsigned tmo_millis = (millis % 1000); - driver_get_now(out); - rest = (out->microsecs) % 1000; - millipart = ((out->microsecs) / 1000UL); - if (rest >= 500) { - ++millipart; - } - secpart = out->secs; - megasecpart = out->megasecs; - millipart += tmo_millis; - secpart += (millipart / 1000000UL); - millipart %= 1000000UL; - secpart += tmo_secs; - megasecpart += (secpart / 1000000UL); - secpart %= 1000000UL; - out->megasecs = megasecpart; - out->secs = secpart; - out->microsecs = (millipart * 1000UL); -} - -static unsigned relative_timeout(ErlDrvNowData *in) -{ - ErlDrvNowData now; - unsigned rest; - unsigned long millipart, in_millis, in_secs, in_megasecs; - - driver_get_now(&now); - - in_secs = in->secs; - in_megasecs = in->megasecs; - - rest = (now.microsecs) % 1000; - millipart = ((now.microsecs) / 1000UL); - if (rest >= 500) { - ++millipart; - } - in_millis = ((in->microsecs) / 1000UL); - if ( in_millis < millipart ) { - if (in_secs > 0) { - --in_secs; - } else { - in_secs = (1000000UL - 1UL); - if (in_megasecs <= now.megasecs) { - return 0; - } else { - --in_megasecs; - } - } - in_millis += 1000UL; - } - in_millis -= millipart; - - if (in_secs < now.secs) { - if (in_megasecs <= now.megasecs) { - return 0; - } else { - --in_megasecs; - } - in_secs += 1000000; - } - in_secs -= now.secs; - if (in_megasecs < now.megasecs) { - return 0; - } else { - in_megasecs -= now.megasecs; - } - return (unsigned) ((in_megasecs * 1000000000UL) + - (in_secs * 1000UL) + - in_millis); -} - -#ifdef DEBUG -static int nowcmp(ErlDrvNowData *d1, ErlDrvNowData *d2) -{ - /* Assume it's not safe to do signed conversion on megasecs... */ - if (d1->megasecs < d2->megasecs) { - return -1; - } else if (d1->megasecs > d2->megasecs) { - return 1; - } else if (d1->secs != d2->secs) { - return ((int) d1->secs) - ((int) d2->secs); - } - return ((int) d1->microsecs) - ((int) d2->microsecs); -} -#endif - static void fire_multi_timers(MultiTimerData **first, ErlDrvPort port, ErlDrvData data) { - unsigned next_timeout; + ErlDrvTime next_timeout; if (!*first) { ASSERT(0); return; } #ifdef DEBUG { - ErlDrvNowData chk; - driver_get_now(&chk); - chk.microsecs /= 10000UL; - chk.microsecs *= 10000UL; - chk.microsecs += 10000; - ASSERT(nowcmp(&chk,&((*first)->when)) >= 0); + ErlDrvTime chk = erl_drv_monotonic_time(ERL_DRV_MSEC); + ASSERT(chk >= (*first)->when); } #endif do { @@ -12264,9 +12167,9 @@ static void fire_multi_timers(MultiTimerData **first, ErlDrvPort port, return; } (*first)->prev = NULL; - next_timeout = relative_timeout(&((*first)->when)); - } while (next_timeout == 0); - driver_set_timer(port,next_timeout); + next_timeout = (*first)->when - erl_drv_monotonic_time(ERL_DRV_MSEC); + } while (next_timeout <= 0); + driver_set_timer(port, (unsigned long) next_timeout); } static void clean_multi_timers(MultiTimerData **first, ErlDrvPort port) @@ -12289,8 +12192,10 @@ static void remove_multi_timer(MultiTimerData **first, ErlDrvPort port, MultiTim driver_cancel_timer(port); *first = p->next; if (*first) { - unsigned ntmo = relative_timeout(&((*first)->when)); - driver_set_timer(port,ntmo); + ErlDrvTime ntmo = (*first)->when - erl_drv_monotonic_time(ERL_DRV_MSEC); + if (ntmo < 0) + ntmo = 0; + driver_set_timer(port, (unsigned long) ntmo); } } if (p->next != NULL) { @@ -12304,26 +12209,14 @@ static MultiTimerData *add_multi_timer(MultiTimerData **first, ErlDrvPort port, void (*timeout_fun)(ErlDrvData drv_data, ErlDrvTermData caller)) { -#define eq_mega(a, b) ((a)->when.megasecs == (b)->when.megasecs) -#define eq_sec(a, b) ((a)->when.secs == (b)->when.secs) MultiTimerData *mtd, *p, *s; mtd = ALLOC(sizeof(MultiTimerData)); - absolute_timeout(timeout, &(mtd->when)); + mtd->when = erl_drv_monotonic_time(ERL_DRV_MSEC) + ((ErlDrvTime) timeout) + 1; mtd->timeout_function = timeout_fun; mtd->caller = caller; mtd->next = mtd->prev = NULL; for(p = *first,s = NULL; p != NULL; s = p, p = p->next) { - if (p->when.megasecs >= mtd->when.megasecs) { - break; - } - } - for (; p!= NULL && eq_mega(p, mtd); s = p, p = p->next) { - if (p->when.secs >= mtd->when.secs) { - break; - } - } - for (; p!= NULL && eq_mega(p, mtd) && eq_sec(p, mtd); s = p, p = p->next) { - if (p->when.microsecs >= mtd->when.microsecs) { + if (p->when >= mtd->when) { break; } } @@ -12353,12 +12246,6 @@ static MultiTimerData *add_multi_timer(MultiTimerData **first, ErlDrvPort port, } return mtd; } -#undef eq_mega -#undef eq_sec - - - - /*----------------------------------------------------------------------------- -- cgit v1.2.3 From b721bebe663ca3abc747591b28726a367bdb9758 Mon Sep 17 00:00:00 2001 From: JP Date: Mon, 21 Sep 2015 22:52:46 +0000 Subject: erts: Fix sendfile:ing of large files on FreeBSD If the file was larger than the OS send buffer the call would fail before this patch. --- erts/emulator/drivers/unix/unix_efile.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c index 06ba986044..61148dd58d 100644 --- a/erts/emulator/drivers/unix/unix_efile.c +++ b/erts/emulator/drivers/unix/unix_efile.c @@ -39,6 +39,11 @@ #ifdef HAVE_SYS_UIO_H #include #include +#if defined(HAVE_SENDFILE) && (defined(__FreeBSD__) || defined(__DragonFly__)) +/* Need to define __BSD_VISIBLE in order to expose prototype of sendfile */ +#define __BSD_VISIBLE 1 +#include +#endif #endif #if defined(HAVE_SENDFILE) && (defined(__linux__) || (defined(__sun) && defined(__SVR4))) #include -- cgit v1.2.3 From 56090db3ea417157a749bdd810fc61d117493f1f Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 23 Feb 2016 19:45:01 +0100 Subject: erts: Change erl_exit into erts_exit This is mostly a pure refactoring. Except for the buggy cases when calling erlang:halt() with a positive integer in the range -(INT_MIN+2) to -INT_MIN that got confused with ERTS_ABORT_EXIT, ERTS_DUMP_EXIT and ERTS_INTR_EXIT. Outcome OLD erl_exit(n, ) NEW erts_exit(n, ) ------- ------------------- ------------------------------------------- exit(Status) n = -Status <= 0 n = Status >= 0 crashdump+abort n > 0, ignore n n = ERTS_ERROR_EXIT < 0 The outcome of the old ERTS_ABORT_EXIT, ERTS_INTR_EXIT and ERTS_DUMP_EXIT are the same as before (even though their values have changed). --- erts/emulator/drivers/common/efile_drv.c | 15 +-------------- erts/emulator/drivers/common/inet_drv.c | 12 ++++++------ erts/emulator/drivers/win32/win_con.c | 4 ++-- 3 files changed, 9 insertions(+), 22 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 3b6abec25e..05187341a4 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -125,8 +125,6 @@ #include "dtrace-wrapper.h" -void erl_exit(int n, char *fmt, ...); - static ErlDrvSysInfo sys_info; /* For explanation of this var, see comment for same var in erl_async.c */ @@ -515,21 +513,10 @@ struct t_data static void *ef_safe_alloc(Uint s) { void *p = EF_ALLOC(s); - if (!p) erl_exit(1, "efile drv: Can't allocate %lu bytes of memory\n", (unsigned long)s); - return p; -} - -#if 0 /* Currently not used */ - -static void *ef_safe_realloc(void *op, Uint s) -{ - void *p = EF_REALLOC(op, s); - if (!p) erl_exit(1, "efile drv: Can't reallocate %lu bytes of memory\n", (unsigned long)s); + if (!p) erts_exit(ERTS_ERROR_EXIT, "efile drv: Can't allocate %lu bytes of memory\n", (unsigned long)s); return p; } -#endif - /********************************************************************* * ErlIOVec manipulation functions. */ diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 89011d89ad..66b0893682 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -1574,7 +1574,7 @@ static const struct in6_addr in6addr_loopback = #endif /* HAVE_IN6 */ /* XXX: is this a driver interface function ??? */ -void erl_exit(int n, char*, ...); +void erts_exit(int n, char*, ...); /* * Malloc wrapper, @@ -1587,7 +1587,7 @@ void erl_exit(int n, char*, ...); 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__); + erts_exit(ERTS_ERROR_EXIT,"Out of virtual memory in malloc (%s)", __FILE__); return ret; } #define ALLOC(X) alloc_wrapper(X) @@ -1595,7 +1595,7 @@ static void *alloc_wrapper(ErlDrvSizeT 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__); + erts_exit(ERTS_ERROR_EXIT,"Out of virtual memory in realloc (%s)", __FILE__); return ret; } #define REALLOC(X,Y) realloc_wrapper(X,Y) @@ -1856,7 +1856,7 @@ check_double_release(InetDrvBufStk *bs, ErlDrvBinary* buf) int i; for (i = 0; i < bs->buf.pos; ++i) { if (bs->buf.stk[i] == buf) { - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Multiple buffer release in inet_drv, this " "is a bug, save the core and send it to " "support@erlang.ericsson.se!"); @@ -7117,7 +7117,7 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc, do { \ ErlDrvSizeT new_need = ((Ptr) - (*dest)) + (Size); \ if (new_need > dest_used) { \ - erl_exit(1,"Internal error in inet_drv, " \ + erts_exit(ERTS_ERROR_EXIT,"Internal error in inet_drv, " \ "miscalculated buffer size"); \ } \ dest_used = new_need; \ @@ -7494,7 +7494,7 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc, do { \ int need; \ if ((Index) > spec_allocated) { \ - erl_exit(1,"Internal error in inet_drv, " \ + erts_exit(ERTS_ERROR_EXIT,"Internal error in inet_drv, " \ "miscalculated buffer size"); \ } \ need = (Index) + (N); \ diff --git a/erts/emulator/drivers/win32/win_con.c b/erts/emulator/drivers/win32/win_con.c index 0d63d46698..7fe708dc7b 100644 --- a/erts/emulator/drivers/win32/win_con.c +++ b/erts/emulator/drivers/win32/win_con.c @@ -279,7 +279,7 @@ ConInit(void) } /* - ConNormalExit() is called from erl_exit() when the emulator + ConNormalExit() is called from erts_exit() when the emulator is stopping. If the exit has not been initiated by this console thread (WM_DESTROY or ID_BREAK), the function must invoke the console thread to save the user preferences. @@ -529,7 +529,7 @@ ConThreadInit(LPVOID param) /* PostQuitMessage() results in WM_QUIT which makes GetMessage() return 0 (which stops the main loop). Before we return from - the console thread, the ctrl_handler is called to do erl_exit. + the console thread, the ctrl_handler is called to do erts_exit. */ (*ctrl_handler)(CTRL_CLOSE_EVENT); return msg.wParam; -- cgit v1.2.3 From a31eab5469b7740d7aa30b3135a9b834ba958f7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Fri, 4 Mar 2016 16:03:15 +0100 Subject: erts: Increase ttsl_drv logging capabilities --- erts/emulator/drivers/unix/ttsl_drv.c | 148 +++++++++++++++++++++++----------- 1 file changed, 100 insertions(+), 48 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/unix/ttsl_drv.c b/erts/emulator/drivers/unix/ttsl_drv.c index 25cad37e25..abfc52d3bc 100644 --- a/erts/emulator/drivers/unix/ttsl_drv.c +++ b/erts/emulator/drivers/unix/ttsl_drv.c @@ -199,7 +199,7 @@ static void my_debug_printf(char *fmt, ...) erts_vsnprintf(buffer,1024,fmt,args); va_end(args); erts_fprintf(debuglog,"%s\n",buffer); - //erts_printf("Debuglog = %s\n",buffer); + /*erts_printf("Debuglog = %s\n",buffer);*/ } #else @@ -261,15 +261,17 @@ static int ttysl_init(void) if (debuglog != NULL) setbuf(debuglog,NULL); } - DEBUGLOG(("Debuglog = %s(0x%ld)\n",dl,(long) debuglog)); + DEBUGLOG(("ttysl_init: Debuglog = %s(0x%ld)\n",dl,(long) debuglog)); } #endif + DEBUGLOG(("ttysl_init: ttysl_port = %d\n", ttysl_port)); return 0; } static ErlDrvData ttysl_start(ErlDrvPort port, char* buf) { #ifndef HAVE_TERMCAP + DEBUGLOG(("ttysl_start: failure - no TERMCAP configured!\n")); return ERL_DRV_ERROR_GENERAL; #else char *s, *t, *l; @@ -277,36 +279,46 @@ static ErlDrvData ttysl_start(ErlDrvPort port, char* buf) int flag; extern int using_oldshell; /* set this to let the rest of erts know */ + DEBUGLOG(("ttysl_start: driver input \"%s\", ttysl_port = %d (-1 expected)", buf, ttysl_port)); utf8buf_size = 0; - if (ttysl_port != (ErlDrvPort)-1) - return ERL_DRV_ERROR_GENERAL; + if (ttysl_port != (ErlDrvPort)-1) { + DEBUGLOG(("ttysl_start: failure with ttysl_port = %d, not initialized properly?\n", ttysl_port)); + return ERL_DRV_ERROR_GENERAL; + } - if (!isatty(0) || !isatty(1)) + DEBUGLOG(("ttysl_start: isatty(0) = %d (1 expected), isatty(1) = %d (1 expected)", isatty(0), isatty(1))); + if (!isatty(0) || !isatty(1)) { + DEBUGLOG(("ttysl_start: failure in isatty, isatty(0) = %d, isatty(1) = %d", isatty(0), isatty(1))); return ERL_DRV_ERROR_GENERAL; + } /* Set the terminal modes to default leave as is. */ canon = echo = sig = 0; /* Parse the input parameters. */ for (s = strchr(buf, ' '); s; s = t) { - s++; - /* Find end of this argument (start of next) and insert NUL. */ - if ((t = strchr(s, ' '))) { - *t = '\0'; - } - if ((flag = ((*s == '+') ? 1 : ((*s == '-') ? -1 : 0)))) { - if (s[1] == 'c') canon = flag; - if (s[1] == 'e') echo = flag; - if (s[1] == 's') sig = flag; - } - else if ((ttysl_fd = open(s, O_RDWR, 0)) < 0) - return ERL_DRV_ERROR_GENERAL; + s++; + /* Find end of this argument (start of next) and insert NUL. */ + if ((t = strchr(s, ' '))) { + *t = '\0'; + } + if ((flag = ((*s == '+') ? 1 : ((*s == '-') ? -1 : 0)))) { + if (s[1] == 'c') canon = flag; + if (s[1] == 'e') echo = flag; + if (s[1] == 's') sig = flag; + } + else if ((ttysl_fd = open(s, O_RDWR, 0)) < 0) { + DEBUGLOG(("ttysl_start: failed to open ttysl_fd, open(%s, O_RDWR, 0)) = %d\n", s, ttysl_fd)); + return ERL_DRV_ERROR_GENERAL; + } } + if (ttysl_fd < 0) ttysl_fd = 0; if (tty_init(ttysl_fd, canon, echo, sig) < 0 || - tty_set(ttysl_fd) < 0) { + tty_set(ttysl_fd) < 0) { + DEBUGLOG(("ttysl_start: failed init tty or set tty\n")); ttysl_port = (ErlDrvPort)-1; tty_reset(ttysl_fd); return ERL_DRV_ERROR_GENERAL; @@ -314,6 +326,7 @@ static ErlDrvData ttysl_start(ErlDrvPort port, char* buf) /* Set up smart line and termcap stuff. */ if (!start_lbuf() || !start_termcap()) { + DEBUGLOG(("ttysl_start: failed to start_lbuf or start_termcap\n")); stop_lbuf(); /* Must free this */ tty_reset(ttysl_fd); return ERL_DRV_ERROR_GENERAL; @@ -335,10 +348,10 @@ static ErlDrvData ttysl_start(ErlDrvPort port, char* buf) l = setlocale(LC_CTYPE, ""); /* Set international environment */ if (l != NULL) { utf8_mode = (strcmp(nl_langinfo(CODESET), "UTF-8") == 0); - DEBUGLOG(("setlocale: %s\n",l)); + DEBUGLOG(("ttysl_start: setlocale: %s",l)); } #endif - DEBUGLOG(("utf8_mode is %s\n",(utf8_mode) ? "on" : "off")); + DEBUGLOG(("ttysl_start: utf8_mode is %s",(utf8_mode) ? "on" : "off")); sys_signal(SIGCONT, cont); sys_signal(SIGWINCH, winch); @@ -348,6 +361,7 @@ static ErlDrvData ttysl_start(ErlDrvPort port, char* buf) /* we need to know this when we enter the break handler */ using_oldshell = 0; + DEBUGLOG(("ttysl_start: successful start\n")); return (ErlDrvData)ttysl_port; /* Nothing important to return */ #endif /* HAVE_TERMCAP */ } @@ -418,6 +432,7 @@ static ErlDrvSSizeT ttysl_control(ErlDrvData drv_data, static void ttysl_stop(ErlDrvData ttysl_data) { + DEBUGLOG(("ttysl_stop: ttysl_port = %d\n",ttysl_port)); if (ttysl_port != (ErlDrvPort)-1) { stop_lbuf(); stop_termcap(); @@ -617,12 +632,13 @@ static int check_buf_size(byte *s, int n) int ch; int size = 10; + DEBUGLOG(("check_buf_size: n = %d",n)); while(pos < n) { /* Indata is always UTF-8 */ if ((ch = pick_utf8(s,n,&pos)) < 0) { /* XXX temporary allow invalid chars */ ch = (int) s[pos]; - DEBUGLOG(("Invalid UTF8:%d",ch)); + DEBUGLOG(("check_buf_size: Invalid UTF8:%d",ch)); ++pos; } if (utf8_mode) { /* That is, terminal is UTF8 compliant */ @@ -630,7 +646,7 @@ static int check_buf_size(byte *s, int n) #ifdef HAVE_WCWIDTH int width; #endif - DEBUGLOG(("Printable(UTF-8:%d):%d",pos,ch)); + DEBUGLOG(("check_buf_size: Printable(UTF-8:%d):%d",pos,ch)); size++; #ifdef HAVE_WCWIDTH if ((width = wcwidth(ch)) > 1) { @@ -640,21 +656,21 @@ static int check_buf_size(byte *s, int n) } else if (ch == '\t') { size += 8; } else { - DEBUGLOG(("Magic(UTF-8:%d):%d",pos,ch)); + DEBUGLOG(("check_buf_size: Magic(UTF-8:%d):%d",pos,ch)); size += 2; } } else { if (ch <= 255 && isprint(ch)) { - DEBUGLOG(("Printable:%d",ch)); + DEBUGLOG(("check_buf_size: Printable:%d",ch)); size++; } else if (ch == '\t') size += 8; else if (ch >= 128) { - DEBUGLOG(("Non printable:%d",ch)); + DEBUGLOG(("check_buf_size: Non printable:%d",ch)); size += (octal_or_hex_positions(ch) + 1); } else { - DEBUGLOG(("Magic:%d",ch)); + DEBUGLOG(("check_buf_size: Magic:%d",ch)); size += 2; } } @@ -664,10 +680,12 @@ static int check_buf_size(byte *s, int n) lbuf_size = size + lpos + BUFSIZ; if ((lbuf = driver_realloc(lbuf, lbuf_size * sizeof(Uint32))) == NULL) { + DEBUGLOG(("check_buf_size: alloc failure of %d bytes", lbuf_size * sizeof(Uint32))); driver_failure(ttysl_port, -1); return(0); } } + DEBUGLOG(("check_buf_size: success\n")); return(1); } @@ -685,6 +703,8 @@ static void ttysl_from_erlang(ErlDrvData ttysl_data, char* buf, ErlDrvSizeT coun if (lpos > MAXSIZE) put_chars((byte*)"\n", 1); + DEBUGLOG(("ttysl_from_erlang: OP = %d", buf[0])); + switch (buf[0]) { case OP_PUTC_SYNC: /* Using sync means that we have to send an ok to the @@ -695,7 +715,7 @@ static void ttysl_from_erlang(ErlDrvData ttysl_data, char* buf, ErlDrvSizeT coun the port_command. */ /* fall through */ case OP_PUTC: - DEBUGLOG(("OP: Putc(%lu)",(unsigned long) count-1)); + DEBUGLOG(("ttysl_from_erlang: 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); @@ -738,6 +758,7 @@ static void ttysl_from_erlang(ErlDrvData ttysl_data, char* buf, ErlDrvSizeT coun ERL_DRV_USE|ERL_DRV_WRITE,1); break; } else { + DEBUGLOG(("ttysl_from_erlang: driver failure in writev(%d,..) = %d (errno = %d)\n", ttysl_fd, written, errno)); driver_failure_posix(ttysl_port, errno); return; } @@ -774,6 +795,9 @@ static void ttysl_to_tty(ErlDrvData ttysl_data, ErlDrvEvent fd) { ErlDrvSizeT sz; iov = driver_peekq(ttysl_port,&qlen); + + DEBUGLOG(("ttysl_to_tty: qlen = %d", qlen)); + if (iov) written = writev(ttysl_fd, iov, qlen > MAXIOV ? MAXIOV : qlen); else @@ -782,6 +806,7 @@ static void ttysl_to_tty(ErlDrvData ttysl_data, ErlDrvEvent fd) { if (errno == EINTR) { continue; } else if (errno != ERRNO_BLOCK){ + DEBUGLOG(("ttysl_to_tty: driver failure in writev(%d,..) = %d (errno = %d)\n", ttysl_fd, written, errno)); driver_failure_posix(ttysl_port, errno); } break; @@ -804,6 +829,7 @@ static void ttysl_to_tty(ErlDrvData ttysl_data, ErlDrvEvent fd) { /* flush has been called, which means we should terminate when queue is empty. This will not send any exit message */ + DEBUGLOG(("ttysl_to_tty: ttysl_terminate normal\n")); driver_failure_atom(ttysl_port, "normal"); break; } @@ -814,6 +840,7 @@ static void ttysl_to_tty(ErlDrvData ttysl_data, ErlDrvEvent fd) { } static void ttysl_flush_tty(ErlDrvData ttysl_data) { + DEBUGLOG(("ttysl_flush_tty: ..")); ttysl_terminate = 1; return; } @@ -834,6 +861,8 @@ static void ttysl_from_tty(ErlDrvData ttysl_data, ErlDrvEvent fd) p += utf8buf_size; utf8buf_size = 0; } + + DEBUGLOG(("ttysl_from_tty: remainder = %d", left)); if ((i = read((int)(SWord)fd, (char *) p, left)) >= 0) { if (p != b) { @@ -847,7 +876,7 @@ static void ttysl_from_tty(ErlDrvData ttysl_data, ErlDrvEvent fd) utf8buf_size = i -pos; memcpy(utf8buf,b+pos,utf8buf_size); } else if (ch == -1) { - DEBUGLOG(("Giving up on UTF8 mode, invalid character")); + DEBUGLOG(("ttysl_from_tty: Giving up on UTF8 mode, invalid character")); utf8_mode = 0; goto latin_terminal; } @@ -864,6 +893,7 @@ static void ttysl_from_tty(ErlDrvData ttysl_data, ErlDrvEvent fd) } } } else { + DEBUGLOG(("ttysl_from_tty: driver failure in read(%d,..) = %d\n", (int)(SWord)fd, i)); driver_failure(ttysl_port, -1); } } @@ -1155,7 +1185,7 @@ static int write_buf(Uint32 *s, int n) byte *octbuff; byte octtmp[256]; int octbytes; - DEBUGLOG(("Escaped: %d", ch)); + DEBUGLOG(("write_buf: Escaped: %d", ch)); octbytes = octal_or_hex_positions(ch); if (octbytes > 256) { octbuff = driver_alloc(octbytes); @@ -1164,11 +1194,11 @@ static int write_buf(Uint32 *s, int n) } octbytes = 0; octal_or_hex_format(ch, octbuff, &octbytes); - DEBUGLOG(("octbytes: %d", octbytes)); + DEBUGLOG(("write_buf: octbytes: %d", octbytes)); outc('\\'); for (i = 0; i < octbytes; ++i) { outc(lastput = octbuff[i]); - DEBUGLOG(("outc: %d", (int) lastput)); + DEBUGLOG(("write_buf: outc: %d", (int) lastput)); } n -= octbytes+1; s += octbytes+1; @@ -1180,7 +1210,7 @@ static int write_buf(Uint32 *s, int n) --n; s++; #endif } else { - DEBUGLOG(("Very unexpected character %d",(int) *s)); + DEBUGLOG(("write_buf: Very unexpected character %d",(int) *s)); ++n; --s; } @@ -1242,6 +1272,9 @@ static int start_termcap(void) size_t envsz = 1024; char *env = NULL; char *c; + int tres; + + DEBUGLOG(("start_termcap: ..")); capbuf = driver_alloc(1024); if (!capbuf) @@ -1249,9 +1282,10 @@ static int start_termcap(void) eres = erl_drv_getenv("TERM", capbuf, &envsz); if (eres == 0) env = capbuf; - else if (eres < 0) + else if (eres < 0) { + DEBUGLOG(("start_termcap: failure in erl_drv_getenv(\"TERM\", ..) = %d\n", eres)); goto false; - else /* if (eres > 1) */ { + } else /* if (eres > 1) */ { char *envbuf = driver_alloc(envsz); if (!envbuf) goto false; @@ -1261,7 +1295,8 @@ static int start_termcap(void) if (eres == 0) break; newenvbuf = driver_realloc(envbuf, envsz); - if (eres < 0 || !newenvbuf) { + if (eres < 0 || !newenvbuf) { + DEBUGLOG(("start_termcap: failure in erl_drv_getenv(\"TERM\", ..) = %d or realloc buf == %p\n", eres, newenvbuf)); env = newenvbuf ? newenvbuf : envbuf; goto false; } @@ -1269,8 +1304,10 @@ static int start_termcap(void) } env = envbuf; } - if (tgetent((char*)lbuf, env) <= 0) - goto false; + if ((tres = tgetent((char*)lbuf, env)) <= 0) { + DEBUGLOG(("start_termcap: failure in tgetent(..) = %d\n", tres)); + goto false; + } if (env != capbuf) { env = NULL; driver_free(env); @@ -1286,8 +1323,11 @@ static int start_termcap(void) if (!(left = tgetflag("bs") ? "\b" : tgetstr("bc", &c))) left = "\b"; /* Can't happen - but does on Solaris 2 */ right = tgetstr("nd", &c); - if (up && down && left && right) - return TRUE; + if (up && down && left && right) { + DEBUGLOG(("start_termcap: successful start\n")); + return TRUE; + } + DEBUGLOG(("start_termcap: failed start\n")); false: if (env && env != capbuf) driver_free(env); @@ -1364,10 +1404,13 @@ static void update_cols(void) static struct termios tty_smode, tty_rmode; -static int tty_init(int fd, int canon, int echo, int sig) -{ - if (tcgetattr(fd, &tty_rmode) < 0) - return -1; +static int tty_init(int fd, int canon, int echo, int sig) { + int tres; + DEBUGLOG(("tty_init: fd = %d, canon = %d, echo = %d, sig = %d", fd, canon, echo, sig)); + if ((tres = tcgetattr(fd, &tty_rmode)) < 0) { + DEBUGLOG(("tty_init: failure in tcgetattr(%d,..) = %d\n", fd, tres)); + return -1; + } tty_smode = tty_rmode; /* Default characteristics for all usage including termcap output. */ @@ -1420,6 +1463,7 @@ static int tty_init(int fd, int canon, int echo, int sig) #endif tty_smode.c_lflag &= ~(ISIG|IEXTEN); } + DEBUGLOG(("tty_init: successful init\n")); return 0; } @@ -1430,20 +1474,25 @@ static int tty_init(int fd, int canon, int echo, int sig) static int tty_set(int fd) { - DEBUGF(("Setting tty...\n")); + int tres; + DEBUGF(("tty_set: Setting tty...\n")); - if (tcsetattr(fd, TCSANOW, &tty_smode) < 0) + if ((tres = tcsetattr(fd, TCSANOW, &tty_smode)) < 0) { + DEBUGLOG(("tty_set: failure in tcgetattr(%d,..) = %d\n", fd, tres)); return(-1); + } return(0); } static int tty_reset(int fd) /* of terminal device */ { - DEBUGF(("Resetting tty...\n")); + int tres; + DEBUGF(("tty_reset: Resetting tty...\n")); - if (tcsetattr(fd, TCSANOW, &tty_rmode) < 0) + if ((tres = tcsetattr(fd, TCSANOW, &tty_rmode)) < 0) { + DEBUGLOG(("tty_reset: failure in tcsetattr(%d,..) = %d\n", fd, tres)); return(-1); - + } return(0); } @@ -1458,6 +1507,7 @@ static int tty_reset(int fd) /* of terminal device */ static RETSIGTYPE suspend(int sig) { if (tty_reset(ttysl_fd) < 0) { + DEBUGLOG(("signal: failure in suspend(%d), can't reset tty %d\n", sig, ttysl_fd)); fprintf(stderr,"Can't reset tty \n"); exit(1); } @@ -1469,6 +1519,7 @@ static RETSIGTYPE suspend(int sig) sys_signal(sig, suspend); /* Reset signal handler */ if (tty_set(ttysl_fd) < 0) { + DEBUGLOG(("signal: failure in suspend(%d), can't set tty %d\n", sig, ttysl_fd)); fprintf(stderr,"Can't set tty raw \n"); exit(1); } @@ -1479,6 +1530,7 @@ static RETSIGTYPE suspend(int sig) static RETSIGTYPE cont(int sig) { if (tty_set(ttysl_fd) < 0) { + DEBUGLOG(("signal: failure in cont(%d), can't set tty raw %d\n", sig, ttysl_fd)); fprintf(stderr,"Can't set tty raw\n"); exit(1); } -- cgit v1.2.3 From 3c7e658ac4c497cd154bea4178fd560561c78d0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Fri, 26 Feb 2016 18:10:38 +0100 Subject: erts: Use fcntl(fd, F_FULLFSYNC) instead of fdatasync on Mac OSX The syscall fdatasync does not work as intended on Mac OSX. Both the function fsync and fdatasync now uses fcntl(fd, F_FULLFSYNC) on Mac OSX. --- erts/emulator/drivers/unix/unix_efile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c index 00da48b107..ac9b681d03 100644 --- a/erts/emulator/drivers/unix/unix_efile.c +++ b/erts/emulator/drivers/unix/unix_efile.c @@ -467,7 +467,7 @@ int efile_fdatasync(Efile_error *errInfo, /* Where to return error codes. */ int fd) /* File descriptor for file to sync data. */ { -#ifdef HAVE_FDATASYNC +#if defined(HAVE_FDATASYNC) && !defined(__DARWIN__) return check_error(fdatasync(fd), errInfo); #else return efile_fsync(errInfo, fd); -- cgit v1.2.3 From 6664eed554974336909d3ffe03f20349cc4c38fd Mon Sep 17 00:00:00 2001 From: Henrik Nord Date: Tue, 15 Mar 2016 15:19:56 +0100 Subject: update copyright-year --- erts/emulator/drivers/common/efile_drv.c | 2 +- erts/emulator/drivers/common/erl_efile.h | 2 +- erts/emulator/drivers/common/gzio.h | 2 +- erts/emulator/drivers/common/gzio_zutil.h | 2 +- erts/emulator/drivers/common/inet_drv.c | 2 +- erts/emulator/drivers/common/ram_file_drv.c | 2 +- erts/emulator/drivers/common/zlib_drv.c | 2 +- erts/emulator/drivers/unix/bin_drv.c | 2 +- erts/emulator/drivers/unix/multi_drv.c | 2 +- erts/emulator/drivers/unix/sig_drv.c | 2 +- erts/emulator/drivers/unix/ttsl_drv.c | 2 +- erts/emulator/drivers/unix/unix_efile.c | 2 +- erts/emulator/drivers/vxworks/vxworks_resolv.c | 2 +- erts/emulator/drivers/win32/registry_drv.c | 2 +- erts/emulator/drivers/win32/ttsl_drv.c | 2 +- erts/emulator/drivers/win32/win_con.c | 2 +- erts/emulator/drivers/win32/win_con.h | 2 +- erts/emulator/drivers/win32/win_efile.c | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 3088dfd572..a9adbfb8be 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2013. All Rights Reserved. + * Copyright Ericsson AB 1996-2016. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/erts/emulator/drivers/common/erl_efile.h b/erts/emulator/drivers/common/erl_efile.h index be5a891486..42300c9ba4 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-2013. All Rights Reserved. + * Copyright Ericsson AB 1997-2016. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/erts/emulator/drivers/common/gzio.h b/erts/emulator/drivers/common/gzio.h index a6fe2fb6f5..ee0ebe7bd8 100644 --- a/erts/emulator/drivers/common/gzio.h +++ b/erts/emulator/drivers/common/gzio.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * Copyright Ericsson AB 1999-2016. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/erts/emulator/drivers/common/gzio_zutil.h b/erts/emulator/drivers/common/gzio_zutil.h index 9eefb86637..b229ae4efd 100644 --- a/erts/emulator/drivers/common/gzio_zutil.h +++ b/erts/emulator/drivers/common/gzio_zutil.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2009. All Rights Reserved. + * Copyright Ericsson AB 2009-2016. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index b219669ce5..e87d141ddb 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2015. All Rights Reserved. + * Copyright Ericsson AB 1997-2016. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/erts/emulator/drivers/common/ram_file_drv.c b/erts/emulator/drivers/common/ram_file_drv.c index 9cb44d0b7e..bcdfe6a186 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-2011. All Rights Reserved. + * Copyright Ericsson AB 1997-2016. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/erts/emulator/drivers/common/zlib_drv.c b/erts/emulator/drivers/common/zlib_drv.c index 364048174c..440ba956d8 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-2013. All Rights Reserved. + * Copyright Ericsson AB 2003-2016. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/erts/emulator/drivers/unix/bin_drv.c b/erts/emulator/drivers/unix/bin_drv.c index 21fb398907..4b633bb0cf 100644 --- a/erts/emulator/drivers/unix/bin_drv.c +++ b/erts/emulator/drivers/unix/bin_drv.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2009. All Rights Reserved. + * Copyright Ericsson AB 1996-2016. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/erts/emulator/drivers/unix/multi_drv.c b/erts/emulator/drivers/unix/multi_drv.c index 7f8c2d9a0d..eddc57d4d4 100644 --- a/erts/emulator/drivers/unix/multi_drv.c +++ b/erts/emulator/drivers/unix/multi_drv.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2009. All Rights Reserved. + * Copyright Ericsson AB 1996-2016. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/erts/emulator/drivers/unix/sig_drv.c b/erts/emulator/drivers/unix/sig_drv.c index e6f2ecc494..68ad6b9156 100644 --- a/erts/emulator/drivers/unix/sig_drv.c +++ b/erts/emulator/drivers/unix/sig_drv.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2009. All Rights Reserved. + * Copyright Ericsson AB 1996-2016. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/erts/emulator/drivers/unix/ttsl_drv.c b/erts/emulator/drivers/unix/ttsl_drv.c index abfc52d3bc..a925de4dfd 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-2013. All Rights Reserved. + * Copyright Ericsson AB 1996-2016. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c index ac9b681d03..1949007222 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-2013. All Rights Reserved. + * Copyright Ericsson AB 1997-2016. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/erts/emulator/drivers/vxworks/vxworks_resolv.c b/erts/emulator/drivers/vxworks/vxworks_resolv.c index a7de53c692..c2cdf4a90b 100644 --- a/erts/emulator/drivers/vxworks/vxworks_resolv.c +++ b/erts/emulator/drivers/vxworks/vxworks_resolv.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2009. All Rights Reserved. + * Copyright Ericsson AB 1997-2016. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/erts/emulator/drivers/win32/registry_drv.c b/erts/emulator/drivers/win32/registry_drv.c index 4e396aa8d9..a03a030df8 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-2013. All Rights Reserved. + * Copyright Ericsson AB 1997-2016. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/erts/emulator/drivers/win32/ttsl_drv.c b/erts/emulator/drivers/win32/ttsl_drv.c index 4bd766a8a8..99e7fb25a4 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-2013. All Rights Reserved. + * Copyright Ericsson AB 1996-2016. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/erts/emulator/drivers/win32/win_con.c b/erts/emulator/drivers/win32/win_con.c index 7fe708dc7b..0bcccfe405 100644 --- a/erts/emulator/drivers/win32/win_con.c +++ b/erts/emulator/drivers/win32/win_con.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2012. All Rights Reserved. + * Copyright Ericsson AB 1997-2016. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/erts/emulator/drivers/win32/win_con.h b/erts/emulator/drivers/win32/win_con.h index 3f4e89a195..7a642cd7ed 100644 --- a/erts/emulator/drivers/win32/win_con.h +++ b/erts/emulator/drivers/win32/win_con.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2007-2009. All Rights Reserved. + * Copyright Ericsson AB 2007-2016. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c index d95f29f49d..2d366b5833 100644 --- a/erts/emulator/drivers/win32/win_efile.c +++ b/erts/emulator/drivers/win32/win_efile.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2014. All Rights Reserved. + * Copyright Ericsson AB 1997-2016. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. -- cgit v1.2.3 From 9516f34338d1e701949ec28ab8a5d0ace8b5e65d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Tue, 15 Mar 2016 18:00:22 +0100 Subject: Fix ttsl_drv logging without TERMCAP --- erts/emulator/drivers/unix/ttsl_drv.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/unix/ttsl_drv.c b/erts/emulator/drivers/unix/ttsl_drv.c index abfc52d3bc..4f15ce0980 100644 --- a/erts/emulator/drivers/unix/ttsl_drv.c +++ b/erts/emulator/drivers/unix/ttsl_drv.c @@ -264,14 +264,12 @@ static int ttysl_init(void) DEBUGLOG(("ttysl_init: Debuglog = %s(0x%ld)\n",dl,(long) debuglog)); } #endif - DEBUGLOG(("ttysl_init: ttysl_port = %d\n", ttysl_port)); return 0; } static ErlDrvData ttysl_start(ErlDrvPort port, char* buf) { #ifndef HAVE_TERMCAP - DEBUGLOG(("ttysl_start: failure - no TERMCAP configured!\n")); return ERL_DRV_ERROR_GENERAL; #else char *s, *t, *l; -- cgit v1.2.3 From d166fec5d5c901a93e21a1ea7b3165b6fe68d320 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 30 Mar 2016 15:32:22 +0200 Subject: erts: Fix "hanging" VM caused by exiting tty_sl driver Bug introduced on master in a31eab5469b7740d. --- erts/emulator/drivers/unix/ttsl_drv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/unix/ttsl_drv.c b/erts/emulator/drivers/unix/ttsl_drv.c index 4f15ce0980..35ccfa589a 100644 --- a/erts/emulator/drivers/unix/ttsl_drv.c +++ b/erts/emulator/drivers/unix/ttsl_drv.c @@ -823,12 +823,13 @@ static void ttysl_to_tty(ErlDrvData ttysl_data, ErlDrvEvent fd) { if (sz == 0) { driver_select(ttysl_port,(ErlDrvEvent)(long)ttysl_fd, ERL_DRV_WRITE,0); - if (ttysl_terminate) + if (ttysl_terminate) { /* flush has been called, which means we should terminate when queue is empty. This will not send any exit message */ DEBUGLOG(("ttysl_to_tty: ttysl_terminate normal\n")); driver_failure_atom(ttysl_port, "normal"); + } break; } } -- cgit v1.2.3 From 3168f03a80b548094032a33c90a7fd0638493b07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Thu, 31 Mar 2016 16:42:29 +0200 Subject: Refactor time_t in efile_drv --- erts/emulator/drivers/common/efile_drv.c | 12 ++++++------ erts/emulator/drivers/common/erl_efile.h | 6 +++--- erts/emulator/drivers/unix/unix_efile.c | 10 +++++----- 3 files changed, 14 insertions(+), 14 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 3088dfd572..ee14bd8bba 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -2900,12 +2900,12 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + 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); - 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)); + 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 = get_int64(buf + 3 * 4); + d->info.modifyTime = get_int64(buf + 5 * 4); + d->info.cTime = get_int64(buf + 7 * 4); FILENAME_COPY(d->b, buf + 9*4); #ifdef USE_VM_PROBES diff --git a/erts/emulator/drivers/common/erl_efile.h b/erts/emulator/drivers/common/erl_efile.h index be5a891486..7ffeed6b9d 100644 --- a/erts/emulator/drivers/common/erl_efile.h +++ b/erts/emulator/drivers/common/erl_efile.h @@ -105,9 +105,9 @@ typedef struct _Efile_info { Uint32 inode; /* Inode number. */ Uint32 uid; /* User id of owner. */ Uint32 gid; /* Group id of owner. */ - 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 + Sint64 accessTime; /* Last time the file was accessed. */ + Sint64 modifyTime; /* Last time the file was modified. */ + Sint64 cTime; /* Creation time (Windows) or last * inode change (Unix). */ } Efile_info; diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c index ac9b681d03..81ed1996df 100644 --- a/erts/emulator/drivers/unix/unix_efile.c +++ b/erts/emulator/drivers/unix/unix_efile.c @@ -537,9 +537,9 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, else pInfo->type = FT_OTHER; - pInfo->accessTime = statbuf.st_atime; - pInfo->modifyTime = statbuf.st_mtime; - pInfo->cTime = statbuf.st_ctime; + pInfo->accessTime = (Sint64)statbuf.st_atime; + pInfo->modifyTime = (Sint64)statbuf.st_mtime; + pInfo->cTime = (Sint64)statbuf.st_ctime; pInfo->mode = statbuf.st_mode; pInfo->links = statbuf.st_nlink; @@ -578,8 +578,8 @@ efile_write_info(Efile_error *errInfo, Efile_info *pInfo, char *name) } } - tval.actime = pInfo->accessTime; - tval.modtime = pInfo->modifyTime; + tval.actime = (time_t)pInfo->accessTime; + tval.modtime = (time_t)pInfo->modifyTime; return check_error(utime(name, &tval), errInfo); } -- cgit v1.2.3 From 5ae46e823a8a52ed4e5b960ff62975894b1a8302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 29 Mar 2016 09:10:13 +0200 Subject: Handle multi-giga byte writes to files Test cases that write 4Gb to a file at once would fail on OS X and FreeBSD. By running a simple test program on OS X (El Capitan 10.11.4/Darwin 15.4.0), I found that writev() can handle more than 4Gb of data, while write() only can handle less than 2Gb. (Note that efile_drv.c will use write() if there is only one element in the io vector, and writev() if there is more than one.) It is tempting to attempt to piggy-back on the existing mechanism for segmenting write operations in efile_drv.c, but because of the complex code I find it too dangerous, both from a correctness and performance perspective. Instead do the change in unix_efile.c, which is considerably simpler. --- erts/emulator/drivers/unix/unix_efile.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c index ac9b681d03..c097bc1950 100644 --- a/erts/emulator/drivers/unix/unix_efile.c +++ b/erts/emulator/drivers/unix/unix_efile.c @@ -638,12 +638,21 @@ efile_writev(Efile_error* errInfo, /* Where to return error codes */ do { w = writev(fd, &iov[cnt], b); } while (w < 0 && errno == EINTR); + if (w < 0 && errno == EINVAL) { + goto single_write; + } } else + single_write: /* Degenerated io vector - use regular write */ #endif { do { - w = write(fd, iov[cnt].iov_base, iov[cnt].iov_len); + size_t iov_len = iov[cnt].iov_len; + size_t limit = 1024*1024*1024; /* 1GB */ + if (iov_len > limit) { + iov_len = limit; + } + w = write(fd, iov[cnt].iov_base, iov_len); } while (w < 0 && errno == EINTR); ASSERT(w <= iov[cnt].iov_len || (w == -1 && errno != EINTR)); -- cgit v1.2.3 From 011954e851d421b882b0b4eaeda04cfc2895d70a Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Wed, 4 May 2016 14:09:04 +0200 Subject: Rewrite inet_drv for AF_LOCAL --- erts/emulator/drivers/common/inet_drv.c | 384 ++++++++++++++++++-------------- 1 file changed, 215 insertions(+), 169 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index bd4543f831..71e321df26 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2015. All Rights Reserved. + * Copyright Ericsson AB 1997-2016. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -712,7 +713,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #ifdef HAVE_SOCKLEN_T # define SOCKLEN_T socklen_t #else -# define SOCKLEN_T int +# define SOCKLEN_T size_t #endif #include "packet_parser.h" @@ -726,6 +727,22 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) (((unsigned char*) (s))[1] << 8) | \ (((unsigned char*) (s))[0])) +/* strnlen doesn't exist everywhere */ +static size_t my_strnlen(const char *s, size_t maxlen) +{ + size_t i = 0; + while (i < maxlen && s[i] != '\0') + i++; + return i; +} + +/* Check that some character in the buffer != '\0' */ +static int is_nonzero(const char *s, size_t n) +{ + size_t i; + for (i = 0; i < n; i++) if (s[i] != '\0') return !0; + return 0; +} #ifdef VALGRIND # include @@ -751,6 +768,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 */ #define INET_AF_LOCAL 5 +#define INET_AF_UNDEFINED 6 /* Unknown */ /* open and INET_REQ_GETTYPE enumeration */ #define INET_TYPE_STREAM 1 @@ -1042,23 +1060,29 @@ typedef union { } inet_address; -/* for AF_INET & AF_INET6 */ -#define inet_address_port(x) ((x)->sai.sin_port) +#define inet_address_port(x) \ + ((((x)->sai.sin_family == AF_INET) || \ + ((x)->sai.sin_family == AF_INET6)) ? \ + ((x)->sai.sin_port) : -1) #ifdef HAVE_SYS_UN_H -#define localaddrlen(family, data) \ - ((family == AF_LOCAL) ? *(unsigned char*)(data) : 0) +#define localaddrlen(data) \ + ((((unsigned char*)(data))[0] == INET_AF_LOCAL) ? \ + (1 + 1 + ((unsigned char*)(data))[1]) : 1) #else - 0 +#define localaddrlen(data) (1) #endif #if defined(HAVE_IN6) && defined(AF_INET6) -#define addrlen(family, data) \ - ((family == AF_INET) ? sizeof(struct in_addr) : \ - ((family == AF_INET6) ? sizeof(struct in6_addr) : localaddrlen(family, data))) +#define addrlen(data) \ + ((((unsigned char*)(data))[0] == INET_AF_INET) ? \ + (1 + 2 + 4) : \ + ((((unsigned char*)(data))[0] == INET_AF_INET6) ? \ + (1 + 2 + 16) : localaddrlen(data))) #else -#define addrlen(family, data) \ - ((family == AF_INET) ? sizeof(struct in_addr) : localaddrlen(family, data)) +#define addrlen(data) \ + ((((unsigned char*)(data))[0] == INET_AF_INET) ? \ + (1 + 2 + 4) : localaddrlen(data)) #endif typedef struct _multi_timer_data { @@ -1149,8 +1173,10 @@ typedef struct { inet_address peer_addr; /* fake peer address */ inet_address name_addr; /* fake local address */ - inet_address* peer_ptr; /* fake peername or NULL */ - inet_address* name_ptr; /* fake sockname or NULL */ + inet_address* peer_ptr; /* fake peername or NULL */ + inet_address* name_ptr; /* fake sockname or NULL */ + SOCKLEN_T peer_addr_len; /* fake peername size */ + SOCKLEN_T name_addr_len; /* fake sockname size */ int bufsz; /* minimum buffer constraint */ unsigned int hsz; /* the list header size, -1 is large !!! */ @@ -1489,6 +1515,7 @@ static int async_ref = 0; /* async reference id generator */ } while (0) static ErlDrvTermData am_ok; +static ErlDrvTermData am_undefined; static ErlDrvTermData am_tcp; static ErlDrvTermData am_error; static ErlDrvTermData am_einval; @@ -1505,6 +1532,7 @@ static ErlDrvTermData am_ssl_tls; static ErlDrvTermData am_udp; static ErlDrvTermData am_udp_passive; static ErlDrvTermData am_udp_error; +static ErlDrvTermData am_local; #endif #ifdef HAVE_SCTP static ErlDrvTermData am_sctp; @@ -1714,46 +1742,59 @@ static void *realloc_wrapper(void *current, ErlDrvSizeT size){ #endif #ifdef HAVE_UDP -static int load_ip_port(ErlDrvTermData* spec, int i, char* buf) -{ - spec[i++] = ERL_DRV_INT; - spec[i++] = (ErlDrvTermData) get_int16(buf); - return i; -} - -static int load_ip_address(ErlDrvTermData* spec, int i, int family, char* buf) +static int load_address(ErlDrvTermData* spec, int i, char* buf) { int n; - if (family == AF_INET) { - for (n = 0; n < 4; n++) { + switch (*buf++) { /* Family */ + case INET_AF_INET: { + for (n = 2; n < 2+4; n++) { spec[i++] = ERL_DRV_INT; spec[i++] = (ErlDrvTermData) ((unsigned char)buf[n]); } spec[i++] = ERL_DRV_TUPLE; spec[i++] = 4; + spec[i++] = ERL_DRV_INT; + spec[i++] = (ErlDrvTermData) get_int16(buf); + break; } #if defined(HAVE_IN6) && defined(AF_INET6) - else if (family == AF_INET6) { - for (n = 0; n < 16; n += 2) { + case INET_AF_INET6: { + for (n = 2; n < 2+16; n += 2) { spec[i++] = ERL_DRV_INT; spec[i++] = (ErlDrvTermData) get_int16(buf+n); } spec[i++] = ERL_DRV_TUPLE; spec[i++] = 8; + spec[i++] = ERL_DRV_INT; + spec[i++] = (ErlDrvTermData) get_int16(buf); + break; } #endif #ifdef HAVE_SYS_UN_H - else if (family == AF_LOCAL) { + case INET_AF_LOCAL: { int len = *(unsigned char*)buf++; - i = LOAD_STRING(spec, i, buf, len); + i = LOAD_ATOM(spec, i, am_local); + i = LOAD_BUF2BINARY(spec, i, buf, len); + spec[i++] = ERL_DRV_TUPLE; + spec[i++] = 2; + spec[i++] = ERL_DRV_INT; + spec[i++] = 0; + break; } #endif - else { + default: { /* INET_AF_UNDEFINED */ + i = LOAD_ATOM(spec, i, am_undefined); + spec[i++] = ERL_DRV_INT; + spec[i++] = 0; spec[i++] = ERL_DRV_TUPLE; + spec[i++] = 2; + spec[i++] = ERL_DRV_INT; spec[i++] = 0; + break; + } } return i; -} + } #endif @@ -1761,10 +1802,13 @@ static int load_ip_address(ErlDrvTermData* spec, int i, int family, char* buf) /* For SCTP, we often need to return {IP, Port} tuples: */ static int inet_get_address(char* dst, inet_address* src, unsigned int* len); -#define LOAD_IP_AND_PORT_CNT \ +/* Max of {{int()*8},int()} | {{int()*4},int()} | + * {{'local',binary()},int()} + */ +#define LOAD_INET_GET_ADDRESS_CNT \ (8*LOAD_INT_CNT + LOAD_TUPLE_CNT + LOAD_INT_CNT + LOAD_TUPLE_CNT) -static int load_ip_and_port +static int load_inet_get_address (ErlDrvTermData* spec, int i, inet_descriptor* desc, struct sockaddr_storage* addr) { @@ -1782,8 +1826,7 @@ static int load_ip_and_port /* NB: the following functions are safe to use, as they create tuples of copied Ints on the "spec", and do not install any String pts -- a ptr to "abuf" would be dangling upon exiting this function: */ - i = load_ip_address(spec, i, desc->sfamily, abuf+3); - i = load_ip_port (spec, i, abuf+1); + i = load_address(spec, i, abuf); /* IP,Port | Family,Addr */ i = LOAD_TUPLE (spec, i, 2); return i; } @@ -2475,7 +2518,6 @@ static ErlDrvTermData am_http_error; static ErlDrvTermData am_abs_path; static ErlDrvTermData am_absoluteURI; static ErlDrvTermData am_star; -static ErlDrvTermData am_undefined; static ErlDrvTermData am_http; static ErlDrvTermData am_https; static ErlDrvTermData am_scheme; @@ -3166,7 +3208,7 @@ static int sctp_parse_async_event ASSERT(sptr->spc_length <= sz); /* No buffer overrun */ i = LOAD_ATOM (spec, i, am_sctp_paddr_change); - i = load_ip_and_port(spec, i, desc, &sptr->spc_aaddr); + i = load_inet_get_address(spec, i, desc, &sptr->spc_aaddr); switch (sptr->spc_state) { @@ -3617,18 +3659,12 @@ static int packet_binary_message i = LOAD_ATOM(spec, i, am_udp ); /* UDP only */ # endif i = LOAD_PORT(spec, i, desc->dport); /* S */ - - alen = addrlen(desc->sfamily, data+3); - i = load_ip_address(spec, i, desc->sfamily, data+3); - i = load_ip_port(spec, i, data+1); /* IP, Port */ - -# ifdef HAVE_SYS_UN_H - /* AF_LOCAL addresses have a prefix byte containing address length */ - if (desc->sfamily == AF_LOCAL) - alen++; -# endif - offs += (alen + 3); - len -= (alen + 3); + + alen = addrlen(data); + i = load_address(spec, i, data); /* IP,Port | Family,Addr */ + + offs += alen; + len -= alen; # ifdef HAVE_SCTP if (!IS_SCTP(desc)) @@ -4015,6 +4051,7 @@ static int inet_init() # endif INIT_ATOM(ok); + INIT_ATOM(undefined); INIT_ATOM(tcp); #ifdef HAVE_UDP INIT_ATOM(udp); @@ -4031,6 +4068,7 @@ static int inet_init() #ifdef HAVE_UDP INIT_ATOM(udp_passive); INIT_ATOM(udp_error); + INIT_ATOM(local); #endif INIT_ATOM(empty_out_q); INIT_ATOM(ssl_tls); @@ -4043,7 +4081,6 @@ static int inet_init() INIT_ATOM(abs_path); INIT_ATOM(absoluteURI); am_star = driver_mk_atom("*"); - INIT_ATOM(undefined); INIT_ATOM(http); INIT_ATOM(https); INIT_ATOM(scheme); @@ -4139,7 +4176,7 @@ static int inet_init() /* -** Set a inaddr structure: +** Set an inaddr structure: ** src = [P1,P0,X1,X2,.....] ** dst points to a structure large enugh to keep any kind ** of inaddr. @@ -4180,13 +4217,15 @@ static char* inet_set_address(int family, inet_address* dst, } #endif #ifdef HAVE_SYS_UN_H - else if ((family == AF_LOCAL) && (*len >= 3+sizeof(struct sockaddr_un))) { - int n = *((unsigned char*)src+2); - dst->sal.sun_family = family; - sys_memcpy(dst->sal.sun_path, src+3, n); - dst->sal.sun_path[n-1] = '\0'; - *len = n; - return src + 3 + n; + else if ((family == AF_LOCAL) && (*len >= 1)) { + int n = *((unsigned char*)src); + if ((*len < 1+n) || (sizeof(dst->sal.sun_path) < n+1)) + return NULL; + sys_memzero((char*)dst, sizeof(struct sockaddr_un)); + dst->sal.sun_family = family; + sys_memcpy(dst->sal.sun_path, src+1, n); + *len = offsetof(struct sockaddr_un, sun_path) + n; + return src + 1 + n; } #endif return NULL; @@ -4217,17 +4256,8 @@ static char *inet_set_faddress(int family, inet_address* dst, # endif # ifdef HAVE_SYS_UN_H case INET_AF_LOCAL: { - int n; - if (*len || *len < 3) return NULL; - family = AF_LOCAL; - /* Next two bytes are the length of the local path (< 256) */ - src++; - n = *(unsigned char*)src++; - if (n+3 > *len) return NULL; - dst->sal.sun_family = family; - sys_memcpy(dst->sal.sun_path, src, n); - *len = n; - break; + family = AF_LOCAL; + break; } # endif case INET_AF_ANY: @@ -4303,6 +4333,7 @@ static char *inet_set_faddress(int family, inet_address* dst, */ static int inet_get_address(char* dst, inet_address* src, unsigned int* len) { + /* Compare the code with inet_address_to_erlang() */ int family; short port; @@ -4326,51 +4357,32 @@ static int inet_get_address(char* dst, inet_address* src, unsigned int* len) } #endif #ifdef HAVE_SYS_UN_H - else if ((family == AF_LOCAL) && *len > 0) { - int n = *len - 4; - dst[0] = INET_AF_LOCAL; - put_int16(0, dst+1); - if (n == 0 || n >= sizeof(src->sal.sun_path)) { - *(dst+3) = 0; - *len = 3+1; - } else { - *(dst+3) = n; - sys_memcpy(dst+4, src->sal.sun_path, n); - *len = 3+1+n; - } - return 0; - } + else if (family == AF_LOCAL) { + size_t n, m; + if (*len < offsetof(struct sockaddr_un, sun_path)) return -1; + n = *len - offsetof(struct sockaddr_un, sun_path); + if (255 < n) return -1; + /* Portability fix: Assume that the address is a zero terminated + * string, except when the first byte is \0 i.e the + * string length is 0. Then use the reported length instead. + * This fix handles Linux's abstract socket address + * nonportable extension. + */ + m = my_strnlen(src->sal.sun_path, n); + if ((m == 0) && is_nonzero(src->sal.sun_path, n)) + m = n; + dst[0] = INET_AF_LOCAL; + dst[1] = (char) ((unsigned char) m); + sys_memcpy(dst+2, src->sal.sun_path, m); + *len = 1 + 1 + m; + return 0; + } #endif - return -1; -} - -static int inet_family_get_address(inet_descriptor* desc, char* dst, inet_address* src, unsigned int* len) -{ -#ifdef HAVE_SYS_UN_H - if (desc->sfamily == AF_LOCAL) { - int n = *len - 4; - dst[0] = INET_AF_LOCAL; - put_int16(0, dst+1); - if (n <= 0 || n >= sizeof(src->sal.sun_path)) { - if (desc->name_ptr) { - char* p = desc->name_ptr->sal.sun_path; - n = strlen(p); - *(dst+3) = n; - sys_memcpy(dst+4, p, n); - *len = 3+1+n; - } else { - *(dst+3) = 0; - *len = 3+1; - } - } else { - *(dst+3) = n; - sys_memcpy(dst+4, src->sal.sun_path, n); - *len = 3+1+n; - } - return 0; + else { + dst[0] = INET_AF_UNDEFINED; + *len = 1; } -#endif - return inet_get_address(dst, src, len); + return -1; } /* Same as the above, but take family from the address structure, @@ -4378,7 +4390,9 @@ static int inet_family_get_address(inet_descriptor* desc, char* dst, inet_addres ** according to the size of the current, ** and return the resulting encoded size */ -static int inet_address_to_erlang(char *dst, inet_address **src) { +static int +inet_address_to_erlang(char *dst, inet_address **src, SOCKLEN_T sz) { + /* Compare the code with inet_get_address() */ short port; switch ((*src)->sa.sa_family) { @@ -4405,15 +4419,26 @@ static int inet_address_to_erlang(char *dst, inet_address **src) { #endif #ifdef HAVE_SYS_UN_H case AF_LOCAL: { - int n = strlen((*src)->sal.sun_path); + size_t n, m; + if (sz < offsetof(struct sockaddr_un, sun_path)) return -1; + n = sz - offsetof(struct sockaddr_un, sun_path); + if (255 < n) return -1; + /* Portability fix: Assume that the address is a zero terminated + * string, except when the first byte is \0 i.e the + * string length is 0. Then use the reported length instead. + * This fix handles Linux's abstract socket address + * nonportable extension. + */ + m = my_strnlen((*src)->sal.sun_path, n); + if ((m == 0) && is_nonzero((*src)->sal.sun_path, n)) + m = n; if (dst) { dst[0] = INET_AF_LOCAL; - put_int16(0, dst+1); - *(dst+3) = n; - sys_memcpy(dst+1+2+1, (*src)->sal.sun_path, n); + dst[1] = (char) ((unsigned char) m); + sys_memcpy(dst+2, (*src)->sal.sun_path, m); } (*src) = (inet_address *) (&(*src)->sal + 1); - return 1+2+1+n; + return 1 + 1 + m; } #endif default: @@ -4424,7 +4449,7 @@ static int inet_address_to_erlang(char *dst, inet_address **src) { /* Encode n encoded addresses from addrs in the result buffer */ static ErlDrvSizeT reply_inet_addrs -(int n, inet_address *addrs, char **rbuf, ErlDrvSizeT rsize) { +(int n, inet_address *addrs, char **rbuf, ErlDrvSizeT rsize, SOCKLEN_T sz) { inet_address *ia; int i, s; ErlDrvSizeT rlen; @@ -4432,11 +4457,19 @@ static ErlDrvSizeT reply_inet_addrs if (IS_SOCKET_ERROR(n)) return ctl_error(sock_errno(), rbuf, rsize); if (n == 0) return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); + /* The sz argument is only used when we have got an actual size + * of addrs[0] from e.g getsockname() and then n == 1 + * so we will loop over 1 element below. Otherwise sz + * would be expected to differ between addresses but that + * can only happen for AF_LOCAL and we will only be called with + * n > 1 for SCTP and that will never (?) happen with AF_LOCAL + */ + /* Calculate result length */ rlen = 1; ia = addrs; for (i = 0; i < n; i++) { - s = inet_address_to_erlang(NULL, &ia); + s = inet_address_to_erlang(NULL, &ia, sz); if (s < 0) break; rlen += s; } @@ -4447,7 +4480,7 @@ static ErlDrvSizeT reply_inet_addrs rlen = 1; ia = addrs; for (i = 0; i < n; i++) { - s = inet_address_to_erlang((*rbuf)+rlen, &ia); + s = inet_address_to_erlang((*rbuf)+rlen, &ia, sz); if (s < 0) break; rlen += s; } @@ -4511,8 +4544,7 @@ static void desc_close_read(inet_descriptor* desc) static int erl_inet_close(inet_descriptor* desc) { free_subscribers(&desc->empty_out_q_subs); - if ((desc->prebound == 0 || desc->sfamily == AF_LOCAL) && - (desc->state & INET_F_OPEN)) { + if ((desc->prebound == 0) && (desc->state & INET_F_OPEN)) { desc_close(desc); desc->state = INET_STATE_CLOSED; } else if (desc->prebound && (desc->s != INVALID_SOCKET)) { @@ -4589,6 +4621,7 @@ static ErlDrvSSizeT inet_ctl_open(inet_descriptor* desc, int domain, int type, char** rbuf, ErlDrvSizeT rsize) { int save_errno; + int protocol; #ifdef HAVE_SETNS int current_ns, new_ns; current_ns = new_ns = 0; @@ -4627,7 +4660,11 @@ static ErlDrvSSizeT inet_ctl_open(inet_descriptor* desc, int domain, int type, } } #endif - if ((desc->s = sock_open(domain, type, desc->sprotocol)) == INVALID_SOCKET) + protocol = desc->sprotocol; +#ifdef HAVE_SYS_UN_H + if (domain == AF_LOCAL) protocol = 0; +#endif + if ((desc->s = sock_open(domain, type, protocol)) == INVALID_SOCKET) save_errno = sock_errno(); #ifdef HAVE_SETNS if (desc->netns != NULL) { @@ -4692,13 +4729,6 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type, return ctl_error(sock_errno(), rbuf, rsize); if (name.sa.sa_family != domain) return ctl_error(EINVAL, rbuf, rsize); -#ifdef HAVE_SYS_UN_H - if (domain == AF_LOCAL) { - sys_memcpy(&desc->name_addr, &name, sizeof(desc->name_addr)); - if (desc->name_ptr == NULL) - desc->name_ptr = &desc->name_addr; - } -#endif } #ifdef __OSE__ /* for fdopen duplicating the sd will allow to uniquely identify @@ -7550,14 +7580,14 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc, #ifdef HAVE_SCTP #define LOAD_PADDRINFO_CNT \ - (2*LOAD_ATOM_CNT + LOAD_ASSOC_ID_CNT + LOAD_IP_AND_PORT_CNT + \ + (2*LOAD_ATOM_CNT + LOAD_ASSOC_ID_CNT + LOAD_INET_GET_ADDRESS_CNT + \ 4*LOAD_INT_CNT + LOAD_TUPLE_CNT) static int load_paddrinfo (ErlDrvTermData * spec, int i, inet_descriptor* desc, struct sctp_paddrinfo* pai) { i = LOAD_ATOM (spec, i, am_sctp_paddrinfo); i = LOAD_ASSOC_ID (spec, i, pai->spinfo_assoc_id); - i = load_ip_and_port(spec, i, desc, &pai->spinfo_address); + i = load_inet_get_address(spec, i, desc, &pai->spinfo_address); switch(pai->spinfo_state) { case SCTP_ACTIVE: @@ -7973,7 +8003,7 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc, /* Fill in the response: */ PLACE_FOR(spec, i, 2*LOAD_ATOM_CNT + LOAD_ASSOC_ID_CNT + - LOAD_IP_AND_PORT_CNT + 2*LOAD_TUPLE_CNT); + LOAD_INET_GET_ADDRESS_CNT + 2*LOAD_TUPLE_CNT); switch (eopt) { case SCTP_OPT_PRIMARY_ADDR: i = LOAD_ATOM(spec, i, am_sctp_primary_addr); @@ -7987,7 +8017,7 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc, ASSERT(0); } i = LOAD_ASSOC_ID (spec, i, sp.sspp_assoc_id); - i = load_ip_and_port(spec, i, desc, &sp.sspp_addr); + i = load_inet_get_address(spec, i, desc, &sp.sspp_addr); i = LOAD_TUPLE (spec, i, 3); i = LOAD_TUPLE (spec, i, 2); break; @@ -8034,11 +8064,11 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc, /* Fill in the response: */ PLACE_FOR(spec, i, 2*LOAD_ATOM_CNT + LOAD_ASSOC_ID_CNT + - LOAD_IP_AND_PORT_CNT + 4*LOAD_INT_CNT); + LOAD_INET_GET_ADDRESS_CNT + 4*LOAD_INT_CNT); i = LOAD_ATOM (spec, i, am_sctp_peer_addr_params); i = LOAD_ATOM (spec, i, am_sctp_paddrparams); i = LOAD_ASSOC_ID (spec, i, ap.spp_assoc_id); - i = load_ip_and_port(spec, i, desc, &ap.spp_address); + i = load_inet_get_address(spec, i, desc, &ap.spp_address); i = LOAD_INT (spec, i, ap.spp_hbinterval); i = LOAD_INT (spec, i, ap.spp_pathmaxrxt); @@ -8752,19 +8782,19 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, assoc_id = get_int32(buf); n = p_sctp_getpaddrs(desc->s, assoc_id, &sa); - rlen = reply_inet_addrs(n, (inet_address *) sa, rbuf, rsize); + rlen = reply_inet_addrs(n, (inet_address *) sa, rbuf, rsize, 0); if (n > 0) p_sctp_freepaddrs(sa); return rlen; } #endif { /* Fallback to sock_peer */ inet_address addr; - unsigned int sz; + SOCKLEN_T sz; int i; sz = sizeof(addr); i = sock_peer(desc->s, (struct sockaddr *) &addr, &sz); - return reply_inet_addrs(i >= 0 ? 1 : i, &addr, rbuf, rsize); + return reply_inet_addrs(i >= 0 ? 1 : i, &addr, rbuf, rsize, sz); } } @@ -8772,15 +8802,21 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, char tbuf[sizeof(inet_address)]; inet_address peer; inet_address* ptr; - unsigned int sz = sizeof(peer); + unsigned int sz; DEBUGF(("inet_ctl(%ld): PEER\r\n", (long)desc->port)); if (!(desc->state & INET_F_ACTIVE)) return ctl_error(ENOTCONN, rbuf, rsize); - if ((ptr = desc->peer_ptr) == NULL) { + if ((ptr = desc->peer_ptr) != NULL) { + sz = desc->peer_addr_len; + } + else { ptr = &peer; - if (IS_SOCKET_ERROR(sock_peer(desc->s, (struct sockaddr*)ptr,&sz))) + sz = sizeof(peer); + if (IS_SOCKET_ERROR + (sock_peer + (desc->s, (struct sockaddr*)ptr, &sz))) return ctl_error(sock_errno(), rbuf, rsize); } if (inet_get_address(tbuf, ptr, &sz) < 0) @@ -8795,11 +8831,12 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, } else if (len < 2) return ctl_error(EINVAL, rbuf, rsize); - else if (inet_set_address(desc->sfamily, &desc->peer_addr, - buf, &len) == NULL) + else if (inet_set_faddress + (desc->sfamily, &desc->peer_addr, buf, &len) == NULL) return ctl_error(EINVAL, rbuf, rsize); else { desc->peer_ptr = &desc->peer_addr; + desc->peer_addr_len = (SOCKLEN_T) len; return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); } } @@ -8821,19 +8858,19 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, assoc_id = get_int32(buf); n = p_sctp_getladdrs(desc->s, assoc_id, &sa); - rlen = reply_inet_addrs(n, (inet_address *) sa, rbuf, rsize); + rlen = reply_inet_addrs(n, (inet_address *) sa, rbuf, rsize, 0); if (n > 0) p_sctp_freeladdrs(sa); return rlen; } #endif { /* Fallback to sock_name */ inet_address addr; - unsigned int sz; + SOCKLEN_T sz; int i; sz = sizeof(addr); i = sock_name(desc->s, (struct sockaddr *) &addr, &sz); - return reply_inet_addrs(i >= 0 ? 1 : i, &addr, rbuf, rsize); + return reply_inet_addrs(i >= 0 ? 1 : i, &addr, rbuf, rsize, sz); } } @@ -8841,16 +8878,21 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, char tbuf[sizeof(inet_address)]; inet_address name; inet_address* ptr; - unsigned int sz = sizeof(name); + unsigned int sz; DEBUGF(("inet_ctl(%ld): NAME\r\n", (long)desc->port)); if (!IS_BOUND(desc)) return ctl_error(EINVAL, rbuf, rsize); /* address is not valid */ - if ((ptr = desc->name_ptr) == NULL) { + if ((ptr = desc->name_ptr) != NULL) { + sz = desc->name_addr_len; + } + else { ptr = &name; - if (IS_SOCKET_ERROR(sock_name(desc->s, (struct sockaddr*)ptr, &sz))) + sz = sizeof(name); + if (IS_SOCKET_ERROR + (sock_name(desc->s, (struct sockaddr*)ptr, &sz))) return ctl_error(sock_errno(), rbuf, rsize); } if (inet_get_address(tbuf, ptr, &sz) < 0) @@ -8858,18 +8900,19 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, return ctl_reply(INET_REP_OK, tbuf, sz, rbuf, rsize); } - case INET_REQ_SETNAME: { /* set fake peername Port Address */ + case INET_REQ_SETNAME: { /* set fake sockname Port Address */ if (len == 0) { desc->name_ptr = NULL; return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); } else if (len < 2) return ctl_error(EINVAL, rbuf, rsize); - else if (inet_set_address(desc->sfamily, &desc->name_addr, - buf, &len) == NULL) + else if (inet_set_faddress + (desc->sfamily, &desc->name_addr, buf, &len) == NULL) return ctl_error(EINVAL, rbuf, rsize); else { desc->name_ptr = &desc->name_addr; + desc->name_addr_len = (SOCKLEN_T) len; return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); } } @@ -8877,7 +8920,7 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, case INET_REQ_BIND: { /* bind socket */ char tbuf[2]; inet_address local; - short port; + int port; DEBUGF(("inet_ctl(%ld): BIND\r\n", (long)desc->port)); @@ -8894,13 +8937,14 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, desc->state = INET_STATE_BOUND; - if ((port = inet_address_port(&local)) == 0) { + port = inet_address_port(&local); + if (port == 0) { SOCKLEN_T adrlen = sizeof(local); sock_name(desc->s, &local.sa, &adrlen); port = inet_address_port(&local); } - port = sock_ntohs(port); - put_int16(port, tbuf); + else if (port == -1) port = 0; + put_int16(sock_ntohs((Uint16) port), tbuf); return ctl_reply(INET_REP_OK, tbuf, 2, rbuf, rsize); } @@ -9469,8 +9513,8 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, timeout = get_int32(buf); buf += 4; len -= 4; - if (inet_set_address(desc->inet.sfamily, &desc->inet.remote, - buf, &len) == NULL) + if (inet_set_faddress + (desc->inet.sfamily, &desc->inet.remote, buf, &len) == NULL) return ctl_error(EINVAL, rbuf, rsize); code = sock_connect(desc->inet.s, @@ -11528,6 +11572,9 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, case INET_AF_INET6: return ctl_xerror("eafnosupport", rbuf, rsize); break; +#endif +#ifdef HAVE_SYS_UN_H + case INET_AF_LOCAL: af = AF_LOCAL; break; #endif default: return ctl_error(EINVAL, rbuf, rsize); @@ -11611,7 +11658,7 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, /* For SCTP, we do not set the peer's addr in desc->remote, as multiple peers are possible: */ - if (inet_set_address(desc->sfamily, &remote, buf, &len) == NULL) + if (inet_set_faddress(desc->sfamily, &remote, buf, &len) == NULL) return ctl_error(EINVAL, rbuf, rsize); sock_select(desc, FD_CONNECT, 1); @@ -11651,8 +11698,8 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, /* Ignore timeout */ buf += 4; len -= 4; - if (inet_set_address(desc->sfamily, - &desc->remote, buf, &len) == NULL) + if (inet_set_faddress + (desc->sfamily, &desc->remote, buf, &len) == NULL) return ctl_error(EINVAL, rbuf, rsize); code = sock_connect(desc->s, @@ -11832,12 +11879,12 @@ static void packet_inet_timeout(ErlDrvData e) /* THIS IS A "send*" REQUEST; on the Erlang side: "port_command". -** input should be: P1 P0 Address buffer . +** input should be: Family Address buffer . ** For UDP, buffer (after Address) is just data to be sent. ** For SCTP, buffer contains a list representing 2 items: ** (1) 6 parms for sctp_sndrcvinfo, as in sctp_get_sendparams(); ** (2) 0+ real data bytes. -** There is no destination address -- SCTYP send is performed over +** There is no destination address -- SCTP send is performed over ** an existing association, using "sctp_sndrcvinfo" specified. */ static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len) @@ -11912,7 +11959,7 @@ static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len) /* UDP socket. Even if it is connected, there is an address prefix here -- ignored for connected sockets: */ sz = len; - qtr = inet_set_address(desc->sfamily, &other, ptr, &sz); + qtr = inet_set_faddress(desc->sfamily, &other, ptr, &sz); if (qtr == NULL) { inet_reply_error(desc, EINVAL); return; @@ -12090,7 +12137,7 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event) inet_input_count(desc, n); udesc->i_ptr += n; - inet_family_get_address(desc, abuf, &other, &len); + inet_get_address(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, @@ -12624,9 +12671,8 @@ int erts_sock_connect(erts_sock_t socket, byte *ip_addr, int len, Uint16 port) if (!inet_set_address(AF_INET, &addr, buf, &blen)) return 0; - if (IS_SOCKET_ERROR(sock_connect(s, - (struct sockaddr *) &addr, - sizeof(struct sockaddr_in)))) + if (IS_SOCKET_ERROR + (sock_connect(s, (struct sockaddr *) &addr, blen))) return 0; return 1; } -- cgit v1.2.3 From 03e6d8e02a187633a6a09c77e36670f0892d063d Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Thu, 2 Jun 2016 08:44:59 +0200 Subject: AF_UNIX is more portable Fix dialyzer warning for improper list in prim_inet by not using an improper list. --- erts/emulator/drivers/common/inet_drv.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 71e321df26..46adbb09f7 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -3639,7 +3639,7 @@ static int tcp_error_message(tcp_descriptor* desc, int err) ** {sctp, S, IP, Port, {[AncilData], Event_or_Data}} ** where ** [H1,...,HSz] are msg headers (without IP/Port, UDP only), -** [AddrLen, H2,...,HSz] are msg headers for UDP AF_LOCAL only +** [AddrLen, H2,...,HSz] are msg headers for UDP AF_UNIX only ** Data : List() | Binary() */ static int packet_binary_message @@ -4217,7 +4217,7 @@ static char* inet_set_address(int family, inet_address* dst, } #endif #ifdef HAVE_SYS_UN_H - else if ((family == AF_LOCAL) && (*len >= 1)) { + else if ((family == AF_UNIX) && (*len >= 1)) { int n = *((unsigned char*)src); if ((*len < 1+n) || (sizeof(dst->sal.sun_path) < n+1)) return NULL; @@ -4256,7 +4256,7 @@ static char *inet_set_faddress(int family, inet_address* dst, # endif # ifdef HAVE_SYS_UN_H case INET_AF_LOCAL: { - family = AF_LOCAL; + family = AF_UNIX; break; } # endif @@ -4357,7 +4357,7 @@ static int inet_get_address(char* dst, inet_address* src, unsigned int* len) } #endif #ifdef HAVE_SYS_UN_H - else if (family == AF_LOCAL) { + else if (family == AF_UNIX) { size_t n, m; if (*len < offsetof(struct sockaddr_un, sun_path)) return -1; n = *len - offsetof(struct sockaddr_un, sun_path); @@ -4418,7 +4418,7 @@ inet_address_to_erlang(char *dst, inet_address **src, SOCKLEN_T sz) { return 1 + 2 + 16; #endif #ifdef HAVE_SYS_UN_H - case AF_LOCAL: { + case AF_UNIX: { size_t n, m; if (sz < offsetof(struct sockaddr_un, sun_path)) return -1; n = sz - offsetof(struct sockaddr_un, sun_path); @@ -4461,8 +4461,8 @@ static ErlDrvSizeT reply_inet_addrs * of addrs[0] from e.g getsockname() and then n == 1 * so we will loop over 1 element below. Otherwise sz * would be expected to differ between addresses but that - * can only happen for AF_LOCAL and we will only be called with - * n > 1 for SCTP and that will never (?) happen with AF_LOCAL + * can only happen for AF_UNIX and we will only be called with + * n > 1 for SCTP and that will never (?) happen with AF_UNIX */ /* Calculate result length */ @@ -4662,7 +4662,7 @@ static ErlDrvSSizeT inet_ctl_open(inet_descriptor* desc, int domain, int type, #endif protocol = desc->sprotocol; #ifdef HAVE_SYS_UN_H - if (domain == AF_LOCAL) protocol = 0; + if (domain == AF_UNIX) protocol = 0; #endif if ((desc->s = sock_open(domain, type, protocol)) == INVALID_SOCKET) save_errno = sock_errno(); @@ -8719,7 +8719,7 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, } #endif #ifdef HAVE_SYS_UN_H - else if (desc->sfamily == AF_LOCAL) { + else if (desc->sfamily == AF_UNIX) { put_int32(INET_AF_LOCAL, &tbuf[0]); } #endif @@ -9424,7 +9424,7 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, #endif #ifdef HAVE_SYS_UN_H case INET_AF_LOCAL: - domain = AF_LOCAL; + domain = AF_UNIX; break; #endif default: @@ -9455,7 +9455,7 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, #endif #ifdef HAVE_SYS_UN_H case INET_AF_LOCAL: - domain = AF_LOCAL; + domain = AF_UNIX; break; #endif default: @@ -11521,7 +11521,7 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, break; #endif #ifdef HAVE_SYS_UN_H - case INET_AF_LOCAL: af = AF_LOCAL; break; + case INET_AF_LOCAL: af = AF_UNIX; break; #endif default: return ctl_error(EINVAL, rbuf, rsize); @@ -11574,7 +11574,7 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, break; #endif #ifdef HAVE_SYS_UN_H - case INET_AF_LOCAL: af = AF_LOCAL; break; + case INET_AF_LOCAL: af = AF_UNIX; break; #endif default: return ctl_error(EINVAL, rbuf, rsize); -- cgit v1.2.3 From f429adba7e7a862b9949821b40aa3cba12455b3e Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Wed, 8 Jun 2016 09:56:04 +0200 Subject: Remove internal state BOUND from inet_drv --- erts/emulator/drivers/common/inet_drv.c | 81 ++++++++++++++++----------------- 1 file changed, 39 insertions(+), 42 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 06dfb2dd10..93ea9f5dcb 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -627,6 +627,7 @@ static int is_nonzero(const char *s, size_t n) */ /* general address encode/decode tag */ +#define INET_AF_UNSPEC 0 #define INET_AF_INET 1 #define INET_AF_INET6 2 #define INET_AF_ANY 3 /* INADDR_ANY or IN6ADDR_ANY_INIT */ @@ -655,7 +656,7 @@ static int is_nonzero(const char *s, size_t n) /* INET_REQ_GETSTATUS enumeration */ #define INET_F_OPEN 0x0001 -#define INET_F_BOUND 0x0002 +/* INET_F_BOUND removed - renumber when there comes a bigger rewrite */ #define INET_F_ACTIVE 0x0004 #define INET_F_LISTEN 0x0008 #define INET_F_CON 0x0010 @@ -853,19 +854,15 @@ static int is_nonzero(const char *s, size_t n) #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_CONNECTED (INET_STATE_OPEN | INET_F_ACTIVE) +#define INET_STATE_LISTENING (INET_STATE_OPEN | INET_F_LISTEN) +#define INET_STATE_CONNECTING (INET_STATE_OPEN | 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) -#define IS_BOUND(d) \ - (((d)->state & INET_F_BOUND) == INET_F_BOUND) - #define IS_CONNECTED(d) \ (((d)->state & INET_STATE_CONNECTED) == INET_STATE_CONNECTED) @@ -1287,6 +1284,7 @@ static int async_ref = 0; /* async reference id generator */ static ErlDrvTermData am_ok; static ErlDrvTermData am_undefined; +static ErlDrvTermData am_unspec; static ErlDrvTermData am_tcp; static ErlDrvTermData am_error; static ErlDrvTermData am_einval; @@ -1553,10 +1551,18 @@ static int load_address(ErlDrvTermData* spec, int i, char* buf) break; } #endif - default: { /* INET_AF_UNDEFINED */ - i = LOAD_ATOM(spec, i, am_undefined); + case INET_AF_UNSPEC: { + i = LOAD_ATOM(spec, i, am_unspec); + i = LOAD_BUF2BINARY(spec, i, buf, 0); + spec[i++] = ERL_DRV_TUPLE; + spec[i++] = 2; spec[i++] = ERL_DRV_INT; spec[i++] = 0; + break; + } + default: { /* INET_AF_UNDEFINED */ + i = LOAD_ATOM(spec, i, am_undefined); + i = LOAD_BUF2BINARY(spec, i, buf, 0); spec[i++] = ERL_DRV_TUPLE; spec[i++] = 2; spec[i++] = ERL_DRV_INT; @@ -3823,6 +3829,7 @@ static int inet_init() INIT_ATOM(ok); INIT_ATOM(undefined); + INIT_ATOM(unspec); INIT_ATOM(tcp); #ifdef HAVE_UDP INIT_ATOM(udp); @@ -4149,6 +4156,10 @@ static int inet_get_address(char* dst, inet_address* src, unsigned int* len) return 0; } #endif + else if (family == AF_UNSPEC) { + dst[0] = INET_AF_UNSPEC; + *len = 1; + } else { dst[0] = INET_AF_UNDEFINED; *len = 1; @@ -4419,10 +4430,12 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type, char** rbuf, ErlDrvSizeT rsize) { inet_address name; - unsigned int sz = sizeof(name); + unsigned int sz; if (bound) { /* check that it is a socket and that the socket is bound */ + sz = sizeof(name); + sys_memzero((char *) &name, sz); if (IS_SOCKET_ERROR(sock_name(s, (struct sockaddr*) &name, &sz))) return ctl_error(sock_errno(), rbuf, rsize); if (name.sa.sa_family != domain) @@ -4437,10 +4450,7 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type, driver_select(desc->port, desc->event, ERL_DRV_READ, 1); #endif - if (bound) - desc->state = INET_STATE_BOUND; - else - desc->state = INET_STATE_OPEN; + desc->state = INET_STATE_OPEN; if (type == SOCK_STREAM) { /* check if connected */ sz = sizeof(name); @@ -8448,7 +8458,6 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, if (len != 4) return ctl_error(EINVAL, rbuf, rsize); if (! IS_OPEN(desc)) return ctl_xerror(EXBADPORT, rbuf, rsize); - if (! IS_BOUND(desc)) return ctl_xerror(EXBADSEQ, rbuf, rsize); #ifdef HAVE_SCTP if (IS_SCTP(desc) && p_sctp_getpaddrs) { @@ -8524,7 +8533,6 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, if (len != 4) return ctl_error(EINVAL, rbuf, rsize); if (! IS_OPEN(desc)) return ctl_xerror(EXBADPORT, rbuf, rsize); - if (! IS_BOUND(desc)) return ctl_xerror(EXBADSEQ, rbuf, rsize); #ifdef HAVE_SCTP if (IS_SCTP(desc) && p_sctp_getladdrs) { @@ -8546,6 +8554,7 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, int i; sz = sizeof(addr); + sys_memzero((char *) &addr, sz); i = sock_name(desc->s, (struct sockaddr *) &addr, &sz); return reply_inet_addrs(i >= 0 ? 1 : i, &addr, rbuf, rsize, sz); } @@ -8559,15 +8568,13 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, DEBUGF(("inet_ctl(%ld): NAME\r\n", (long)desc->port)); - if (!IS_BOUND(desc)) - return ctl_error(EINVAL, rbuf, rsize); /* address is not valid */ - if ((ptr = desc->name_ptr) != NULL) { sz = desc->name_addr_len; } else { ptr = &name; sz = sizeof(name); + sys_memzero((char *) &name, sz); if (IS_SOCKET_ERROR (sock_name(desc->s, (struct sockaddr*)ptr, &sz))) return ctl_error(sock_errno(), rbuf, rsize); @@ -8612,11 +8619,12 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, if (IS_SOCKET_ERROR(sock_bind(desc->s,(struct sockaddr*) &local, len))) return ctl_error(sock_errno(), rbuf, rsize); - desc->state = INET_STATE_BOUND; + desc->state = INET_STATE_OPEN; port = inet_address_port(&local); if (port == 0) { SOCKLEN_T adrlen = sizeof(local); + sys_memzero((char *) &local, adrlen); sock_name(desc->s, &local.sa, &adrlen); port = inet_address_port(&local); } @@ -9136,8 +9144,6 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, return ctl_xerror(EXBADPORT, rbuf, rsize); if (!IS_OPEN(INETP(desc))) return ctl_xerror(EXBADPORT, rbuf, rsize); - if (!IS_BOUND(INETP(desc))) - return ctl_xerror(EXBADSEQ, rbuf, rsize); if (len != 2) return ctl_error(EINVAL, rbuf, rsize); backlog = get_int16(buf); @@ -9160,8 +9166,6 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, return ctl_xerror(EXBADPORT, rbuf, rsize); if (IS_CONNECTED(INETP(desc))) return ctl_error(EISCONN, rbuf, rsize); - if (!IS_BOUND(INETP(desc))) - return ctl_xerror(EXBADSEQ, rbuf, rsize); if (IS_CONNECTING(INETP(desc))) return ctl_error(EINVAL, rbuf, rsize); if (len < 6) @@ -9262,6 +9266,7 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, return ctl_reply(INET_REP_OK, tbuf, 2, rbuf, rsize); } else { n = sizeof(desc->inet.remote); + sys_memzero((char *) &remote, n); s = sock_accept(desc->inet.s, (struct sockaddr*) &remote, &n); if (s == INVALID_SOCKET) { if (sock_errno() == ERRNO_BLOCK) { @@ -10147,6 +10152,7 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event) inet_async_op *this_op = desc->inet.opt; len = sizeof(desc->inet.remote); + sys_memzero((char *) &remote, len); s = sock_accept(desc->inet.s, (struct sockaddr*) &remote, &len); if (s == INVALID_SOCKET && sock_errno() == ERRNO_BLOCK) { /* Just try again, no real error, just a ghost trigger from poll, @@ -10213,6 +10219,7 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event) while (desc->inet.state == INET_STATE_MULTI_ACCEPTING) { len = sizeof(desc->inet.remote); + sys_memzero((char *) &remote, len); s = sock_accept(desc->inet.s, (struct sockaddr*) &remote, &len); if (s == INVALID_SOCKET && sock_errno() == ERRNO_BLOCK) { /* Just try again, no real error, keep the last return code */ @@ -10653,7 +10660,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 = INET_STATE_BOUND; /* restore state */ + desc->inet.state = INET_STATE_OPEN; /* restore state */ ret = async_error(INETP(desc), sock_errno()); goto done; } @@ -10666,7 +10673,7 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event) (void *)&error, &sz); if ((code < 0) || error) { - desc->inet.state = INET_STATE_BOUND; /* restore state */ + desc->inet.state = INET_STATE_OPEN; /* restore state */ ret = async_error(INETP(desc), error); goto done; } @@ -11075,8 +11082,6 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, if (!IS_OPEN(desc)) return ctl_xerror(EXBADPORT, rbuf, rsize); - if (!IS_BOUND(desc)) - return ctl_xerror(EXBADSEQ, rbuf, rsize); #ifdef HAVE_SCTP if (IS_SCTP(desc)) { inet_address remote; @@ -11163,8 +11168,6 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, 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 (len != 2) return ctl_error(EINVAL, rbuf, rsize); @@ -11211,7 +11214,7 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, return ctl_error(sock_errno(), rbuf, rsize); } - desc->state = INET_STATE_BOUND; + desc->state = INET_STATE_OPEN; return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); } @@ -11228,8 +11231,6 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, 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); @@ -11270,8 +11271,6 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, /* INPUT: Timeout(4), Length(4) */ if (!IS_OPEN(desc)) return ctl_xerror(EXBADPORT, rbuf, rsize); - if (!IS_BOUND(desc)) - return ctl_error(EINVAL, rbuf, rsize); if (desc->active || (len != 8)) return ctl_error(EINVAL, rbuf, rsize); timeout = get_int32(buf); @@ -11336,10 +11335,6 @@ static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len) inet_reply_error(desc, EINVAL); return; } - if (!IS_BOUND(desc)) { - inet_reply_error(desc, EINVAL); - return; - } #ifdef HAVE_SCTP if (IS_SCTP(desc)) @@ -11470,6 +11465,8 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event) while(packet_count--) { unsigned int len = sizeof(other); + sys_memzero((char *) &other, sizeof(other)); + /* udesc->i_buf is only kept between SCTP fragments */ if (udesc->i_buf == NULL) { udesc->i_bufsz = desc->bufsz + len; @@ -11665,7 +11662,7 @@ static int packet_inet_output(udp_descriptor* udesc, HANDLE event) (struct sockaddr*) &desc->remote, &sz); if (IS_SOCKET_ERROR(code)) { - desc->state = INET_STATE_BOUND; /* restore state */ + desc->state = INET_STATE_OPEN; /* restore state */ ret = async_error(desc, sock_errno()); goto done; } @@ -11678,7 +11675,7 @@ static int packet_inet_output(udp_descriptor* udesc, HANDLE event) (void *)&error, &sz); if ((code < 0) || error) { - desc->state = INET_STATE_BOUND; /* restore state */ + desc->state = INET_STATE_OPEN; /* restore state */ ret = async_error(desc, error); goto done; } -- cgit v1.2.3 From e0881861bb8d4bf796134f072e67608c6f32b4c6 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Thu, 16 Jun 2016 13:13:49 +0200 Subject: Return eafnosupport when not supported --- erts/emulator/drivers/common/inet_drv.c | 247 ++++++++++++++++++-------------- 1 file changed, 139 insertions(+), 108 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 93ea9f5dcb..5ce0e1de9e 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -591,6 +591,8 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) (((unsigned char*) (s))[1] << 8) | \ (((unsigned char*) (s))[0])) +#ifdef HAVE_SYS_UN_H + /* strnlen doesn't exist everywhere */ static size_t my_strnlen(const char *s, size_t maxlen) { @@ -608,6 +610,8 @@ static int is_nonzero(const char *s, size_t n) return 0; } +#endif + #ifdef VALGRIND # include #else @@ -1301,6 +1305,8 @@ static ErlDrvTermData am_ssl_tls; static ErlDrvTermData am_udp; static ErlDrvTermData am_udp_passive; static ErlDrvTermData am_udp_error; +#endif +#ifdef HAVE_SYS_UN_H static ErlDrvTermData am_local; #endif #ifdef HAVE_SCTP @@ -1328,7 +1334,10 @@ static ErlDrvTermData am_ipv6_v6only; static ErlDrvTermData am_netns; #endif -/* speical errors for bad ports and sequences */ +static char str_eafnosupport[] = "eafnosupport"; +static char str_einval[] = "einval"; + +/* special errors for bad ports and sequences */ #define EXBADPORT "exbadport" #define EXBADSEQ "exbadseq" @@ -3846,6 +3855,8 @@ static int inet_init() #ifdef HAVE_UDP INIT_ATOM(udp_passive); INIT_ATOM(udp_error); +#endif +#ifdef HAVE_SYS_UN_H INIT_ATOM(local); #endif INIT_ATOM(empty_out_q); @@ -3955,74 +3966,88 @@ static int inet_init() /* ** Set an inaddr structure: -** src = [P1,P0,X1,X2,.....] +** *src = [P1,P0,X1,X2,.....] ** dst points to a structure large enugh to keep any kind ** of inaddr. ** *len is set to length of src on call ** and is set to actual length of dst on return -** return NULL on error and ptr after port address on success +** return NULL if ok or ptr to errno string for error */ static char* inet_set_address(int family, inet_address* dst, - char* src, ErlDrvSizeT* len) + char* *src, ErlDrvSizeT* len) { short port; - if ((family == AF_INET) && (*len >= 2+4)) { + switch (family) { + case AF_INET: { + if (*len < 2+4) return str_einval; sys_memzero((char*)dst, sizeof(struct sockaddr_in)); - port = get_int16(src); + port = get_int16(*src); #ifndef NO_SA_LEN dst->sai.sin_len = sizeof(struct sockaddr_in); #endif dst->sai.sin_family = family; dst->sai.sin_port = sock_htons(port); - sys_memcpy(&dst->sai.sin_addr, src+2, 4); + sys_memcpy(&dst->sai.sin_addr, (*src)+2, 4); *len = sizeof(struct sockaddr_in); - return src + 2+4; + *src += 2 + 4; + return NULL; } #if defined(HAVE_IN6) && defined(AF_INET6) - else if ((family == AF_INET6) && (*len >= 2+16)) { + case AF_INET6: { + if (*len < 2+16) return str_einval; sys_memzero((char*)dst, sizeof(struct sockaddr_in6)); - port = get_int16(src); + port = get_int16(*src); #ifndef NO_SA_LEN dst->sai6.sin6_len = sizeof(struct sockaddr_in6); #endif dst->sai6.sin6_family = family; dst->sai6.sin6_port = sock_htons(port); dst->sai6.sin6_flowinfo = 0; /* XXX this may be set as well ?? */ - sys_memcpy(&dst->sai6.sin6_addr, src+2, 16); - *len = sizeof(struct sockaddr_in6); - return src + 2+16; + sys_memcpy(&dst->sai6.sin6_addr, (*src)+2, 16); + *len = sizeof(struct sockaddr_in6); + *src += 2 + 16; + return NULL; } #endif #ifdef HAVE_SYS_UN_H - else if ((family == AF_UNIX) && (*len >= 1)) { - int n = *((unsigned char*)src); - if ((*len < 1+n) || (sizeof(dst->sal.sun_path) < n+1)) - return NULL; + case AF_UNIX: { + int n; + if (*len == 0) return str_einval; + n = *((unsigned char*)(*src)); /* Length field */ + if ((*len < 1+n) || (sizeof(dst->sal.sun_path) < n+1)) { + return str_einval; + } sys_memzero((char*)dst, sizeof(struct sockaddr_un)); dst->sal.sun_family = family; - sys_memcpy(dst->sal.sun_path, src+1, n); + sys_memcpy(dst->sal.sun_path, (*src)+1, n); *len = offsetof(struct sockaddr_un, sun_path) + n; - return src + 1 + n; + *src += 1 + n; + return NULL; } #endif - return NULL; + } + return str_eafnosupport; } /* ** Set an inaddr structure, address family comes from source data, ** or from argument if source data specifies constant address. ** -** src = [TAG,P1,P0] when TAG = INET_AF_ANY | INET_AF_LOOPBACK -** src = [TAG,P1,P0,X1,X2,...] when TAG = INET_AF_INET | INET_AF_INET6 | INET_AF_LOCAL +** *src = [TAG,P1,P0] +** when TAG = INET_AF_ANY | INET_AF_LOOPBACK +** *src = [TAG,P1,P0,X1,X2,...] +** when TAG = INET_AF_INET | INET_AF_INET6 | INET_AF_LOCAL +** *src = [TAG,Len,...] +** when TAG = INET_AF_LOCAL */ static char *inet_set_faddress(int family, inet_address* dst, - char *src, ErlDrvSizeT* len) { + char* *src, ErlDrvSizeT* len) { int tag; - if (*len < 1) return NULL; + if (*len < 1) return str_einval; (*len) --; - tag = *(src ++); + tag = *((*src) ++); switch (tag) { case INET_AF_INET: family = AF_INET; @@ -4042,8 +4067,8 @@ static char *inet_set_faddress(int family, inet_address* dst, case INET_AF_LOOPBACK: { int port; - if (*len < 2) return NULL; - port = get_int16(src); + if (*len < 2) return str_einval; + port = get_int16(*src); switch (family) { case AF_INET: { struct in_addr addr; @@ -4055,7 +4080,7 @@ static char *inet_set_faddress(int family, inet_address* dst, addr.s_addr = sock_htonl(INADDR_LOOPBACK); break; default: - return NULL; + return str_einval; } sys_memzero((char*)dst, sizeof(struct sockaddr_in)); #ifndef NO_SA_LEN @@ -4077,7 +4102,7 @@ static char *inet_set_faddress(int family, inet_address* dst, paddr = &in6addr_loopback; break; default: - return NULL; + return str_einval; } sys_memzero((char*)dst, sizeof(struct sockaddr_in6)); #ifndef NO_SA_LEN @@ -4091,12 +4116,13 @@ static char *inet_set_faddress(int family, inet_address* dst, } break; # endif default: - return NULL; + return str_einval; } - return src + 2; + *src += 2; + return NULL; } break; default: - return NULL; + return str_eafnosupport; } return inet_set_address(family, dst, src, len); } @@ -6691,7 +6717,6 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) case SCTP_OPT_SET_PEER_PRIMARY_ADDR: { ErlDrvSizeT alen; - char *after; CHKLEN(curr, ASSOC_ID_LEN); /* XXX: These 2 opts have isomorphic value data structures, @@ -6702,12 +6727,9 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) /* Fill in "arg.prim.sspp_addr": */ alen = ptr + len - curr; - after = inet_set_faddress(desc->sfamily, - (inet_address*) (&arg.prim.sspp_addr), - curr, &alen); - if (after == NULL) - return -1; - curr = after; + if (inet_set_faddress + (desc->sfamily, (inet_address*) (&arg.prim.sspp_addr), + &curr, &alen) != NULL) return -1; proto = IPPROTO_SCTP; if (eopt == SCTP_OPT_PRIMARY_ADDR) @@ -6733,7 +6755,6 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) case SCTP_OPT_PEER_ADDR_PARAMS: { ErlDrvSizeT alen; - char *after; # ifdef HAVE_STRUCT_SCTP_PADDRPARAMS_SPP_FLAGS int eflags, cflags, hb_enable, hb_disable, pmtud_enable, pmtud_disable; @@ -6748,12 +6769,9 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) /* Fill in "pap.spp_address": */ alen = ptr + len - curr; - after = inet_set_faddress(desc->sfamily, - (inet_address*) (&arg.pap.spp_address), - curr, &alen); - if (after == NULL) - return -1; - curr = after; + if (inet_set_faddress + (desc->sfamily, (inet_address*) (&arg.pap.spp_address), + &curr, &alen) != NULL) return -1; CHKLEN(curr, 4 + 2 + 3*4); @@ -7740,7 +7758,7 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc, struct sctp_paddrparams ap; unsigned int sz = sizeof(ap); int n; - char *after; + char *before, *xerror; ErlDrvSizeT alen; if (buflen < ASSOC_ID_LEN) RETURN_ERROR(spec, -EINVAL); @@ -7748,13 +7766,22 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc, buf += ASSOC_ID_LEN; buflen -= ASSOC_ID_LEN; alen = buflen; - after = inet_set_faddress(desc->sfamily, - (inet_address*) (&ap.spp_address), - buf, &alen); - if (after == NULL) RETURN_ERROR(spec, -EINVAL); - buflen -= after - buf; - buf = after; - + before = buf; + xerror = + inet_set_faddress + (desc->sfamily, (inet_address*) (&ap.spp_address), + &buf, &alen); + if (xerror != NULL) { +#ifdef EAFNOSUPPORT + if (xerror == str_eafnosupport) { + RETURN_ERROR(spec, -EAFNOSUPPORT); + } +#else + RETURN_ERROR(spec, -EINVAL); +#endif + } + buflen -= buf - before; + if (sock_getopt(desc->s, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &ap, &sz) < 0) continue; /* Fill in the response: */ @@ -7980,7 +8007,7 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc, { struct sctp_paddrinfo pai; unsigned int sz = sizeof(pai); - char *after; + char *before, *xerror; ErlDrvSizeT alen; if (buflen < ASSOC_ID_LEN) RETURN_ERROR(spec, -EINVAL); @@ -7988,13 +8015,22 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc, buf += ASSOC_ID_LEN; buflen -= ASSOC_ID_LEN; alen = buflen; - after = inet_set_faddress(desc->sfamily, - (inet_address*) (&pai.spinfo_address), - buf, &alen); - if (after == NULL) RETURN_ERROR(spec, -EINVAL); - buflen -= after - buf; - buf = after; - + before = buf; + xerror = + inet_set_faddress + (desc->sfamily, (inet_address*) (&pai.spinfo_address), + &buf, &alen); + if (xerror != NULL) { +#ifdef EAFNOSUPPORT + if (xerror == str_eafnosupport) { + RETURN_ERROR(spec, -EAFNOSUPPORT); + } +#else + RETURN_ERROR(spec, -EINVAL); +#endif + } + buflen -= buf - before; + if (sock_getopt(desc->s, IPPROTO_SCTP, SCTP_GET_PEER_ADDR_INFO, &pai, &sz) < 0) continue; /* Fill in the response: */ @@ -8511,15 +8547,16 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, } case INET_REQ_SETPEER: { /* set fake peername Port Address */ + char *xerror; if (len == 0) { desc->peer_ptr = NULL; return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); } else if (len < 2) return ctl_error(EINVAL, rbuf, rsize); - else if (inet_set_faddress - (desc->sfamily, &desc->peer_addr, buf, &len) == NULL) - return ctl_error(EINVAL, rbuf, rsize); + else if ((xerror = inet_set_faddress + (desc->sfamily, &desc->peer_addr, &buf, &len)) != NULL) + return ctl_xerror(xerror, rbuf, rsize); else { desc->peer_ptr = &desc->peer_addr; desc->peer_addr_len = (SOCKLEN_T) len; @@ -8585,15 +8622,16 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, } case INET_REQ_SETNAME: { /* set fake sockname Port Address */ + char *xerror; if (len == 0) { desc->name_ptr = NULL; return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); } else if (len < 2) return ctl_error(EINVAL, rbuf, rsize); - else if (inet_set_faddress - (desc->sfamily, &desc->name_addr, buf, &len) == NULL) - return ctl_error(EINVAL, rbuf, rsize); + else if ((xerror = inet_set_faddress + (desc->sfamily, &desc->name_addr, &buf, &len)) != NULL) + return ctl_xerror(xerror, rbuf, rsize); else { desc->name_ptr = &desc->name_addr; desc->name_addr_len = (SOCKLEN_T) len; @@ -8602,7 +8640,7 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, } case INET_REQ_BIND: { /* bind socket */ - char tbuf[2]; + char tbuf[2], *xerror; inet_address local; int port; @@ -8613,8 +8651,9 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, if (desc->state != INET_STATE_OPEN) return ctl_xerror(EXBADPORT, rbuf, rsize); - if (inet_set_faddress(desc->sfamily, &local, buf, &len) == NULL) - return ctl_error(EINVAL, rbuf, rsize); + if ((xerror = inet_set_faddress + (desc->sfamily, &local, &buf, &len)) != NULL) + return ctl_xerror(xerror, rbuf, rsize); if (IS_SOCKET_ERROR(sock_bind(desc->s,(struct sockaddr*) &local, len))) return ctl_error(sock_errno(), rbuf, rsize); @@ -9081,10 +9120,6 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, case INET_AF_INET6: domain = AF_INET6; break; -#else - case INET_AF_INET6: - return ctl_xerror("eafnosupport", rbuf, rsize); - break; #endif #ifdef HAVE_SYS_UN_H case INET_AF_LOCAL: @@ -9092,7 +9127,7 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, break; #endif default: - return ctl_error(EINVAL, rbuf, rsize); + return ctl_xerror(str_eafnosupport, 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); @@ -9112,10 +9147,6 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, case INET_AF_INET6: domain = AF_INET6; break; -#else - case INET_AF_INET6: - return ctl_xerror("eafnosupport", rbuf, rsize); - break; #endif #ifdef HAVE_SYS_UN_H case INET_AF_LOCAL: @@ -9123,7 +9154,7 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, break; #endif default: - return ctl_error(EINVAL, rbuf, rsize); + return ctl_xerror(str_eafnosupport, rbuf, rsize); } if (buf[1] != INET_TYPE_STREAM) return ctl_error(EINVAL, rbuf, rsize); @@ -9156,7 +9187,7 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, case INET_REQ_CONNECT: { /* do async connect */ int code; - char tbuf[2]; + char tbuf[2], *xerror; unsigned timeout; DEBUGF(("tcp_inet_ctl(%ld): CONNECT\r\n", (long)desc->inet.port)); @@ -9173,9 +9204,9 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, timeout = get_int32(buf); buf += 4; len -= 4; - if (inet_set_faddress - (desc->inet.sfamily, &desc->inet.remote, buf, &len) == NULL) - return ctl_error(EINVAL, rbuf, rsize); + if ((xerror = inet_set_faddress + (desc->inet.sfamily, &desc->inet.remote, &buf, &len)) != NULL) + return ctl_xerror(xerror, rbuf, rsize); code = sock_connect(desc->inet.s, (struct sockaddr*) &desc->inet.remote, len); @@ -10955,16 +10986,12 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, case INET_AF_INET: af = AF_INET; break; #if defined(HAVE_IN6) && defined(AF_INET6) case INET_AF_INET6: af = AF_INET6; break; -#else - case INET_AF_INET6: - return ctl_xerror("eafnosupport", rbuf, rsize); - break; #endif #ifdef HAVE_SYS_UN_H case INET_AF_LOCAL: af = AF_UNIX; break; #endif default: - return ctl_error(EINVAL, rbuf, rsize); + return ctl_xerror(str_eafnosupport, rbuf, rsize); } switch (buf[1]) { case INET_TYPE_STREAM: type = SOCK_STREAM; break; @@ -11008,16 +11035,12 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, case INET_AF_INET: af = AF_INET; break; #if defined(HAVE_IN6) && defined(AF_INET6) case INET_AF_INET6: af = AF_INET6; break; -#else - case INET_AF_INET6: - return ctl_xerror("eafnosupport", rbuf, rsize); - break; #endif #ifdef HAVE_SYS_UN_H case INET_AF_LOCAL: af = AF_UNIX; break; #endif default: - return ctl_error(EINVAL, rbuf, rsize); + return ctl_xerror(str_eafnosupport, rbuf, rsize); } switch (buf[1]) { case INET_TYPE_STREAM: type = SOCK_STREAM; break; @@ -11085,6 +11108,7 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, #ifdef HAVE_SCTP if (IS_SCTP(desc)) { inet_address remote; + char *xerror; if (IS_CONNECTING(desc)) return ctl_error(EINVAL, rbuf, rsize); @@ -11096,8 +11120,9 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, /* For SCTP, we do not set the peer's addr in desc->remote, as multiple peers are possible: */ - if (inet_set_faddress(desc->sfamily, &remote, buf, &len) == NULL) - return ctl_error(EINVAL, rbuf, rsize); + if ((xerror = inet_set_faddress + (desc->sfamily, &remote, &buf, &len)) != NULL) + return ctl_xerror(xerror, rbuf, rsize); sock_select(desc, FD_CONNECT, 1); code = sock_connect(desc->s, &remote.sa, len); @@ -11133,12 +11158,13 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, else if (len < 6) return ctl_error(EINVAL, rbuf, rsize); else { + char *xerror; /* Ignore timeout */ buf += 4; len -= 4; - if (inet_set_faddress - (desc->sfamily, &desc->remote, buf, &len) == NULL) - return ctl_error(EINVAL, rbuf, rsize); + if ((xerror = inet_set_faddress + (desc->sfamily, &desc->remote, &buf, &len)) != NULL) + return ctl_xerror(xerror, rbuf, rsize); code = sock_connect(desc->s, (struct sockaddr*) &desc->remote, len); @@ -11202,11 +11228,13 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, while (curr < buf+len) { + char *xerror; /* List item format: see "inet_set_faddress": */ ErlDrvSizeT alen = buf + len - curr; - curr = inet_set_faddress(desc->sfamily, &addr, curr, &alen); - if (curr == NULL) - return ctl_error(EINVAL, rbuf, rsize); + xerror = inet_set_faddress + (desc->sfamily, &addr, &curr, &alen); + if (xerror != NULL) + return ctl_xerror(xerror, rbuf, rsize); /* Invoke the call: */ if (p_sctp_bindx(desc->s, (struct sockaddr *)&addr, 1, @@ -11325,6 +11353,7 @@ static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len) inet_descriptor* desc = INETP(udesc); char* ptr = buf; char* qtr; + char* xerror; ErlDrvSizeT sz; int code; inet_address other; @@ -11387,9 +11416,10 @@ static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len) /* UDP socket. Even if it is connected, there is an address prefix here -- ignored for connected sockets: */ sz = len; - qtr = inet_set_faddress(desc->sfamily, &other, ptr, &sz); - if (qtr == NULL) { - inet_reply_error(desc, EINVAL); + qtr = ptr; + xerror = inet_set_faddress(desc->sfamily, &other, &qtr, &sz); + if (xerror != NULL) { + inet_reply_error_am(desc, driver_mk_atom(xerror)); return; } len -= (qtr - ptr); @@ -11975,7 +12005,7 @@ void erts_sock_close(erts_sock_t socket) int erts_sock_connect(erts_sock_t socket, byte *ip_addr, int len, Uint16 port) { SOCKET s = (SOCKET) socket; - char buf[2 + 4]; + char buf[2 + 4], *p; ErlDrvSizeT blen = 6; inet_address addr; @@ -11985,7 +12015,8 @@ int erts_sock_connect(erts_sock_t socket, byte *ip_addr, int len, Uint16 port) put_int16(port, buf); memcpy((void *) (buf + 2), (void *) ip_addr, 4); - if (!inet_set_address(AF_INET, &addr, buf, &blen)) + p = buf; + if (inet_set_address(AF_INET, &addr, &p, &blen) != NULL) return 0; if (IS_SOCKET_ERROR -- cgit v1.2.3