Converting to Multi-Threaded Socket Application - c

As I am currently doing this project in only C, I've up untill this point only used my webserver as a single threaded application. However, I dont want that anymore! So I have the following code that handles my Work.
void BeginListen()
{
CreateSocket();
BindSocket();
ListenOnSocket();
while ( 1 )
{
ProcessConnections();
}
}
Now I've added fork(); before the start of ProcessConnection(); which helpes me allowing multiple connections! However, when I add code for daemoning the application found in this answer. I've encounted a little problem, using fork() will create a copy of my whole running app, which is the purpose of fork(). So, I'd like to solve this problem.
My ProcessConnection() looks like this
void ProcessConnections()
{
fork();
addr_size = sizeof(connector);
connecting_socket = accept(current_socket, (struct sockaddr *)&connector, &addr_size);
if ( connecting_socket < 0 )
{
perror("Accepting sockets");
exit(-1);
}
HandleCurrentConnection(connecting_socket);
DisposeCurrentConnection();
}
How would I do to simply just add a couple of lines above or after connecting=socket = accept... in order to make it accept more than one connection at the time? Can i use fork(); but when it comes down to DisposeCurrentConnection(); I want to kill that process and just have the parent-thread running.

I'm not a 100% sure what it is that you're trying to do, buy off the top of my head, I'd prefer to do the fork after the accept, and simply exit() when you're done. Keep in mind though, that you need to react to the SIGCHLD signal when the child process exits, otherwise you'll have a ton of zombie-processes hanging around, waiting to deliver their exit-status to the parent process. C-pseudo-code:
for (;;) {
connecting_socket = accept(server_socket);
if (connecting_socket < 0)
{
if (errno == EINTR)
continue;
else
{
// handle error
break;
}
}
if (! (child_pid = fork ()))
{
// child process, do work with connecting socket
exit (0);
}
else if (child_pid > 0)
{
// parent process, keep track of child_pid if necessary.
}
else
{
// fork failed, unable to service request, send 503 or equivalent.
}
}
The child_pid is needed to (as already mentioned) to kill the child-process, but also if you wish to use waitpid to collect the exit status.
Concerning the zombie-processes, if you're not interested in what happened to the process, you could install a signal hander for SIGCHLD and just loop on waitpid with -1 until it there are no more child-processes, like this
while (-1 != waitpid (-1, NULL, WNOHANG))
/* no loop body */ ;
The waitpid function will return the pid of the child that exited, so if you wish you can correlate this to some other information about the connection (if you did keep track of the pid). Keep in mind that accept will probably exit with errno set to EINTR, without a valid connection if a SIGCHLD is caught, so remember to check for this on accepts return.
EDIT:
Don't forget to check for error conditions, i.e. fork returns -1.

Talking about fork() and threads on unix is not strictly correct. Fork creates a whole new process, which has no shared address space with the parent.
I think you are trying to achieve a process-per-request model, much like a traditional unix web server such as NCSA httpd or Apache 1.x, or possibly build a multi-threaded server with shared global memory:
Process-per-request servers:
When you call fork(), the system creates a clone of the parent process, including file descriptiors. This means that you can accept the socket request and then fork. The child process has the socket request, which it can reply to and then terminate.
This is relatively efficient on unix, as the memory of the process is not physically copied - the pages are shared between the process. The system uses a mechanism called copy-on-write to make copies on a page-by-page basis when the child process writes to memory. Thus, the overhead of a process-per-request server on unix is not that great, and many systems use this architecture.

Better to use select() function which enables u to listen and connect from different
requests in one program.... It avoids blocking but forking creates a new address space
for the copy of the program which leads to memory inefficiency....
select(Max_descr, read_set, write_set, exception_set, time_out);
i.e u can
fd_set* time_out;
fd_set* read_set;
listen(1);
listen(2);
while(1)
{
if(select(20, read_set, NULL,NULL, timeout) >0)
{
accept(1);
accept(2); .....
pthread_create(func);....
}
else
}

Check the return value of fork(). If it is zero, you are the child process, and you can exit() after doing your work. If it is a positive number then it's the process ID of the newly created process. This can let you kill() the child processes if they are hanging around too long for some reason.

As per my comment, this server is not really multi-threaded, it is multi-process.
If you want a simple way to make it accept multiple connections (and you don't care too much about performance) then you can make it work with inetd. This leaves the work of spawning the processes and being a daemon to inetd, and you just need to write a program that handles and processes a single connection. edit: or if this is a programming exercise for you, you could grab the source of inetd and see how it does it
You can also do what you want to do without either threads or new processes, using select.
Here's an article that explains how to use select (pretty low overhead compared to fork or threads - here's an example of a lightweight web server written this way)
Also if you're not wedded to doing this in C, and C++ is OK, you might consider porting your code to use ACE. That is also a good place to look for design patterns of how to do this as I believe it supports pretty much any connection handling model and is very portable.

