How to share variables among threads? - c

I am working on a server-client project which allows the server to exchange messages
with a client individually. However, I have to modify the server so that when the server sends a message, it is sent to all connected clients.
I know this involves sharing variables among threads but I am confused on how to go about do this?
Any tips/guidence will be appreciated!
Server Code:
#include<stdio.h>
#include<string.h> //strlen
#include<stdlib.h> //strlen
#include<sys/socket.h>
#include<arpa/inet.h> //inet_addr
#include<unistd.h> //write
#include<pthread.h> //for threading , link with lpthread
#define MAX 80
#define PORT 6543
#define SA struct sockaddr
// Function designed for chat between client and server.
void join( pthread_t *thread_id)
{
if(!pthread_join( *thread_id , NULL))
printf("thread %ld complted\n",*thread_id);
pthread_exit(0);//to exit the current thread
}
void func(int *sockfd)
{
char buff[MAX];
int n;
// infinite loop for chat
for (;;) {
bzero(buff, MAX);
// read the message from client and copy it in buffer
read(*sockfd, buff, sizeof(buff));
// print buffer which contains the client contents
printf("From client: %s\t To client : ", buff);
bzero(buff, MAX);
n = 0;
// copy server message in the buffer
while ((buff[n++] = getchar()) != '\n');
// and send that buffer to client
write(*sockfd, buff, sizeof(buff));
// if msg contains "Exit" then server exit and chat ended.
if (strncmp("exit", buff, 4) == 0) {
printf("Server Exit...\n");
break;
}
}
}
// Driver function
int main()
{
int sockfd, connfd, len;
struct sockaddr_in servaddr, cli;
pthread_t thread_id,jointhread_id;
// socket create and verification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
printf("socket creation failed...\n");
exit(0);
}
else
printf("Socket successfully created..\n");
bzero(&servaddr, sizeof(servaddr));
// assign IP, PORT
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(PORT);
// Binding newly created socket to given IP and verification
if ((bind(sockfd, (SA*)&servaddr, sizeof(servaddr))) != 0) {
printf("socket bind failed...\n");
exit(0);
}
else
printf("Socket successfully binded..\n");
// Now server is ready to listen and verification
if ((listen(sockfd, 5)) != 0) {
printf("Listen failed...\n");
exit(0);
}
else
printf("Server listening..\n");
len = sizeof(cli);
// Accept the data packet from client and verification
while(connfd = accept(sockfd, (SA*)&cli, &len))
{
if (connfd < 0) {
printf("server acccept failed...\n");
exit(0);
}
else
printf("server acccept the client..%d.\n",connfd);
if( pthread_create( &thread_id , NULL , func , (void*) &connfd) < 0)
{
perror("could not create thread");
return 1;
}
if( pthread_create( &jointhread_id , NULL , join , (void*) &thread_id) < 0)
{
perror("could not create thread");
return 1;
}
}
// After chatting close the socket
close(sockfd);
}

