C http server stops after unpredictable time - c

I am writing a custom HTTP server in C for my OpenWrt router. It makes use of the uclibc library. I am only using one static buffer which I am very careful not to overflow, and no multi-threading is involved. It doesn't contain any complex data structures, and what it does is that:
it listen() s on the socket
reads the request after accept() ing
gets an html page by sending an http request to a predefined remote server (not a proxy)
sends the result through the accepted connection, and closes both.
The program would just stop running after some time, (it can be on receiving the first request, or after working under heavy strain for more that 2 hours). I am getting no error messages through the console, or anything, the program just stops. I have watched it and, as expected it doesn't consume more and more memory as it runs...
Is it possible that the kernel stops it if it thinks its abusing the CPU? How do I overcome that?
Are there some quirks to watch for in socket programming in C that are known to cause such crashes?
Can the stability issues be caused by using the Barrier Bracker (bleeding edge) branch of OpenWrt? Although the router itself never stops working...
Where do I start to look for the source of the problem?

Ok, first, I would like to thank everybody for helping. After writing a lot of netcat testers, I have pinpointed the problem. The program would crash - end without a single error message, if the connection is closed by the client before the last write or read occurs.
The write or read would raise a SIGPIPE signal which by default crashed the program if not handled manually... More info here: How to prevent SIGPIPE or prevent the server from ending?

This seems to be similar to what your trying to do,
as shown on http://www.cs.rpi.edu/~moorthy/Courses/os98/Pgms/socket.html
Is this socket setup the same/similar to what your performing in your code?
/* A simple server in the internet domain using TCP
The port number is passed as an argument */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
void error(char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno, clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("ERROR on accept");
bzero(buffer,256);
n = read(newsockfd,buffer,255);
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s\n",buffer);
n = write(newsockfd,"I got your message",18);
if (n < 0) error("ERROR writing to socket");
return 0;
}

Related

TCP IP socket communication in C. During the client exit, intimating server?

I am checking the communication between 2 entities (A and B) for their presence. A is a server and B is a client. When the server is up and running, it waits for connections and when B starts, it sends a message "Available" every one second. Now, the problem is, when I terminate the B program( ctrl+c or press the close button of the terminal), the server A does not recognise and still continues its operation. I would like for it to display message like "B is no more available" or "communicating partner is off". I understand TCP would be a best fit for the connection oriented communication. Please suggest me the changes to incorporate the display message on server A, when B is closed.
PS: amateur in socket programming
EDIT1: Managed to display the Message. However, since the server is designed to listen to many connections, I would like to make it accept the connections and not end the loop. Any guidance here would be useful.
SERVER(A) TCP SERVER
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
int main( int argc, char *argv[] ) {
int sockfd, newsockfd, portno, clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
/* Initialize socket structure */
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = 5001;
// create socket and get file descriptor
sockfd = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
clilen = sizeof(cli_addr);
// bind the host address using bind() call
if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){
perror("ERROR on binding\n");
exit(1);
}
// start listening for the clients,
// here process will go in sleep mode and will wait for the incoming connection
listen(sockfd, 5);
// accept actual connection from the client
newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen);
// inside this while loop, implemented communication with read/write or send/recv function
//printf("start");
while (1) {
bzero(buffer,256);
n = read(newsockfd, buffer, 255);
if (n < 0){
perror("ERROR in reading from socket");
exit(1);
}
if (n == 0){
perror("Client has abruptly ended\n");
close(sockfd);
exit(1);
}
printf("client said: %s \n", buffer);
n = write(newsockfd, buffer, strlen(buffer));
if (n < 0){
perror("ERROR in writing to socket");
exit(1);
}
// escape this loop, if the client sends message "quit"
// if (!bcmp(buffer, "quit", 4))
// break;
}
return 0;
}
CLIENT(B) TCP CLIENT
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
int main(int argc, char *argv[]) {
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
portno = 5001;
// create socket and get file descriptor
sockfd = socket(AF_INET, SOCK_STREAM, 0);
server = gethostbyname("127.0.0.1");
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(portno);
// connect to server with server address which is set above (serv_addr)
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
perror("ERROR while connecting");
exit(1);
}
// inside this while loop, implement communicating with read/write or send/recv function
while (1) {
strcpy(buffer,"Available");
n = write(sockfd,buffer,strlen(buffer));
if (n < 0){
perror("ERROR while writing to socket");
exit(1);
}
bzero(buffer,256);
n = read(sockfd, buffer, 255);
if (n < 0){
perror("ERROR while reading from socket");
exit(1);
}
printf("server replied: %s \n", buffer);
// escape this loop, if the server sends message "quit"
//if (!bcmp(buffer, "quit", 4))
// break;
sleep(1);
}
return 0;
}
Please anybody tell me how to handle that issue?
When the client closes the TCP connection, the server's call to read(newsockfd) will return 0 to indicate that the connection has closed. At that point, the server should close(newsockfd), print your "Client has gone away message", and not use newsockfd anymore (i.e. either the server program should exit, or, more usefully, it should just break out of its while(1)-loop and go back to calling accept() again, so that the next time a client runs it too can connect to the server)

