0

I have a multiclient Server Socket and I want to block the acces for other Clients, when sending "BEG" to the Server. To open the other Clients again, the Client has to send "END" to the Server. While other Clients are blocked off, they only can use "quit" to exit the Server and if they use conditions() they fall asleep.

So other Clients are blocked for the function conditions() if one process used "BEG", but the process himself has still acces to the function.

If I compile my Code, the Server is running, everything is fine but the Mutexe doesn't work. The Code is going into the if statement of "BEG" and the Mutex should be locked, but other Clients aren't blocked off.

If I connect a second Client, the Client gets kicked if I use conditions().

My question is, why does the mutex not work for other Clients or in generell? How to check if the Mutex is working?

Edit: Now my Semaphore doesn't block other processes

Edit 2: I found a way, not the best but one. Now some clients are getting kicked from the Server after using one condition().

main.c:

int state = 0;

int beg() {
    state = 1;
    return 0;
}

int end() {
    state = 0;
    return 0;
}

int main() {
    int pid, t;
    char *eingabe, *inputBuffer[BUFSIZE];
    char delimiter[] = "\n ";
    int rfd = erstelleSocket();
    int cfd;

    semaphor semID1 = semGET();
    semaphor semID2 = semGET2();

    marker[0] = 1;
    t = semctl(semID1, 1, SETALL, marker);
    if (t == -1) {
        fprintf(stderr, "Error with marker\n");
    }

    t = semctl(semID2, 1, SETALL, marker);
    if (t == -1) {
        fprintf(stderr, "Error with marker\n");
    }
    
    
    while(1){
        cfd = accept(rfd, (struct sockaddr *) &client, &client_len);

        if (cfd < 0) {
            close(cfd);
            fprintf(stderr, "connection failed\n");
            break;
        }
        pid = fork();

        if (pid < 0) {
            fprintf(stderr, "Error in new process creation\n");
        }

        if (pid == 0) {
            bzero(input, sizeof(input));
            bytes_read = read(cfd, input, BUFSIZE);
            strncat(input, " ", strlen(" "));
            input[strcspn(input, "\r\n")] = 0;

            while (bytes_read > 0) {
                eingabe = strtok(input, delimiter);
                int i = 0;
                while (eingabe != NULL) {
                    inputBuffer[i++] = eingabe;
                    eingabe = strtok(NULL, delimiter);
                }

                if (strncmp("quit", inputBuffer[0], 4) == 0) {
                    close(cfd);
                    break;
                }
                

                if (state != 1) {
                    down(semID2, 0); //down is a function with semop()
                }

                down(semID1, 0);

                conditions(inputBuffer[0],
                           inputBuffer[1],
                           inputBuffer[2],
                           cfd, semID1, shmID);

                up(semID1, 0);

               if (state != 1) {
                    up(semID2, 0); //up is a function with semop()
                }

                bzero(input, sizeof(input));
                bytes_read = read(cfd, input, BUFSIZE);
                strncat(input, " ", strlen(" "));
                input[strcspn(input, "\r\n")] = 0;


                close(rfd);
            }
        }
        close(cfd);
   }
   close(rfd);
}

my condition function:

void conditions(char *eingabehalter1,
                char *eingabehalter2,
                char *eingabehalter3,
                int cfd, int shmID) {
    if (strncmp("PUT", eingabehalter1, 3) == 0) {
        put(eingabehalter2, eingabehalter3, cfd, shmID);
    } else if (strncmp("GET", eingabehalter1, 3) == 0) {
        get(eingabehalter2, cfd, shmID);
    } else if (strncmp("DEL", eingabehalter1, 3) == 0) {
        del(eingabehalter2, cfd, shmID);
    } else if (strncmp("BEG", eingabehalter1, 3) == 0) {
        beg();
    } else if (strncmp("END", eingabehalter1, 3) == 0) {
        end();
    } else {
        write(cfd, "cmd_nonexistent\n", strlen("cmd_nonexistent\n"));
    }
}

createSocket.c:

    int rfd; // Rendevouz-Descriptor

    rfd = socket(AF_INET, SOCK_STREAM, 0);
    
    int option = 1;
    setsockopt(rfd,SOL_SOCKET, SO_REUSEADDR, (const void *) &option, sizeof(int));

    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons(PORT);
    int brt = bind(rfd, (struct sockaddr *) &server, sizeof(server));
    
    int lrt = listen(rfd, 5);
    
    return rfd;
}

main.h:

#include "shmmemory.h"
#include "semaphoren.h"

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>

#include <unistd.h>

#include <netinet/in.h>

#define PORT 5678

struct sockaddr_in server;
struct sockaddr_in client; 
socklen_t client_len; 
char input[BUFSIZE]; 
int bytes_read; 
int erstelleSocket();

void conditions(char *eingabehalter1,
                char *eingabehalter2,
                char *eingabehalter3,
                int cfd, int shmID);

int beg();
int end();

unsigned short marker[2];
Kevin
  • 1
  • 3
  • It's not clear what your question is. What happens when you run this code? Why is that wrong? Btw, you should ensure the full, compilable (but minimal) code needed to reproduce the problem is included, not just part of it. – underscore_d Jun 29 '20 at 13:50
  • 1
    I hope it's better now – Kevin Jun 29 '20 at 14:17
  • I wouldn't use a new process for each connection. That won't scale very far. Use a single threaded event driven model with EPOLL Also have you considered what happens if a client connection gets lost and the server doesn't know right away? you'll need to timeout the semaphore so that the client can't hold it for too long and do nothing with it. – hookenz Jun 30 '20 at 01:48