Unfortunately, there were a number of bugs ...
Wrong prototype for thread functions
Race condition for connfd as mentioned in my top comments (passing connfd to func as a pointer).
Doing getchar destroys the message data from the read of sockfd
I've produced a version below that illustrates this.
But, to actually get the code closer to what is required for your stated purpose, required a fair amount of refactoring. There's a second version further down that illustrates my take on that.
Here's an annotated version that shows the bugs and some fixes [mostly what it took to get it to compile cleanly].
It wraps original code with #if ORIG and new code with #if FIX and each place has a comment about the bug it's fixing
#include <stdio.h>
#include <string.h> // strlen
#include <stdlib.h> // strlen
#include <sys/socket.h>
#include <arpa/inet.h> // inet_addr
#include <unistd.h> // write
#include <pthread.h> // for threading , link with lpthread
#define MAX 80
#define PORT 6543
#define SA struct sockaddr
#define ORIG 0
#define FIX 1
// Function designed for chat between client and server.
// NOTE/BUG -- the main thread has to join the thread
#if ORIG
void
join(pthread_t *thread_id)
{
if (!pthread_join(*thread_id, NULL))
printf("thread %ld complted\n", *thread_id);
// to exit the current thread
pthread_exit(0);
}
#endif
// NOTE/BUG: this is the _wrong_ signature for a thread function
#if ORIG
void
func(int *sockfd)
#else
void *
func(void *ptr)
#endif
{
#if FIX
int sockfd = (long) ptr;
#endif
char buff[MAX];
int n;
// infinite loop for chat
for (;;) {
bzero(buff, MAX);
// read the message from client and copy it in buffer
// NOTE/BUG: this has a race condition
// NOTE/BUG: we need the actual length
#if ORIG
read(*sockfd, buff, sizeof(buff));
#else
int rlen = read(sockfd, buff, sizeof(buff));
#endif
// print buffer which contains the client contents
printf("From client: %s\t To client : ", buff);
bzero(buff, MAX);
// copy server message in the buffer
// NOTE/BUG: this is destroying the data that was
#if ORIG
n = 0;
while ((buff[n++] = getchar()) != '\n');
#endif
// and send that buffer to client
#if ORIG
write(*sockfd, buff, sizeof(buff));
#else
write(sockfd, buff, rlen);
#endif
// if msg contains "Exit" then server exit and chat ended.
if (strncmp("exit", buff, 4) == 0) {
printf("Server Exit...\n");
break;
}
}
// NOTE/BUG: we must return the error code
#if FIX
return (void *) 0;
#endif
}
// Driver function
int
main()
{
int sockfd, connfd, len;
struct sockaddr_in servaddr, cli;
pthread_t thread_id, jointhread_id;
// socket create and verification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
printf("socket creation failed...\n");
exit(0);
}
else
printf("Socket successfully created..\n");
// assign IP, PORT
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(PORT);
// Binding newly created socket to given IP and verification
if ((bind(sockfd, (SA *) & servaddr, sizeof(servaddr))) != 0) {
printf("socket bind failed...\n");
exit(0);
}
else
printf("Socket successfully binded..\n");
// Now server is ready to listen and verification
if ((listen(sockfd, 5)) != 0) {
printf("Listen failed...\n");
exit(0);
}
else
printf("Server listening..\n");
// Accept the data packet from client and verification
len = sizeof(cli);
// NOTE/BUG: connfd can be zero for a valid connection
#if ORIG
while (connfd = accept(sockfd, (SA *) &cli, &len)) {
#else
while (1) {
connfd = accept(sockfd, (SA *) &cli, &len);
#endif
if (connfd < 0) {
printf("server acccept failed...\n");
exit(0);
}
else
printf("server acccept the client..%d.\n", connfd);
#if ORIG
if (pthread_create(&thread_id, NULL, func, (void *) &connfd) < 0) {
perror("could not create thread");
return 1;
}
#else
if (pthread_create(&thread_id, NULL, func, (void *) ((long) connfd)) < 0) {
perror("could not create thread");
return 1;
}
#endif
// NOTE/BUG -- creating a separate thread just to join the above thread does
// not help
#if ORIG
if (pthread_create(&jointhread_id, NULL, join, (void *) &thread_id) < 0) {
perror("could not create thread");
return 1;
}
#endif
}
// After chatting close the socket
close(sockfd);
return 0;
}
Here's a refactored version that implements the multiple client message echo that you wanted.
It uses a per-thread task block to control things. Each client, when it receives a message, sends it all other clients.
It also does a bit of interthread locking using mutexes.
Having a given client thread do all the echo to the other clients is but one way to do this. There are others (e.g. all client threads queue the message to the master/main thread and it does the echo)
This is a lot closer but you'll have more work to do in func to receive/send the client message.
Anyway, here is the code:
#include <stdio.h>
#include <string.h> // strlen
#include <stdlib.h> // strlen
#include <sys/socket.h>
#include <arpa/inet.h> // inet_addr
#include <unistd.h> // write
#include <pthread.h> // for threading , link with lpthread
#define MAX 80
#define PORT 6543
#define SA struct sockaddr
#define ORIG 0
#define FIX 1
enum {
TSKSTATE_IDLE, // task slot free/available
TSKSTATE_PENDING, // task is being created
TSKSTATE_RUNNING, // task is alive and running
TSKSTATE_DONE // task has completed (but not reaped)
};
typedef struct tsk tsk_t;
struct tsk {
tsk_t *tsk_next; // chain pointer
pthread_t tsk_tid; // thread id
long tsk_xid; // sequential task id
int tsk_sockfd; // client socket descriptor
int tsk_state; // current task state
pthread_mutex_t tsk_mutex; // per-thread mutex
void *tsk_rtn; // thread's return value
};
// NOTE: using an array obviates the need for a master lock if we used a
// linked list here instead -- by passing TSKMAX to listen below [in main],
// we guarantee that main can always find a free task slot when it needs one
#define TSKMAX 5
tsk_t tsklist[TSKMAX]; // active task list
#define TSKFORALL(_tsk) \
_tsk = &tsklist[0]; _tsk < &tsklist[TSKMAX]; ++_tsk
long tskxid; // sequential task id
__thread tsk_t *tskcur; // current thread's tsk block
pthread_mutex_t master_lock = PTHREAD_MUTEX_INITIALIZER;
// lockall -- lock all threads
void
lockall(void)
{
pthread_mutex_lock(&master_lock);
}
// unlockall -- lock all threads
void
unlockall(void)
{
pthread_mutex_unlock(&master_lock);
}
// tsklock -- lock single thread
void
tsklock(tsk_t *tsk)
{
pthread_mutex_lock(&tsk->tsk_mutex);
}
// tskunlock -- unlock single thread
void
tskunlock(tsk_t *tsk)
{
pthread_mutex_unlock(&tsk->tsk_mutex);
}
// tskreapall -- release all completed threads
void
tskreapall(void)
{
tsk_t *tsk;
lockall();
for (TSKFORALL(tsk)) {
tsklock(tsk);
if (tsk->tsk_state == TSKSTATE_DONE) {
pthread_join(tsk->tsk_tid,&tsk->tsk_rtn);
tsk->tsk_state = TSKSTATE_IDLE;
}
tskunlock(tsk);
}
}
// tsksendall -- send message to all other clients
void
tsksendall(char *msg,int len)
{
tsk_t *tsk;
lockall();
for (TSKFORALL(tsk)) {
if (tsk == tskcur)
continue;
tsklock(tsk);
if (tsk->tsk_state == TSKSTATE_RUNNING)
write(tsk->tsk_sockfd,msg,len);
tskunlock(tsk);
}
}
void *
func(void *ptr)
{
tskcur = ptr;
char buff[MAX];
#if ORIG
int n;
#endif
tsklock(tskcur);
tskcur->tsk_state = TSKSTATE_RUNNING;
tskunlock(tskcur);
// infinite loop for chat
// NOTE: this loop still needs work ...
for (;;) {
bzero(buff, MAX);
// read the message from client and copy it in buffer
int rlen = read(tskcur->tsk_sockfd, buff, sizeof(buff));
// print buffer which contains the client contents
printf("From client: %s\t To client : ", buff);
bzero(buff, MAX);
// copy server message in the buffer
// NOTE/BUG: this is destroying the data that was
#if ORIG
n = 0;
while ((buff[n++] = getchar()) != '\n');
#endif
// and send that buffer to client
write(tskcur->tsk_sockfd, buff, rlen);
// if msg contains "Exit" then server exit and chat ended.
if (strncmp("exit", buff, 4) == 0) {
printf("Server Exit...\n");
break;
}
// echo message to all other clients
tsksendall(buff,rlen);
}
tsklock(tskcur);
tskcur->tsk_state = TSKSTATE_DONE;
close(tskcur->tsk_sockfd);
tskcur->tsk_sockfd = -1;
tskunlock(tskcur);
return (void *) 0;
}
// Driver function
int
main(void)
{
int sockfd, connfd;
socklen_t len;
struct sockaddr_in servaddr, cli;
int state;
tsk_t *tsktry;
tsk_t *tsknew;
// socket create and verification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
printf("socket creation failed...\n");
exit(0);
}
else
printf("Socket successfully created..\n");
// assign IP, PORT
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(PORT);
// Binding newly created socket to given IP and verification
if ((bind(sockfd, (SA *) & servaddr, sizeof(servaddr))) != 0) {
printf("socket bind failed...\n");
exit(0);
}
else
printf("Socket successfully binded..\n");
// Now server is ready to listen and verification
if ((listen(sockfd, TSKMAX)) != 0) {
printf("Listen failed...\n");
exit(0);
}
else
printf("Server listening..\n");
// Accept the data packet from client and verification
len = sizeof(cli);
for (TSKFORALL(tsktry)) {
pthread_mutex_init(&tsktry->tsk_mutex,NULL);
tsktry->tsk_state = TSKSTATE_IDLE;
}
while (1) {
connfd = accept(sockfd, (SA *) &cli, &len);
if (connfd < 0) {
printf("server acccept failed...\n");
exit(0);
}
else
printf("server acccept the client..%d.\n", connfd);
// reap all completed threads
tskreapall();
// find an idle slot
tsknew = NULL;
for (TSKFORALL(tsktry)) {
tsklock(tsktry);
state = tsktry->tsk_state;
if (state == TSKSTATE_IDLE) {
tsknew = tsktry;
tsknew->tsk_state = TSKSTATE_PENDING;
}
tskunlock(tsktry);
if (tsknew != NULL)
break;
}
tsknew->tsk_xid = ++tskxid;
tsknew->tsk_sockfd = connfd;
if (pthread_create(&tsknew->tsk_tid, NULL, func, tsknew) < 0) {
perror("could not create thread");
return 1;
}
}
// After chatting close the socket
close(sockfd);
return 0;
}