Socket connection refused due to a burst of connections

I am using sockets in order to synchronize several remote processes.
The idea is that a process creates a pthread which manages the server side, just like that:
void *listener(void * in) {
int sockfd;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
int n = *((int *) in);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
int option = 1;
setsockopt(sockfd, SOL_SOCKET, (SO_REUSEPORT | SO_REUSEADDR), (char*) &option, sizeof (option));
bzero((char *) &serv_addr, sizeof (serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(PORT);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0)
error("ERROR on binding");
if (listen(sockfd, n) < 0)
error("ERROR when listening");
clilen = sizeof (cli_addr);
int cnt = 0;
while (cnt < n) {
int newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0) {
error("ERROR on accept");
}
cnt++;
}
close(sockfd);
return 0;
}
Meanwhile, the other processes would execute:
int sockfd;
struct sockaddr_in serv_addr;
struct hostent *server;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname(_managementHost); //managementHost);
if (server == NULL)
error("ERROR, no such host\n");
bzero((char *) &serv_addr, sizeof (serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *) server->h_addr, (char *) &serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(PORT);
if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0)
error("ERROR connection");
close(sockfd);
Now, the problem I have is when I have a lot of processes trying to connect at the same time to the server, some of them are throwing connection refused errors.
I guess that is because the accepts may not be ready... In fact, I have read that it could happen, but I have not found my specific case.
Could anyone shed light on the matter?
A possible solution that occurs to me, is to create a thread for each accept, but I would prefer to avoid it.
Thank you.
EDIT: corrected double initialization of socket in the server. Thanks to #Remy Lebeau.
Now, the problem I have is when I have a lot of processes trying to connect at the same time to the server, some of them are throwing connection refused errors.
A listening TCP socket has a backlog of pending connections. The 2nd parameter of listen() specifies how many connections are allowed to be in the backlog queue before they are accepted. If a new client tries to connect when the backlog is full, the client is refused. There is nothing the client or server can do about that. It is the client's responsibility to detect the error and re-connect at a later time.
Your listener() is accepting clients until it reaches a designated number of connections, but you are also using that same number for the listen backlog queue size. The number of active connections and the number of pending connections are two different things. If you are expecting a lot of clients to connect at the same time, you need a large backlog size to avoid the refusal errors. But that backlog should be sized proportional to the traffic you are expecting. If you have 1000 clients, but they connect only 20 at a time, you would set the backlog to, say, 25, not 1000.
Your listener() has some other logic bugs. It is calling socket() twice and saving the two sockets to the same sockfd variable, so it is leaking the first socket. You need to remove the second call to socket() (the one just before setsockopt()). You are also leaking the sockets that accept() returns. You need to close() an accepted socket after you are doing using it.
Just make your server concurrent by calling fork to spawn a child for each client. Easiest way to do it, IMO. Avoids threading and will stop the connection refused errors.
EDIT: You could also look into pre-forking your server. You'd have to research how you want to handle locking around accept, though (if you're locking at all).