Related

child process seems to get stuck in sleep in a while loop

I have a C program that forks a child process at some point in a loop. The child process waits for the parent process to finish its job (some numerical calculations). If things go wrong, the parent process aborts and the child process should continue from the state when it was forked and retry the calculation with some modifications. Otherwise, the parents keeps running, and the child process should be killed.
The communication between the parent and child process is through a memory mapped file, which only has 1 byte as a character that indicates the status of the parent process.
The memory map is done like this
char child_flag[]="W";
fp1 = fopen( "child_interface.dat","wb");
// the interface file has two bytes, but only one is meaningful to the program
fwrite(child_flag, 1, sizeof(child_flag), fp1);
fclose(fp1);
printf("child_interface.dat created\n");
if(mmap_child_flag() ==0) {
printf("memory map of parent-child interface successful.\n");
fflush(stdout);
}
The wait loop in the child process is like this
child_pid = fork();
if (child_pid ==0) { /* child process, wait for parent process to finish*/
mmap_child_flag();
while(child_file[0]=='W' ){ //Child waits
usleep(100000);
}
if(child_file[0]=='R'){ // run child process (as a new parent process)
child_file[0]='W';
goto label2;
}
if(child_file[0]=='K'){ //Kill child process
exit(0);
}
}
The problem is that the child process seems to get stuck in the sleep while loop, even when the parent process has set the status to 'K' (checked in the file that is memory mapped). This code has been run on several linux based super computers, and the behavior seems very inconsistent. On some platforms, it can run smoothly, but on some others, it constantly get stuck in the while loop. Sometimes, if I add some statements inside the while loop after the usleep call, it can then run just fine.
However, I'm not sure if the sleep while loop is the root cause of this problem. My guess is that because the process has almost nothing to do except to check a byte in the memory, the system let it sleep all the time and somehow "forget" to let it check the memory. Can such thing happen in the Linux system?
This the function that does the actual mapping
/* Memory map for parent-child processes interface */
int mmap_child_flag()
{
int fd_child;
struct stat st_child;
// open files
if ((fd_child = open("child_interface.dat", O_RDWR)) == -1){
perror("open child_interface.dat");
exit(1);
}
// stat
if (stat("child_interface.dat", &st_child) == -1){
perror("stat of child_interface.dat");
exit(1);
}
// map, child_file is global char array
child_file = mmap(0, st_child.st_size, PROT_WRITE, MAP_SHARED, fd_child, 0);
if (child_file == (char *)(-1)) {
perror("mmap child_interface.dat");
exit(1);
}
return 0;
}
The problem is that the child process seems to get stuck in the sleep while loop, even when the parent process has set the status to 'K' (checked in the file that is memory mapped).
There are several odd things about your program, with one of them being that you are using shared memory for this task at all. See below for a better approach.
Issues with the current approach
As to the question as it stands, however, you have a synchronization problem. The contents of the mapped memory are being changed outside the scope of the child process, but you've given it no reason to suspect that that might be the case. The compiler can therefore assume that if the wait loop condition is satisfied when it is first evaluated, then it will be satisfied on every subsequent evaluation, too.
For a more complicated interaction, you might need to set up a process-shared mutex or similar to guard access to the shared memory, but for this, it would probably be sufficient to declare child_file as a pointer to volatile char.
A better approach
You want the child to wait for a one- or maybe two-byte instruction from the parent. You presently do this by polling the contents of a shared memory segment, but that's complex to set up and use, as you discovered. It would be a lot easier to use a pipe to convey the needed information from parent to child:
setup: Declare an array. Call pipe().
child use: The child performs a blocking read() on the pipe.
parent use: write() the message to the pipe when ready, then close it. Or just close it.
Note that the pipe itself then provides adequate synchronization, and that there is no need for a wait loop. Note also that the child can detect the case that the parent dies without sending any message, which your shared memory approach does not support.
A shared memory region is good for sharing a lot of data, but it is a bad way to communicate between processes. The reason is that you can't get a notification that something has been changed, nor do you get a notification if the other user of the shared memory died.
To communicate between two processes, use pipe() if you need to create a one-way communication channel, or if you need bidirectional communication, use socketpair(). You can use poll() to wait for the other side to send some data. You will also get notified if the process on the other side terminated.
You were using a loop like this:
while(child_file[0]=='W' ){ //Child waits
usleep(100000);
}
This is bad, since you are wasting on average 50 ms of time that you could have spent doing something useful. Apart from that, there is also the problem that both the compiler and the CPU can sometimes change the order in which things are written to memory. If you have more data in child_file than just the flag at the start, then this might be an issue, unless you use atomics or explicit barriers.