Related

read input & save in shared memory in Socket in C

I work on the server side Socket (use Telnet client) in Linux. Client input a line with command(GET/PUT/DEL, key and an associated value (spaces to seperate in between). This key-value pair is then passed accordingly on to the function(GET/PUT/DEL), which saves the data in the shared memory (keyValueStore).
Expected client side: (> is the output from Server)
GET key1
> GET:key1:key_nonexistent
PUT key1 value1
> PUT:key1:value1
PUT key2 value2
> PUT:key2:value2
DEL key2
> DEL:key2:key_deleted
Questions:
1/ i tried to use strtok() and keyValueStore to seperate & save the tokens in a normal c file, but how should I do (or transform) it into the data transfer communication between server and client?
2/ when or where should I call the command functions (e.g. int put(char* key, char* value) )? in server.c after reading the input but before giving output?
Any advices is appreicated. Thanks for your kindness!
server.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define BUFSIZE 1024 // Buffer Size
#define TRUE 1
#define PORT 5678
int main() {
int rfd; // Create-Descriptor
int cfd; // Connection-Descriptor (accept)
struct sockaddr_in client;
socklen_t client_len;
char in[BUFSIZE];
int bytes_read;
// 1. socket()
rfd = socket(AF_INET, SOCK_STREAM, 0);
if (rfd < 0 ){
fprintf(stderr, "Error\n");
exit(-1);
}
//Initialize the server address by the port and IP
struct sockaddr_in server;
memset(&server, '\0', sizeof(server));
server.sin_family = AF_INET; // Internet address family: v4 address
server.sin_addr.s_addr = INADDR_ANY; // Server IP address
server.sin_port = htons(PORT); // Server port
// 2. bind()
int brt = bind(rfd, (struct sockaddr *) &server, sizeof(server));
if (brt < 0 ){
fprintf(stderr, "Error\n");
exit(-1);
}
// 3. listen() = listen for connections
int lrt = listen(rfd, 5);
if (lrt < 0 ){
fprintf(stderr, "Error\n");
exit(-1);
}
while (1) {
// 4. accept()
cfd = accept(rfd, (struct sockaddr *) &client, &client_len);
// read() = read from a socket (Client's data)
bytes_read = read(cfd, in, BUFSIZE);
while (bytes_read > 0) {
printf("sending back the %d bytes I received...\n", bytes_read);
// write() = write data on a socket (Client's data)
write(cfd, in, bytes_read);
bytes_read = read(cfd, in, BUFSIZE);
}
close(cfd);
}
close(rfd);
}
Input.c
#include <stdio.h>
#include <string.h>
#include <stdio.h>
#define MAX_ARRAY 100
int main() {
typedef struct Value_ {
char key[MAX_ARRAY];
char value[MAX_ARRAY];
} KeyStorage;
KeyStorage storageKey[MAX_ARRAY];
char client_input[MAX_ARRAY];
char *argv[3];
char *token;
int count = 0;
while (1) {
printf("Input: ");
gets(client_input);
//get the first token
token = strtok(client_input, " ");
int i = 0;
//walk through other tokens
while (token != NULL) {
argv[i] = token;
i++;
token = strtok(NULL, " ");
}
argv[i] = NULL; //argv ends with NULL
// arg[0] = command z.B. GET, PUT
printf("Commend: %s\n", argv[0]);
strcpy(storageKey[count].key, argv[1]);
printf("Key: %s\n", storageKey[count].key);
strcpy(storageKey[count].value, argv[2]);
printf("Value: %s\n", storageKey[count].value);
count++;
if (strcmp(argv[0], "QUIT") == 0) {
break;
}
}
return 0;
}
There are a number of errors in your code. I have fixed all to build a working example. Of course, this is not your complete application and there is even a lot of room for enhancements.
I developed and tested my code with MSVC2019 under Windows but I used a #define to isolate Windows specific code so it should compile and run correctly under Linux as well (I have not tested that).
The main problem your code had is a misunderstanding of TCP connection. It is a stream oriented connection and you must assemble "command lines" yourself, receiving one character at a time.
It is only when a line is complete that you can parse it to detect the command sent by the client. I made simple: only one command "exit" does something (close the connection). Everything else is simply ignored.
I made line assembling the easy way. That means that there is no edit possible. Backspace, delete, cursor keys and more and input as any other characters and doesn't work a a user would expect. You should take care of that.
Finally, I kept the code close to what you used. This code is single user. It accept a connection, accept commands from it and only accept a new connection once the first is closed. This is not normally the way to create a server program. To make it multiuser, you should use non-blocking socket and select() or use multi-threading.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#ifdef WIN32
#include <WinSock2.h>
#include <io.h>
typedef int socklen_t;
#pragma warning(disable : 4996) // No warning for deprecated function names such as read() and write()
#else
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define closesocket close
#endif
#define BUFSIZE 1024 // Buffer Size
#define TRUE 1
#define PORT 5678
int main(int argc, char *argv[])
{
#ifdef WIN32
int iResult;
WSADATA wsaData;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed: %d\n", iResult);
return 1;
}
#endif
int rfd; // Create-Descriptor
int cfd; // Connection-Descriptor (accept)
struct sockaddr_in client;
socklen_t client_len;
char in[BUFSIZE];
int bytes_read;
// 1. socket()
rfd = socket(AF_INET, SOCK_STREAM, 0);
if (rfd < 0) {
fprintf(stderr, "Error\n");
exit(-1);
}
// Initialize the server address by the port and IP
struct sockaddr_in server;
memset(&server, '\0', sizeof(server));
server.sin_family = AF_INET; // Internet address family: v4 address
server.sin_addr.s_addr = INADDR_ANY; // Server IP address
server.sin_port = htons(PORT); // Server port
// 2. bind()
int brt = bind(rfd, (struct sockaddr*)&server, sizeof(server));
if (brt < 0) {
fprintf(stderr, "Error\n");
exit(-1);
}
// 3. listen() = listen for connections
int lrt = listen(rfd, 5);
if (lrt < 0) {
fprintf(stderr, "Error\n");
exit(-1);
}
while (1) {
client_len = sizeof(client);
cfd = accept(rfd, (struct sockaddr*)&client, &client_len);
if (cfd < 0) {
fprintf(stderr, "accept failed with error %d\n", WSAGetLastError());
exit(-1);
}
printf("Client connected\n");
while (1) {
/*
// Send prompt to client
char* prompt = "> ";
if (send(cfd, prompt, strlen(prompt), 0) <= 0) {
fprintf(stderr, "send() failed with error %d\n", WSAGetLastError());
exit(1);
}
*/
// read a line from a socket (Client's data)
int bytes_idx = -1;
while (1) {
if (bytes_idx >= (int)sizeof(in)) {
fprintf(stderr, "input buffer overflow\n");
break;
}
// Receive on byte (character) at a time
bytes_read = recv(cfd, &in[++bytes_idx], 1, 0);
if (bytes_read <= 0) // Check error or no data read
break;
/*
printf("sending back the %d bytes I received...\n", bytes_read);
if (send(cfd, &in[bytes_idx], 1, 0) <= 0) {
fprintf(stderr, "send() failed with error %d\n", WSAGetLastError());
exit(1);
}
*/
if (in[bytes_idx] == '\n') {
// Received a complete line, including CRLF
// Remove ending CR
bytes_idx--;
if ((bytes_idx >= 0) && (in[bytes_idx] == '\r'))
in[bytes_idx] = 0;
break;
}
}
if (bytes_idx > 0) { // Check for empty line
printf("Received \"%s\"\n", in);
// Check for client command
if (stricmp(in, "exit") == 0)
break;
else {
printf("Client sent unknown command\n");
}
}
}
closesocket(cfd);
printf("Client disconnected\n");
}
closesocket(rfd);
#ifdef WIN32
WSACleanup();
#endif
}

