Linux TCP server, sending RAW data to few clients every X seconds - c

I'm writing simple TCP server and I found some issue. Maybe you can help me a bit.
So, I wrote an echo server first (to test connection with computer client). It's working okay, but now I need to change it a bit. Server should sent char[100] to client when it connects and sent same char[] to every client every X seconds/minutes.
I've trying many changes, but application only crashes. Commented some of my "mistakes" in this code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
/* BufferLength is 100 bytes */
#define BufferLength 100
/* Server port */
#define SERVPORT 6000
int main(){
/* Variable and structure definitions. */
int sd, wyslij, sd2, rc, length = sizeof(int);
int totalcnt = 0, on = 1;
char temp;
char buffer[BufferLength];
struct sockaddr_in serveraddr;
struct sockaddr_in their_addr;
fd_set read_fd;
struct timeval timeout;
timeout.tv_sec = 15;
timeout.tv_usec = 0;
char datadata[100] = "This is a test string from server lol!!! ";
/* Get a socket descriptor */
if((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
perror("Server-socket() error");
/* exit */
exit (-1);
}else
printf("Server-socket() is OK\n");
/* Allow socket descriptor to be reusable */
if((rc = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on))) < 0){
perror("Server-setsockopt() error");
close(sd);
exit (-1);
}else
printf("Server-setsockopt() is OK\n");
/* bind to an address */
memset(&serveraddr, 0x00, sizeof(struct sockaddr_in));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(SERVPORT);
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
printf("Using %s, listening at %d\n", inet_ntoa(serveraddr.sin_addr), SERVPORT);
if((rc = bind(sd, (struct sockaddr *)&serveraddr, sizeof(serveraddr))) < 0){
perror("Server-bind() error");
/* Close the socket descriptor */
close(sd);
/* and just exit */
exit(-1);
}else
printf("Server-bind() is OK\n");
/* queue up to 10 clients */
if((rc = listen(sd, 10)) < 0){
perror("Server-listen() error");
close(sd);
exit (-1);
}else
printf("Server-Ready for client connection...\n");
/* accept() the incoming connection request. */
int sin_size = sizeof(struct sockaddr_in);
if((sd2 = accept(sd, (struct sockaddr *)&their_addr, &sin_size)) < 0){
perror("Server-accept() error");
close(sd);
exit (-1);
}else
printf("Server-accept() is OK\n");
/*client IP*/
printf("Server-new socket, sd2 is OK...\n");
printf("Got connection from the client: %s\n", inet_ntoa(their_addr.sin_addr));
/* Wait for up to 15 seconds on */
/* select() for data to be read. */
FD_ZERO(&read_fd);
FD_SET(sd2, &read_fd);
rc = select(sd2+1, &read_fd, NULL, NULL, &timeout);
/* rc = write(sd2, datadata, sizeof(datadata)); */
if((rc == 1) && (FD_ISSET(sd2, &read_fd))){
/* rc = write(sd2, datadata, sizeof(datadata)); */
/* Read data from the client. */
totalcnt = 0;
while(totalcnt < BufferLength){
/* read() from client */
rc = read(sd2, &buffer[totalcnt], (BufferLength - totalcnt));
if(rc < 0){
perror("Server-read() error");
close(sd);
close(sd2);
exit (-1);
}else if (rc == 0){
printf("Client program has issued a close()\n");
close(sd);
close(sd2);
exit(-1);
}
else{
totalcnt += rc;
printf("Server-read() is OK\n");
}
}
}else if (rc < 0){
perror("Server-select() error");
close(sd);
close(sd2);
exit(-1);
}
/* rc == 0 */
else{
printf("Server-select() timed out.\n");
close(sd);
close(sd2);
exit(-1);
}
/* Shows the data */
printf("Received data from the client: %s\n", buffer);
/* write() some bytes of string, */
/* back to the client. */
printf("Server-Echoing back to client...\n");
rc = write(sd2, datadata, sizeof(datadata));
if(rc != totalcnt){
perror("Server-write() error");
/* Get the error number. */
rc = getsockopt(sd2, SOL_SOCKET, SO_ERROR, &temp, &length);
if(rc == 0){
/* Print out the asynchronously */
/* received error. */
errno = temp;
perror("SO_ERROR was: ");
}else
printf("Server-write() is OK\n");
close(sd);
close(sd2);
exit(-1);
}
/* Close the connection to the client and */
/* close the server listening socket. */
close(sd2);
close(sd);
exit(0);
return 0;
}
Thanks a lot buddies!

