COMS 4995 Advanced Systems Programming

Index of 2024-1/code/11

Parent directory
Makefile
recv-unix.c
send-unix.c

Makefile

CC = gcc
CFLAGS  = -g -Wall

executables = recv-unix   send-unix
objects     = recv-unix.o send-unix.o

.PHONY: default
default: $(executables)

$(executables):

$(objects):

.PHONY: clean
clean:
	rm -f *~ *.out $(objects) $(executables)

.PHONY: all
all: clean default

recv-unix.c

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <assert.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>

static void die(const char *m) { perror(m); exit(1); }

void handle_sigint(int signo) {}

int main(int argc, char **argv)
{
    struct sigaction sa;
    sa.sa_handler = &handle_sigint;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    if (sigaction(SIGINT, &sa, NULL) != 0) {
        die("sigaction");
    }

    if (argc != 2) {
        fprintf(stderr, "usage: %s <num-chars>\n", argv[0]);
        exit(1);
    }

    int num_to_recv = atoi(argv[1]);
    int fd;

    struct sockaddr_un  un,  clnt_un;
    socklen_t           len, clnt_len;
    
    char *name = "serv-dom-sock";
    assert(strlen(name) < sizeof(un.sun_path));

    // create a UNIX domain datagram socket
    if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
        die("socket failed");

    // remove the server domain socket file if exists already
    unlink(name);

    // fill in the server domain socket address structure
    memset(&un, 0, sizeof(un));
    un.sun_family = AF_UNIX;
    strcpy(un.sun_path, name);
    len = offsetof(struct sockaddr_un, sun_path) + strlen(name);

    // bind the server domain socket name to the descriptor
    if (bind(fd, (struct sockaddr *)&un, len) < 0) 
        die("bind failed");

    char *buf = malloc(num_to_recv + 1);
    char reply[100];
    int i = 0, n;

    for (;;) {
        memset(buf, 0, num_to_recv + 1);
        clnt_len = sizeof(clnt_un);
        n = recvfrom(fd, buf, num_to_recv, 0,
                     (struct sockaddr *) &clnt_un, &clnt_len);
        if (n < 0) {
            if (errno == EINTR)
                break;
            else
                die("recvfrom failed");
        }
        fprintf(stderr, "\"%s\" received from ", buf);
        write(STDERR_FILENO, clnt_un.sun_path,
                clnt_len - offsetof(struct sockaddr_un, sun_path));
        fprintf(stderr, " (clnt_len:%d), ", clnt_len);

        snprintf(reply, sizeof(reply), "[%d]{%s}", ++i, buf);
        n = sendto(fd, reply, strlen(reply), 0, 
                   (struct sockaddr *) &clnt_un, clnt_len);
        if (n != strlen(reply)) {
            die("sendto failed");
        }
        fprintf(stderr, "sent back %d bytes: %s\n", n, reply);
    }

    // Clean up
    fprintf(stderr, "Server shutting down\n");
    free(buf);
    close(fd);
    unlink(name);
}

send-unix.c

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <assert.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>

static void die(const char *m) { perror(m); exit(1); }

int main(int argc, char **argv)
{
    if (argc != 3) {
        fprintf(stderr, "usage: %s <msg> <num-repeat>\n", argv[0]);
        exit(1);
    }

    const char *msg = argv[1];
    int num_repeat = atoi(argv[2]);

    int fd;
    socklen_t my_len;
    struct sockaddr_un my_un;

    char my_name[sizeof(my_un.sun_path)];
    snprintf(my_name, sizeof(my_name), "clnt-dom-sock.%d", getpid());

    // create a UNIX domain datagram socket
    if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
        die("socket failed");

    // fill in my own domain socket address structure
    memset(&my_un, 0, sizeof(my_un));
    my_un.sun_family = AF_UNIX;
    strcpy(my_un.sun_path, my_name);
    my_len = offsetof(struct sockaddr_un, sun_path) + strlen(my_name);

    // bind my own domain sock name to the descriptor
    if (bind(fd, (struct sockaddr *)&my_un, my_len) < 0) 
        die("bind failed");

    socklen_t serv_len;
    struct sockaddr_un serv_un;
    char *serv_name = "serv-dom-sock";
    assert(strlen(serv_name) < sizeof(serv_un.sun_path));

    // fill in the server's domain socket address structure
    memset(&serv_un, 0, sizeof(serv_un));
    serv_un.sun_family = AF_UNIX;
    strcpy(serv_un.sun_path, serv_name);
    serv_len = offsetof(struct sockaddr_un, sun_path) + strlen(serv_name);

    int i, n;

    // send messages
    for (i = 0; i < num_repeat; i++) {
        n = sendto(fd, msg, strlen(msg), 0,
                   (struct sockaddr *) &serv_un, serv_len);
        if (n != strlen(msg))
            die("sendto failed");
        else 
            fprintf(stderr, "[%d] sent %d bytes: \"%s\"\n", i+1, n, msg);
    }

    // receive replies
    char reply[100];
    for (i = 0; i < num_repeat; i++) {
        memset(reply, 0, sizeof(reply));
        n = recvfrom(fd, reply, sizeof(reply), 0, NULL, NULL);
        if (n < 0) 
            die("recvfrom failed");
        else
            fprintf(stderr, "%d bytes received: \"%s\"\n", n, reply);
    }

    // clean up
    close(fd);
    unlink(my_name);
}