How do I use both writefds and readfds for multiple client server communication program in C language?

I am currently trying to create a multiple client-server which enables server to perform both read and write functions in C language. I am able to read the data from the client using readfds and putting it as parameter in SELECT. When I added in writefds, the client fails to connect to the server. I am not sure what is the issue behind it, whether this is the correct method to transmit and receive data
This is the code for my server
#include <stdio.h>
#include <string.h> //strlen
#include <stdlib.h>
#include <errno.h>
#include <unistd.h> //close
#include <arpa/inet.h> //close
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h> //FD_SET, FD_ISSET, FD_ZERO macros
#define TRUE 1
#define FALSE 0
#define PORT 8080
int main(int argc , char *argv[])
{
int opt = TRUE;
int master_socket , addrlen , new_socket , client_socket[30] ,
max_clients = 2 , activity, i , valread , sd;
int max_sd;
struct sockaddr_in address;
char buffer[1025]; //data buffer of 1K
fd_set readfds;
fd_set writefds;
char *message = "Welcome to Server\r\n";
//initialise all client_socket[] to 0 so not checked
for (i = 0; i < max_clients; i++)
{
//client_socket[i] = 0;
}
//create a master socket
if( (master_socket = socket(AF_INET , SOCK_STREAM , 0)) == 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
if( setsockopt(master_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt,
sizeof(opt)) < 0 )
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
//type of socket created
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );
//bind the socket to localhost port 8888
if (bind(master_socket, (struct sockaddr *)&address, sizeof(address))<0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
printf("Listener on port %d \n", PORT);
if (listen(master_socket, 3) < 0)
{
perror("listen");
exit(EXIT_FAILURE);
}
addrlen = sizeof(address);
puts("Waiting for connections ...");
for(;;)
{
//clear the socket set
FD_ZERO(&readfds);
FD_ZERO(&writefds);
//add master socket to set
FD_SET(master_socket, &readfds);
FD_SET(master_socket, &writefds);
max_sd = master_socket;
//add child sockets to set
for ( i = 0 ; i < max_clients ; i++)
{
//socket descriptor
sd = client_socket[i];
//if valid socket descriptor then add to read list
if(sd > 0)
FD_SET( sd , &readfds);
//highest file descriptor number, need it for the select function
if(sd > max_sd)
max_sd = sd;
}
//wait for an activity on one of the sockets , timeout is NULL ,
//so wait indefinitely
activity = select( max_sd + 1 , &readfds , &writefds, NULL , NULL);
if ((activity < 0) && (errno!=EINTR))
{
printf("select error");
}
if (FD_ISSET(master_socket, &readfds))
{
if ((new_socket = accept(master_socket,
(struct sockaddr *)&address, (socklen_t*)&addrlen))<0)
{
perror("accept");
exit(EXIT_FAILURE);
}
else {
printf("Connected to socket \n");
}
bzero(buffer, 1025);
int n=0;
read(new_socket, buffer, sizeof(buffer));
printf("From client: %s\t To client: ", buffer);
bzero(buffer, 1025);
//add new socket to array of sockets
for (i = 0; i < max_clients; i++)
{
//if position is empty
if( client_socket[i] == 0 )
{
client_socket[i] = new_socket;
printf("Adding to list of sockets as %d\n" , i+1);
}
}
}
else if(FD_ISSET(master_socket, &readfds)) {
printf("From client: %s\t To client : ", buffer);
bzero(buffer, 1025);
// copy server message in the buffer
while ((buffer[n++] = getchar()) != '\n')
;
write(new_socket, buffer, sizeof(buffer));
}
else{
//else its some IO operation on some other socket
for (i = 0; i < max_clients; i++)
{
sd = client_socket[i];
if (FD_ISSET( sd , &readfds))
{
//Check if it was for closing , and also read the
//incoming message
if ((valread = read( sd , buffer, 1024)) == 0)
{
close( sd );
client_socket[i] = 0;
}
//Echo back the message that came in
else
{
}
}
}
}//else
}
return 0;
}
This is the code for the client
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#define MAX 1000
#define PORT 8080
#define SA struct sockaddr
void func(int sockfd)
{
char buff[MAX];
int n;
int firstConnect = 1;
for (;;)
{
bzero(buff, sizeof(buff));
n = 0;
if(firstConnect==1) {
printf("Enter the string : ");
firstConnect = 0;
while ((buff[n++] = getchar()) != '\n')
;
write(sockfd, buff, sizeof(buff));
}
bzero(buff, sizeof(buff));
read(sockfd, buff, sizeof(buff));
printf("From Server: %s\t To Server : ", buff);
while ((buff[n++] = getchar()) != '\n');
write(sockfd, buff, sizeof(buff));
if ((strncmp(buff, "exit", 4)) == 0)
{
printf("Client Exit...\n");
break;
}
}
}
int main()
{
printf("CLIENT");
int sockfd, connfd;
struct sockaddr_in servaddr, cli;
// socket create and varification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1)
{
printf("socket creation failed...\n");
exit(0);
}
else
printf("Socket successfully created..\n");
bzero(&servaddr, sizeof(servaddr));
// assign IP, PORT
servaddr.sin_family = AF_INET;
// servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
servaddr.sin_addr.s_addr = inet_addr("127.8.1.0");
servaddr.sin_port = htons(PORT);
// connect the client socket to server socket
if (connect(sockfd, (SA*)&servaddr, sizeof(servaddr)) != 0)
{
printf("connection with the server failed...\n");
exit(0);
}
else
printf("connected to the server..\n");
// function for chat
func(sockfd);
// close the socket
close(sockfd);
}
As side node, it appears that you expect read to zero-terminate received data. That is not the case. The length of received data is in the return value of read, it must not be ignored.
It also appears that you expect write to find the end of the string you are sending. That doesn't happen. You must specify the exact length of the data you are sending, rather than the length of the buffer that contains the data.
send/write and recv/read functions work on binary data rather than zero-terminated strings and can send/receive less than the specified size or may return an error. Learn how to use these functions correctly by not ignoring the return value and handling errors and partial reads and writes.

Communication: Sending a message from a client to a server

My Server can handle multiple clients/switches at a time.
My problem is in my switch I believe, I'm trying to send an open message to the the controller. I create the the tcp socket in the switch and then right after I try to send the message to the controller, however when I try to do this, the socket disconnects from the controller and goes into an infinite loop. I'm not sure why this occurs as I'm creating and sending the message outside of my while loop. If I comment where I send the message, the socket stays connected to the controller and I am able to wait for one of a set of file descriptors to become ready to perform I/O, currently I only have the keyboard and the socket. My socket also receives a message from the controller when it's connected "You are connected to the server". In addition since my switch socket disconnects my recv() return error code 107 due to the fact the socket is disconnected.
I'm not sure If I provided too much code to look through but I added comments where I thought my error was occurring in the switch as well as the controller. Greatly appreciated for some help. I didn't add any of my own header files because they are not necessary.
This where I execute the switch. Sends and receive messages here.
#include "switch.h"
#include "openFIFO.h"
#include "packets.h"
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<poll.h>
#include <signal.h>
void do_switch(int swIport, char *trafficfile,int swJport, int swKport, int IPlow, int IPhigh,char serverAddress[256], unsigned short portNumber){
int switch_sock;
char server_response[256];
struct pollfd pfds[6];
int rval;
/* Switch */
Switch sw;
sw.swJport = swJport;
sw.swIport = swIport;
sw.swKport = swKport;
sw.IPlow = IPlow;
sw.IPhigh = IPhigh;
int switchLength = sizeof(Switch);
// printf("\n\nstruct switchLength: %d\n", switchLength);
// printf("\n\nSwitch Struct: swIport: %d, swJport: %d, swKport: %d,
IPlow: %d, IPhigh: %d\n", sw.swIport, sw.swJport, sw.swKport, sw.IPlow,
sw.IPhigh);
printf("\n\nSwitch created with the following: swIport: %d, trafficfile:
%s, swJport: %d, swKport: %d, IPlow: %d, IPhigh: %d, serverAddress: %s,
portNumber: %d\n", swIport, trafficfile, swJport, swKport, IPlow, IPhigh,
serverAddress, portNumber);
int fifoWrite[2];
int fifoRead[2];
int counter = 0;
char message[20] = "Hello";
/* Create fifos */
if(swJport != -1){
fifoWrite[0] = openWF(swIport,swJport);
fifoRead[0] = openReadFifo(swJport, swIport);
counter = counter + 2;
}
if(swKport != -1){
fifoWrite[1] = openWF(swIport,swKport);
fifoRead[1] = openReadFifo(swKport, swIport);
counter = counter + 2;
}else if(swKport == -1){
fifoWrite[0] = openWF(swIport,swKport);
fifoRead[0] = openReadFifo(swKport, swIport);
counter = counter + 2;
}
printf("fifoWrite[0]: %d\n", fifoWrite[0]);
printf("fifoRead[0]: %d\n", fifoRead[0]);
printf("fifoWrite[1]: %d\n", fifoWrite[1]);
printf("fifoRead[1]: %d\n", fifoRead[1]);
/* Establish connection between the controller and switch */
/* Send a open packet to the controller */
/* Sending a stuct */
//PROBELM HERE BELOW!!!!!!!
switch_sock = CreateTCPClientSocket(portNumber, serverAddress);
if(send(switch_sock, message, sizeof(message), 0) == -1){
fprintf(stderr, "Send() Failed");
}
else{
printf("Open packet is being sent to the controller\n");
}
/* Initialize poll parameters */
//Keyboard
pfds[0].fd = STDIN_FILENO;
pfds[0].events = POLLIN;
// Socket!
pfds[1].fd = switch_sock;
pfds[1].events = POLLIN;
printf("Starting switch............................\n\n");
while(1){
rval = poll(pfds,2,-1);
if(rval == 0){
fprintf(stderr, "Poll timed out. \n");
}if(rval == -1){
fprintf(stderr, "ERROR: poll() failed");
exit(0);
}
/* Check Keyboard */
if(pfds[0].revents & POLLIN && pfds[0].fd == 0){
int a;
char command[1024][256];
int commands;
char buf[256];
commands = read(0, buf, 256);
buf[commands] = '\0';
buf[commands] = '\0';
char *token;
token = strtok(buf, " ");
while(token != NULL){
strcpy(command[a], token);
a++;
token = strtok(NULL, " ");
}
a = 0;
bzero(buf, 256);
if(strcmp(command[0], "list") == 0){
//TODO: Make a print function
printf("print_switch()\n");
}
if(strcmp(command[0], "exit") == 0){
//TODO: Make a print function
printf(" print_switch()\n");
printf("switch-disconnected\n");
close(switch_sock);
exit(0)
}
}
/* Server sent a welcome message */
// Might be PROBELM HERE BELOW when trying to send the initial packet to
controller!!!!!!!
if(pfds[1].revents & POLLIN){
recv(switch_sock, &server_response, sizeof(server_response), 0);
printf("%s\n", server_response);
}
}
}
Creates a TCP Socket for the switch.
int CreateTCPClientSocket( unsigned short port, char *serverAddress){
int sock; /*socket to create */
struct sockaddr_in servAddr; /* Local address */
/* Construct local address structure */
/* Create socket for incoming connections */
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0){
fprintf(stderr,"ERROR: socket() failed\n");
exit(0);
}
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(port);
servAddr.sin_addr.s_addr = inet_addr(serverAddress);
if(connect(sock, (struct sockaddr *)&servAddr, sizeof(struct sockaddr)) <
0){
printf("Error code: %d\n", errno);
fprintf(stderr, "ERROR: connect() just failed\n");
exit(0);
}
return sock;
}
This is the controller
#include "controller.h"
#include "packets.h"
#include "switch.h"
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
void do_controller(int nSwitch, int portNumber){
int controller_sock; /* Socket descriptor for server/controller */
int clnSocket; /*Socket descriptor for clients */
int activity;
int max_sd;
int sd;
int client_socket[nSwitch];
struct sockaddr_in address;
int addrlen;
/* Controller stuff */
Controller cont;
cont.ackCounter = 0;
cont.openCounter = 0;
Switch sw;
char message[256] = "You have reached the server\n";
char recv_message[20];
printf("\n\nController created: nSwitch: %d on portNumber: %d\n", nSwitch, portNumber);
/* Initialise all client_socket[] to 0 so not checked */
for(int i = 0; i < nSwitch; i++){
client_socket[i] = 0;
}
/*Create the server/controller socket */
controller_sock = CreateTCPServerSocket(portNumber);
//addrlen = sizeof(address);
/* Prepare for nonblocking I/O polling/select from the controller socket */
printf("Starting server.........\n\n");
while(1){
/* Zero the socket set and set for server sockets */
/* This must be reset every time select() is called */
/* Add keyboard to descriptor */
/* Add client and controller sockets to set */
FD_ZERO(&sockSet);
FD_SET(STDIN_FILENO, &sockSet);
FD_SET(controller_sock, &sockSet);
max_sd = controller_sock;
//max_sd = 0;
printf("nSwitch: %d\n", nSwitch);
for(int x = 0; x < nSwitch; x++){
sd = client_socket[x];
printf("sd: %d\n\n", sd);
if(sd > 0)
FD_SET(sd, &sockSet);
if(sd > max_sd)
max_sd = sd;
}
printf("max_sd: %d\n", max_sd);
//wait for one of the sockets, timeout is Null,
//so wait indefinitely
activity = select(max_sd + 1, &sockSet, NULL, NULL,NULL);
//printf("Activity: %d\n", activity);
if(activity < 0){
fprintf(stderr, "ERROR: select()\n");
exit(0);
}
/*Check keyboard */
if(FD_ISSET(STDIN_FILENO, &sockSet)){
int a;
char command[1024][256];
int commands;
char buf[256];
commands = read(0, buf, 256);
buf[commands] = '\0';
char *token;
token = strtok(buf, " ");
while(token != NULL){
strcpy(command[a], token);
a++;
token = strtok(NULL, " ");
}
a = 0;
bzero(buf, 256);
if(strcmp(command[0], "list") == 0){
//TODO: Make a print function
print_controller(&cont, nSwitch);
}
if(strcmp(command[0], "exit") == 0){
//TODO: Make a print function
print_controller(&cont, nSwitch);
exit(0);
}
continue;
}
/* Check the incoming FIFOS from the controller an attached switches */
/*If something happened on the controller socket,
then its an incomming connection. Accept new communitcation.Wait for a client to connect.
Recieve packets sent to the controller_sock
*/
if(FD_ISSET(controller_sock, &sockSet)){
clnSocket = AcceptTCPConnection(controller_sock);
if(send(clnSocket, message, sizeof(message), 0) != sizeof(message)){
fprintf(stderr, "Send()");
exit(0);
}
puts("Welcome message sent successfuly");
//PROBELM HERE BELOW!!!!!!! Returns error code 107 because the
socket disconnected.
recv(controller_sock, &recv_message, sizeof(recv_message), 0);
printf("This is my recv_message: %s\n", recv_message);
/*add new socket to array of sockets*/
for(int a = 0; a < nSwitch; a++){
/*if position is empty */
if(client_socket[a] == 0){
client_socket[a] = clnSocket;
printf("Adding to list of sockets as %d\n", client_socket[a]);
break;
}
}
}
/* Communicate with the sockets and handle TCP Client */
for(int z = 0; z <nSwitch; z++){
sd = client_socket[z];
/*Check if it was socket closed, and do other stuff */
if(FD_ISSET(sd ,&sockSet )){
getpeername(sd , (struct sockaddr*)&address , (socklen_t*)&addrlen);
printf("Host disconnected , ip %s , port %d \n" , inet_ntoa(address.sin_addr) , ntohs(address.sin_port));
close( sd );
client_socket[z] = 0;
}else{
//Do stuff for the client
printf("This is the client %d\n", sd);
}
}
}
}
These are the controllers functions: Assign a port to socket,Set socket to listen
int AcceptTCPConnection(int servSock){
int clntSock; /* Socket descriptor for client */
unsigned int clientAddressLen; /* sizeof(client_address); Length of client */
struct sockaddr_in cli_addr; /* Client address */
/* Set the size of the in-out parameter */
clientAddressLen = sizeof(cli_addr);
printf("ClientAddressLen: %x\n", clientAddressLen);
/* Wait for a client to connect */
if ((clntSock = accept(servSock, (struct sockaddr *) &cli_addr,
&clientAddressLen)) < 0){
fprintf(stderr, "ERROR: accept failed\n");
exit(0);
}
/* clntSock is connected to a client! */
//infrom user of socket number used in send and receive commands
printf("Handling client %s\n", inet_ntoa(cli_addr.sin_addr));
printf("New connection: socket fd is: %d, ip is: %s, port: %d\n\n",
clntSock, inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
return clntSock;
}
Create a TCP socket
int CreateTCPServerSocket(unsigned short port){
int sock; /* socket to create */
struct sockaddr_in servAddr; /* Local address */
/* Create socket for incoming connections */
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0){
fprintf(stderr,"ERROR: socket() failed\n");
exit(0);
}
/* Construct local address structure */
/* Define the server address */
//bzero((char *) &server_address, sizeof(server_address));
memset(&servAddr, 0, sizeof(servAddr)); /* Zero out structure */
servAddr.sin_family = AF_INET; /* Internet address family
*/
servAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface
*/
servAddr.sin_port = htons(port); /* Local port */
/* Bind to the local address */
printf("New connection: ip is: %s, port: %d\n\n",
inet_ntoa(servAddr.sin_addr), ntohs(servAddr.sin_port));
if (bind(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0){
printf("Error code: %d\n", errno);
fprintf(stderr,"ERROR: bind() just failed\n");
exit(0);
}
/* Mark the socket so it will listen for incoming connections */
if (listen(sock, 5) < 0){
fprintf(stderr,"ERROR: listen() failed\n");
exit(0);
}
return sock;
}

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).