You may want to check out D.J. Bernstein's tcpserver (see http://cr.yp.to/ucspi-tcp/tcpserver.html). Basically, you can simply run your C program under tcpserver, and tcpserver will handle everything as far as setting up the sockets, listing for incoming connections on whatever port you are using, etc. When an incoming connection arrives on the port that you specify, tcpserver will spawn an instance of your program and pipe incoming info from the client to your program's STDIN, and pipe outgoing info from your program's STDOUT back to the client. This way, you can concentrate on your program's core logic (and simply read/write to stdout/stdin), and let tcpserver handle all of the heavy lifting as far as the sockets, etc.

Well, I ran your program against a simple TCP client code and did not see any crash. So, you probably should add gdb info to that. Also, in the program, I don't see where your programs wakes up periodically (you do have a comment) and sends data to the client. You should also consider adding the client fd to the list of read fd set and have one common select() call. If the select() returns a read-event on the listener, then that is a new connection and you should call accept. If the select() returns a read-event on a child fd, then you have some data to read adn you should call recv()/read().

Related

Is it possible to launch multiple servers listening to a different IP socket address?

I'm trying to launch multiple servers, at once, in a c program. For the sake of simplicity let's say 5 servers.
If I understand well the sockets, each of them must be listening to a different IP socket address (different PORT, different IP interface address).
I thought to do that inside a loop, incrementing port number by i at each turn. Here's my current code just to launch one server. I know it's possible with bash by launching the same process in background, but in C I really don't know how to do that and if it's even possible
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>
long PORT;
int main(int argc, char const *argv[])
{
/* 1. Open a socket
2. Bind to a address(and port).
3. Listen for incoming connections.
4. Accept connections
5. Read/Send
*/
int listenerSocket; /* socket for accepting connections */
int clientSocket; /* socket connected to client */
struct sockaddr_in server;
struct sockaddr_in client; /* client address information */
char buf[100]; /* buffer for sending & receiving data */
int errnum;
listenerSocket = socket(AF_INET, SOCK_STREAM, 0);
if(listenerSocket == -1){
perror("erreur lors de la création du socket");
}
PORT = strtol(argv[1], NULL, 10);
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port= htons(PORT);
if (bind(listenerSocket, (struct sockaddr *)&server, sizeof(server)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
puts("Server waiting for connection...");
while(1){
if (listen(listenerSocket, 5) < 0){
perror("listen failed");
exit(EXIT_FAILURE);
}
int c = sizeof(client);
if((clientSocket = accept(listenerSocket, (struct sockaddr*) &client, &c)) < 0){
puts("error accepting the request");
perror("Accept()");
}
puts("connection accepted");
while(1){
if( recv(clientSocket, buf, sizeof(buf), 0) < 0) {
errnum = errno;
perror("Recv()");
printf("val printed by errno: %d\n",errno);
}
printf("Message : %s\n", buf);
}
if (send(clientSocket, buf, sizeof(buf), 0) < 0)
{
perror("Send()");
exit(7);
}
close(clientSocket);
close(listenerSocket);
printf("Server ended successfully\n");
exit(0);
}

Static variable in C

I have this program that is a part of a server with tcp protocol, that gets a number from the client and uses it in another function.
Also I have a static int type variable that i want to count each time the server gets a message from a client, but each time it does not keep its value;
The variable is counter
Can you guys tell me why this is happening?
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// used port
#define PORT 1114
// error code
extern int errno;
static int counter;
int main ()
{
struct sockaddr_in server; // structure used by server
struct sockaddr_in from;
char message[100]; //message received from client
int socketDescriptor; //socket descriptor
//creating socket
if ((socketDescriptor = socket (AF_INET, SOCK_STREAM, 0)) == -1)
{
perror ("[server]Error at socket\n");
return errno;
}
//preparing data structures
bzero (&server, sizeof (server));
bzero (&from, sizeof (from));
//filling structures
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl (INADDR_ANY);
server.sin_port = htons (PORT);
//attach socket to descriptor
if (bind (socketDescriptor, (struct sockaddr *) &server, sizeof (struct sockaddr)) == -1)
{
perror ("[server]Error at bind\n");
return errno;
}
//server is listening
if (listen (socketDescriptor, 2) == -1)
{
perror ("[server]Error at listen\n");
return errno;
}
/serving concurrent the clients
while (1)
{
int client;
int length = sizeof (from);
printf ("[server]Waiting at port %d...\n",PORT);
fflush (stdout);
//accepting client
client = accept (socketDescriptor, (struct sockaddr *) &from, &length);
counter ++;
switch(fork())
{
case -1:
perror("fork err\n");
exit(2);
case 0:
//error if failed connection
if (client < 0)
{
perror ("[server]Error at accept\n");
continue;
}
//conenction established
bzero (message, 100);
printf ("[server]Waiting for message...\n");
fflush (stdout);
//reading message
if (read (client, message, 100) <= 0)
{
perror ("[server]Error at read\n");
close (client); //closing connection
continue; //keep listening
}
printf ("[server]Message was received%s\n", message);
//this is where I want to increment counter, when I want to verify message
int number;
number = atoi(message);//convert char to int
printf("The number is: %d\n", number);//print number
printf("The counter is : %d\n", counter);
fflush(stdout);
exit(2);
}
close (client);
} /* while */
} /* main */
Just move counter++ to the parent process. When the child process starts it gets a copy of counter and the one you modify does not affect it's copy (original actually) in the parent process. If you update it in the parent process you will achieve what you want.
int main(int argc, char ** argv)
{
int number;
int listenfd, connfd, n;
pid_t childpid;
socklen_t clilen;
char message[MAXLINE], answer[MAXLINE];
struct sockaddr_in clientaddr, serveraddr;
int counter;
counter = 0;
// create socket
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("ERROR at creating socket\n");
exit(2);
}
// preparation of socket address
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(PORT);
// bind the socket
bind(listenfd, (struct sockaddr *) &serveraddr, sizeof(serveraddr));
// listen to the socket
listen(listenfd, LIMIT);
printf("Server running, waiting for connections at port : %d\n", PORT);
while (1)
{
clilen = sizeof(clientaddr);
// accept a connection
connfd = accept(listenfd, (struct sockaddr *) &clientaddr, &clilen);
printf("Recieved guest\n");
switch (fork())
{
case -1:
perror("fork err\n");
exit(2);
case 0:
/* eroare la acceptarea conexiunii de la un client */
if (connfd < 0)
{
perror("[server]Eroare la accept().\n");
continue;
}
/* s-a realizat conexiunea, se astepta mesajul */
bzero(message, 100);
printf("[server]Asteptam mesajul...\n");
fflush(stdout);
/* citirea mesajului */
if (read(connfd, message, 100) <= 0)
{
perror("[server]Eroare la read() de la client.\n");
close(connfd); /* inchidem conexiunea cu clientul */
continue; /* continuam sa ascultam */
}
printf ("[server]Message was received...%s\n", message);
fflush(stdout);
number = atoi(message);
printf("The number is: %d\n", number);
printf ("%d\n", counter + 1);
_exit(0); // The child should not create further grand children
default:
counter++;
break;
}//switch
}//for
close(connfd);
}//main
You appear to be forking before setting the counter. Since forking duplicates the entire process, the copy of counter in each child process is different from the parent.
Sharing variables between applications in C can be tricky, but actually there's a pretty easy fix for your case and it will improve performance too. If you look at your code, you're forking after the connect and then handling, in the child, the possibiliy that the connfd < 0. If you handled that in the parent process, the counter could belong to the parent and could be incremented before the fork.
A few other notes here come to mind. Remember, fork duplicates the parent process, so the children in your case are still within a while(1) loop. When you continue you loop back to the next iteration of the while(1) loop, but this doesn't seem correct; you want the child process to exit when it's done handling the connection. This also means as you accept connections, you fork but the fork never dies - I guess that's more a "process leak" than a memory leak, but will certainly eat up memory. Finally, just to throw it out there, forking to handle each request is probably the slowest way to concurrently handle connections. I've had great success with pthread in this case. Since threads share a process space, the threads can even persist and handle many connections before dying ( put the connections on a queue and have the threads poll it, for example ) becasuse they can continue to share connections with their "parent" ( though it's really a sibling thread in this case).

How to check whether a client has joined a multicast group?

End goal:
For the parent process of the server to know what clients join or leave the multicast group. So far I've only tried to check on clients joining, for I assume checking on those leaving is a similar matter.
My method(s) so far:
Checking for changes in the socket of the multicast group through select().
After joining, the client executes a sendto() directed to the (parent process of) the server program. The select() in the server is meant to recognize any changes, but apparently doesn't, and thus retval != 0 is never true.
Results so far
I Have tried with many different IP addresses and constants such as INADDR_ANY, but I've only managed as far as sending a message back to the client through the multicast, and this one interpret it as if the server-program had sent it. The most common result is the server-program not receiving any message at all.
Here is my client code:
/* Receiver/client multicast Datagram*/
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_MSG 100
struct sockaddr_in localSock, servSock;
struct ip_mreq group;
int sd, n;
int datalen, mcastport;
char msg[MAX_MSG];
int main(int argc, char *argv[])
{
if(argc!=3) {
printf("usage : %s <address> <port>\n",argv[0]);
exit(0);
}
mcastport = atoi(argv[2]);
/* Create a datagram socket on which to receive. */
sd = socket(AF_INET, SOCK_DGRAM, 0);
if(sd < 0)
{
perror("Opening datagram socket error");
exit(1);
}
else
printf("Opening datagram socket....OK.\n");
/* Enable SO_REUSEADDR to allow multiple instances of this */
/* application to receive copies of the multicast datagrams. */
{
int reuse = 1;
if(setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0)
{
perror("Setting SO_REUSEADDR error");
close(sd);
exit(1);
}
else
printf("Setting SO_REUSEADDR...OK.\n");
}
/* Bind to the proper port number with the IP address */
/* specified as INADDR_ANY. */
memset((char *) &localSock, 0, sizeof(localSock));
localSock.sin_family = AF_INET;
localSock.sin_port = htons(mcastport);
localSock.sin_addr.s_addr = INADDR_ANY;
if(bind(sd, (struct sockaddr*)&localSock, sizeof(localSock)))
{
perror("Binding datagram socket error");
close(sd);
exit(1);
}
else
printf("Binding datagram socket...OK.\n");
printf("Enter the group's name you want to join:\n");
scanf("%s", msg);
/* Join the multicast group 226.1.1.1 on the local IP address */
/* interface. Note that this IP_ADD_MEMBERSHIP option must be */
/* called for each local interface over which the multicast */
/* datagrams are to be received. */
group.imr_multiaddr.s_addr = inet_addr(argv[1]);
group.imr_interface.s_addr = inet_addr("127.0.0.1");
if(setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group)) < 0)
{
perror("Adding multicast group error");
close(sd);
exit(1);
}
else
printf("Adding multicast group...OK.\n");
/* Initialize the group sockaddr structure with a */
/* group address of 226.1.1.1 and port given by user. */
memset((char *) &servSock, 0, sizeof(servSock));
servSock.sin_family = AF_INET;
servSock.sin_addr.s_addr = inet_addr(argv[1]);
servSock.sin_port = htons(mcastport);
if(sendto(sd, "", 1, 0, (struct sockaddr*) &servSock, sizeof(servSock)) < 0)
{perror("Sending datagram message error");}
else
printf("Sending datagram message...OK\n");
/* Read from the socket. */
if((n=read(sd, msg, MAX_MSG)) < 0)
{
perror("Reading datagram message error");
close(sd);
exit(1);
}
else
{
printf("Reading datagram message...OK.\n");
printf("The message from multicast server is: \"%s\"\n", msg);
}
msg[n] = '\0';
return 0;
}
This is my server program code:
/* Send Multicast Datagram code*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h> /* for strncpy, memset */
#define MAX_MSG 100
struct in_addr localInterface;
struct sockaddr_in groupSock, cliAddr;
int sd, mcastport, maxJoin, maxJoined = 0, pipefd[2], cliLen, cpid;
char msg[MAX_MSG], groupName[MAX_MSG];
int main (int argc, char *argv[ ])
{
/* check command line args */
if(argc < 2) {
printf("usage : %s <port> \n", argv[0]);
exit(1);
}
mcastport = atoi(argv[1]);
/* Create a datagram socket on which to send. */
sd = socket(AF_INET, SOCK_DGRAM, 0);
if(sd < 0)
{
perror("Opening datagram socket error");
exit(1);
}
else
printf("Opening the datagram socket...OK\n");
/* Initialize the group sockaddr structure with a */
/* group address of 225.1.1.1 and port given by user. */
memset((char *) &groupSock, 0, sizeof(groupSock));
groupSock.sin_family = AF_INET;
groupSock.sin_addr.s_addr = inet_addr("226.1.1.1");
groupSock.sin_port = htons(mcastport);
printf("Create a group: ");
scanf("%s", groupName);
printf("Maximum number of clients that can join the group? ");
scanf("%d", &maxJoin);
/* Disable loopback so you do not receive your own datagrams.
{
char loopch = 0;
if(setsockopt(sd, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loopch, sizeof(loopch)) < 0)
{
perror("Setting IP_MULTICAST_LOOP error");
close(sd);
exit(1);
}
else
printf("Disabling the loopback...OK.\n");
}
*/
/* Set local interface for outbound multicast datagrams. */
/* The IP address specified must be associated with a local, */
/* multicast capable interface. */
printf("Setting the local interface...");
localInterface.s_addr = inet_addr("127.0.0.1");
if(setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF, (char *)&localInterface, sizeof(localInterface)) < 0)
{
perror("error");
exit(1);
}
else
printf("OK\n");
if((cpid = fork()) == 0) //child process --sends messages
{
/* Send a message to the multicast group specified by the*/
/* groupSock sockaddr structure. */
printf("Enter a message to send: \n");
scanf("%s", msg);
if(sendto(sd, msg, strlen(msg)+1, 0, (struct sockaddr*)&groupSock, sizeof(groupSock)) < 0)
{perror("Sending datagram message error");}
else
printf("Sending datagram message...OK\n");
/* Try the re-read from the socket if the loopback is not disable
if(read(sd, databuf, datalen) < 0)
{
perror("Reading datagram message error\n");
close(sd);
exit(1);
}
else
{
printf("Reading datagram message from client...OK\n");
printf("The message is: %s\n", databuf);
}
*/
exit(EXIT_SUCCESS);
}
else //parent process --checks for JOINs and QUITs
{
fd_set rfds;
struct timeval tv;
int retval, status;
while (waitpid(cpid, &status, WNOHANG) != cpid)
{
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(sd, &rfds);
/* Wait up to five seconds. */
tv.tv_sec = 5;
tv.tv_usec = 0;
retval = select(sd+1, &rfds, NULL, NULL, &tv);
/* Don't rely on the value of tv now! */
if (retval == -1)
perror("select()");
else if (retval != 0)
{
printf("Data is available now.\n");
/* FD_ISSET(0, &rfds) will be true. */
cliLen = sizeof(cliAddr);
int n;
if((n = recvfrom(sd, msg, MAX_MSG, 0, (struct sockaddr *) &cliAddr,&cliLen)) == -1)
perror("Some bullshit happened");
msg[n] = '\0';
printf("Client IP:port is: %s:%d", inet_ntoa(cliAddr.sin_addr), (int) ntohs(cliAddr.sin_port));
} else
{printf("no data.\n");}
}
exit(0);
}
return 0;
}
Possible solutions I haven't tried:
Maybe I shouldn't use the multicast group to send information client->server, but rather another type of connection? I'm just guessing here. I know you guys don't like doing anyone's work.
I have been at this "simple" issue for several hours and tried reading everywhere I could, including this question which seems very similar, but I haven't managed to solve it in any way. I'm completely striking out here.
If the client sends to the multicast group and the server expects to read that, the server needs to join the multicast group as well.
It isn't a great solution, as all the other client members will also receive that multicast.
It would make more sense for the client to first receive a multicast from the server, and then to respond to the server's address, which is provided via the result arguments of recvfrom().
Two points that may help you:
There is no need to use multicasting if your communication is only local (you use 127.0.0.1 in your code)
Multicast groups are joined by network interfaces, not by processes. Once a network interface has joined a multicast interface, a second joining of the same network interface to the same multicast group will change nothing. Even when it's another process on the same host that requests the second
joining.

