From eaeec753c035c2214be2930290a0a6de411566b0 Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Fri, 7 Dec 2018 15:49:55 +0100 Subject: Pluggable distribution socket implementation for EI --- lib/erl_interface/doc/src/ei_connect.xml | 330 +++++++++++++++++++++++++++++++ 1 file changed, 330 insertions(+) (limited to 'lib/erl_interface/doc') diff --git a/lib/erl_interface/doc/src/ei_connect.xml b/lib/erl_interface/doc/src/ei_connect.xml index 607a7cbff4..af838e065a 100644 --- a/lib/erl_interface/doc/src/ei_connect.xml +++ b/lib/erl_interface/doc/src/ei_connect.xml @@ -85,6 +85,271 @@ the _tmo suffix.

+
+ + User Supplied Socket Implementation +

By default ei supplies a TCP/IPv4 socket interface + that is used when communicating. The user can however plug in + his/her own IPv4 socket implementation. This, for example, in order + to communicate over TLS. A user supplied socket implementation + is plugged in by passing a + callback structure + to either + ei_connect_init_ussi() + or + ei_connect_xinit_ussi().

+ +

All callbacks in the ei_socket_callbacks structure + should return zero on success; and a posix error + code on failure.

+ +

The addr argument of the listen, accept, + and connect callbacks refer to appropriate address + structure for currently used protocol. Currently ei + only supports IPv4. That is, at this time addr always + points to a struct sockaddr_in structure.

+ +

The ei_socket_callbacks structure may be enlarged in + the future. All fields not set, needs to be zeroed out.

+ + + + + + flags + +

Flags informing ei about the behaviour of the + callbacks. Flags should be bitwise or:ed together. If no flag, + is set, the flags field should contain 0. Currently, + supported flags:

+ + EI_SCLBK_FLG_FULL_IMPL + +

+ If set, the accept(), connect(), + writev(), write(), and read() callbacks + implements timeouts. The timeout is passed in the tmo + argument and is given in milli seconds. Note that the + tmo argument to these callbacks differ from the + timeout arguments in the ei API. Zero means a zero + timeout. That is, poll and timeout immediately unless the + operation is successful. EI_SCLBK_INF_TMO + (max unsigned) means infinite timeout. The file + descriptor is in blocking mode when a callback is called, + and it must be in blocking mode when the callback returns. +

+

+ If not set, ei will implement the timeout using + select() in order to determine when to call the + callbacks and when to time out. The tmo arguments + of the accept(), connect(), writev(), + write(), and read() callbacks should be + ignored. The callbacks may be called in non-blocking mode. + The callbacks are not allowed to change between blocking + and non-blocking mode. In order for this to work, + select() needs to interact with the socket primitives + used the same way as it interacts with the ordinary socket + primitives. If this is not the case, the callbacks + need to implement timeouts and this flag should + be set. +

+
+
+

More flags may be introduced in the future.

+
+ int (*socket)(void **ctx, void *setup_ctx) + +

Create a socket and a context for the socket.

+ +

On success it should set *ctx to point to a context for + the created socket. This context will be passed to all other + socket callbacks. This function will be passed the same + setup_context as passed to the preceeding + ei_connect_init_ussi() + or + ei_connect_xinit_ussi() + call.

+ +

During the lifetime of a socket, the pointer *ctx + has to remain the same. That is, it cannot later be + relocated.

+ +

This callback is mandatory.

+
+ + int (*close)(void *ctx) + +

Close the socket identified by ctx and destroy the context.

+ +

This callback is mandatory.

+
+ + int (*listen)(void *ctx, void *addr, int *len, int backlog) + +

Bind the socket identified by ctx to a local interface + and then listen on it.

+ +

The addr and len arguments are both input and output + arguments. When called addr points to an address structure of + lenght *len containing information on how to bind the socket. + Uppon return this callback should have updated the structure referred + by addr with information on how the socket actually was bound. + *len should be updated to reflect the size of *addr + updated. backlog identifies the size of the backlog for the + listen socket.

+ +

This callback is mandatory.

+
+ + int (*accept)(void **ctx, void *addr, int *len, unsigned tmo) + +

Accept connections on the listen socket identified by + *ctx.

+ +

When a connection is accepted, a new context for the accepted + connection should be created and *ctx should be updated + to point to the new context for the accepted connection. When + called addr points to an uninitialized address structure + of lenght *len. Uppon return this callback should have + updated this structure with information about the client address. + *len should be updated to reflect the size of *addr + updated. +

+ +

If the EI_SCLBK_FLG_FULL_IMPL flag has been set, + tmo contains timeout time in milliseconds.

+ +

During the lifetime of a socket, the pointer *ctx + has to remain the same. That is, it cannot later be + relocated.

+ +

This callback is mandatory.

+
+ + int (*connect)(void *ctx, void *addr, int len, unsigned tmo) + +

Connect the socket identified by ctx to the address + identified by addr.

+ +

When called addr points to an address structure of + lenght len containing information on where to connect.

+ +

If the EI_SCLBK_FLG_FULL_IMPL flag has been set, + tmo contains timeout time in milliseconds.

+ +

This callback is mandatory.

+
+ + int (*writev)(void *ctx, const void *iov, long iovcnt, ssize_t *len, unsigned tmo) + +

Write data on the connected socket identified by ctx.

+ +

iov points to an array of struct iovec structures of + length iovcnt containing data to write to the socket. On success, + this callback should set *len to the amount of bytes successfully + written on the socket.

+ +

If the EI_SCLBK_FLG_FULL_IMPL flag has been set, + tmo contains timeout time in milliseconds.

