UNIX domain sockets

UNIX domain sockets enable efficient communication between processes that are running on the same z/TPF processor. UNIX domain sockets support both stream-oriented, TCP, and datagram-oriented, UDP, protocols. You cannot start a UNIX domain socket for raw socket protocols.

You can issue all of the socket application programming interfaces (APIs) that are supported by the z/TPF system for UNIX domain sockets.

To create a UNIX domain socket, use the socket function and specify AF_UNIX as the domain for the socket. The z/TPF system supports a maximum number of 16,383 active UNIX domain sockets at any time. After a UNIX domain socket is created, you must bind the socket to a unique file path by using the bind function. Unlike internet sockets in the AF_INET domain where the socket is bound to a unique IP address and port number, a UNIX domain socket is bound to a file path.

To specify the address of a UNIX domain socket, use the following SOCKADDR_UN address structure. In the address structure, the SUN_FAMILY field specifies the protocol family that is used and the SUN_PATH field specifies the path name of the socket. The SOCKADDR_UN structure is defined in the sys/un.h header file.
#define UNIX_PATH_MAX 108
struct sockaddr_un {
       unsigned short int sun_family; /* AF_UNIX */
       char sun_path[UNIX_PATH_MAX]; /* pathname */
};

When you bind a unique name to a UNIX domain socket by using the bind function, a file is created on the file system for the socket. The socket file is at the path that you specify in the SUN_PATH field of the SOCKADDR_UN structure. When the program closes and the file is no longer required, you must manually delete the socket file from the file system.

Because UNIX domain sockets are processor-unique, specify a socket address that uses a path name of one of the following processor-unique file systems in loosely coupled environments:
  • Memory file system (MFS)
  • Pool file system (PFS)
  • Fixed file system (FFS)
In a loosely coupled environment, do not use a path name that belongs to the z/TPF collection support file system (TFS) for the address of a UNIX domain socket.

Start of changeIf you create UNIX domain sockets, the sockets can be inherited by a child process that is created by using the fork function. For internet sockets, the z/TPF system has a concept of kernel-based sockets, which means that the internet sockets are not bound to a process. However, UNIX domain sockets are treated as process scoped; that is, the socket is cleaned up when the last process exits or when all processes issue a close function on the socket.End of change

If you issue the ZIPDB command, the ZSTAT command, or the ZTTCP DISPLAY command with the STATS parameter specified, information about the messages, bytes, and packet counters of the network services database are not updated for UNIX domain sockets. Messages that are sent across UNIX domain sockets are also not displayed in the IP trace facility.

Examples: Server programs that use UNIX domain sockets