OpenSSL and Network namespace - Closed

I am developing an application using OpenSSL library. I am new to OpenSSL library. My application was working correctly until I tested it within network namespace. My application hangs at SSL_Connect. I am using sockets in the blocking mode. I read somewhere that I should use non-blocking mode instead to solve the issue. So I switched from blocking sockets to non-blocking sockets but my code still gets stuck at SSL_Connect method in the client.
I just have a simple client-server program nothing fancy stuff. I have added SSL methods inside them to make them secure. Everything works perfectly when I run them inside terminal but when I switch to network namespace and run inside virtual network, the client code hangs at SSL_Connect. I am not able to understand what may be causing this problem. Any help will be appreciated!
Here is the code for server.c file:
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <errno.h>
#include <sys/select.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#define SERVER_PORT 12345
#define TRUE 1
#define FALSE 0
main (int argc, char *argv[])
{
int i, len, rc, on = 1;
int listen_sd, max_sd, new_sd;
int desc_ready, end_server = FALSE;
int close_conn;
char buffer[80];
struct sockaddr_in addr;
struct timeval timeout;
fd_set master_set, working_set;
char ch='a';
//ssl initiation
SSL_load_error_strings();
ERR_load_BIO_strings();
ERR_load_SSL_strings();
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_METHOD *meth = SSLv3_server_method();
SSL_CTX *ctx = SSL_CTX_new(meth);
SSL_CTX_use_certificate_file(ctx, "TrustStore.pem", SSL_FILETYPE_PEM);
SSL_CTX_use_PrivateKey_file(ctx, "privatekey.key", SSL_FILETYPE_PEM);
/*************************************************************/
/* Create an AF_INET stream socket to receive incoming */
/* connections on */
/*************************************************************/
listen_sd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_sd < 0)
{
perror("socket() failed");
exit(-1);
}
/*************************************************************/
/* Allow socket descriptor to be reuseable */
/*************************************************************/
rc = setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR,
(char *)&on, sizeof(on));
if (rc < 0)
{
perror("setsockopt() failed");
close(listen_sd);
exit(-1);
}
/*************************************************************/
/* Set socket to be non-blocking. All of the sockets for */
/* the incoming connections will also be non-blocking since */
/* they will inherit that state from the listening socket. */
/*************************************************************/
rc = ioctl(listen_sd, FIONBIO, (char *)&on);
if (rc < 0)
{
perror("ioctl() failed");
close(listen_sd);
exit(-1);
}
/*************************************************************/
/* Bind the socket */
/*************************************************************/
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(SERVER_PORT);
rc = bind(listen_sd,
(struct sockaddr *)&addr, sizeof(addr));
if (rc < 0)
{
perror("bind() failed");
close(listen_sd);
exit(-1);
}
/*************************************************************/
/* Set the listen back log */
/*************************************************************/
rc = listen(listen_sd, 32);
if (rc < 0)
{
perror("listen() failed");
close(listen_sd);
exit(-1);
}
/*************************************************************/
/* Initialize the master fd_set */
/*************************************************************/
FD_ZERO(&master_set);
max_sd = listen_sd;
FD_SET(listen_sd, &master_set);
/*************************************************************/
/* Initialize the timeval struct to 3 minutes. If no */
/* activity after 3 minutes this program will end. */
/*************************************************************/
timeout.tv_sec = 3 * 60;
timeout.tv_usec = 0;
/*************************************************************/
/* Loop waiting for incoming connects or for incoming data */
/* on any of the connected sockets. */
/*************************************************************/
do
{
/**********************************************************/
/* Copy the master fd_set over to the working fd_set. */
/**********************************************************/
memcpy(&working_set, &master_set, sizeof(master_set));
/**********************************************************/
/* Call select() and wait 5 minutes for it to complete. */
/**********************************************************/
printf("Waiting on select()...\n");
rc = select(max_sd + 1, &working_set, NULL, NULL, &timeout);
/**********************************************************/
/* Check to see if the select call failed. */
/**********************************************************/
if (rc < 0)
{
perror(" select() failed");
break;
}
/**********************************************************/
/* Check to see if the 5 minute time out expired. */
/**********************************************************/
if (rc == 0)
{
printf(" select() timed out. End program.\n");
break;
}
/**********************************************************/
/* One or more descriptors are readable. Need to */
/* determine which ones they are. */
/**********************************************************/
desc_ready = rc;
for (i=0; i <= max_sd && desc_ready > 0; ++i)
{
/*******************************************************/
/* Check to see if this descriptor is ready */
/*******************************************************/
if (FD_ISSET(i, &working_set))
{
/****************************************************/
/* A descriptor was found that was readable - one */
/* less has to be looked for. This is being done */
/* so that we can stop looking at the working set */
/* once we have found all of the descriptors that */
/* were ready. */
/****************************************************/
desc_ready -= 1;
/****************************************************/
/* Check to see if this is the listening socket */
/****************************************************/
if (i == listen_sd)
{
printf(" Listening socket is readable\n");
/*************************************************/
/* Accept all incoming connections that are */
/* queued up on the listening socket before we */
/* loop back and call select again. */
/*************************************************/
do
{
/**********************************************/
/* Accept each incoming connection. If */
/* accept fails with EWOULDBLOCK, then we */
/* have accepted all of them. Any other */
/* failure on accept will cause us to end the */
/* server. */
/**********************************************/
new_sd = accept(listen_sd, NULL, NULL);
if (new_sd < 0)
{
if (errno != EWOULDBLOCK)
{
perror(" accept() failed");
end_server = TRUE;
}
break;
}
/**********************************************/
/* Add the new incoming connection to the */
/* master read set */
/**********************************************/
printf(" New incoming connection - %d\n", new_sd);
FD_SET(new_sd, &master_set);
if (new_sd > max_sd)
max_sd = new_sd;
/**********************************************/
/* Loop back up and accept another incoming */
/* connection */
/**********************************************/
} while (new_sd != -1);
}
/****************************************************/
/* This is not the listening socket, therefore an */
/* existing connection must be readable */
/****************************************************/
else
{
printf(" Descriptor %d is readable\n", i);
close_conn = FALSE;
SSL* ssl;
ssl = SSL_new(ctx);
SSL_set_fd(ssl, i);
//handshake
SSL_accept(ssl);
printf("\nHandshake Done\n");
int result = SSL_read(ssl, &ch, sizeof(ch));
if(result<0)
{
printf("\nreading Error");
}
++ch;
result = SSL_write(ssl, &ch, sizeof(ch));
if(result<0)
{
printf("\nwriting Error");
}
/*************************************************/
/* If the close_conn flag was turned on, we need */
/* to clean up this active connection. This */
/* clean up process includes removing the */
/* descriptor from the master set and */
/* determining the new maximum descriptor value */
/* based on the bits that are still turned on in */
/* the master set. */
/*************************************************/
if (close_conn)
{
close(i);
FD_CLR(i, &master_set);
if (i == max_sd)
{
while (FD_ISSET(max_sd, &master_set) == FALSE)
max_sd -= 1;
}
}
} /* End of existing connection is readable */
} /* End of if (FD_ISSET(i, &working_set)) */
} /* End of loop through selectable descriptors */
} while (end_server == FALSE);
/*************************************************************/
/* Cleanup all of the sockets that are open */
/*************************************************************/
for (i=0; i <= max_sd; ++i)
{
if (FD_ISSET(i, &master_set))
close(i);
}
}
Here is the code for client.c file:
/**************************************************************************/
/* Generic client example is used with connection-oriented server designs */
/**************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#define SERVER_PORT 12345
main (int argc, char *argv[])
{
int len, rc;
int sockfd;
char send_buf[80];
char recv_buf[80];
struct sockaddr_in addr;
char ch = 'A';
int result;
//ssl initiation
SSL_load_error_strings();
ERR_load_BIO_strings();
ERR_load_SSL_strings();
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_METHOD *meth;
meth = SSLv3_client_method();
SSL_CTX *ctx;
SSL* ssl;
ctx = SSL_CTX_new(meth);
result = SSL_CTX_load_verify_locations(ctx, "TrustStore1.pem", 0);
printf("\nCA load result = %d\n", result);
printf("\nSSL initialized");
/*************************************************/
/* Create an AF_INET stream socket */
/*************************************************/
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
perror("socket");
exit(-1);
}
/*************************************************/
/* Initialize the socket address structure */
/*************************************************/
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("10.0.0.1");
addr.sin_port = htons(SERVER_PORT);
/*************************************************/
/* Connect to the server */
/*************************************************/
rc = connect(sockfd,
(struct sockaddr *)&addr,
sizeof(struct sockaddr_in));
if (rc < 0)
{
perror("connect");
close(sockfd);
exit(-1);
}
printf("Connect completed.\n");
//ssl-ing the connection
ssl = SSL_new(ctx);
BIO *sbio;
sbio = BIO_new(BIO_s_socket());
BIO_set_fd(sbio, sockfd, BIO_CLOSE);
SSL_set_bio(ssl, sbio, sbio);
//SSL_CTX_set_verify_depth(ctx, 1);
//SSL_set_fd(ssl, sockfd);
printf("Before SSL_connect: %d\n", result);
result = SSL_connect(ssl);
printf("SSL_connect: %d\n", result);
if(SSL_get_peer_certificate(ssl)!=NULL)
{
//check cert
//check_cert(ssl);
//getting the CA certificate
//_ssl = SSL_new(ctx);
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
int result_long = SSL_get_verify_result(ssl);
printf("\nCertificate Check Result: %d", result_long);
if (SSL_get_verify_result(ssl) != X509_V_OK)
{
printf("\nCertiticate Verification Failed\n");
return 0;
//exit(1);
}
else
{
printf("\nCertiticate Verification Succeeded");
}
}
SSL_write(ssl, &ch, 1);
SSL_read(ssl, &ch, 1);
printf("char from server = %c\n", ch);
SSL_shutdown(ssl);
/*************************************************/
/* Close down the socket */
/*************************************************/
close(sockfd);
}

