// blablabla #include <unistd.h> #include <stdio.h> #include <sys/types.h> #include <sys/epoll.h> #include <errno.h> #include <netinet/in.h> #include <sys/socket.h> #include <pthread.h> #include <stdlib.h> #include <fcntl.h> #include <signal.h> #include <sys/stat.h> #include <string.h>
// port to listen to, connection limit, maximum number of threads #define PORT 1800 #define MAXCONN 100 #define MAXTHREADS 10 #define MAXBUF 20000 //socket buffer size
// external program char *EXTERNAL_BIN="/usr/games/fortune";
int sd=-1; // listening socketfd
// connection table struct contable { int fd; //filedes unsigned long peer; //peer inet addr, unused char *buf; // socket buffer char *buf1; // mini socket buffer '> } *ctab[MAXCONN];
int cti=1; //global connection count
// threads struct table struct thstable { int epfd; // epoll fd pthread_t pth; //thread int lock; // a primitive lock - unused } ttab[MAXTHREADS];
int tti=MAXTHREADS; // the number of spawned threads (by default=MAXTHREADS) struct epoll_event *ev[MAXTHREADS]; //epoll events
// remove connection from table void conn_remove(int id, int tid) { if (cti==1) {} if (cti>=2) {
// delete from events pool, close socket ev[tid]->events = EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP; epoll_ctl(ttab[tid].epfd,EPOLL_CTL_DEL,ctab[id]->fd, ev[tid] ); close(ctab[id]->fd); #ifdef DEBUG printf("Client fd #%d closing connection,cti=%d\n",ctab[id]->fd,cti); #endif
//table-related bs ctab[id]->fd=ctab[cti]->fd; strcpy(ctab[id]->buf,ctab[cti]->buf); bzero(ctab[cti]->buf,MAXBUF); cti--; } }
// parse request - very lame void parse(int id, int tid) { char *str=malloc(150); char *str1=malloc(150); char *buf=malloc(1024); FILE *outp; int a=0; pid_t pid;
// VERY VERY LAME!!! if ( strstr(ctab[id]->buf,"\r\n") ) if ( (strstr(ctab[id]->buf,"text/html")) || (strstr(ctab[id]->buf,"text/html")) || (strstr(cta b[id]->buf,"text/html"))) { sprintf(str,"/var/tmp/mypr-np-%d",id); outp=fopen(str,"r"); a=1; sprintf(str1,"%s > %s",EXTERNAL_BIN,str);
sprintf(buf,"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<html><head><title>%s output</title></head><body><center><b><h2>%s output:</center></h2><br><br><center><table height=100% width= 100%><tr align=center valign=top><td><table height=50% width=50% border=1><tr valign=middle align=cent er><td bgcolor=lightyellow>\n",EXTERNAL_BIN,EXTERNAL_BIN); write(ctab[id]->fd,buf,strlen(buf)); system(str1); usleep(1000); while (feof(outp)==0) { if (fgets(buf,1024,outp)) { write(ctab[id]->fd,buf,strlen(buf)); } } close(outp); sprintf(buf,"</td></tr></table></td></tr></table></body></html>\n");
conn_remove(id,tid); }
free(buf);free(str);free(str1); }
// this actually performs the socket I/O void serve(int fd, int tid) { int len,a; int id=0;
// find our conntab entry for (a=1;a<=cti;a++) if (ctab[a]->fd==fd) id=a; if (id==0) {printf("Socket error?!?\n");exit(1);} bzero(ctab[id]->buf1,MAXBUF/10); // read from socket for (a=1;a<=100;a++) { len=read(fd,ctab[id]->buf1,MAXBUF/10); if (len>0) goto cont; usleep(1000); } cont: if (len>0) { strcat(ctab[id]->buf,ctab[id]->buf1); parse(id,tid); } // socket closed? if (len==0) { conn_remove(id,tid); }
}
// wait for socket event and transfer it to serve() void workthread(int num) { int nfds,a,b,fd;
while (1) { out: nfds = epoll_wait(ttab[num].epfd, ev[num],tti,1); usleep(5000); if (nfds < 0) { #ifdef DEBUG printf("Epoll confusion, LOL! '>\n"); #endif goto out; } for (a=1;a<=nfds;a++) { fd=ev[num]->data.fd; if (fd>0) serve(fd,num); } } }
// Another thread designed to terminate incoming connections void listener_thread(void *arg) {
int a=1; struct timeval tv; int len,client; struct sockaddr_in addr; int addrlen = sizeof(addr); int flags;
while (1) { // sleep a little usleep(5000);
// accept connection. fd>=4 means most certainly this is a socket fd client = accept(sd, (struct sockaddr*)&addr, &addrlen); if ((client>=4)&&(addrlen>0)) {
// socket timeouts setting tv.tv_usec=5; tv.tv_sec=0; setsockopt( client, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv) );
// make the newly accepted socket non-blocking.. if ((flags = fcntl(client, F_GETFL, 0)) < 0) { perror("fcntl"); } if (fcntl(client, F_SETFL, flags | O_NONBLOCK) < 0) { perror("fcntl"); }
#ifdef DEBUG printf("Connected: %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); #endif if (cti == MAXCONN) {close(client);} // EXAMPLE OF BAD CONNECTION LIMIT HANDLING!!! else { // tables & epoll bs if (cti>1) cti++; a++; if (a==tti) a=1; ctab[cti]->fd=client; ctab[cti]->peer=addr.sin_addr.s_addr; ev[a]->events = EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP; ev[a]->data.fd=client; epoll_ctl(ttab[a].epfd,EPOLL_CTL_ADD,client, ev[a] ); if (cti==1) cti++; } } } }
// main function int main() {
// socket-related vars struct sockaddr_in addr; int addrlen = sizeof(addr); int flags; struct timeval tv; int len,client,a; // listener thread pthread_t listener;
printf("server starting..\n"); // SIGPIPE suck in a threaded app '> signal( SIGPIPE , SIG_IGN ); // Init Serversocket if ( (sd = socket(PF_INET, SOCK_STREAM, 0)) < 0 ) perror("Socket"); flags=1; // Socket is to be reused (avoid stupid bind:already in use errors) setsockopt( sd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags) ); // bind(), listen() addr.sin_family = AF_INET; addr.sin_port = htons(PORT); addr.sin_addr.s_addr = INADDR_ANY;
if ( bind(sd, (struct sockaddr*)&addr, addrlen) < 0 ) {perror("bind");abort();} if ( listen(sd, MAXCONN) < 0 ) perror("listen"); // non-blocking server socket if ((flags = fcntl(sd, F_GETFL, 0)) < 0) { perror("fcntl"); }
if (fcntl(sd, F_SETFL, flags | O_NONBLOCK) < 0) { perror("fcntl"); } printf("init threads"); // Init worker threads.. for (a=1;a<=tti;a++) { ev[a]=malloc(300); pthread_create(&ttab[a].pth, NULL, workthread, a); ttab[a].epfd=epoll_create(MAXCONN/tti); ttab[a].lock=ttab[a].lock=0; printf("."); } printf("OK!\n");
// Init listener thread pthread_create(&listener, NULL, listener_thread,"");
// Init connection table.. for (a=1;a<=MAXCONN;a++) { ctab[a]=malloc(sizeof(int)*4); ctab[a]->buf=malloc(MAXBUF); bzero(ctab[a]->buf,MAXBUF); ctab[a]->buf1=malloc(MAXBUF/10); bzero(ctab[a]->buf1,MAXBUF/10); ctab[a]->fd=0; }
// wait for listener thread to finish.. pthread_join(listener,NULL); return 0; }
|