How to convert a simple client server TCP program into non blocking one

Hi I was reading about non-blocking calls using select() from Beej's guide, but I'm still confused as to how to change my simple client-server code to one that is non blocking. Could anyone tell me what changes do I need to make in the server code as well as the client code for that?
Here's the server code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno;
socklen_t clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
if (newsockfd < 0)
error("ERROR on accept");
bzero(buffer,256);
n = read(newsockfd,buffer,255);
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s\n",buffer);
n = write(newsockfd,"I got your message",18);
if (n < 0) error("ERROR writing to socket");
close(newsockfd);
close(sockfd);
return 0;
}
Here is the client code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
void error(const char *msg)
{
perror(msg);
exit(0);
}
int main(int argc, char *argv[])
{
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
if (argc < 3) {
fprintf(stderr,"usage %s hostname port\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
printf("Please enter the message: ");
bzero(buffer,256);
fgets(buffer,255,stdin);
n = write(sockfd,buffer,strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
bzero(buffer,256);
n = read(sockfd,buffer,255);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n",buffer);
close(sockfd);
return 0;
}
The way select(2) makes things non-blocking is by waiting for I/O to become possible without blocking (e.g., when new data is available). When using select(), you wouldn't normally have to put the monitored descriptors into non-blocking mode (with e.g. SOCK_NONBLOCK), so in a sense select() is specifically about avoiding having to use non-blocking I/O.
select() is used to wait for events on multiple descriptors at once. An event here is something that would make it possible to read(2) from or (depending on how you use select()) write(2) to the descriptor without blocking.
As an example, you could use select() to simultaneously wait for new client connections and data from already connected clients in your server (assuming you extend it to handle multiple clients). To do this, you would use select() to monitor both sockfd and any descriptors you get back from accept(2). Without select(), you would have to use some form of non-blocking I/O (or separate threads) instead to avoid getting stuck in e.g. the accept() until a new client connects, which would prevent you from seeing data from other clients in the meantime. That would be both messier to implement and also less efficient than sleeping in a single location.
select() doesn't do any I/O by itself. It only notifies you when I/O becomes possible without blocking. You pass it a set of descriptors, and it tells you whenever I/O becomes possible on any of them. (And also tells you which descriptors it's possible on.)
In addition to waiting for data on sockets, you could use select() to wait for e.g. user input on stdin at the same time. There are many different types of descriptors that can be select()ed on.

Why is this custom network-service crashing (written in C)?

I wrote this program which listens on a given port and then, once a connection is received, outputs a single line of text and disconnects. It runs for days, processing thousands of queries, but then (inevitably) crashes and I have to go restart it. Wondering if anyone sees anything wrong with it, or (alternatively) if anyone can suggest a way to make it more robust.
int main(int argc, char *argv[])
{
srand(time(0));
int sockfd, newsockfd, portno;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
int n;
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
while (1)
{
unsigned char write_val;
unsigned char y[BYTES];
int i, j;
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
if (newsockfd < 0)
error("ERROR on accept");
fill_buffer(y); // fills buffer y with a 128-bit string; not included here
for (i=BYTES-1; i >= 0; i--)
{
const void* ZERO = (void *)"0";
const void* ONE = (void *)"1";
for (j=7; j >= 0; j--)
write(newsockfd, (y[i] >> j) & 1 ? ONE : ZERO, 1);
}
write(newsockfd, "\n", 1);
close(newsockfd);
}
close(sockfd);
return 0;
}
anyone sees anything wrong with it
While this code could be made more efficient (by writing all the bytes in one single pass for example), there's no obvious flaw there.
That makes the unpublished part of your code a decent candidate for the problem:
fill_buffer(y); // fills buffer y with a 128-bit string; not included here
If you read more bytes than y[]'s size then you will crash.
or (alternatively) if anyone can suggest a way to make it more robust
Try enlarging the size of this y[] buffer (doubling it can't hurt).
And make sure that fill_buffer() can't read more than BYTES characters.
Publish this missing code in case of doubt.
You could also compile your code with debug symbols and dump a backtrace (with symbols) in a file from your signal handler. This way, if your program crashes, you will know where and why.
The code looks good with some comments.
One somewhat important comment:
portno should be declared as unsigned short. This works OK with an Intel-like (little endian) processor but it won't be portable to a processor with different endianness.
Anyway it was not the reason for your process crashing.
Obviously the crash occurs while executing within the 'while', and by looking at the code, if it crashes for a buffer overflow, the only possibility is within fill_buffer.
If you show the definition of BYTES and fill_buffer it will be easier to help you.
Now, if it is not a buffer overflow, there is the possibility that it aborts in the write if the client closed the connection before the server writes into the socket. In that case the process will receive a signal SIGPIPE and it will abort if the code does not handle that signal.
You can also ignore SIGPIPE with:
signal(SIGPIPE, SIG_IGN);
Other possibility is if you are doing something weird with write_val and you're not showing that code.
I hope this helps.

C sockets: forward a request to port 80 and read response

I have the following code (I'm working from code at http://www.linuxhowtos.org/C_C++/socket.htm) which I'm trying to turn into a proxy server:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
void dostuff(int); /* function prototype */
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
//setup proxy:
int sockfd, newsockfd, portno, pid;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
if (argc < 2) {
fprintf(stderr,"***ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("***ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("***ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
while (1) {
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("***ERROR on accept");
pid = fork();
if (pid < 0)
error("***ERROR on fork");
if (pid == 0) {
close(sockfd);
dostuff(newsockfd);
exit(0);
}
else close(newsockfd);
} /* end of while */
close(sockfd);
return 0; /* we never get here */
}
/******** DOSTUFF() *********************
There is a separate instance of this function
for each connection. It handles all communication
once a connnection has been established.
*****************************************/
void dostuff (int sock)
{
int n;
char buffer[256];
bzero(buffer,256);
n = read(sock,buffer,255);
if (n < 0){
error("***ERROR reading from socket");
}
//printf("Here is the message: %s\n",buffer);
/*
***Forward message to port 80 and read response here
*/
n = write(sock,"I got your message",18);
if (n < 0) error("***ERROR writing to socket");
}
In the function "dostuff" I want to write 'buffer' to port 80, read the response and write this response back over port 20000 (argv[1]).
At the moment, when I set my browser's proxy to 172.16.1.218:20000, all I get is "I got your message". I want to change this to the response from the webpage!
Any pointers in the right direction greatly appreciated.
Here's what I've tried sofar (replace multi-line comment "Forward message to port 80 and read response here" with this code):
int sockfdi, portnoi, ni;
struct sockaddr_in serv_addri;
struct hostent *serveri;
portnoi =80;
sockfdi = socket(AF_INET, SOCK_STREAM, 0);
if (sockfdi < 0){
error("***ERROR opening socket");
}
serveri = gethostbyname("172.16.1.218");
if (serveri == NULL){
fprintf(stderr,"***ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addri, sizeof(serv_addri));
serv_addri.sin_family = AF_INET;
bcopy((char *)serveri->h_addr, (char *)&serv_addri.sin_addr.s_addr, serveri->h_length);
serv_addri.sin_port = htons(portnoi);
if (connect(sockfdi,(struct sockaddr *) &serv_addri,sizeof(serv_addri)) < 0){
error("***ERROR connecting");
}
printf("Please enter the message: ");
bzero(buffer,256);
But every time I try to connect via my webbrowser, the server echos: "***ERROR connecting: Connection refused"
Many thanks in advance,
This is a non-trivial task you set out to do. Currently, you're missing three things, an easy one and two difficult ones:
You have to open a network connection to the server you want to forward the call to (rather easy, see socket() and connect()).
You'll then have a duplex connection, that is two concurrent streams of data, one going from the client to the forwarded server and one from the forwarded server to the client. In order to cope with this concurrency, you either need two threads with blocking I/O or some sort of non-blocking I/O (see select() or AIO).
If you forward an HTTP request without changes to another server, you'll likely end up with invalid server names and IP addresses in the request. The request will then be rejected. So you'll need to parse the HTTP header, do some replacements and forward the modified HTTP request.

Resources