I am reading "The Linux Programming Interface" by Michael Kerrisk. I'm studying about sockets, and I made a simple application using sockets on the unix domain.
I want to know if I'm using sockets properly. Also what features should I add?
There are two programs: server and client. client requires an input file, and it sends the contents of the file to server. server receives the data and prints it out.
Code:
- server.c
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#define BUFFER_LEN 128
void fatal(char* message) {
        // Print error message and exit
        perror(message);
        exit(EXIT_FAILURE);
}
void socket_comm() {
        const char* SOCKET_PATH = "/home/tux/temp/server_sock";
        int socket_fd;
        // Create socket
        socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
        if (socket_fd == -1) {
                fatal("Error while initializing socket");
        }
        // Bind socket to SOCKET_PATH
        socklen_t socket_addr_size;
        struct sockaddr_un socket_addr;
        memset(&socket_addr, 0, sizeof(struct sockaddr_un)); // Initialize to 0
        socket_addr.sun_family = AF_UNIX;
        strncpy(socket_addr.sun_path, SOCKET_PATH, sizeof(socket_addr.sun_path) - 1);
        socket_addr_size = sizeof(socket_addr);
        if (bind(socket_fd, (struct sockaddr *) &socket_addr, sizeof(struct sockaddr_un)) == -1) {
                fatal("Error while binding socket");
        } else {
                printf("Successfully generated server-side socket\n");
        }
        // Mark as passive
        if (listen(socket_fd, 8) == -1) {
                fatal("Cannot mark socket as passive");
        } 
        
        // Connect to client and receive data
        ssize_t numread;
        char buffer[BUFFER_LEN + 1];
        while (1) {
                // Connect to client
                int connect_fd = accept(socket_fd, (struct sockaddr*) &socket_addr, &socket_addr_size);
                if (connect_fd == -1) {
                        fatal("Cannot accept connections");
                        sleep(1);
                }
                
                printf("Connected to client\n");
                // Receive data
                while ((numread = read(connect_fd, buffer, BUFFER_LEN)) > 0) {
                        buffer[numread] = '\0';
                        printf("%s", buffer); 
                }
        }
}
int main() {
        socket_comm();
        return 0;
}
- client.c
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
void fatal(char* message) { 
        // Print message and exit
        perror(message);
        exit(EXIT_FAILURE);
}
long get_data(int argc, char* argv[], char** buffer) {
        // Command line argument must be path to file
        // option "-h" or "--help" prints help
        if (argc != 2 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0) {
                printf("Usage: %s filepath\n",argv[0]);
                printf("Sends data to the server\n");
                exit(EXIT_SUCCESS);
        }
        // Open file
        FILE* fp;
        fp = fopen(argv[1],"r");
        if (fp == NULL) {
                fatal("Cannot open file");
        }
        // Determine file size
        if (fseek(fp, 0, SEEK_END) == -1) {
                fatal("Error determining file size");
        }
        long size = ftell(fp);
        if (size == -1) {
                fatal("Error determining file size");
        }
        rewind(fp);
        
        // Allocate memory for buffer
        *buffer = malloc(size + 1);
        if (*buffer == NULL) {
                fatal("Error allocating memory");
        }
        memset(*buffer, 0, size + 1);
        // Read file and store data in buffer
        fread(*buffer, 1, size, fp);
        if (ferror(fp) != 0) {
                fatal("Error reading file");
        }
        fclose(fp);
        return size;
}
void socket_comm(char* buffer, long size) {
        const char* PEER_SOCKET_PATH = "/home/tux/temp/server_sock";
        int socket_fd;
        // Create socket
        socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
        if (socket_fd == -1) {
                fatal(strerror(errno));
        }
        
        // Connect to server
        struct sockaddr_un peer_socket_addr;
        memset(&peer_socket_addr, 0, sizeof(struct sockaddr_un));
        peer_socket_addr.sun_family = AF_UNIX;
        strncpy(peer_socket_addr.sun_path, PEER_SOCKET_PATH, sizeof(peer_socket_addr.sun_path) - 1);
        
        if (connect(socket_fd, (struct sockaddr*) &peer_socket_addr, sizeof(peer_socket_addr)) == -1) {
                fatal("Error while connecting to server");
        }
        
        printf("Connected to server.\n");
        // Send data to server
        if (write(socket_fd, buffer, size) == -1) {
                fatal("Error sending data to server");
        }
        return;
}
int main(int argc, char* argv[]) {
        char* file_buffer;
        long file_size;
        
        // Get data and file size
        file_size = get_data(argc, argv, &file_buffer);
        // Send data to server
        socket_comm(file_buffer, file_size);
        // Free memory
        free(file_buffer);
        return 0;
}
Codes can be downloaded in my github repo.