The following code example shows a server program for connection-oriented, stream UNIX domain sockets. In the server program, the socket function creates a stream socket in the UNIX domain, and then the bind function assigns a unique name for the socket. The listen function then accepts incoming client connections and creates a connection queue for further incoming requests.
/************************************************************/
/* This is a stream socket server sample program for UNIX   */
/* domain sockets. This program listens for a connection    */
/* from a client program, accepts it, reads data from the   */
/* client, then sends data back to connected UNIX socket.   */
/************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

#define SOCK_PATH  "tpf_unix_sock.server"
#define DATA "Hello from server"

int main(void){

    int server_sock, client_sock, len, rc;
    int bytes_rec = 0;
    struct sockaddr_un server_sockaddr;
    struct sockaddr_un client_sockaddr;     
    char buf[256];
    int backlog = 10;
    memset(&server_sockaddr, 0, sizeof(struct sockaddr_un));
    memset(&client_sockaddr, 0, sizeof(struct sockaddr_un));
    memset(buf, 0, 256);                
    
    /**************************************/
    /* Create a UNIX domain stream socket */
    /**************************************/
    server_sock = socket(AF_UNIX, SOCK_STREAM, 0);
    if (server_sock == -1){
        printf("SOCKET ERROR: %d\n", sock_errno());
        exit(1);
    }
    
    /***************************************/
    /* Set up the UNIX sockaddr structure  */
    /* by using AF_UNIX for the family and */
    /* giving it a filepath to bind to.    */
    /*                                     */
    /* Unlink the file so the bind will    */
    /* succeed, then bind to that file.    */
    /***************************************/
    server_sockaddr.sun_family = AF_UNIX;   
    strcpy(server_sockaddr.sun_path, SOCK_PATH); 
    len = sizeof(server_sockaddr);
    
    unlink(SOCK_PATH);
    rc = bind(server_sock, (struct sockaddr *) &server_sockaddr, len);
    if (rc == -1){
        printf("BIND ERROR: %d\n", sock_errno());
        close(server_sock);
        exit(1);
    }
    
    /*********************************/
    /* Listen for any client sockets */
    /*********************************/
    rc = listen(server_sock, backlog);
    if (rc == -1){ 
        printf("LISTEN ERROR: %d\n", sock_errno());
        close(server_sock);
        exit(1);
    }
    printf("socket listening...\n");
    
    /*********************************/
    /* Accept an incoming connection */
    /*********************************/
    client_sock = accept(server_sock, (struct sockaddr *) &client_sockaddr, &len);
    if (client_sock == -1){
        printf("ACCEPT ERROR: %d\n", sock_errno());
        close(server_sock);
        close(client_sock);
        exit(1);
    }
    
    /****************************************/
    /* Get the name of the connected socket */
    /****************************************/
    len = sizeof(client_sockaddr);
    rc = getpeername(client_sock, (struct sockaddr *) &client_sockaddr, &len);
    if (rc == -1){
        printf("GETPEERNAME ERROR: %d\n", sock_errno());
        close(server_sock);
        close(client_sock);
        exit(1);
    }
    else {
        printf("Client socket filepath: %s\n", client_sockaddr.sun_path);
    }
    
    /************************************/
    /* Read and print the data          */
    /* incoming on the connected socket */
    /************************************/
    printf("waiting to read...\n");
    bytes_rec = recv(client_sock, buf, sizeof(buf), 0);
    if (bytes_rec == -1){
        printf("RECV ERROR: %d\n", sock_errno());
        close(server_sock);
        close(client_sock);
        exit(1);
    }
    else {
        printf("DATA RECEIVED = %s\n", buf);
    }
    
    /******************************************/
    /* Send data back to the connected socket */
    /******************************************/
    memset(buf, 0, 256);
    strcpy(buf, DATA);      
    printf("Sending data...\n");
    rc = send(client_sock, buf, strlen(buf), 0);
    if (rc == -1) {
        printf("SEND ERROR: %d", sock_errno());
        close(server_sock);
        close(client_sock);
        exit(1);
    }   
    else {
        printf("Data sent!\n");
    }
    
    /******************************/
    /* Close the sockets and exit */
    /******************************/
    close(server_sock);
    close(client_sock);
    
    return 0;
}
The following code example shows a server program for connectionless, datagram UNIX domain sockets. In the server program, the socket function creates a datagram socket in the UNIX domain, and then the bind function assigns a unique name for the socket. For connectionless sockets, you do not have to issue the listen function to accept incoming requests from a client.
/************************************************************/
/* This is a datagram socket server sample program for UNIX */
/* domain sockets. This program creates a socket and        */
/* receives data from a client.                             */
/************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

#define SOCK_PATH "tpf_unix_sock.server"

int main(void){

    int server_sock, len, rc;
    int bytes_rec = 0;
    struct sockaddr_un server_sockaddr, peer_sock;
    char buf[256];
    memset(&server_sockaddr, 0, sizeof(struct sockaddr_un));
    memset(buf, 0, 256);
    
    /****************************************/
    /* Create a UNIX domain datagram socket */
    /****************************************/
    server_sock = socket(AF_UNIX, SOCK_DGRAM, 0);
    if (server_sock == -1){
        printf("SOCKET ERROR = %d", sock_errno());
        exit(1);
    }
    
    /***************************************/
    /* Set up the UNIX sockaddr structure  */
    /* by using AF_UNIX for the family and */
    /* giving it a filepath to bind to.    */
    /*                                     */
    /* Unlink the file so the bind will    */
    /* succeed, then bind to that file.    */
    /***************************************/
    server_sockaddr.sun_family = AF_UNIX;
    strcpy(server_sockaddr.sun_path, SOCK_PATH); 
    len = sizeof(server_sockaddr);
    unlink(SOCK_PATH);
    rc = bind(server_sock, (struct sockaddr *) &server_sockaddr, len);
    if (rc == -1){
        printf("BIND ERROR = %d", sock_errno());
        close(server_sock);
        exit(1);
    }
    
    /****************************************/
    /* Read data on the server from clients */
    /* and print the data that was read.    */
    /****************************************/
    printf("waiting to recvfrom...\n");
    bytes_rec = recvfrom(server_sock, buf, 256, 0, (struct sockaddr *) &peer_sock, &len);
    if (bytes_rec == -1){
        printf("RECVFROM ERROR = %d", sock_errno());
        close(server_sock);
        exit(1);
    }
    else {
       printf("DATA RECEIVED = %s\n", buf);
    }
    
    /*****************************/
    /* Close the socket and exit */
    /*****************************/
    close(server_sock);

    return 0;
}

Examples: Client programs that use UNIX domain sockets

