Solved Unable to bind() in basic Unix Socket program

My code:
C:
#include        <stdlib.h>
#include        <stdio.h>
#include        <string.h>
#include        <unistd.h>
#include        <sys/types.h>
#include        <sys/stat.h>
#include        <sys/socket.h>
#include        <sys/un.h>
#include        <sys/procdesc.h>

#define FALSE 0
#define TRUE  1

static const char *socket_path = "/tmp/test_socket";
static const unsigned int nIncomingConnections = 5;

int client(const int socket_var, const struct sockaddr_un *socket_address);
int server(const int socket_var, const struct sockaddr_un *socket_address);

int main(int argc, char **argv) {
        int option = -1;
        int socket_var = 0;

        if (argc < 2) {
                fprintf(stderr, "Nicht genug Funktionsargumente\n");
                return EXIT_FAILURE;
        }

        if (strstr(argv[1], "dienster") != 0) {
                printf("Dienster gewählt\n");
                option = 2;
        } else if (strstr(argv[1], "emptor") != 0) {
                printf("Emptor gewählt\n");
                option = 1;
        } else {
                fprintf(stderr, "Gewählt nicht existiert\n");
                return EXIT_FAILURE;
        };

        if ((socket_var = socket(AF_UNIX, SOCK_STREAM, 0) == -1)) {
                fprintf(stderr, "Fehler im socket() anrufen\n");
                return EXIT_FAILURE;
        }

        struct sockaddr_un *socket_address = (struct sockaddr_un*) calloc(1, sizeof(struct sockaddr_un));
        socket_address->sun_family = AF_UNIX;
        strcpy(socket_address->sun_path, socket_path);
        socket_address->sun_len = SUN_LEN(socket_address);

        int casertn = 0;
        switch (option) {
                case 1:
                        casertn = client(socket_var, socket_address);
                        break;
                case 2:
                        casertn = server(socket_var, socket_address);
                        break;
                default:
                        free(socket_address);
                        return EXIT_FAILURE;
        };

        free(socket_address);
        if (casertn != 0) {
                return EXIT_FAILURE;
        }

        return EXIT_SUCCESS;
}

int client(const int socket_var, const struct sockaddr_un *socket_address) {
        int return_code = 0; // 0 für erfolgreich

        printf("Versucht zu socket verbinden\n");
        int data_len = strlen(socket_address->sun_path) + sizeof(socket_path);
        if (connect(socket_var, (struct sockaddr*) socket_address, data_len) == -1) {
                fprintf(stderr, "Fehler im connect() anruhfen\n");
                return_code = -1;
                goto fazit;
        }

        printf("Emptor: Verbindet\n");

fazit:
        return return_code;
}

int server(const int socket_var, const struct sockaddr_un *socket_address) {
        unlink(socket_path);
        int return_code = 0;

        printf("Versucht zu bind() anruhfen\n");
        if (bind(socket_var, (struct sockaddr*) socket_address, socket_address->sun_len) != 0) {
                fprintf(stderr, "Fehler im socket bind() anruhfen\n");
                return_code = -1;
                goto fazit;
        }

        if (listen(socket_var, nIncomingConnections) != 0) {
                fprintf(stderr, "Fehler im listen() anruhfen\n");
                return_code = -2;
                goto fazit;
        }

        char bWaiting = TRUE;
        while (bWaiting) {
                int s2 = 0;
                unsigned int sock_len = 0;
                printf("Warten auf Verbindung\n");
                if ((s2 = accept(socket_var, NULL, NULL)) == -1) {
                        fprintf(stdout, "Fehler accept() anruhfen\n");
                        break;
                }

                printf("Dienster im Verbindung\n");

                int data_recv = 0;
                char recv_buf[100];
                do {
                        memset(recv_buf, 0, 100*sizeof(char));

                        data_recv = recv(s2, recv_buf, 100, 0);
                        if (data_recv > 0) {
                                printf("Data received: %d : %s \n", data_recv, recv_buf);
                                if (strstr(recv_buf, "quit") != 0) {
                                        printf("Exit command received -> quitting \n");
                                        bWaiting = FALSE;
                                        break;
                                }
                        } else {
                                fprintf(stderr, "Fehler im recv() anruhfen\n");
                                break;
                        }
                } while (data_recv > 0);
                close(s2);
        }


fazit:
        return return_code;
}
when run as cc main.c -o main && ./main dienster is giving informing me that is failing to bind the Unix socket.
 
False alarm, results that I had to replace
C:
        if ((socket_var = socket(AF_UNIX, SOCK_STREAM, 0) == -1)) {
                fprintf(stderr, "Fehler im socket() anrufen\n");
                return EXIT_FAILURE;
        }
with
C:
        socket_var = socket(AF_UNIX, SOCK_STREAM, 0);
        if (socket_var == -1) {
                fprintf(stderr, "Fehler im socket() anrufen\n");
                return EXIT_FAILURE;
        }
because unidentified reasons.
 
You might want to enable clang's sanitizers (address, memory, ...) and/or run your code built with full debugging info through devel/valgrind. Definitely enable compiler warnings and fix them: -Wall -Wextra for starters.