+ +

This callback is optional. Set the writev field + in the the ei_socket_callbacks structure to NULL if not + implemented.

+
+ + int (*write)(void *ctx, const char *buf, ssize_t *len, unsigned tmo) + +

Write data on the connected socket identified by ctx.

+ +

When called buf points to a buffer of length *len + containing the data to write on the socket. On success, this callback + should set *len to the amount of bytes successfully written on + the socket.

+ +

If the EI_SCLBK_FLG_FULL_IMPL flag has been set, + tmo contains timeout time in milliseconds.

+ +

This callback is mandatory.

+
+ + int (*read)(void *ctx, char *buf, ssize_t *len, unsigned tmo) + +

Read data on the connected socket identified by ctx.

+ +

buf points to a buffer of length *len where the + read data should be placed. On success, this callback should update + *len to the amount of bytes successfully read on the socket.

+ +

If the EI_SCLBK_FLG_FULL_IMPL flag has been set, + tmo contains timeout time in milliseconds.

+ +

This callback is mandatory.

+
+ + int (*handshake_packet_header_size)(void *ctx, int *sz) + +

Inform about handshake packet header size to use during the Erlang + distribution handshake.

+ +

On success, *sz should be set to the handshake packet header + size to use. Valid values are 2 and 4. Erlang TCP + distribution use a handshake packet size of 2 and Erlang TLS + distribution use a handshake packet size of 4.

+ +

This callback is mandatory.

+
+ + int (*connect_handshake_complete)(void *ctx) + +

Called when a locally started handshake has completed successfully.

+ +

This callback is optional. Set the connect_handshake_complete field + in the ei_socket_callbacks structure to NULL if not implemented.

+
+ + int (*accept_handshake_complete)(void *ctx) + +

Called when a remotely started handshake has completed successfully.

+ +

This callback is optional. Set the accept_handshake_complete field in + the ei_socket_callbacks structure to NULL if not implemented.

+
+ + int (*get_fd)(void *ctx, int *fd) + +

Inform about file descriptor used by the socket which is identified + by ctx.

+ +

During the lifetime of a socket, the file descriptor + has to remain the same. That is, repeated calls to this + callback with the same context should always report the same + file descriptor.

+

The file descriptor has to be a real file descriptor. + That is, no other operation should be able to get the same file + descriptor until it has been released by the close() + callback.

+
+ +

This callback is mandatory.

+
+
+
struct hostent*ei_gethostbyaddr(const char *addr, int len, int type) @@ -96,6 +361,7 @@

Convenience functions for some common name lookup functions.

+ intei_accept(ei_cnode *ec, int listensock, ErlConnect *conp) @@ -140,6 +406,14 @@ typedef struct { + + intei_close_connection(int fd) + Close a connection. + +

Closes a previously opened connection or listen socket.

+
+
+ intei_connect(ei_cnode* ec, char *nodename) intei_xconnect(ei_cnode* ec, Erl_IpAddr adr, char *alivename) @@ -193,7 +467,9 @@ fd = ei_xconnect(&ec, &addr, ALIVE); intei_connect_init(ei_cnode* ec, const char* this_node_name, const char *cookie, short creation) + intei_connect_init_ussi(ei_cnode* ec, const char* this_node_name, const char *cookie, short creation, ei_socket_callbacks *cbs, int cbs_sz, void *setup_context) intei_connect_xinit(ei_cnode* ec, const char *thishostname, const char *thisalivename, const char *thisnodename, Erl_IpAddr thisipaddr, const char *cookie, short creation) + intei_connect_xinit_ussi(ei_cnode* ec, const char *thishostname, const char *thisalivename, const char *thisnodename, Erl_IpAddr thisipaddr, const char *cookie, short creation, ei_socket_callbacks *cbs, int cbs_sz, void *setup_context) Initialize for a connection.

Initializes the ec structure, to @@ -236,6 +512,21 @@ fd = ei_xconnect(&ec, &addr, ALIVE);

thispaddr if the IP address of the host.

+ +

cbs is a pointer to a + callback structure + implementing and alternative socket interface.

+
+ +

cbs_sz is the size of the structure + pointed to by cbs.

+
+ +

setup_context is a pointer to a structure that + will be passed as second argument to the socket callback + in the cbs structure.

+
+

A C-node acting as a server is assigned a creation number when it calls ei_publish().

@@ -298,6 +589,45 @@ if (ei_connect_init(&ec, "madonna", "cookie...", n++) < 0) {
+ + intei_listen(ei_cnode *ec, int *port, int backlog) + intei_xlisten(ei_cnode *ec, Erl_IpAddr adr, int *port, int backlog) + Create a listen socket. + +

Used by a server process to setup a listen socket which + later can be used for accepting connections from client processes. +

+ + +

ec is the C-node structure.

+
+ +

adr is local interface to bind to.

+
+ +

port is a pointer to an integer containing the + port number to bind to. If *port equals 0 + when calling ei_listen(), the socket will be bound to + an ephemeral port. On success, ei_listen() will update + the value of *port to the port actually bound to. +

+
+ +

backlog is maximum backlog of pending connections.

+
+
+

ei_listen will create a socket, bind to a port on the + local interface identified by adr (or all local interfaces if + ei_listen() is called), and mark the socket as a passive socket + (that is, a socket that will be used for accepting incoming connections). +

+

+ On success, a file descriptor is returned which can be used in a call to + ei_accept(). On failure, ERL_ERROR is returned and + erl_errno is set to EIO.

+
+
+ intei_publish(ei_cnode *ec, int port) Publish a node name. -- cgit v1.2.3