What happens when ptrace(PTRACE_DETATCH,pid,NULL,NULL) is called on a dead pid?

I am trying to capture the command line arguments of all running processes. Some of these processes have command lines that exceed the 4096 character limit of /proc/${pid}/cmdline, so reading that procfs file does not meet my requirement. The processes that interest me can be transient, so I need to be able to read their command line arguments from the stack in /proc/${pid}/mem as soon as I become aware of their pids. This requires attaching to them with ptrace in my C code.
while (pid >= 0){
intPtraceReturnValue = ptrace(PTRACE_ATTACH,pid,NULL,NULL);
if(intPtraceReturnValue != -1){
wait(&intStatus);
readFromProcMem(pid); // function that handles /proc/${pid}/mem reading
intPtraceReturnValue = ptrace(PTRACE_CONT,pid,NULL,NULL);
wait(&intStatus);
intPtraceReturnValue = ptrace(PTRACE_DETATCH,pid,NULL,NULL);
printFoundCommandLineArgs(); // prints results.
}
pid = getNextPid(); // function that interrogates /proc for the next running pid.
}
Sometimes the PTRACE_ATTACH call returns -1. This usually occurs when pipes are invoked, and I can accept that the command line arguments are lost to history by the time I call ptrace in this case. However, in other cases, ptrace attaches ok, but I cannot detach because the process finishes while I am waiting for the kernel mutex to be released by the call with PTRACE_CONT. That is, the call with PTRACE_DETATCH returns -1 if intStatus is set to 0 by the call with PTRACE_CONT. After a few minutes of running this I can't see the memory associated with pids. Sometimes my access to the listing of /proc seems to be denied. In other cases I just get empty results. I suspect that there is a table of ptrace attachments that is not getting sufficiently cleared because ptrace is being called with PTRACE_DETACH on dead pids. Is this the case? if so, how can I clear the dangling attachments manually? If not, what might ptrace doing that would interfere with my access to /proc? I have verified that the other summarized parts of the program work individually when ptrace is not involved. I know that this is a somewhat unorthodox use of ptrace; any thoughts would be appreciated
You have multiple issues, I'll point them out on your code with comments:
while (pid >= 0){
intPtraceReturnValue = ptrace(PTRACE_ATTACH,pid,NULL,NULL);
// here you should call ptrace(PTRACE_INTERRUPT, pid, NULL, NULL) to stop the tracee
if(intPtraceReturnValue != -1){
wait(&intStatus);
readFromProcMem(pid); // function that handles /proc/${pid}/mem reading
// the PTRACE_CONT and wait are unnecessary
// intPtraceReturnValue = ptrace(PTRACE_CONT,pid,NULL,NULL);
// wait(&intStatus);
// the PTRACE_DETACH is enough to trigger the process to continue running
intPtraceReturnValue = ptrace(PTRACE_DETATCH,pid,NULL,NULL);
printFoundCommandLineArgs(); // prints results.
}
pid = getNextPid(); // function that interrogates /proc for the next running pid.
}
From your question it's not clean what the problem is, but I'm pretty sure if you apply the above changes you'd probably get better results.

Avoid variable duplication using fork() in C

I am implementing a server that serves multiple clients and I need some server's variable to be in shared memory so a client actually sees what another client has eventually edited.
I tried looking around but I didn't understand if there is any way to achieve this by using fork() or I totally need to change the way I handle clients. In particular I don't know if I should implement piped processes or threads. Also, what is the simpler way?
This is my code after declaring int var in the main:
while(1) {
printf("Waiting connection...\n");
if ((connfd = accept(listenfd, (struct sockaddr *) NULL, NULL)) < 0) {
perror("Accept Error");
exit(1);
}
if ((pid = fork()) == 0) {
close (listenfd);
printf("Variable: %d\n", var); // var = 0
var = 1;
printf("Variable: %d\n", var); // var = 1
exit(0);
}
close(connfd);
}
When I connect with another client I see again var = 0 because the child generates a copy of the parent process.
Tried using static or declaring global variables outside of the main() but as I understood it has no effect.
fork does not duplicate variables but the entire address space (by definition of fork) of the invoking process.
You might want to use some shared memory, but then you should care about synchronization. Read shm_overview(7) and sem_overview(7) (you could share some memory using mmap(2) but you need to synchronize anyway).
Maybe you don't need to fork, but you just want to have several threads sharing the same address space. Read pthreads(7) and a good pthread tutorial. Then you'll also should care about synchronization, probably using mutexes.
You could also (and instead) use some other form of IPC. Read Advanced Linux Programming, consider using pipe(7)-s and have some event loop around a multiplexing syscall like poll(2)
In a server/client scenario, you might have some request and protocol to query (from inside clients) some state variable (inside the server).
PS. The main issue is not sharing data, it is synchronization and deadlock avoidance.