The replaced code block is exactly the same expressed slightly different, this can't be the reason for "failing", and if it changes the outcome, that's a strong sign of undefined behavior in your code. BTW, I already spot UB for example here:
edit: didn't spot the parentheses error, see ralphbsz's answer. Still, UB remains and will be an issue, so, fix it...

C:
        int data_len = strlen(socket_address->sun_path) + sizeof(socket_path);
        if (connect(socket_var, (struct sockaddr*) socket_address, data_len) == -1) {

The size of struct sockaddr_un is fixed (sizeof(struct sockaddr_un)), that's what you should pass. The sun_path member is an "embedded" (fixed-length) character array.

Also, replace all the mess for allocating and populating it with a simple local variable like this:
C:
struct sockaddr_un socket_address;
memset(&socket_address, 0, sizeof socket_address);
socket_address.sun_family = AF_UNIX;
strncpy(socket_address.sun_path, socket_path, sizeof socket_address.sun_path - 1);
This will also avoid overflowing the sun_path character array, which might have different sizes on different platforms.

Disclaimer: Didn't read all of that code, I guess there's probably more UB...
 
Unidentified reasons: Operator precedence.

What you wrote in the broken version is: "if (( expression )) ...". Note that there are TWO opening and closing parentheses around the expression. That should have set of an alarm bell: the inner opening and closing parentheses are useless! So why did you type them? Because ... we'll get back to that question in a moment.

The expression you wrote was "socket_var = socket(...) == -1". So let's look at this expression: it has two operators, namely = and ==. And no parentheses anywhere, so now we need to look up operator precedence. It turns out that == binds much tighter than =, so what the compiler understood this as is: "socket_var = (socket(...) == -1)". You are calling socket(), and immediately comparing the result to -1. You then throw the result of socket away (!), and storing the result of the comparison (either true or false, the numbers 0 or 1) in socket_var. So after this line, socket_var is not going to be a socket, but either the number 0 or 1. And then later, when you try to do something fun and useful with socket_var, like bind() or connect(), that won't work on 0 or 1.

So let's get back to the question: You should have written "if ((socket_var = socket(...)) == -1)", and it would have worked perfect. Notice how the first parenthesis is closed after the assignment to the variable, and the result of that assignment (the value of socket_var) is compared to -1? And the result of that comparison is then used by if?

By the way, allow me to be obnoxious: I suspect compiling this program with -Wall would have shown you the error.

I vaguely remember that some C coding rules disallow having both an assignment and a comparison in the same expression, exactly for the reason that you have to group them with parentheses to get the correct answer. And a long line of code that relies on the exact placement of parentheses is just a bug waiting to happen.
 
You might want to enable clang's sanitizers (address, memory, ...) and/or run your code built with full debugging info through devel/valgrind. Definitely enable compiler warnings and fix them: -Wall -Wextra for starters.

The replaced code block is exactly the same expressed slightly different, this can't be the reason for "failing", and if it changes the outcome, that's a strong sign of undefined behavior in your code. BTW, I already spot UB for example here:
edit: didn't spot the parentheses error, see ralphbsz's answer. Still, UB remains and will be an issue, so, fix it...

C:
        int data_len = strlen(socket_address->sun_path) + sizeof(socket_path);
        if (connect(socket_var, (struct sockaddr*) socket_address, data_len) == -1) {

The size of struct sockaddr_un is fixed (sizeof(struct sockaddr_un)), that's what you should pass. The sun_path member is an "embedded" (fixed-length) character array.

Also, replace all the mess for allocating and populating it with a simple local variable like this:
C:
struct sockaddr_un socket_address;
memset(&socket_address, 0, sizeof socket_address);
socket_address.sun_family = AF_UNIX;
strncpy(socket_address.sun_path, socket_path, sizeof socket_address.sun_path - 1);
This will also avoid overflowing the sun_path character array, which might have different sizes on different platforms.

Disclaimer: Didn't read all of that code, I guess there's probably more UB...
Documentation sad that I should use SUN_LEN macro for these things, and I will do such thing.
 
Documentation sad that I should use SUN_LEN macro for these things, and I will do such thing.
That's entirely not the point. You may use SUN_LEN on FreeBSD (and other platforms defining it), the only "advantage" is that it has to copy only as much data into kernel space as actually required for the path. It's non-portable though (not specified in POSIX), and just using the full size of struct sockaddr_un is correct.

The actual point is the completely b0rked* size calculation I cited from your code, which definitely yields UB. So, fix it using SUN_LEN if you prefer and don't need full portability, but fix it.

---
*) it used strlen() on the path, which gives you the length of the string without the NUL terminator (so, already wrong), and added the size of some unrelated pointer (your "string" constant) to it, which is a platform-dependent constant (8 on your typical amd64) and isn't related in any way to the size of your sockaddr_un.
 
That's entirely not the point. You may use SUN_LEN on FreeBSD (and other platforms defining it), the only "advantage" is that it has to copy only as much data into kernel space as actually required for the path. It's non-portable though (not specified in POSIX), and just using the full size of struct sockaddr_un is correct.

The actual point is the completely b0rked* size calculation I cited from your code, which definitely yields UB. So, fix it using SUN_LEN if you prefer and don't need full portability, but fix it.

---
*) it used strlen() on the path, which gives you the length of the string without the NUL terminator (so, already wrong), and added the size of some unrelated pointer (your "string" constant) to it, which is a platform-dependent constant (8 on your typical amd64) and isn't related in any way to the size of your sockaddr_un.
My current code:
C:
#include        <stdlib.h>
#include        <stdio.h>
#include        <string.h>
#include        <unistd.h>
#include        <sys/types.h>
#include        <sys/stat.h>
#include        <sys/socket.h>
#include        <sys/un.h>
#include        <sys/procdesc.h>