C: epoll port forwarding proxy doesn't forward all data

I have got this code and I'm trying to use it as a part of my project. The details of the project are not important for now, but what I'm trying to do is to use this port forwarding proxy as proxy between the browser and the local http server.
So if I type http: //127.0.0.1:8999/ in my browser I want to get web page from 127.0.0.1:8888 back. This only works for small web pages (no images, small html files,...). When I try to do this on webpage with a few images, they don't get transmitted or are transmitted only partially.
I have also tested with telnet and a web site with a big html file. I have connected to the proxy and send the HEAD method request. I got all the meta-data, as expected. When I tried GET method I got only part of the web page's html file back.
Could anyone point me in the right direction? I'm really not sure what I am doing wrong.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <errno.h>
#include <signal.h>
#include <assert.h>
#define FALSE 0
#define TRUE 1
#define EPOLL_QUEUE_LEN 256
#define SERVER_PORT 7000
#define LISTEN_PORT 8667 // Proxy Server Listens for this port
#define FORWARD_PORT 8888 // Proxy Server forwards all port LISTEN_PORT data to this port
#define BUFLEN 1024
//Globals
int fd_server;
int sent = 0; // for how many requests were processed to client
int forwardSockets[EPOLL_QUEUE_LEN];
int internalSockets[EPOLL_QUEUE_LEN];
// Function prototypes
static void SystemFatal (const char* message);
static int forwardData (int fd);
void close_fd (int);
// This is the main function which handles the epoll loop and
// accepts connections
// Also handles the data processing back to the client.
int main (int argc, char* argv[])
{
int i, arg, src_port, forwardSD, dest_port;
int num_fds, fd_new, epoll_fd;
int linenum=0;
static struct epoll_event events[EPOLL_QUEUE_LEN], event;
struct sockaddr_in addr, remote_addr;
socklen_t addr_size = sizeof(struct sockaddr_in);
struct sigaction act;
struct hostent *hp;
struct sockaddr_in server_fwd;
char *host;
char line[256], ip[256];
FILE *fp;
fp=fopen("port_forward_config", "r");
//src_port = LISTEN_PORT; // Use the default listen port
while(fgets(line, 256, fp) != NULL)
{
linenum++;
if(line[0] == '#') continue;
sscanf(line, "%s %d %d", &ip, &src_port, &dest_port);
{
fprintf(stderr, "Syntax error, line %d\n", linenum);
continue;
}
}
printf("Reading Config File...\n");
printf("IP %s LPORT %d DPORT %d\n", ip, src_port, dest_port);
host = ip;
// set up the signal handler to close the server socket when CTRL-c is received
act.sa_handler = close_fd;
act.sa_flags = 0;
if ((sigemptyset (&act.sa_mask) == -1 || sigaction (SIGINT, &act, NULL) == -1))
{
perror ("Failed to set SIGINT handler");
exit (EXIT_FAILURE);
}
//--------------------------------------------------------------------------------------------
// Create the listening socket
fd_server = socket (AF_INET, SOCK_STREAM, 0);
if (fd_server == -1)
{
SystemFatal("socket");
}
// set SO_REUSEADDR so port can be resused imemediately after exit, i.e., after CTRL-c
arg = 1;
if (setsockopt (fd_server, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)) == -1)
{
SystemFatal("setsockopt");
}
// Make the server listening socket non-blocking
if (fcntl (fd_server, F_SETFL, O_NONBLOCK | fcntl (fd_server, F_GETFL, 0)) == -1)
{
SystemFatal("fcntl");
}
// Bind to the specified listening port
memset (&addr, 0, sizeof (struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(src_port);
if (bind (fd_server, (struct sockaddr*) &addr, sizeof(addr)) == -1)
{
SystemFatal("bind");
}
// Listen for fd_news; SOMAXCONN is 128 by default
if (listen (fd_server, SOMAXCONN) == -1)
{
SystemFatal("listen");
}
//---------------------------------------------------------------------------------------------
// Create the epoll file descriptor
epoll_fd = epoll_create(EPOLL_QUEUE_LEN);
if (epoll_fd == -1)
{
SystemFatal("epoll_create");
}
// Add the server socket to the epoll event loop
event.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLET;
event.data.fd = fd_server;
if (epoll_ctl (epoll_fd, EPOLL_CTL_ADD, fd_server, &event) == -1)
{
SystemFatal("epoll_ctl");
}
// Execute the epoll event loop
while (TRUE)
{
//struct epoll_event events[MAX_EVENTS];
num_fds = epoll_wait (epoll_fd, events, EPOLL_QUEUE_LEN, -1);
if (num_fds < 0)
{
SystemFatal ("Error in epoll_wait!");
}
for (i = 0; i < num_fds; i++)
{
// Case 1: Error condition
if (events[i].events & (EPOLLHUP | EPOLLERR))
{
fputs("epoll: EPOLLERR", stderr);
//close(events[i].data.fd);
continue;
}
assert (events[i].events & EPOLLIN);
//-----------------------------------------------------------------------------------------
// Case 2: Server is receiving a connection request
if (events[i].data.fd == fd_server)
{
//socklen_t addr_size = sizeof(remote_addr);
fd_new = accept (fd_server, (struct sockaddr*) &remote_addr, &addr_size);
if (fd_new == -1)
{
if (errno != EAGAIN && errno != EWOULDBLOCK)
{
perror("accept");
}
continue;
}
//------------------------------------------------------------------------------------------------
// Make the fd_new non-blocking
if (fcntl (fd_new, F_SETFL, O_NONBLOCK | fcntl(fd_new, F_GETFL, 0)) == -1)
{
SystemFatal("fcntl");
}
// Add the new socket descriptor to the epoll loop
event.data.fd = fd_new;
if (epoll_ctl (epoll_fd, EPOLL_CTL_ADD, fd_new, &event) == -1)
{
SystemFatal ("epoll_ctl");
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
printf(" Remote Address: %s\n", inet_ntoa(remote_addr.sin_addr));
//close(fd_new);
dest_port = FORWARD_PORT; // Used the default forward port
// create internal connection
printf("Trying to create forward socket\n");
if ((forwardSD = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("Cannot create forward socket.");
exit(1);
}
printf("Binding...\n");
bzero((char *)&server_fwd, sizeof(struct sockaddr_in));
server_fwd.sin_family = AF_INET;
server_fwd.sin_port = htons(dest_port);
//host = "192.168.0.10";
if ((hp = gethostbyname(host)) == NULL) {
printf("Failed to get host name");
}
bcopy(hp->h_addr, (char *)&server_fwd.sin_addr, hp->h_length);
printf("Connecting to interal machine.\n");
printf("Server Forward Port: %d\n", ntohs(server_fwd.sin_port));
printf("Server Forward IP: %s\n", inet_ntoa(server_fwd.sin_addr));
// Connecting to interal machine
if (connect (forwardSD, (struct sockaddr *)&server_fwd, sizeof(server_fwd)) == -1) {
perror("connect failed");
exit(1);
}
// Add the new socket descriptor to the epoll loop
event.data.fd = forwardSD;
if (epoll_ctl (epoll_fd, EPOLL_CTL_ADD, forwardSD, &event) == -1)
{
SystemFatal ("epoll_ctl");
}
printf ("Connected: Server: %s\n", hp->h_name);
forwardSockets[fd_new] = forwardSD;
internalSockets[forwardSD] = fd_new;
// end internal connection
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
continue;
}
// Case 3: One of the sockets has read data
if (!forwardData(events[i].data.fd))
{
// epoll will remove the fd from its set
// automatically when the fd is closed
close (events[i].data.fd);
}
}
}
close(fd_server);
exit (EXIT_SUCCESS);
}
/*
This function clears a socket if it has data waiting to be processed.
It takes the string sent from the client and parses it. After it has
done that it will send back to the client the amount of data it requested
for however many requests it defined as well.
*/
static int forwardData (int fd)
{
int n, bytes_to_read;
char *bp, buf[BUFLEN];
int forwardData;
printf ("Forwarding :\n");
//check if internal or external connection to send data back to.
if(forwardSockets[fd] != 0){
forwardData = forwardSockets[fd];
}
if(internalSockets[fd] != 0){
forwardData = internalSockets[fd];
}
bp = buf;
bytes_to_read = BUFLEN;
while ((n = recv (fd, bp, bytes_to_read, 0)) > 0) {
bp += n;
bytes_to_read -= n;
send (forwardData, buf, n, 0);
return TRUE;
}
return TRUE;
}
// Prints the error stored in errno and aborts the program.
static void SystemFatal(const char* message)
{
perror (message);
exit (EXIT_FAILURE);
}
// close fd
void close_fd (int signo)
{
close(fd_server);
exit (EXIT_SUCCESS);
}
It seems like you're using the EPOLLET (edge triggered) flag in all of your epoll events. This flag will cause epoll to only return events when a file descriptor changes from unavailable to available.
Furthermore, in your forwardData function, you receive BUFLEN bytes and then return TRUE. If there are more bytes available, you will never forward them, as your events are edge triggered and will not be resent.
Try modifying forwardData (perhaps remove the return TRUE in the loop) so that all readable data is forwarded before returning.

Resources