The following code example shows a client program for connection-oriented, stream UNIX domain sockets. In the program, the socket function is called to create a socket in the UNIX domain, and then the bind function assigns a unique name for the socket. The connect function then establishes a connection to the server.
/************************************************************/
/* This is a stream socket client sample program for UNIX   */
/* domain sockets. This program creates a socket, connects  */
/* to a server, sends data, then receives and prints a      */
/* message from the server.                                 */
/************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

#define SERVER_PATH "tpf_unix_sock.server"
#define CLIENT_PATH "tpf_unix_sock.client"
#define DATA "Hello from client"

int main(void){

    int client_sock, rc, len;
    struct sockaddr_un server_sockaddr; 
    struct sockaddr_un client_sockaddr; 
    char buf[256];
    memset(&server_sockaddr, 0, sizeof(struct sockaddr_un));
    memset(&client_sockaddr, 0, sizeof(struct sockaddr_un));
     
    /**************************************/
    /* Create a UNIX domain stream socket */
    /**************************************/
    client_sock = socket(AF_UNIX, SOCK_STREAM, 0);
    if (client_sock == -1) {
        printf("SOCKET ERROR = %d\n", sock_errno());
        exit(1);
    }

    /***************************************/
    /* Set up the UNIX sockaddr structure  */
    /* by using AF_UNIX for the family and */
    /* giving it a filepath to bind to.    */
    /*                                     */
    /* Unlink the file so the bind will    */
    /* succeed, then bind to that file.    */
    /***************************************/
    client_sockaddr.sun_family = AF_UNIX;   
    strcpy(client_sockaddr.sun_path, CLIENT_PATH); 
    len = sizeof(client_sockaddr);
    
    unlink(CLIENT_PATH);
    rc = bind(client_sock, (struct sockaddr *) &client_sockaddr, len);
    if (rc == -1){
        printf("BIND ERROR: %d\n", sock_errno());
        close(client_sock);
        exit(1);
    }
        
    /***************************************/
    /* Set up the UNIX sockaddr structure  */
    /* for the server socket and connect   */
    /* to it.                              */
    /***************************************/
    server_sockaddr.sun_family = AF_UNIX;
    strcpy(server_sockaddr.sun_path, SERVER_PATH);
    rc = connect(client_sock, (struct sockaddr *) &server_sockaddr, len);
    if(rc == -1){
        printf("CONNECT ERROR = %d\n", sock_errno());
        close(client_sock);
        exit(1);
    }
    
    /************************************/
    /* Copy the data to the buffer and  */
    /* send it to the server socket.    */
    /************************************/
    strcpy(buf, DATA);                 
    printf("Sending data...\n");
    rc = send(client_sock, buf, strlen(buf), 0);
    if (rc == -1) {
        printf("SEND ERROR = %d\n", sock_errno());
        close(client_sock);
        exit(1);
    }   
    else {
        printf("Data sent!\n");
    }

    /**************************************/
    /* Read the data sent from the server */
    /* and print it.                      */
    /**************************************/
    printf("Waiting to recieve data...\n");
    memset(buf, 0, sizeof(buf));
    rc = recv(client_sock, buf, sizeof(buf));
    if (rc == -1) {
        printf("RECV ERROR = %d\n", sock_errno());
        close(client_sock);
        exit(1);
    }   
    else {
        printf("DATA RECEIVED = %s\n", buf);
    }
    
    /******************************/
    /* Close the socket and exit. */
    /******************************/
    close(client_sock);
    
    return 0;
}
The following code example shows a client program for connectionless, datagram UNIX domain sockets. In the program, the socket function is called to create a socket in the UNIX domain, and then the bind function assigns a unique name for the socket. For connectionless sockets, you do not have to issue the connect function to connect to the server.
/************************************************************/
/* This is a datagram socket client sample program for UNIX */
/* domain sockets. This program creates a socket and sends  */
/* data to a server.                                        */
/************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

#define SERVER_PATH "tpf_unix_sock.server"
#define DATA "Hello from client\n"

int main(void)
{
    int client_socket, rc;
    struct sockaddr_un remote; 
    char buf[256];
    memset(&remote, 0, sizeof(struct sockaddr_un));
    
    /****************************************/
    /* Create a UNIX domain datagram socket */
    /****************************************/
    client_socket = socket(AF_UNIX, SOCK_DGRAM, 0);
    if (client_socket == -1) {
        printf("SOCKET ERROR = %d\n", sock_errno());
        exit(1);
    }

    /***************************************/
    /* Set up the UNIX sockaddr structure  */
    /* by using AF_UNIX for the family and */
    /* giving it a filepath to send to.    */
    /***************************************/
    remote.sun_family = AF_UNIX;        
    strcpy(remote.sun_path, SERVER_PATH); 
    
    /***************************************/
    /* Copy the data to be sent to the     */
    /* buffer and send it to the server.   */
    /***************************************/
    strcpy(buf, DATA);
    printf("Sending data...\n");
    rc = sendto(client_socket, buf, strlen(buf), 0, (struct sockaddr *) &remote, sizeof(remote));
    if (rc == -1) {
        printf("SENDTO ERROR = %d\n", sock_errno());
        close(client_sock);
        exit(1);
    }   
    else {
        printf("Data sent!\n");
    }
    
    /*****************************/
    /* Close the socket and exit */
    /*****************************/
    rc = close(client_sock);

    return 0;
}