closing socket in BSD sockets

My code is :
int main(int argc, char *argv[])
{
int sockfd, new_fd; /* listen on sock_fd, new connection on new_fd */
struct sockaddr_in my_addr; /* my address information */
struct sockaddr_in their_addr; /* connector's address information */
socklen_t sin_size;
/* generate the socket */
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
/* generate the end point */
my_addr.sin_family = AF_INET; /* host byte order */
my_addr.sin_port = htons(MYPORT); /* short, network byte order */
my_addr.sin_addr.s_addr = INADDR_ANY; /* auto-fill with my IP */
/* bzero(&(my_addr.sin_zero), 8); ZJL*/ /* zero the rest of the struct */
/* bind the socket to the end point */
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) \
== -1) {
perror("bind");
exit(1);
}
/* start listnening */
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
printf("server starts listnening %d...\n",sockfd);
/* repeat: accept, send, close the connection */
/* for every accepted connection, use a sepetate process or thread to serve it */
while(1) { /* main accept() loop */
sin_size = sizeof(struct sockaddr_in);
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, \
&sin_size)) == -1) {
perror("accept");
continue;
}
printf("server: got connection from %s\n", \
inet_ntoa(their_addr.sin_addr));
if ((numbytes=recv(new_fd, buf, MAXDATASIZE, 0)) == -1) {
perror("recv");
exit(1);
}
buf[numbytes] = '\0';
printf("Received: %s",buf);
if (send(new_fd, "Hello, world!\n", MAXDATASIZE, 0) == -1)
perror("send");
close(new_fd);
exit(0);
close(new_fd); /* parent doesn't need this */
while(waitpid(-1,NULL,WNOHANG) > 0); /* clean up child processes */
}
return 0;
}
So whenever I execute this server, after one client uses that it terminates. But If I want to execute it again lets say within 60 seconds, then it gives an error of bind: Address already in use I thought the close() function actually releases the socket so that it would be available to use it again instantly. So what am I missing here?
Before calling bind, you can mark that you want to potentially reuse an address/port using the SO_REUSEADDR socket option:
int reuseaddr = 1;
int err = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
&reuseaddr, sizeof(reuseaddr));
Also, I don't see where BACKLOG is defined, which you use in the listen() call. If this is by chance set to 1, you may want to increase it. Then, while the last socket closes, you can be handling the next call.
Firstly the original form of this code comes from Beej's guide
You have supplied code which is either very wrong or edited for brevity. After sending the "Hello World" response you call exit(0); Please add curly braces.
if (send(new_fd, "Hello, world!\n", MAXDATASIZE, 0) == -1)
perror("send");
close(new_fd);
exit(0);
Beej;s code:
if (!fork()) { // this is the child process
close(sockfd); // child doesn't need the listener
if (send(new_fd, "Hello, world!", 13, 0) == -1)
perror("send");
close(new_fd);
exit(0);
}
close(new_fd); // parent doesn't need this`
May I also point out that Beej's code and yours does not handle the event where 'recv' returns 0 in the case a connection was lost or aborted by the client. On a side note remember a call to recv will block.
if ((numbytes=recv(new_fd, buf, MAXDATASIZE, 0)) == -1) {
perror("recv");
exit(1);
}
While this seems it probably wont affect the crash this particular issue may cause unexpected crashes later when the client is closed unexpectedly.
Delay is due to TIME_WAIT
In the process of terminating a connection, the important thing to keep in mind is that the application process on both sides of the connection must independently close its half of the connection. Due to the Three Way Handshake policy of a TCP connection,kernel waits for the acknowledgment that the connection on the other side is also closed
However, You can override this functionality by following methods:
Method 1
In the /etc/sysctl.conf file, add the following lines to persist it after reboot:
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1
Method 2
echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle
echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse

Resources