The Eclipse OpenJ9 project has a port library implementation of network socket communication. As I understand the code may be a bit stale in places because it hasn't been used much.
The proposal is to take this code, brush it off and move it in the port library of OMR so that other projects that consume omr can take advantage of it.
Attn: @pdbain-ibm , @charliegracie
Unfavourable circumstance: Some of j9sock implementations outdated or contains some stale code. We will redesign/rewrite/clean up the code and make it part of OMR implementations.
OMR Common Data Structures:
1.
// The Plan for OMR
typedef struct omraddrinfo_struct {
void *addr_info;
int length;
} omraddrinfo_struct;
// j9sock
typedef struct j9addrinfo_struct {
void *addr_info;
int length;
#if defined(WIN32)
int flags;
#endif
} j9addrinfo_struct;
md5-ae55741360ba97f4fb1e13561d422386
// The Plan for OMR
typedef struct hostent omrhostent;
md5-04aed1addb090b515f906fa87be5b9dc
// j9sock
typedef struct hostent OSHOSTENT;
md5-37ff359a5ae7252fa5c7f5bc197bc28d
// The Plan for OMR
#if defined(WIN32)
typedef SOCKET omrsocket;
#else
typedef int omrsocket;
#endif
md5-04aed1addb090b515f906fa87be5b9dc
// j9sock
#if defined(WIN32)
typedef SOCKET OSSOCKET; /* as returned by socket() */
#else /* !WIN32 */
typedef int OSSOCKET; /* as returned by socket() */
#endif /* !WIN32 */
md5-91cc4c414640d98f4c86dfa6723dd156
// The Plan for OMR ***Need help to decide where to put these data structures
// OMR unix_include
typedef struct sockaddr omrsockaddr;
typedef struct sockaddr_in omrsockaddr_in; /* for IPv4 addresses*/
typedef struct sockaddr_in6 omrsockaddr_in6; /* for IPv6 addresses*/
typedef struct sockaddr_storage omrsockaddr_storage; /* Big enough storage for IPv4 or IPv6 addresses */
typedef struct addrinfo omraddrinfo; /* addrinfo structure for both IPv4 and IPv6 */
// OMR win32_include
typedef SOCKADDR omrsockaddr; /* for IPv4 */
typedef SOCKADDR_IN omrsockaddr_in; /* for IPv4 addresses*/
typedef SOCKADDR_IN6 omrsockaddr_in6; /* for IPv6 addresses*/
typedef struct sockaddr_storage omrsockaddr_storage; /* Big enough storage for IPv4 or IPv6 addresses */
typedef struct addrinfoW omraddrinfo; /* addrinfo structure – Unicode for both IPv4 and IPv6 */
md5-04aed1addb090b515f906fa87be5b9dc
// j9sock
#if defined(WIN32)
typedef SOCKADDR_IN OSSOCKADDR; /* as used by bind() and friends */
typedef struct sockaddr_storage OSSOCKADDR_STORAGE; /* IPv6 */
#else
typedef struct sockaddr_in OSSOCKADDR; /* as used by bind() and friends */
#if !defined(J9ZTPF) /* z/TPF doesn't have IPv6 */
typedef struct sockaddr_storage OSSOCKADDR_STORAGE; /* IPv6 */
#endif /* !defined(J9ZTPF) */
#endif /* !WIN32 */
// j9sock unix_include
typedef struct sockaddr OSADDR;
typedef struct sockaddr_in6 OSSOCKADDR_IN6; /* IPv6 */
typedef struct addrinfo OSADDRINFO; /* IPv6 */
// j9sock win32_include
typedef SOCKADDR OSADDR;
typedef struct addrinfoW OSADDRINFO; /* IPv6 - Unicode */
typedef SOCKADDR_IN6 OSSOCKADDR_IN6; /* IPv6 */
md5-11f0fa029a371fec80777c7fde54d136
// j9sock
#if defined(LINUX) || defined(AIXPPC) || defined(J9ZOS390) || defined(OSX)
#define SOCKET_CAST(x) ((struct j9socket_struct*) x)->sock
#else /* defined(LINUX) || defined(AIXPPC) || defined(J9ZOS390) || defined(OSX) */
/* all the non-unix ports use this variant */
/* The sockets returned as a j9socket_t (j9socket_struct*) are not actual structs, we just pretend that the pointer is a struct and never dereference it.
*/
#ifdef NO_LVALUE_CASTING
#define SOCKET_CAST(x) (*((OSSOCKET *) &(x)))
#else /* NO_LVALUE_CASTING */
#define SOCKET_CAST(x) ((OSSOCKET)x)
#endif /* !NO_LVALUE_CASTING */
#endif /* defined(LINUX) || defined(AIXPPC) || defined(J9ZOS390) || defined(OSX) */
md5-e0ea7c15407a116c8473bf6c3ea3384d
//The Plan for OMR
typedef struct linger omrlinger;
md5-04aed1addb090b515f906fa87be5b9dc
// j9sock
typedef struct linger OSLINGER;
md5-903b4e2ae7b7580f3170f285004eb2f0
// j9sock
typedef struct ip_mreq OSIPMREQ;
typedef struct ipv6_mreq OSIPMREQ6;
md5-de64d0bdf815f424e82e6fe77475bf14
// j9sock
typedef struct j9sockaddr_struct {
#if defined(IPv6_FUNCTION_SUPPORT) || (defined(WIN32))
OSSOCKADDR_STORAGE addr;
#else
OSSOCKADDR addr;
#endif
} j9sockaddr_struct;
/*
* Socket structure on windows requires 2 sockets due to the fact that microsoft does not
* handle ipv6-mapped ipv6 addresses. Therefore we need to listen to sockets on both
* the ipv6 and ipv4 stacks, when in a mode where we support ipv6.
*/
typedef struct j9socket_struct {
#if defined(WIN32)
OSSOCKET ipv4;
OSSOCKET ipv6;
uint8_t flags;
#else /* WIN32 */
OSSOCKET sock;
uint16_t family;
#endif /* !WIN32 */
} j9socket_struct;
typedef struct j9hostent_struct {
OSHOSTENT *entity;
} j9hostent_struct;
md5-d84691c464257eb9cad6bea276c7ffc7
// j9sock
/* structure for returning either and IPV4 or IPV6 ip address */
typedef struct j9ipAddress_struct {
union {
#if defined(IPv6_FUNCTION_SUPPORT) || ((defined(WIN32)))
uint8_t bytes[sizeof(struct in6_addr)];
#else
uint8_t bytes[sizeof(struct in_addr)];
#endif
struct in_addr inAddr;
#if defined(IPv6_FUNCTION_SUPPORT) || ((defined(WIN32)))
struct in6_addr in6Addr;
#endif
} addr;
uint32_t length;
uint32_t scope;
} j9ipAddress_struct;
Will add this in later if need to.
I attached files that I put together here:
1) List of Basic data structures and APIs that Unix and Windows has. For Windows, on their website, it is recommended that we use the UNICODE functions and data structures but they also provide a list of ANSI functions and data structures.
unix_and_windows_socket_api.docx
2) A list of all the j9sock.c library function
J9sock_common_functions.docx
Attn: @DanHeidinga
@caohaley Starting with data-structures is not a good idea. First, you need to describe/propose the new socket API. Before proposing the new socket API, you need to study the existing the j9sock API.
Next steps:
| j9sock function | description | Linux | AIX | zOS | OSX | Windows |
| ------------- | ------------- | ------------- | ------------- | ------------- | ------------- | ------------- |
| j9sock_accept | LINK | accept | accept | accept | accept | accept |
| xxxx | xxxx | .... | .... | .... | .... | .... |
| j9sock function | IPv4/IPv6 | UDP/TCP |
| ------------- | ------------- | ------------- |
| j9sock_accept | Yes (Windows) | No |
| xxxx | xxxx | .... | .... |
Side notes:
I’m not quite familiar with J9STPF socket API and will need help with that: J9ZTPF macro covers the implementation for the zTPF system which is a real time OS for mainframes. zTPF should be similar to other Unix systems (Linux, AIX, zOS, OSX). There may be subtle differences. We don't have zTPF machines for testing. We leave placeholders for the zTPF implementation, and the zTPF team ports the implementation if needed.| j9sock function | description | LINUX | AIX | zOS | OSX | Windows |
|---|---|---|---|---|---|---|
| j9sock_accept | LINK | accept | accept | accept | accept | accept |
| j9sock_bind | LINK | bind | bind | bind | bind | bind |
| j9sock_close | LINK | close | close | close | close | close|
| j9sock_connect | LINK | connect | connect | connect | connect | connect |
| j9sock_freeaddrinfo | LINK | freeaddrinfo | freeaddrinfo | freeaddrinfo | freeaddrinfo | freeaddrinfo |
| j9sock_getaddrinfo | LINK | getaddrinfo | getaddrinfo | getaddrinfo | getaddrinfo | getaddrinfo |
| j9sock_listen | LINK | listen | listen | listen | listen | listen |
| j9sock_read | LINK | recv | recv | recv | recv | recv |
| j9sock_readfrom | LINK | recvfrom | recvfrom | recvfrom | recvfrom | recvfrom |
| j9sock_shutdown | LINK | shutdown | shutdown | shutdown | shutdown | shutdown |
| j9sock_socket | LINK | socket | socket | socket | socket | socket |
| j9sock_write | LINK | send | send | send | send | send |
| j9sock_writeto | LINK | sendto | sendto | sendto | sendto | sendto |
| j9sock function | description | LINUX | AIX | zOS | OSX | Windows |
|---|---|---|---|---|---|---|
| j9sock_select | LINK | select | select | select | select | select |
| j9sock_fdset_zero, j9sock_fdset_set, j9sock_fdset_clr, j9sock_fdset_isset | LINK | FD_ZERO, FD_SET, FD_CLR, FD_ISSET | FD_SET, FD_CLR, FD_ISSET | FD_ZERO, FD_SET, FD_CLR, FD_ISSET | FD_ZERO, FD_SET, FD_CLR, FD_ISSET | FD_ZERO, FD_SET, FD_CLR, FD_ISSET |
| j9sock function | description | LINUX | AIX | zOS | OSX | Windows |
|---|---|---|---|---|---|---|
| j9sock_gethostbyaddr | LINK | gethostbyaddr Obslete, should use getaddrinfo() and getnameinfo() instead | gethostbyaddr | gethostbyaddr Moved to obsolescence in Single UNIX Specification, Version 3 and may be withdrawn in a future version. | gethostbyaddr | gethostbyaddr No longer recommended for use as of Windows Sockets 2 and the getnameinfo() should be used. However, gethostbyaddr is capable of returning a NetBIOS name whereas getnameinfo() is not |
| j9sock_gethostbyname | LINK | gethostbyname Obsolete, use getaddrinfo() and getnameinfo() instead | gethostbyname | gethostbyaddr Moved to obsolescence in Single UNIX Specification, Version 3 and may be withdrawn in a future version | gethostbyname | gethostbyname Deprecated by the introduction of the getaddrinfo function |
| j9sock_gethostname | LINK | gethostname | gethostname | gethostname | gethostname | gethostname |
| j9sock_getnameinfo | LINK | getnameinfo | getnameinfo | getnameinfo | getnameinfo | getnameinfo |
| j9sock_getpeername | LINK | getpeername | getpeername | getpeername | getpeername | getpeername |
| j9sock_getsockname | LINK | getsockname | getsockname | getsockname | getsockname | getsockname |
| j9sock function | description | LINUX | AIX | zOS | OSX | Windows |
|---|---|---|---|---|---|---|
| j9sock_htonl | LINK | htonl | htonl | htonl | htonl | htonl |
| j9sock_htons | LINK | htons | htons | htons | htons | htons |
| j9sock_inetaddr | LINK | inet_addr | inet_addr | inet_addr | inet_addr | inet_addr |
| j9sock_ntohl | LINK | ntohl | ntohl | ntohl | ntohl | ntohl |
| j9sock_ntohs | LINK | ntohs | ntohs | ntohs | ntohs | ntohs |
j9sock function | IPv4/IPv6 | UDP/TCP
-- | -- | --
j9sock_accept | Yes (Windows), will need to configure address family | No
j9sock_bind | No, as long as parameters are in the same address family | No
j9sock_close | No | No
j9sock_connect | Yes (Windows), will need to configure address family | No. But for UDP, connect may be called multiple times to change/set/unset association with a destination addres. For TCP, it may be only called once to make a connection.
j9sock_freeaddrinfo | No | No
j9sock_getaddrinfo | No | No
j9sock_listen | No | Yes, UDP does not use listen and thus not supported
j9sock_read | No | Yes basically. This function only applied to connected sockets (zOS). Recv is usually only used for connected sockets but could be used for connectionless sockets as well (Linux, AIX, OSX, Windows)
j9scok_readfrom | No | Yes basically. Can be used with unconnected/connectionless sockets or connected sockets as well (Linux, OSX, Windows). Used with unconnected(AIX)/datagram(zOS) sockets
j9sock_shutdown | No | Yes. Shutdown is for full duplex connections but if you want to shutdown a connected datagram socket, it is possible (Linux, Windows).
j9sock_socket | No. You simply pass in the argument whether or not you want a IPv4 socket or IPv6 socket | No. You simply pass in the argument whether or not you want a stream, datagram or other kind of socket
j9sock_write | No | Yes. Only used in connected mode
j9sock_writeto | No | Yes. Can be used with connected or unconnected sockets (Linux, zOS, OSX, Windows). Used with unconnected sockets (AIX)
j9sock function | IPv4/IPv6 | UDP/TCP
-- | -- | --
j9sock_select | No | Yes. Works for connected stream sockets.
j9sock_fdset_zero, j9sock_fdset_set, j9sock_fdset_clr, j9sock_fdset_isset | No | No
j9sock function | IPv4/IPv6 | UDP/TCP
-- | -- | --
j9sock_gethostbyaddr | Yes. May not work well with IPv6 | No
j9sock_gethostbyname | Yes. Does not work with IPv6 | No
j9sock_gethostname | No | No
j9sock_getnameinfo | No | No
j9sock_getpeername | Yes. Will need to configure address storage structure passed in for IPv4 vs IPv6 | No
j9sock_getsockname | Yes. Will need to configure address storage structure passed in for IPv4 vs IPv6 | No
j9sock function | IPv4/IPv6 | UDP/TCP
-- | -- | --
j9sock_htonl | Yes if converting address. | No
j9sock_htons | Yes if converting address. | No
j9sock_inetaddr | Yes. Does not work for IPv6 | No
j9sock_ntohl | Yes if converting address. | No
j9sock_ntohs | Yes if converting address. | No
Unfavourable circumstance: Some of j9sock implementations outdated or contains some stale code. We will redesign/clean up the j9sock code and make it part of OMR implementations.
The design of how to set up the data structures and the functions are all based off j9sock implementations. They're minimalised, by removing what I think are no longer needed, or fixed so that it can use the current network programming APIs.
This minimalistic socket API proposal will only contain the basic socket functions needed for connection. There are more functions needed to send/receive data, host information queries and so on. They will be included after the minimalistic socket API is implemented.
Functions included in the minimalistic socket API proposal:
OMRSockAddrInfoNode and omrsock_addrinfo_t/* addrinfo struct
* - data structure for getaddrinfo and freeaddrinfo functions
* - OMRAddrInfo* addrInfo will be different depending on the Operating System's respective addrinfo
* structures (defined later on) and is the pointer to the first addrinfo of the linked list
* - int length counts how many addrinfo nodes there are in the linked list
*/
typedef struct OMRSockAddrInfoNode {
OMRAddrInfo* addrInfo;
int length;
} OMRSockAddrInfo;
typedef OMRSockAddrInfoNode* omrsock_addrinfo_t;
omrsock_socket_t/* socket pointer
* - pointer to a socket descriptor
* - points to a OMRSocket which is an SOCKET type for
* Windows but int for all other operating systems
* - this will be used by the potential user to pass into function calls as a parameter
*/
typedef OMRSocket* omrsock_socket_t;
OMRSockSockAddr and omrsock_sockaddr_t/* sockaddr struct
* - used to store ip addresses. If IPv6 is supported, then we use omrsockaddr_storage,
* which can store IPv4 or Ipv6 addresses.
*/
typedef struct OMRSockSockAddr {
#if defined(IPv6_FUNCTION_SUPPORT)
OMRSockAddrStorage addr;
#else
OMRSockAddr addr;
#endif
} OMRSockSockAddr;
typedef OMRSockSockAddr* omrsock_sockaddr_t;
OMRHostent/* hostent may be still used by some programmers but isn't used as much anymore
*/
typedef struct hostent OMRHostent;
OMRSocket, the socket descriptorOMRSockAddr, the generic sockaddr parameter for passing into many API functions, may be casted both ways from and to sockaddr_in and sockaddr_in6OMRSockAddrIn, the IP address for IPv4 socketsOMRSockAddrIn6, the IP address for IPv6 socketsOMRSockAddrStorage, the storage is large enough for either IPv4 or IPv6 address, used for when you don't know which address family the address will beOMRAddrInfo, the addrinfo structure, which is a linked list of addresses and related information (such as address family, protocols, etc.)// OMR unix_include
typedef int OMRSocket;
typedef struct sockaddr OMRSockAddr;
typedef struct sockaddr_in OMRSockAddrIn; /* for IPv4 addresses*/
typedef struct sockaddr_in6 OMRSockAddrIn6; /* for IPv6 addresses*/
typedef struct sockaddr_storage OMRSockAddrStorage; /* Big enough storage for IPv4 or IPv6 addresses */
typedef struct addrinfo OMRAddrInfo; /* addrinfo structure for both IPv4 and IPv6 */
// OMR win32_include
typedef SOCKET OMRSocket;
typedef SOCKADDR OMRSockAddr; /* for IPv4 */
typedef SOCKADDR_IN OMRSockAddrIn; /* for IPv4 addresses*/
typedef SOCKADDR_IN6 OMRSockAddrIn6; /* for IPv6 addresses*/
typedef struct sockaddr_storage OMRSockAddrStorage; /* Big enough storage for IPv4 or IPv6 addresses */
typedef struct addrinfoW OMRAddrInfo; /* addrinfo structure – Unicode for both IPv4 and IPv6 */
omrsock_getaddrinfo:
/**
* Answers a list of addresses as an opaque struct in "result".
*
* Use the following functions to extract the details:
* \arg \ref omrsock_getaddrinfo_length
* \arg \ref omrsock_getaddrinfo_name
* \arg \ref omrsock_getaddrinfo_address
* \arg \ref omrsock_getaddrinfo_family
*
* @param[in] portLibrary The port library.
* @param[in] name The name of the host in either host name format or in IPv4 or IPv6 accepted notations.
* @param[in] hints Hints on what results are returned and how the response if formed (can be NULL for default action). Use omrsock_getaddrinfo_create_hints to create the hints
* @param[out] result An opaque pointer to a list of results (omraddrinfo_struct must be preallocated).
*
* @return 0, if no errors occurred, otherwise the (negative) error code.
*
* @note you must free the "result" structure with @ref omrsock_freeaddrinfo to free up memory.
*/
int32_t
omrsock_getaddrinfo(struct OMRPortLibrary *portLibrary, char *node, char *service, struct omrsock_addrinfo_t hints, struct omrsock_addrinfo_t result);
Notes for Implementation:
OMRSockAddrInfoNode to hold the outputs of omrsock_getaddrinfo. OMRSockAddrInfoNode using functions like omrsock_getaddrinfo_length, omrsock_getaddrinfo_name and on so. Therefore, they would use the index of the linked list to check information in the respective node. If they want to traverse the linked list, they would use a for-loop and extracting information individually using the index.omrsock_getaddrinfo_create_hints to create the hints to pass into this function.omrsock_freeaddrinfo:
/**
* Frees the memory created by the call to @ref omrsock_getaddrinfo().
*
* @param[in] portLibrary The port library.
* @param[in] handle Hints on what results are returned for getaddrinfo.
*
* @return 0, if no errors occurred, otherwise the (negative) error code.
*
*/
int32_t
omrsock_freeaddrinfo(struct OMRPortLibrary *portLibrary, omrsock_addrinfo_t handle);
omrsock_socket:
/**
* Creates a new socket descriptor and any related resources.
*
* @param[in] portLibrary The port library.
* @param[out] sock Pointer to the omrsocket, to be allocated
* @param[in] family The address family
* \arg OMRSOCK_AFINET, for a IPv4 socket
* \arg OMRSOCK_AFINET6, for a IPv6 socket
* @param[in] socktype Specifies what type of socket is created
* \arg OMRSOCK_STREAM, for a stream socket
* \arg OMRSOCK_DGRAM, for a datagram socket
* @param[in] protocol Type/family specific creation parameter
*
* @return 0, if no errors occurred, otherwise the (negative) error code.
*/
int32_t
omrsock_socket(struct OMRPortLibrary *portLibrary, omrsock_socket_t sock, int32_t family, int32_t socktype, int32_t protocol);
Implementation Note:
omrsock_bind:
/**
* The bind function is used on an unconnected socket before subsequent
* calls to the connect or listen functions. When a socket is created with a
* call to the socket function, it exists in a name space (address family), but
* it has no name assigned to it. Use bind to establish the local association
* of the socket by assigning a local name to an unnamed socket.
*
* @param[in] portLibrary The port library.
* @param[in] sock The socket that will be be associated with the specified name.
* @param[in] addr Address to bind to socket.
*
* @return 0, if no errors occurred, otherwise the (negative) error code.
*/
int32_t
omrsock_bind(struct OMRPortLibrary *portLibrary, omrsock_socket_t sock, omrsock_sockaddr_t addr);
omrsock_listen:
/**
* Set the socket to listen for incoming connection requests. This call is made prior to accepting requests,
* via the @ref omrsock_accept function. The backlog specifies the maximum length of the queue of pending connections,
* after which further requests are rejected.
*
* @param[in] portLibrary The port library.
* @param[in] sock Pointer to the socket to modify.
* @param[in] backlog The maximum number of queued requests.
*
* @return 0, if no errors occurred, otherwise the (negative) error code.
*/
int32_t
omrsock_listen(struct OMRPortLibrary *portLibrary, omrsock_socket_t sock, int32_t backlog);
omrsock_connect:
/**
* Establish a connection to a peer.
*
* For stream sockets, it first binds the socket if it hasn't already been done. Then, it
* tries to set up a connection.
*
* For datagram sockets, connect function will set up the peer information. No actual
* connection is made. Subsequent calls to connect can be made to change destination address.
*
* It is not recommended that users call this
* function multiple times to determine when the connection attempt has succeeded.
* Instead, the omrsock_select() function can be used to determine when the socket
* is ready for reading or writing.
*
* @param[in] portLibrary The port library.
* @param[in] sock pointer to the unconnected local socket.
* @param[in] addr pointer to the sockaddr, specifying remote host/port.
*
* @return 0, if no errors occurred, otherwise the (negative) error code.
*/
omrsock_connect(struct OMRPortLibrary *portLibrary, omrsock_socket_t sock, omrsock_sockaddr_t addr)
omrsock_accept:
/**
* The accept function extracts the first connection on the queue of pending connections
* on socket serverSock. It then creates a new socket and returns a handle to the new socket.
* The newly created socket is the socket that will handle the actual the connection and
* has the same properties as socket serverSock.
*
* The accept function can block the caller until a connection is present if no pending
* connections are present on the queue.
*
* @param[in] portLibrary The port library.
* @param[in] serverSock A omrsock_socket_t that tries to accept a connection.
* @param[in] addrHandle An optional pointer to a buffer that receives the address of the connecting
* entity, as known to the communications layer. The exact format of the addr parameter
* is determined by the address family established when the socket was created
* @param[out] sockHandle A pointer to a omrsock_socket_t which will point to the newly created
* socket once accept returns successfully
*
* @return 0, if no errors occurred, otherwise the (negative) error code.
*/
int32_t
omrsock_accept(struct OMRPortLibrary *portLibrary, omrsock_socket_t serverSock, omrsock_sockaddr addrHandle, omrsock_socket_t *sockHandle);
omrsock_close:
/**
* The close function closes a socket. Use it to release the socket descriptor socket so
* further references to socket will fail.
*
* @param[in] portLibrary The port library.
* @param[in] sock j9socket_t which will be closed.
*
* @return 0, if no errors occurred, otherwise the (negative) error code.
*/
int32_t
omrsock_close(struct OMRPortLibrary *portLibrary, omrsock_socket_t sock)
J9SocketPTB which is a Per-thread buffer for platform-dependent socket information. Should we do something like that too?The way to establish communications doesn't change with our OMRSock API. The potential user will simply have to call the OMR version of these function calls. For example, omrsock_socket() instead of socket(), omrsock_bind() instead of bind() and so on.
Typical Order of Function Calls to Establish TCP communication:
_Server:_
socket() -> bind() -> listen() -> accept() -> read()/write() -> close()
After server calls listen(), it is ready to accept connection requests. The connection requests are placed in a queue of the size that you set when you called listen(). When server accepts a connection, it accepts the first connection request in the queue and a new socket is created. While it is setting up the connection in accept(), it blocks communication. Once connection is set up, the communication happens through read() or write().
_Client:_
socket() -> connect() -> read()/write() -> close()
The client calls connect() to attempt setting up a connection with the server. connect() returns after it successfully connects (or can't connect returning an error code) to the server.
Typical Order of Function Calls to Establish UDP communication:
_Server:_
socket() -> bind() -> sendto()/recvfrom() -> close()
The server needs to bind() to the interfaces that it wants to receive from. The sendto(), recvfrom() contains the address of the peer that receives or sent out the data.
_Client:_
socket() -> sendto()/recvfrom() -> close()
The client uses sendto() and recvfrom() to send to a specified address.
However, omrsock_getaddrinfo() is different from getaddrinfo() for the users:
The potential users will need to create hints using omrsock_getaddrinfo_create_hints() and pass the hints into the omrsock_getaddrinfo(). The hints will specify what kind of address you are looking for, what address family, protocol, etc. and the results will be filtered accordingly. omrsock_getaddrinfo() essentially takes the hostname and service name and fills in the information of the host including address, address family, protocols etc. for you. It returns a linked list of OMRAddrInfo inside, with the pointer to the first OMRAddrInfo in OMRSockAddrInfoNode.
omrsock_getaddrinfo_create_hints() -> omrsock_getaddrinfo()
Usually, programmers traverse the linked list and bind to the first one they can.
An example using socket API on an Operating System like Linux directly:
#define PORT "3333"
struct addrinfo hints;
struct addrinfo* res;
struct addrinfo* p;
int sock;
/* Set hints to only return results that are IPv6 and Stream */
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_STREAM;
getaddrinfo(NULL, PORT, &hints, &res);
/* Traverse through results */
for (p = res; p != NULL; p = p->ai_next){
/* Try to create a socket with addrinfo and bind to it */
sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if(-1 == sock){
/* making socket failed */
continue;
}
if(-1 == bind(sock, p->ai_addr, p->ai_addrlen)){
/* binding socket failed */
continue;
}
break;
}
/* Now you can try to connect and then send/receive data as you wish */
Using our OMRSock API:
#define PORT "3333"
OMRPORT_ACCESS_FROM_OMRPORT(portLibrary);
struct OMRSockAddrInfoNode hintsStruct;
struct OMRSockAddrInfoNode resStruct;
omrsock_addrinfo_t hints = &hintsStruct;
omrsock_addrinfo_t res = &resStruct;
OMRSOCKET sock;
/* Set hints to only return results that are IPv6 and Stream */
omrsock_getaddrinfo_create_hints(hints, OMR_AFINET6, OMR_STREAM, 0, 0);
omrsock_getaddrinfo("NULL", PORT, hints, res);
/* Traverse through results */
for (int i = 0; i < res->length; i++){
int family = 0;
int socktype = 0;
int protocol = 0;
omrsock_getaddrinfo_family(res, &family, i);
omrsock_getaddrinfo_socktype(res, &socktype, i);
omrsock_getaddrinfo_protocol(res, &protocol, i);
/* Try to create a socket and bind to it */
if(0 != omrsock_socket(&sock, family, socktype, protocol)){
/* making socket failed */
continue;
}
if(0 != omrsock_bind(&sock, p->ai_addr, p->ai_addrlen)){
/* binding socket failed */
continue;
}
break;
}
/* Now you can try to connect and then send/receive data as you wish */
As can be seen, our OMRSock API will need the users to traverse using an index, rather than traversing through an linked list directly.
@caohaley Good work. It will be easier to review if the above code is in a pull request with stubs for API functions. Here is some feedback:
1) You will either be using OMRSockAddr or OMRSockAddrStorage depending on IPv6_FUNCTION_SUPPORT.
typedef struct OMRSockSockAddr {
#if defined(IPv6_FUNCTION_SUPPORT)
OMRSockAddrStorage addr;
#else
OMRSockAddr addr;
#endif
} OMRSockSockAddr;
You don't need OMRSockSockAddr. Instead, you can use:
#if defined(IPv6_FUNCTION_SUPPORT)
typedef struct sockaddr_storage OMRSockSocketAddr; /* Big enough storage for IPv4 or IPv6 addresses */
#else /* defined(IPv6_FUNCTION_SUPPORT) */
typedef struct sockaddr OMRSockSocketAddr;
#endif /* defined(IPv6_FUNCTION_SUPPORT) */
typedef OMRSockSocketAddr* omrsock_socketaddr_t;
IPv6_FUNCTION_SUPPORT: Make a note on how/where/who defines this flag. It seems unclear at this point.
When drafting the PR, follow ... Comment conditional compilation directives (#if, #ifdef, #ifndef, #else, #elif, #endif).
Consistency in naming. Should all struct names start with OMRSock*? OMRAddrInfo (doesn't have OMRSock)? OMRSockSockAddr (SockSock gets confusing).
omrsock_getaddrinfo: input variables char *node, char *service are undefined in the description.
OMR uses Doxygen comments. So, \arg and \ref [incorrect syntax] should be replaced with @arg and @ref.
Remaining functions look good: freeaddrinfo, socket, bind, listen, connect, accept and close.
How are API users going to read, write, sendto and recvfrom? Do these operations need API functions?
Using keyword struct: struct OMRPortLibrary *portLibrary and omrsock_addrinfo_t hints. struct does not need to be added to var_t type-structures. It is only used with Var type-structures. This pattern is noticeable within OMR. In getaddrinfo, you use struct with omrsock_addrinfo_t hints/result, which is not needed.
Was there a reason why the j9sockaddr_struct had both ipv4 and ipv6 sockets in it? Is it still necessary now?
Only one field OSSOCKADDR_STORAGE or OSSOCKADDR is used at a time in j9sockaddr_struct depending upon IPv6_FUNCTION_SUPPORT. You don't need both if only one is used. Refer to point 1.
getaddrinfo requires a hints structure but if hints structure is allocated and deallocated for the users, it'll be more convenient for them and there won't be memory leaks. j9sock does this by using J9SocketPTB which is a Per-thread buffer for platform-dependent socket information. Should we do something like that too?
API should abstract such functionality. So, propose API functions to manage the hints structure.
Should we support both ANSI and Unicode implementations or just Unicode?
We should only support Unicode (recommended) functions if they are available on all Windows variants supported by OMR.
This issue is stale because it has been open 180 days with no activity. Remove stale label or comment on the issue or it will be closed in 60 days.
PR connected to this issue are still being created/merged so this issue is not stale.
|Linux Function Name| omrsock API Function Name|
|---|---|
| - | omrsock_getaddrinfo_create_hints|
|getaddrinfo | omrsock_getaddrinfo|
| - | omrsock_addrinfo_length|
| - | omrsock_addrinfo_family|
| - | omrsock_addrinfo_socktype|
| - | omrsock_addrinfo_protocol|
|freeaddrinfo | omrsock_freeaddrinfo|
| - | omrsock_sockaddr_init|
| - | omrsock_sockaddr_init6|
|socket | omrsock_socket|
| - | omrsock_socket_getfd|
|bind | omrsock_bind|
|listen | omrsock_listen|
|accept | omrsock_accept|
|send | omrsock_send|
|sendto | omrsock_sendto|
|recv | omrsock_recv|
|recvfrom | omrsock_recvfrom|
| - | omrsock_pollfd_init|
| - | omrsock_get_pollfd_info|
|poll | omrsock_poll|
|FD_ZERO | omrsock_fdset_zero|
|FD_SET | omrsock_fdset_set|
|FD_CLR | omrsock_fdset_clr|
|FD_ISSET | sock_fdset_isset|
|select | omrsock_select|
|close | omrsock_close|
|htons | omrsock_htons|
|htonl | sock_htonl|
|inet_pton | omrsock_inet_pton|
|fcntl | omrsock_fcntl|
| - | omrsock_timeval_init|
| - | omrsock_linger_init|
|setsockopt | sock_setsockopt_int|
|setsockopt | sock_setsockopt_linger|
|setsockopt | sock_setsockopt_timeval|
|getsockopt | sock_getsockopt_int|
|getsockopt | sock_getsockopt_linger|
|getsockopt | sock_getsockopt_timeval|
@mpirvu: Should this issue remain open if the work is complete and merged?
This issue can be closed as the work is complete.