/* global includs and libraries */
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <netdb.h>
#include <time.h>
#include <signal.h>
/* global constants and defines */
#define MAX_CLIENT 8192
#define MAX_BUFFER 4096
#define NUM_PORT 0
/*
On exit procedure.
*/
void exiterr(const char* szMsg)
{
fprintf(stderr, "%s\n", szMsg);
exit(-1);
}
/*
Make the process a daemon.
*/
void Daemonize(void)
{
pid_t pid, sid;
/* already a daemon */
if ( getppid() == 1 ) return;
/* Fork off the parent process */
pid = fork();
if (pid < 0) {
exit(1);
}
/* If we got a good PID, then we can exit the parent process. */
if (pid > 0) {
exit(0);
}
/* At this point we are executing as the child process */
/* Change the file mode mask */
umask(0);
/* Create a new SID for the child process */
sid = setsid();
if (sid < 0) {
exit(1);
}
/* Change the current working directory. This prevents the current
directory from being locked; hence not being able to remove it. */
if ((chdir("/")) < 0) {
exit(1);
}
/* Redirect standard files to /dev/null */
freopen("/dev/null", "r", stdin);
freopen("/dev/null", "w", stdout);
freopen("/dev/null", "w", stderr);
}
/*
Client Thread. Each client is executed on its own thread.
Continueously read and serve client until it closes the connection.
*/
void* ServeClientThread(void* pArg)
{
pthread_detach(pthread_self());
/* This is the critical section object (statically allocated). */
static pthread_mutex_t cs_mutex = PTHREAD_MUTEX_INITIALIZER;
int paddrlen;
int* pclientsd = (int*) pArg;
int clientsd = pclientsd[0];
char buffer[MAX_BUFFER];
struct sockaddr_in clientsock;
struct hostent *phe;
struct in_addr addr;
paddrlen = sizeof(clientsock);
// get client port number
if (getpeername(clientsd, (struct sockaddr*) &clientsock, &paddrlen) < 0)
return NULL;
// get client doman name
if ((phe = gethostbyaddr((char*) &clientsock.sin_addr, sizeof(clientsock.sin_addr), AF_INET)) == NULL)
return NULL;
// get client ip address
addr.s_addr = *(u_long*) phe->h_addr_list[0];
printf("Client Connected: [%d][%s][%s][%d]\n", clientsd, phe->h_name, inet_ntoa(addr), ntohs(clientsock.sin_port));
while (1)
{
memset(buffer, 0, sizeof(buffer));
recv(clientsd, buffer, sizeof(buffer), 0);
if (strlen(buffer) == 0)
break;
/* Enter the critical section -- other threads are locked out */
pthread_mutex_lock( &cs_mutex );
/* Do some thread-safe processing! */
printf("%d:%s", clientsd, buffer);
/*Leave the critical section -- other threads can now pthread_mutex_lock() */
pthread_mutex_unlock( &cs_mutex );
}
printf("Closed: [%d]\n", clientsd);
close(clientsd);
pthread_exit(NULL);
}
/*
Main Driver Routine
*/
int main(int argc, char* argv[])
{
int sd, err, clientsd, paddrlen;
int paramlist[1];
pthread_t tid;
struct sockaddr_in localsock;
struct sockaddr_in remotesock;
// cancel certain signals
signal(SIGINT, SIG_IGN);
signal(SIGPIPE, SIG_IGN);
signal(SIGTERM, SIG_IGN);
// setup local socket
memset(&localsock, 0, sizeof(localsock));
localsock.sin_family = AF_INET;
localsock.sin_addr.s_addr = INADDR_ANY;
localsock.sin_port = htons(NUM_PORT);
// create a socket
if ((sd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
exiterr("Error: socket()");
// bind to socket
if (bind(sd, (struct sockaddr*) &localsock, sizeof(localsock)) < 0)
exiterr("Error: bind()");
paddrlen = (int) sizeof(remotesock);
// get socket name
if (getsockname(sd, (struct sockaddr*) &remotesock, &paddrlen) < 0)
exiterr("Error: getsockname()");
// listen on socket
if (listen(sd, MAX_CLIENT) < 0)
exiterr("Error: listen()");
printf("TCP Multi-threaded Server online. Port number: %d\n", ntohs(remotesock.sin_port));
while (1)
{
// acccept incomming client connection
paramlist[0] = clientsd = accept(sd, (struct sockaddr*) &remotesock, &paddrlen);
// serve each client with its own thread
pthread_create(&tid, NULL, (void*) ServeClientThread, (void*) paramlist);
// pthread_join(tid, NULL);
// close(clientsd);
}
return 0;
}