/*********************************************************************************
* File Name : thread_server.c
*---------------------------------------------------------------------------------
* 간단한 쓰레드 서버
*---------------------------------------------------------------------------------
* gcc -o thread_server thread_server.c -lthread -lsocket -lnsl
*********************************************************************************/
#include <netdb.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <time.h>
#include <signal.h>
#include <thread.h>
#include <string.h>
#include <errno.h>
union sock
{
struct sockaddr s;
struct sockaddr_in i;
};
#define SMAX 15
struct scorebd
{
time_t tevent;
thread_t thread;
int sig;
} scorebd[SMAX];
mutex_t sb_lock;
thread_t thr_master;
void *handling(void *);
void handto();
void *timing(void *);
void timer();
void master();
void reqto(int);
int sigtype();
void thr_reg();
void thr_unreg();
main(int argc,char *argv[])
{
int port;
union sock sock,work;
int wsd,sd;
int addlen;
struct sigaction siginfo;
int i,rv,nrv;
if(argc != 2) exit(1);
else port = atoi(argv[1]); /* 첫번째 아규먼트로 포트 설정 */
sigemptyset(&(siginfo.sa_mask));
sigaddset(&(siginfo.sa_mask),SIGHUP);
sigaddset(&(siginfo.sa_mask),SIGALRM);
sigprocmask(SIG_SETMASK,&(siginfo.sa_mask),NULL);
if(thr_create(NULL,0,timing,NULL,0,NULL) == -1)
{
perror("Creating timing thread");
exit(2);
}
thr_master = thr_self();
sigemptyset(&(siginfo.sa_mask));
sigaddset(&(siginfo.sa_mask),SIGUSR1);
thr_sigsetmask(SIG_UNBLOCK,&(siginfo.sa_mask),NULL);
siginfo.sa_handler = master;
siginfo.sa_flags = 0;
sigaction(SIGUSR1,&siginfo,NULL);
if((sd = socket(AF_INET,SOCK_STREAM,0)) == -1)
{
perror("No socket");
exit(1);
}
sock.i.sin_family = AF_INET;
sock.i.sin_port = port;
sock.i.sin_addr.s_addr = INADDR_ANY;
if(bind(sd,&(sock.s),sizeof(struct sockaddr)) == -1)
{
perror("Bad Bind");
exit(1);
}
if(listen(sd,5) == -1)
{
perror("Bad listen");
exit(1);
}
while(1)
{
wsd = accept(sd,&(work.s),&addlen);
thr_create(NULL,0,handling,&wsd,0,NULL);
}
}
void *timing(void *arg)
{
struct sigaction siginfo;
sigemptyset(&(siginfo.sa_mask));
sigaddset(&(siginfo.sa_mask),SIGALRM);
sigaddset(&(siginfo.sa_mask),SIGHUP);
siginfo.sa_handler = timer;
siginfo.sa_flags = 0;
thr_sigsetmask(SIG_UNBLOCK,&(siginfo.sa_mask),NULL);
sigaction(SIGALRM,&siginfo,NULL);
sigaction(SIGHUP,&siginfo,NULL);
alarm(1);
while(1)
{
pause();
thr_yield();
}
}
void timer(int sig)
{
int i,n;
time_t now;
time(&now);
mutex_lock(&sb_lock);
for(i=0;i<SMAX;i++)
{
if(scorebd[i].thread)
{
if(sig == SIGHUP)
{
scorebd[i].sig = SIGHUP;
thr_kill(scorebd[i].thread,SIGUSR1);
}
else if(sig == SIGALRM)
{
if(scorebd[i].tevent < now)
{
scorebd[i].sig = SIGALRM;
thr_kill(scorebd[i].thread,SIGUSR1);
}
}
}
}
if(sig == SIGHUP) thr_kill(thr_master,SIGUSR1);
mutex_unlock(&sb_lock);
alarm(1);
return;
}
void *handling(void *sd)
{
int nrv,wsd;
int i;
char buff[BUFSIZ];
FILE *logfp = NULL;
struct sigaction siginfo;
thread_t me;
wsd = *(int *)sd;
me = thr_self();
sigemptyset(&(siginfo.sa_mask));
sigaddset(&(siginfo.sa_mask),SIGUSR1);
thr_sigsetmask(SIG_UNBLOCK,&(siginfo.sa_mask),NULL);
siginfo.sa_handler = handto;
siginfo.sa_flags = 0;
sigaction(SIGUSR1,&siginfo,NULL);
thr_reg();
while(1)
{
reqto(20);
nrv = read(wsd,buff+i,BUFSIZ-i);
if(nrv > 0)
{
char *crlfp;
int fraglen;
i += nrv;
buff[i] = '\0';
if(crlfp=strstr(buff,"\r\n"))
{
*crlfp = '\0';
if(logfp == NULL)
{
logfp = fopen(buff,"w");
if(logfp == NULL)
{
close(wsd);
return;
}
}
else fprintf(logfp,"%s\n",buff);
fraglen = (buff+i)-(crlfp+2);
if(fraglen)
{
strcpy(buff,crlfp+2);
i = fraglen;
}
else i = 0;
}
}
else if (nrv == 0)
{
close(wsd);
fclose(logfp);
thr_unreg();
return;
}
else if(nrv < 0)
{
switch(sigtype(me))
{
case SIGALRM :
write(wsd,"Timed out - bye\r\n",17);
break;
case SIGHUP :
write(wsd,"Closing down - bye\r\n",20);
break;
}
close(wsd);
fclose(logfp);
thr_unreg();
return;
}
} /* while */
}
void reqto(int dt)
{
time_t now;
thread_t me;
int i;
time(&now);
me = thr_self();
mutex_lock(&sb_lock);
for(i=0;i<SMAX;i++)
{
if(scorebd[i].thread == me)
{
scorebd[i].tevent = now + dt;
break;
}
}
if(i == SMAX) abort();
mutex_unlock(&sb_lock);
}
int sigtype()
{
thread_t me;
int i,rv = 0;
me = thr_self();
mutex_lock(&sb_lock);
for(i=0;i<SMAX;i++)
{
if(scorebd[i].thread == me)
{
rv = scorebd[i].sig;
scorebd[i].sig = 0;
break;
}
}
mutex_unlock(&sb_lock);
return rv;
}
void thr_reg()
{
thread_t me;
int i;
me = thr_self();
mutex_lock(&sb_lock);
for(i=0;i<SMAX;i++)
{
if(scorebd[i].thread == 0)
{
scorebd[i].thread = me;
break;
}
}
if(i==SMAX) abort();
mutex_unlock(&sb_lock);
return;
}
void thr_unreg()
{
thread_t me;
int i;
me = thr_self();
mutex_lock(&sb_lock);
for(i=0;i<SMAX;i++)
{
if(scorebd[i].thread == me)
{
scorebd[i].thread = 0;
break;
}
}
if(i == SMAX) abort();
mutex_unlock(&sb_lock);
return;
}
void handto(int sig)
{
return;
}
void master(int sig)
{
int i;
mutex_lock(&sb_lock);
for(i=0;i<SMAX;i++)
{
if(scorebd[i].thread) thr_join(scorebd[i].thread,NULL,NULL);
}
mutex_unlock(&sb_lock);
exit(0);
}