#include        <errno.h>

#define FALSE 0
#define TRUE  1

static const char *socket_path = "/tmp/test_socket";
static const unsigned int nIncomingConnections = 5;

int client(const int listen_socket, const struct sockaddr_un *socket_address);
int server(const int listen_socket, const struct sockaddr_un *socket_address);

int main(int argc, char **argv) {
        int option = -1;
        int listen_socket = 0;

        if (argc < 2) {
                fprintf(stderr, "Nicht genug Funktionsargumente\n");
                return EXIT_FAILURE;
        }

        if (strstr(argv[1], "dienster") != 0) {
                printf("Dienster gewählt\n");
                option = 2;
        } else if (strstr(argv[1], "emptor") != 0) {
                printf("Emptor gewählt\n");
                option = 1;
        } else {
                fprintf(stderr, "Gewählt nicht existiert\n");
                return EXIT_FAILURE;
        };

        listen_socket = socket(AF_UNIX, SOCK_STREAM, 0);
        if (listen_socket == -1) {
                fprintf(stderr, "Fehler im socket() anrufen\n");
                return EXIT_FAILURE;
        }

        struct sockaddr_un *socket_address = (struct sockaddr_un*) calloc(1, sizeof(struct sockaddr_un));
        socket_address->sun_family = AF_UNIX;
        strncpy(socket_address->sun_path, socket_path, strlen(socket_path));
        socket_address->sun_len = SUN_LEN(socket_address);

        int casertn = 0;
        switch (option) {
                case 1:
                        casertn = client(listen_socket, socket_address);
                        break;
                case 2:
                        casertn = server(listen_socket, socket_address);
                        break;
                default:
                        free(socket_address);
                        return EXIT_FAILURE;
        };

        free(socket_address);
        if (casertn != 0) {
                return EXIT_FAILURE;
        }

        return EXIT_SUCCESS;
}

int client(const int listen_socket, const struct sockaddr_un *socket_address) {
        int return_code = 0; // 0 für erfolgreich

        printf("Versucht zu socket verbinden\n");
        if (connect(listen_socket, (struct sockaddr*) socket_address, socket_address->sun_len) == -1) {
                fprintf(stderr, "Fehler im connect() anruhfen\n");
                return_code = -1;
                goto fazit;
        }

        printf("Emptor: Verbindet\n");

        char recv_buf[200];
        char send_buf[100];
        while (TRUE) {
                if (fgets(send_buf, 100, stdin) == NULL) {
                        fprintf(stderr, "fgets()\n");
                        break;
                }

                int data_read = strlen(send_buf);
                int data_send = send(listen_socket, send_buf, data_read, 0);
                if (data_send != data_read) {
                        fprintf(stderr, "Fehler im send() anruhfen\n");
                        exit(EXIT_FAILURE);
                }

                int data_recv = recv(listen_socket, recv_buf, 200, 0);
                if (data_recv < 0) {
                        fprintf(stderr, "Fehler im recv() anruhfen\n");
                        return_code = -1;
                        goto fazit;
                }
                int data_outp = fwrite(recv_buf, sizeof(char), data_recv, stdout);
                if (data_outp != data_recv) {
                        fprintf(stderr, "Fehler im fwrite() anruhfen\n");
                        return_code = -2;
                        goto fazit;
                }
        }

fazit:
        return return_code;
}

int server(const int listen_socket, const struct sockaddr_un *socket_address) {
        unlink(socket_path);
        int return_code = 0;

        printf("Versucht zu bind() anruhfen\n");
        if (bind(listen_socket, (struct sockaddr*) socket_address, socket_address->sun_len) != 0) {
                fprintf(stderr, "Fehler im socket bind() anruhfen: %i\n", errno);
                return_code = -1;
                goto fazit;
        }

        while (TRUE) {
                if (listen(listen_socket, nIncomingConnections) != 0) {
                        fprintf(stderr, "Fehler im listen() anruhfen\n");
                        return_code = -2;
                        goto fazit;
                }

                char bWaiting = TRUE;
                while (bWaiting) {
                        int s2 = 0;
                        printf("Warten auf Verbindung\n");
                        if ((s2 = accept(listen_socket, NULL, NULL)) == -1) {
                                fprintf(stdout, "Fehler accept() anruhfen\n");
                                break;
                        }

                        printf("Dienster im Verbindung\n");

                        int data_recv = 0;
                        char recv_buf[100];
                        char send_buf[200];
                        do {
                                memset(recv_buf, 0, 100*sizeof(char));
                                memset(send_buf, 0, 200*sizeof(char));

                                data_recv = recv(s2, recv_buf, 100, 0);
                                if (data_recv > 0) {
                                        sprintf(send_buf, "Data received: %d : %s \n", data_recv, recv_buf);
                                        printf("%s", send_buf);
                                        send(s2, send_buf, 200, 0);
                                        if (strstr(recv_buf, "quit\n") != 0) {
                                                printf("Exit command received -> quitting \n");
                                                bWaiting = FALSE;
                                                break;
                                        }
                                } else {
                                        fprintf(stderr, "Fehler im recv() anruhfen\n");
                                        break;
                                }
                        } while (data_recv > 0);
                        close(s2);
                }
        }

fazit:
        return return_code;
}
Not warnings with cc main.c -o main -Wall -Wextra -std=c99
 