2 Answers2

1

Your approach cannot work because you're trying to combine fork with threads. fork creates a copy of the parent's address space for each child process, which means that each child process has its own copy of the mutex object. Process-shared mutexes are possible in POSIX, with special attributes, but I suspect even those don't work with fork; they have to be placed in shared memory.

Have you considered creating threads with pthread_create for the service loop? Or else you can implement this entirely using fork (no pthread material). The children can use POSIX named semaphores (sem_open, et al) or possibly, dare I say it, System V IPC.

Also, don't use strtok in multithreaded code, and clearing memory to zero was standardized in 1989's ANSI C as memset(pointer, 0, size). Since that was 31 years ago, it's okay to lay bzero to rest.

Kaz
  • 55,781
  • 9
  • 100
  • 149
  • Can you give me an approach how to solve it please? – Kevin Jun 29 '20 at 14:27
  • I'm sorry, I understand your approach, but I don't get it how it really works or to implement that, could you may help me please? – Kevin Jun 29 '20 at 16:18
  • The StackOverflow format doesn't really fit project collaboration. Why don't you put the code on some code hosting site, and find some volunteers to help with it in some programming forum? – Kaz Jun 29 '20 at 21:49
  • @Kevin For this kind of thing, I only know the `comp.unix.programmer` newsgroup. I think you missed a key thing in my answer: `sem_open`. Every process needs to call `sem_open` to obtain a new object which attaches to the named semaphore. They cannot share an inherited `sem_t` object; that's the same mistake as with the mutex. – Kaz Jun 29 '20 at 22:17
0

The way you initialize the semaphores is wrong for your use case. From the man page of sem_init():

#include <semaphore.h>

int sem_init(sem_t *sem, int pshared, unsigned int value);

If pshared has the value 0, then the semaphore is shared between the threads of a process, and should be located at some address that is visible to all threads (e.g., a global variable, or a variable allocated dynamically on the heap).

If pshared is nonzero, then the semaphore is shared between processes, and should be located in a region of shared memory

Based on the above explanations from the man page, the things you need change are:

Semaphore declaration

Since you are using semaphores between processes, you need to declare the variable as shared. You can do that via mmap() to create unnamed UNIX semaphore as follows:

sem_t* sem_var = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0)

if (sem_var == MAP_FAILED)   // Shared memory creation failed.
   goto handle_shm_fail;

Semaphore initialization

Since you are using POSIX semaphores, to make your child use the same semaphores, pshared is set to 1 indicating semaphore is shared between processes.

if (sem_init(sem_var, 1, 1) != 0)   // Semaphore initialization failed. 
   goto handle_sem_fail;

NOTE: In your code sem_var is of type sem_t, now it is a pointer to sem_t. Accordingly, you need to update your code.

m0hithreddy
  • 1,752
  • 1
  • 10
  • 17
  • I updated my code, and it's still not doing it what I want – Kevin Jun 30 '20 at 12:56
  • @Kevin There might be another issue in your code. What I addressed is related to process synchronization. So your processes are not yet synchronized? Did you verify it till that part? – m0hithreddy Jun 30 '20 at 14:43
  • @Kevin I see your code edited. Since all your parents are having parent child relation, there is no need for you to create a named semaphore. And you need to check the success status of ``sem_open()``. If both ``O_CREAT`` and ``O_EXCL`` are specified in ``oflag``, then an error is returned if a semaphore with the given name already exists. And what is the logic behind calling ``sem_unlink()`` immediately after calling ``sem_open()`` – m0hithreddy Jun 30 '20 at 14:56
  • My Code is working, if I remove the semaphore Problem from this Thread. It's handling multiple Clients and the shared memory is working too. The critical sections to write in the shared memory are secured by other semaphores. But I don't get it how to handle this. And I used ```sem_unlink()``` there, because I saw it here https://stackoverflow.com/a/15908638/13728720 – Kevin Jun 30 '20 at 16:21
  • @Keven Your description of the problem is very much unclear. "I want to block the acces for other Clients, when sending "BEG" to the Server. " -- You want to block the access to other clients by sending "BEG" or before sending "BEG"? What do you mean by when sending "BEG"? – m0hithreddy Jun 30 '20 at 17:33
  • @Keven "While other Clients are blocked off, they only can use "quit" to exit the Server and if they use conditions() they fall asleep." -- Where do you implemented the code for blocking others clients and putting them in sleep()? Does your conditions() function has some logic to do this? – m0hithreddy Jun 30 '20 at 17:39
  • I want to block the acces to other clients by sending "BEG". The meaning of it in theory is, that you close a semaphore and put it back up with "END". While this is activated other clients should be able to exit the process with "quit". ```condition()``` is the function to acces the shared memory with other commands sending to the Server. It's a else if ladder for accepting commands. – Kevin Jun 30 '20 at 20:30
  • @Kevin Okay, day-by-day, your code is getting complicated and more things are becoming unclear and unclean. If you have no constraint such as "use semaphores only," I suggest you adopting threads for multi-processing. The advantages you have over this are 1) No need to worry about shared memory problems; you just declare variables as global or place them on the heap, and you are good to go. 2) Pthreads offer mutex locks, which are comparatively easy to use then semaphores shared between processes. I am not discouraging the use of ``fork()`` and semaphores, but threads are good for starters – m0hithreddy Jul 01 '20 at 08:26