Can I simulate multiple clients this way?

I wrote a small server program. I wanted to see how it is handling multiple requests. So I wrote the following program to simulate multiple clients.
Pseudo Code:
main()
{
//set up all necessary data structures to connect to the server
fork();
fork();
fork();
create_socket();
connect()
//more code
}
Is there a better way of doing it? What tools I can use to test multi threaded program in C(at least the basic functionality)?
You've basically created a "process-fan" with this approach, so yes, that can work, although it's not threading ... you're actually creating new processes. Therefore you will want, in order to prevent zombie child processes, to "wait" for all processes to complete in each process that has spawned a new process. You could do this with the following line at or near the end of your main() for all processes that have called fork() (i.e., include the child-processes as well since they are spawning additional processes):
while(wait(NULL) != -1 || errno == EINTR);
This will wait for all the child-processes the current process has spawned, while preventing any early returns of wait() due to your process catching a signal. When there are no remaining child-processes for the current process, then wait() will return -1 and set errno to ECHILD, thus exiting the while-loop.

c / fork / signals / best practice closing open sockets in different processes

Hallo erveyone,
two days before I was asking about threads and fork. Now I ended up using the fork methods.
Creating a second process, parent and child are executing different code, but both end up in a while loop, because one is sending forever packets through a socket and the other one is listening forever on a socket. Now I want them to clean up, when ctrl-c is pressed, i.e. both should close their open sockets before returning.
I have three files, first one, the main file creates the processes. In the second file is written the parent code, in the third the child code. Some more information (code snippets) you can find here: c / interrupted system call / fork vs. thread
Now my question, where do I have to put the signal handler, or do I have to specify two of them, one for each process? It seems like a simple question, but not for me somehow. I tried different ways. But could only make one of the guys successful to clean up before returning (my English is bad, sorry therefore). both have to do different things, that's the problem for me, so one handler wouldn't be enough, right?
struct sigaction new_action;
new_action.sa_handler = termination_handler_1;
sigemptyset (&new_action.sa_mask);
new_action.sa_flags = 0;
sigaction(SIGINT, &new_action, NULL);
....more code here ...
/* will run until crtl-c is pressed */
while(keep_going) {
recvlen = recvfrom(sockfd_in, msg, itsGnMaxSduSize_MIB, 0, (struct sockaddr *) &incoming, &ilen);
if(recvlen < 0) {
perror("something went wrong / incoming\n");
exit(1);
}
buflen = strlen(msg);
sentlen = ath_sendto(sfd, &athinfo, &addrnwh, &nwh, buflen, msg, &selpv2, &depv);
if(sentlen == E_ERR) {
perror("Failed to send network header packet.\n");
exit(1);
}
}
close(sockfd_in);
/* Close network header socket */
gnwh_close(sfd);
/* Terminate network header library */
gnwh_term();
printf("pc2wsu: signal received, closed all sockets and so on!\n");
return 0;
}
void termination_handler_1(wuint32 signum) {
keep_going = 0;
}
As you can see, handling the signal in my case is just changing the loop condition "keep_going". After exiting the loop, each process should clean up.
Thanks in advance for your help.
nyyrikki
There is no reason to close the sockets. When a process exits (as is the default action for SIGINT), all its file descriptors are inherently closed. Unless you have other essential cleanup to do (like saving data to disk) then forget about handling the signal at all. It's almost surely the wrong thing to do.
Your code suffers from a race condition. You test for keep_going and then enter recvfrom, but it might have gotten the signal between then. That is pretty unlikely, so we will ignore it.
It sounds like the sender and receiver were started by the same process and that process was started from the shell. If you have not done anything, they will be in the same process group and all three processes will receive SIGINT when you hit ^C. Thus it would be best if both processes handled SIGINT if you want to run cleanup code (note closing FDs isn't a good reason...the fds will be autoclosed when the process exits). If these are TCP sockets between the two, closing one side would eventually cause the other side to close (but for sender, not until they try to send again).

Resources