Well, still UB, e.g. here:
C:
                                data_recv = recv(s2, recv_buf, 100, 0);
                                if (data_recv > 0) {
                                        sprintf(send_buf, "Data received: %d : %s \n", data_recv, recv_buf);

How to check:

Bash:
cc -fsanitize=address -O0 -g -omain main.c
./main dienster &
printf XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | socat STDIN UNIX-CONNECT:/tmp/test_socket

Result:

Code:
==46679==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fffffffe2a4 at pc 0x00000026fa2e bp 0x7fffffffd8b0 sp 0x7fffffffd040
READ of size 103 at 0x7fffffffe2a4 thread T0
    #0 0x26fa2d in printf_common(void*, char const*, __va_list_tag*) /usr/src/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc:563:9
    #1 0x270432 in vsprintf /usr/src/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc:1671:1
    #2 0x270d05 in sprintf /usr/src/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc:1714:1
    #3 0x2fb80a in server /home/felix/c/f_sock/main.c:157:41
    #4 0x2fade5 in main /home/felix/c/f_sock/main.c:59:35
    #5 0x80045ded9 in __libc_start1 (/lib/libc.so.7+0x83ed9)
    #6 0x24d6ff in _start /usr/src/lib/csu/amd64/crt1_s.S:83

Address 0x7fffffffe2a4 is located in stack of thread T0 at offset 132 in frame
    #0 0x2fb3bf in server /home/felix/c/f_sock/main.c:119

  This frame has 2 object(s):
    [32, 132) 'recv_buf' (line 149)
    [176, 376) 'send_buf' (line 150) <== Memory access at offset 132 partially underflows this variable

Not exploitable as long as the compiler places send_buf directly after recv_buf, because then, send_buf "by accident" provides the missing NUL terminator for sprintf(). But definitely undefined behavior, with variables arranged in a different way on the stack, anything (including remote code execution) could happen.
 
Well, still UB, e.g. here:
C:
                                data_recv = recv(s2, recv_buf, 100, 0);
                                if (data_recv > 0) {
                                        sprintf(send_buf, "Data received: %d : %s \n", data_recv, recv_buf);

How to check:

Bash:
cc -fsanitize=address -O0 -g -omain main.c
./main dienster &
printf XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | socat STDIN UNIX-CONNECT:/tmp/test_socket

Result:

Code:
==46679==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fffffffe2a4 at pc 0x00000026fa2e bp 0x7fffffffd8b0 sp 0x7fffffffd040
READ of size 103 at 0x7fffffffe2a4 thread T0
    #0 0x26fa2d in printf_common(void*, char const*, __va_list_tag*) /usr/src/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc:563:9
    #1 0x270432 in vsprintf /usr/src/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc:1671:1
    #2 0x270d05 in sprintf /usr/src/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc:1714:1
    #3 0x2fb80a in server /home/felix/c/f_sock/main.c:157:41
    #4 0x2fade5 in main /home/felix/c/f_sock/main.c:59:35
    #5 0x80045ded9 in __libc_start1 (/lib/libc.so.7+0x83ed9)
    #6 0x24d6ff in _start /usr/src/lib/csu/amd64/crt1_s.S:83

Address 0x7fffffffe2a4 is located in stack of thread T0 at offset 132 in frame
    #0 0x2fb3bf in server /home/felix/c/f_sock/main.c:119

  This frame has 2 object(s):
    [32, 132) 'recv_buf' (line 149)
    [176, 376) 'send_buf' (line 150) <== Memory access at offset 132 partially underflows this variable

Not exploitable as long as the compiler places send_buf directly after recv_buf, because then, send_buf "by accident" provides the missing NUL terminator for sprintf(). But definitely undefined behavior, with variables arranged in a different way on the stack, anything (including remote code execution) could happen.
Thanks for the unasked undefined behaviour checks, here goes my currest state of the code, which should not have any undefined behaviour as far as I am aware, even it still does not allow me to send messages with Ctrl+D. This last thing probably requires a custom rutine based in fgetc[cmd] rather than [cmd]fgets.
C:
#include        <stdlib.h>
#include        <stdio.h>
#include        <string.h>
#include        <unistd.h>
#include        <sys/types.h>
#include        <sys/stat.h>
#include        <sys/socket.h>
#include        <sys/un.h>
#include        <sys/procdesc.h>

#include        <errno.h>

#define FALSE 0
#define TRUE  1

static const char *socket_path = "/tmp/test_socket";
static const unsigned int nIncomingConnections = 5;

int client(const int listen_socket, const struct sockaddr_un *socket_address);
int server(const int listen_socket, const struct sockaddr_un *socket_address);

int main(int argc, char **argv) {
        int option = -1;
        int listen_socket = 0;

        if (argc < 2) {
                fprintf(stderr, "Nicht genug Funktionsargumente\n");
                return EXIT_FAILURE;
        }

        if (strstr(argv[1], "dienster") != 0) {
                printf("Dienster gewählt\n");
                option = 2;
        } else if (strstr(argv[1], "emptor") != 0) {
                printf("Emptor gewählt\n");
                option = 1;
        } else {
                fprintf(stderr, "Gewählt nicht existiert\n");
                return EXIT_FAILURE;
        };

        listen_socket = socket(AF_UNIX, SOCK_STREAM, 0);
        if (listen_socket == -1) {
                fprintf(stderr, "Fehler im socket() anrufen\n");
                return EXIT_FAILURE;
        }

        struct sockaddr_un *socket_address = (struct sockaddr_un*) calloc(1, sizeof(struct sockaddr_un));
        socket_address->sun_family = AF_UNIX;
        strncpy(socket_address->sun_path, socket_path, strlen(socket_path));
        socket_address->sun_len = SUN_LEN(socket_address);

        int casertn = 0;
        switch (option) {
                case 1:
                        casertn = client(listen_socket, socket_address);
                        break;
                case 2:
                        unlink(socket_path);
                        casertn = server(listen_socket, socket_address);
                        break;
                default:
                        free(socket_address);
                        return EXIT_FAILURE;
        };

        free(socket_address);
        if (casertn != 0) {
                return EXIT_FAILURE;
        }

        return EXIT_SUCCESS;
}

int client(const int listen_socket, const struct sockaddr_un *socket_address) {
        int return_code = 0; // 0 für erfolgreich

        printf("Versucht zu socket verbinden\n");
        if (connect(listen_socket, (struct sockaddr*) socket_address, socket_address->sun_len) == -1) {
                fprintf(stderr, "Fehler im connect() anruhfen\n");
                return_code = -1;
                goto fazit;
        }

        printf("Emptor: Verbindet\n");

        char recv_buf[200];
        char send_buf[101];
        while (TRUE) {
                if (fgets(send_buf, 101, stdin) == NULL) {
                        if (ferror(stdin) != 0) {
                                fprintf(stderr, "Fehler im fgets() anruhfen\n");
                                return_code = -1;
                                goto fazit;
                        }
                        break;
                }

                int data_read = strlen(send_buf);
                int data_send = send(listen_socket, send_buf, data_read, 0);
                if (data_send != data_read) {
                        fprintf(stderr, "Fehler im send() anruhfen\n");
                        return_code = -2;
                        goto fazit;
                }

                int data_recv = recv(listen_socket, recv_buf, 200, 0);
                if (data_recv < 0) {
                        fprintf(stderr, "Fehler im recv() anruhfen\n");
                        return_code = -3;
                        goto fazit;
                }
                int data_outp = fwrite(recv_buf, sizeof(char), data_recv, stdout);
                if (data_outp != data_recv) {
                        fprintf(stderr, "Fehler im fwrite() anruhfen\n");
                        return_code = -4;
                        goto fazit;
                }

                if (strstr(send_buf, "exire\n") != 0) { // strstr() is not what I need.
                        break;
                }
        }

fazit:
        return return_code;
}

int server(const int listen_socket, const struct sockaddr_un *socket_address) {
        int return_code = 0;

        printf("Versucht zu bind() anruhfen\n");
        if (bind(listen_socket, (struct sockaddr*) socket_address, socket_address->sun_len) != 0) {
                fprintf(stderr, "Fehler im socket bind() anruhfen: %i\n", errno);
                return_code = -1;
                goto fazit;
        }

        while (TRUE) {
                if (listen(listen_socket, nIncomingConnections) != 0) {
                        fprintf(stderr, "Fehler im listen() anruhfen\n");
                        return_code = -2;
                        goto fazit;
                }

                char bWaiting = TRUE;
                while (bWaiting) {
                        int s2 = 0;
                        printf("Warten auf Verbindung\n");
                        if ((s2 = accept(listen_socket, NULL, NULL)) == -1) {
                                fprintf(stdout, "Fehler accept() anruhfen\n");
                                break;
                        }

                        printf("Dienster im Verbindung\n");

                        int data_recv = 0;
                        char recv_buf[100];
                        char send_buf[200];
                        do {
                                memset(recv_buf, 0, 100*sizeof(char));
                                memset(send_buf, 0, 200*sizeof(char));

                                data_recv = recv(s2, recv_buf, 100, 0);
                                if (data_recv > 0) {
                                        sprintf(send_buf, "Data received: %d : \0", data_recv);
                                        int data_send = strlen(send_buf); // data_send cannot be greater than 100 because in the worst case it is the lesser than 50 sprintfs constant + the less than 50 %d
                                        strncpy(send_buf + data_send, recv_buf, data_recv); // send_buf + data_send cannot overflow because in worst case it is send_buf + 100
                                        data_send += data_recv;

                                        if (send_buf[data_send - 1] != '\n') { // data_send cannot be less than 1 because sprintf has a bigger than 1 string
                                                send_buf[data_send] = '\n'; // data_send cannot be greater than 200 because in the worst case it is 100 + lesser than 50 sprintfs constant + less than 50 %d
                                                data_send += 1;
                                        }

                                        printf("%.*s", data_send, send_buf);
                                        send(s2, send_buf, data_send, 0);
                                } else {
                                        fprintf(stderr, "Fehler im recv() anruhfen\n");
                                        break;
                                }
                        } while (data_recv > 0);
                        close(s2);
                }
        }

fazit:
        return return_code;
}
Note for my: looks like NFS mounted directories can hold unix sockets form the same host to the same host. TODO: test with multiple hosts.
 
Not warnings with cc main.c -o main -Wall -Wextra -std=c99
But does it work?

Old joke from Don Knuth, in a letter to a colleague where he explains an algorithm: Beware of bugs in the above code; I have only proved it correct, not tried it.

Like the discussion about AI in another thread, that's sort of the summary of trying to write code using techniques that lead to provable correctness: The code often fails anyway, due to real-world effects the proof method doesn't know about.
 
Thanks for the unasked undefined behaviour checks, here goes my currest state of the code, which should not have any undefined behaviour as far as I am aware
"Solved" in the most overcomplicated way one could imagine. The root cause for the UB was calling functions accepting pointers to strings (defined as a byte sequence terminated by a NUL byte) on something you can't guarantee to be a string (100 bytes read from some socket, IOW, "user input").

It could be as simple as
C:
int data_recv;
int data_send;
while ((data_recv = recv(s2, recv_buf, sizeof recv_buf - 1, 0)) > 0)
{
    recv_buf[data_recv] = 0; // append NUL
    data_send = sprintf(send_buf, "received %d bytes: %s\n", data_recv, recv_buf);
    send(s2, send_buf, data_send, 0);
}
BTW, as you don't ever use the flags parameter of send() and recv(), you could just as well use the more generic read() and write() instead. Advantage, the code works unmodified on any file descriptor, not just sockets.

That's the hint here, you seem to be kind of new to C programming, then better listen to advice you get and ask if you don't understand something, don't assume you "know better". Same for my previous hint: It's not wrong to allocate memory for your struct sockaddr_un, but it's just completely unnecessary and inefficient, a normal local variable will do.

Note for my: looks like NFS mounted directories can hold unix sockets form the same host to the same host. TODO: test with multiple hosts.
A local socket is local. The entry in the filesystem is just a description of that local socket. Other systems (e.g. Windows) don't put it in the filesystem but some special other namespace instead. Of course you can put that "special file" anywhere you like, but it's still a local socket.

If you want remote sockets, that's what e.g. TCP is for.

edit: I wrote a tool, remusock, to make Unix sockets available on a remote machine. Of course, to achieve that, it transports the data via TCP. It's meant for use with tools that insist to offer something only on a local socket. When writing your OWN software and you need remote communication, just support TCP sockets directly.
 
But does it work?

Old joke from Don Knuth, in a letter to a colleague where he explains an algorithm: Beware of bugs in the above code; I have only proved it correct, not tried it.

Like the discussion about AI in another thread, that's sort of the summary of trying to write code using techniques that lead to provable correctness: The code often fails anyway, due to real-world effects the proof method doesn't know about.
Not having warnings in C is not too relevant, this language is too hard to statically analyze, specially for the machine.
"Solved" in the most overcomplicated way one could imagine. The root cause for the UB was calling functions accepting pointers to strings (defined as a byte sequence terminated by a NUL byte) on something you can't guarantee to be a string (100 bytes read from some socket, IOW, "user input").

It could be as simple as
C:
int data_recv;
int data_send;
while ((data_recv = recv(s2, recv_buf, sizeof recv_buf - 1, 0)) > 0)
{
recv_buf[data_recv] = 0; // append NUL
data_send = sprintf(send_buf, "received %d bytes: %s\n", data_recv, recv_buf);
send(s2, send_buf, data_send, 0);
}
BTW, as you don't ever use the flags parameter of send() and recv(), you could just as well use the more generic read() and write() instead. Advantage, the code works unmodified on any file descriptor, not just sockets.
Firstly without trying to sound like I know better, but your suggestion has a bug. That is, when the server gets a message that has already at least one line break at the end, the server does still add an extra line break.
C:
                        int data_recv = 0;
                        while (data_recv = recv(s2, recv_buf, sizeof recv_buf - 1, 0)) {
                                        recv_buf[data_recv] = 0;
                                        int data_send = sprintf(send_buf, "received %d bytes: %s", data_recv, recv_buf);

                                        if (send_buf[data_send - 1] != '\n') {
                                                send_buf[data_send] = '\n';
                                                data_send += 1;
                                        }

                                        printf("%.*s", data_send, send_buf); // I want the logs
                                        send(s2, send_buf, data_send, 0);
                        }
                        close(s2);
Here my solution, in the same style, for comparasion
C:
                        int data_recv = 0;
                        while (data_recv = recv(s2, recv_buf, sizeof recv_buf, 0)) {
                                sprintf(send_buf, "Data received: %d : \0", data_recv);
                                int data_send = strlen(send_buf); // data_send cannot be greater than 100 because in the worst case it is the lesser than 50 sprintfs constant + the less than 50 %d
                                strncpy(send_buf + data_send, recv_buf, data_recv); // send_buf + data_send cannot overflow because in worst case it is send_buf + 100
                                data_send += data_recv;

                                if (send_buf[data_send - 1] != '\n') { // data_send cannot be less than 1 because sprintf has a bigger than 1 string
                                        send_buf[data_send] = '\n'; // data_send cannot be greater than 200 because in the worst case it is 100 + lesser than 50 sprintfs constant + less than 50 %d
                                        data_send += 1;
                                }

                                printf("%.*s", data_send, send_buf);
                                send(s2, send_buf, data_send, 0);
                        }
It is certainly has some calls, whih can be removed if one bothers to read the man pages of the already in use subroutines, and also use information which is already in the code, which goes like:
C:
                        int data_recv = 0;
                        while (data_recv = recv(s2, recv_buf, sizeof recv_buf, 0)) {
                                int data_send = sprintf(send_buf, "Data received: %d : ", data_recv); // data_send cannot be greater than 100 because in the worst case it is the lesser than 50 sprintfs constant + the less than 50 %d
                                strncpy(send_buf + data_send, recv_buf, data_recv); // send_buf + data_send cannot overflow because in worst case it is send_buf + 100
                                data_send += data_recv;

                                if (send_buf[data_send - 1] != '\n') { // data_send cannot be less than 1 because sprintf has a bigger than 1 string
                                        send_buf[data_send] = '\n'; // data_send cannot be greater than 200 because in the worst case it is 100 + lesser than 50 sprintfs constant + less than 50 %d
                                        data_send += 1;
                                }

                                printf("%.*s", data_send, send_buf);
                                send(s2, send_buf, data_send, 0);
                        }
Now using the information that is already implied in the code, it can be simplified to
C:
                        int data_recv = 0;
                        while (data_recv = recv(s2, recv_buf, sizeof recv_buf, 0)) {
                                int data_send = sprintf(send_buf, "Data received: %d : %.*s", data_recv, data_recv, recv_buf);

                                if (send_buf[data_send - 1] != '\n') {
                                        send_buf[data_send] = '\n';
                                        data_send += 1;
                                }

                                printf("%.*s", data_send, send_buf);
                                send(s2, send_buf, data_send, 0);
                        }
And recalling the your suggesiton with bug fix
C:
                        int data_recv = 0;
                        while (data_recv = recv(s2, recv_buf, sizeof recv_buf - 1, 0)) {
                                        recv_buf[data_recv] = 0;
                                        int data_send = sprintf(send_buf, "received %d bytes: %s", data_recv, recv_buf);

                                        if (send_buf[data_send - 1] != '\n') {
                                                send_buf[data_send] = '\n';
                                                data_send += 1;
                                        }

                                        printf("%.*s", data_send, send_buf); // I want the logs
                                        send(s2, send_buf, data_send, 0);
                        }
                        close(s2);
They look very similar in complexity, for what I know, they are interchangable for most intents and proporses.
That's the hint here, you seem to be kind of new to C programming, then better listen to advice you get and ask if you don't understand something, don't assume you "know better". Same for my previous hint: It's not wrong to allocate memory for your struct sockaddr_un, but it's just completely unnecessary and inefficient, a normal local variable will do.
I don't understand how one could think such thing for this thread, that I think perfect of myself, but certainly I am beffer than the random blogpost from where I steal the original size calculations. (Why can't I just copy for my previous Unix Sockets program?, which used SUN_LEN).
 
Not having warnings in C is not too relevant, this language is too hard to statically analyze, specially for the machine.
Somewhat correct premise (yes, it's impossible to reliably tell whether some C code exposes UB or not by static analysis), but wrong conclusion: Not having any warnings is VERY relevant. Modern C compilers warn about exactly the things that quite often turn out plain wrong.
Firstly without trying to sound like I know better, but your suggestion has a bug.
You know, for calling something a bug, there has to be some specification first.
That is, when the server gets a message that has already at least one line break at the end, the server does still add an extra line break.
With some code receiving chunks of data of a fixed maximum size, this is just consistent behavior. If you want to implement some text-based line-oriented protocol, you'll have much more to consider, like how to handle embedded non-printable characters (especially NUL), how to handle input lines longer than your buffer, etc ... you might be better off using fdopen(3) on your sockets and use the <stdio.h> functions on that as a starting point. But your code looked a lot more like an experimental toy to get some initial grip on sockets programming at all, and I'd really suggest to stick to that and really understand the basics first.
but certainly I am beffer than the random blogpost from where I steal the original size calculations.
I'd be very surprised to find some blog with exactly the code of your first version, this size calculation was wrong in multiple ways. Part of it might be confusion of arrays and pointers. If socket_path is an array, sizeof socket_path gives you the size of that array as expected ... but in your code, it was a pointer.
(Why can't I just copy for my previous Unix Sockets program?, which used SUN_LEN)
AGAIN, SUN_LEN is not wrong, it's just non-portable. As is the sun_len field of the struct sockaddr_un. You can still use it on systems providing it, you just used it wrong, by instead doing some weird and wrong size calculation for your connect() call... if you want your code to work on every POSIX-compliant system, don't use it, if you're fine with code requiring it (AFAIK it exists in all the BSDs and Linux), then use it.
 
BTW, for reference, here's what POSIX specifies for struct sockaddr_un:

So, portable (to POSIX systems) code should pretend any other fields in this struct don't exist. Looking at it, I see I missed pointing out something important with my suggested code to avoid the allocation for the struct. It's really unnecessary to allocate it, but you should zero out the whole struct first to avoid triggering some extended behavior by the extended struct members not known in POSIX, again, for example like that:

C:
const char *sockpath = ...; // e.g. get from commandline, or "/tmp/test.sock"

struct sockaddr_un addr;
memset(&addr, 0, sizeof addr); // zero-out everything, including unknown/extended fields
addr.sun_family = AF_UNIX;
snprintf(addr.sun_path, sizeof addr.sun_path, "%s", sockpath);

Edit, the version making use of SUN_LEN would just append this extra line and later use addr.sun_len instead of sizeof addr when calling e.g. connect():

C:
addr.sun_len = SUN_LEN(&addr);
 
I'd be very surprised to find some blog with exactly the code of your first version, this size calculation was wrong in multiple ways. Part of it might be confusion of arrays and pointers. If socket_path is an array, sizeof socket_path gives you the size of that array as expected ... but in your code, it was a pointer.
I copied for several sites, and mixed with own code, specially after I could not trackback the error subject of this thread, so I probably just panicked and changed the size calculation out of confusion, my lesson is always start debugging checking the errornos.
AGAIN, SUN_LEN is not wrong, it's just non-portable. As is the sun_len field of the struct sockaddr_un. You can still use it on systems providing it, you just used it wrong, by instead doing some weird and wrong size calculation for your connect() call... if you want your code to work on every POSIX-compliant system, don't use it, if you're fine with code requiring it (AFAIK it exists in all the BSDs and Linux), then use it.
I did not say that is wrong.
Somewhat correct premise (yes, it's impossible to reliably tell whether some C code exposes UB or not by static analysis), but wrong conclusion: Not having any warnings is VERY relevant. Modern C compilers warn about exactly the things that quite often turn out plain wrong.
I did not mean to say that they are useless, just that they are non conclusive.
With some code receiving chunks of data of a fixed maximum size, this is just consistent behavior. If you want to implement some text-based line-oriented protocol, you'll have much more to consider, like how to handle embedded non-printable characters (especially NUL), how to handle input lines longer than your buffer, etc ... you might be better off using fdopen(3) on your sockets and use the <stdio.h> functions on that as a starting point. But your code looked a lot more like an experimental toy to get some initial grip on sockets programming at all, and I'd really suggest to stick to that and really understand the basics first.
As you say, it is a toy/prototype to get a basic echo server running, for have a lab of how to setup UNIX Doman Sockets authentication
, and as such it better behave as I feel more comfortable with.
 
Just for completeness, using the SUN_LEN macro has another implication: It requires .sun_path to be NUL-terminated, stealing you one character from its maximum length. You could still chose whether to use .sun_len doing your own calculation, or setting it to 0 for full POSIX compliance, and (in both cases) get the full maximum length (104 characters on FreeBSD). Example with setting .sun_len:

C:
size_t pathlen = strlen(sockpath);
struct sockaddr_un addr;
if (pathlen > sizeof addr.sun_path) {
    // path too long for socket, error out ...
}
memset(&addr, 0, sizeof addr);
addr.sun_famliy = AF_UNIX;
strncpy(addr.sun_path, sockpath, sizeof addr.sun_path);
addr.sun_len = pathlen < sizeof addr.sun_path
    ? sizeof addr - sizeof addr.sun_path + pathlen
    : sizeof addr;

As you say, it is a toy/prototype to get a basic echo server running, for have a lab of how to setup UNIX Doman Sockets authentication
By that, you mean coming up with your own custom authentication mechanism? That will be an interesting thing. In real life, you'd avoid doing that by all means and use something that works, for reasons ;), but probably nice for learning...
 
By that, you mean coming up with your own custom authentication mechanism? That will be an interesting thing. In real life, you'd avoid doing that by all means and use something that works, for reasons ;), but probably nice for learning...
Aside of how to do authentication in real word applications, but this would be something like a Sandbox Runtime, like bwrap in linux, where the aplications could request some authorizations.
 
Back
Top