aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/drivers/common/inet_drv.c
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/drivers/common/inet_drv.c')
-rw-r--r--erts/emulator/drivers/common/inet_drv.c793
1 files changed, 751 insertions, 42 deletions
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index 4cc31c1344..09d90f4984 100644
--- a/erts/emulator/drivers/common/inet_drv.c
+++ b/erts/emulator/drivers/common/inet_drv.c
@@ -86,6 +86,17 @@
#endif
typedef unsigned long long llu_t;
+#ifndef INT16_MIN
+#define INT16_MIN (-32768)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+
+#ifdef __OSE__
+#include "inet.h"
+#endif
+
#ifdef __WIN32__
#define STRNCASECMP strncasecmp
@@ -189,6 +200,7 @@ typedef unsigned long long llu_t;
#define HAVE_MULTICAST_SUPPORT
+#define HAVE_UDP
#define ERRNO_BLOCK WSAEWOULDBLOCK
@@ -282,7 +294,135 @@ 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__)
+
+/*
+ * 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)
+
+#else /* !__OSE__ && !__WIN32__ */
#include <sys/time.h>
#ifdef NETDB_H_NEEDS_IN_H
@@ -323,6 +463,8 @@ static unsigned long one_value = 1;
#include <setns.h>
#endif
+#define HAVE_UDP
+
/* SCTP support -- currently for UNIX platforms only: */
#undef HAVE_SCTP
#if defined(HAVE_SCTP_H)
@@ -545,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
@@ -612,6 +754,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
@@ -846,9 +989,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
@@ -958,6 +1102,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:
@@ -1001,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;
@@ -1016,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);
@@ -1029,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,
@@ -1038,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,
@@ -1045,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,
@@ -1063,6 +1293,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);
@@ -1112,6 +1343,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 =
@@ -1175,6 +1407,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 */
@@ -1186,29 +1419,54 @@ 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)
+#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)
+/* 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_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;
static ErlDrvTermData am_sctp_error;
static ErlDrvTermData am_true;
static ErlDrvTermData am_false;
@@ -1218,6 +1476,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;
@@ -1412,6 +1671,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;
@@ -1446,6 +1706,7 @@ static int load_ip_address(ErlDrvTermData* spec, int i, int family, char* buf)
}
return i;
}
+#endif
#ifdef HAVE_SCTP
@@ -1466,8 +1727,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
@@ -1612,10 +1873,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
@@ -3276,6 +3539,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
@@ -3366,8 +3630,42 @@ 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
+** {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 !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 {
+#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
+ }
+#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);
+ }
+
+#ifdef HAVE_UDP
+/*
** send active message {udp_error|sctp_error, S, Error}
*/
static int packet_error_message(udp_descriptor* udesc, int err)
@@ -3393,7 +3691,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:
@@ -3409,7 +3707,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) {
@@ -3427,8 +3725,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;
}
@@ -3455,12 +3752,11 @@ 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;
}
-
+#ifdef HAVE_UDP
static int
packet_reply_binary_data(inet_descriptor* desc, unsigned int hsz,
ErlDrvBinary * bin, int offs, int len,
@@ -3479,11 +3775,11 @@ 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;
}
}
+#endif
/* ----------------------------------------------------------------------------
@@ -3525,6 +3821,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);
@@ -3534,6 +3831,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);
@@ -3657,15 +3955,22 @@ 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);
INIT_ATOM(inet_reply);
INIT_ATOM(timeout);
INIT_ATOM(closed);
+ 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);
@@ -3684,7 +3989,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: */
@@ -4013,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.
@@ -4022,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;
@@ -4063,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)
@@ -4146,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;
@@ -4166,7 +4547,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);
@@ -4181,8 +4569,15 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type,
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
@@ -4208,8 +4603,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);
@@ -5658,8 +6052,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);
@@ -5755,6 +6166,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;
@@ -5762,6 +6174,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:
@@ -5970,7 +6383,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;
}
@@ -6103,6 +6517,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;
@@ -6625,6 +7054,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;
@@ -6707,6 +7141,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;
@@ -6716,6 +7151,7 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc,
TRUNCATE_TO(0,ptr);
}
continue;
+#endif
#ifdef HAVE_SETNS
case INET_LOPT_NETNS:
@@ -6997,7 +7433,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)
{
@@ -7010,6 +7449,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);
@@ -7806,6 +8248,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;
@@ -7839,6 +8282,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;
}
@@ -8214,11 +8666,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);
@@ -8551,6 +9011,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(&copy_desc->inet);
+#endif
+
*err = 0;
return copy_desc;
}
@@ -8612,8 +9077,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,
@@ -8835,7 +9314,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);
@@ -8869,7 +9348,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) {
@@ -8901,6 +9381,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);
@@ -9039,6 +9521,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)
{
@@ -9102,6 +9594,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
@@ -9221,12 +9729,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));
-
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;
@@ -9634,7 +10143,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:
@@ -9655,7 +10303,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) {
@@ -9724,7 +10372,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;
@@ -10050,6 +10697,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);
@@ -10059,6 +10749,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 ?
@@ -10124,6 +10815,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));
@@ -10135,8 +10833,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;
}
@@ -10149,6 +10847,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) {
@@ -10293,6 +10997,7 @@ static udp_descriptor* sctp_inet_copy(udp_descriptor* desc, SOCKET s, int* err)
+#ifdef HAVE_UDP
static int packet_inet_init()
{
return 0;
@@ -10323,6 +11028,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)
@@ -10333,6 +11039,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
@@ -10848,7 +11555,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)
@@ -10870,6 +11577,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);
@@ -11126,6 +11834,7 @@ static int packet_inet_output(udp_descriptor* udesc, HANDLE event)
DEBUGF(("packet_inet_output(%ld) }\r\n", (long)desc->port));
return ret;
}
+#endif
/*---------------------------------------------------------------------------*/