Main Page | Class Hierarchy | Class List | File List | Class Members

wserver.cc

00001 #include <signal.h>
00002 #include "sstuff.hh"
00003 #include <vector>
00004 #include "mtasker.hh"
00005 #include "misc.hh"
00006 
00007 
00009 struct WSEvent
00010 {
00011   enum {Read,Write} what;
00012   Socket *who;
00013 };
00014 
00015 /* We need to provide this operator because MTasker orders event keys */
00016 bool operator<(const WSEvent &a, const WSEvent &b)
00017 {
00018   if(a.what<b.what)
00019     return true;
00020   if(a.what>b.what)
00021     return false;
00022 
00023   if(a.who<b.who)
00024     return true;
00025   return false;
00026 }
00027 
00028 /* The MTaker! */
00029 MTasker<WSEvent> MT;
00030 
00031 
00033 class BufferedIO
00034 {
00035 public:
00036   BufferedIO(Socket *sock)
00037   {
00038     d_buffer=new char[1024];
00039     d_socket=sock;
00040     d_pos=d_available=0;
00041   }
00042   ~BufferedIO()
00043   {
00044     delete[] d_buffer;
00045   }
00046   void writeLine(const string &line)
00047   {
00048     write(line.c_str(),line.size());
00049   }
00050   void write(const char *buf, unsigned int toWrite)
00051   {
00052     int written=0;
00053     int res=0;
00054     WSEvent ws;
00055     ws.who=d_socket;
00056     ws.what=WSEvent::Write;
00057     
00058     do {
00059       res=d_socket->tryWrite(buf+written,toWrite);  
00060       if(!res) {
00061         MT.waitEvent(ws);
00062         continue;
00063       }
00064       
00065       written+=res;
00066       toWrite-=res;
00067     }while(toWrite);
00068   }
00069   
00070   int getchar()
00071   {
00072     if(d_pos==d_available) {
00073       // we emptied the buffer, see that we get new stuff
00074 
00075       WSEvent ws;
00076       ws.who=d_socket;
00077       ws.what=WSEvent::Read;
00078       if(!MT.waitEvent(ws,0,5)) 
00079         throw NetworkError("Timeout!");
00080     
00081       int res=d_socket->read(d_buffer,1024);
00082       if(!res)
00083         return -1; 
00084       d_available=res;
00085       d_pos=0;
00086     }
00087 
00088     return d_buffer[d_pos++];    
00089   }
00090 
00091   void readLine(string &line)
00092   {
00093     line.clear();
00094     int c;
00095     for(;;) {
00096       c=getchar();
00097       if(c==-1)
00098         break;
00099       line.append(1,(char)c);
00100       if(c=='\n')
00101         break;
00102     }  
00103   }
00104 
00105 private:
00106   char *d_buffer;
00107   Socket *d_socket;
00108   size_t d_pos, d_available;
00109 };
00110 
00111 
00112 
00113 
00114 void connection(void *p)
00115 {
00116   Socket *client=(Socket *)p;
00117   int chunksize=65000;          /* disk IO chunk to do at any one time */
00118 
00119   vector<string> words;
00120   BufferedIO bio(client);
00121 
00122   try {
00123     string line;
00124     bio.readLine(line); // GET line
00125     stringtok(words,line," \t\r\n");
00126     if(words.size()<2) {
00127       cerr<<"Malformed GET line"<<endl;
00128       delete client;
00129       return;
00130     }
00131     string fname=words[1];
00132     if(fname=="/" || fname.find("../")!=string::npos) // brute force ../ cutout
00133       fname="index.html";
00134 
00135     cout<<"["<<MT.getTid()<<"] Request for file '"<<fname<<"'"; cout.flush();
00136     
00137     do {
00138       bio.readLine(line);
00139     }while(line!="\r\n");  // ignore other request lines
00140 
00141     FILE *fp=fopen(("./"+fname).c_str(),"r");
00142     if(!fp) {
00143       cout<<". Sending 404, not there"<<endl;
00144       bio.writeLine("HTTP/1.1 404 OK\r\n"
00145                     "Server: MTasker\r\n"
00146                     "Connection: close\r\n"
00147                     "Content-Type: text/html; charset=iso-8859-1\r\n\r\n");
00148     
00149       bio.writeLine("<H1>MTasker webserver</H1>\r\n");
00150       bio.writeLine("File '"+fname+"' is missing\r\n");
00151     }
00152     else {
00153       cout<<". Serving"; cout.flush();
00154       bio.writeLine("HTTP/1.1 200 OK\r\n"
00155                     "Server: MTasker\r\n"
00156                     "Connection: close\r\n"
00157                     "Content-Type: text/html; charset=iso-8859-1\r\n\r\n");
00158 
00159       vector<char>buffer(chunksize);
00160       int len;
00161       try {
00162         while((len=fread(&buffer[0],1,chunksize,fp))) {
00163           bio.write(&buffer[0],len);
00164         }
00165       }
00166       catch(...) {
00167         fclose(fp);
00168         throw;
00169       }
00170       fclose(fp);
00171       cout<<". Done"<<endl;
00172     }
00173   }
00174   catch(NetworkError &ne) {
00175     cerr<<"Fatal error in connection thread: "<<ne<<endl;
00176   }
00177   delete client;
00178 }
00179 
00180 int main(int argc, char **argv)
00181 {
00182   signal(SIGPIPE,SIG_IGN);
00183   try {
00184     Socket s(InterNetwork, Stream); 
00185     IPEndpoint ep;
00186     ep.address.byte=0;
00187     ep.port=8000;
00188     s.bind(ep);
00189     s.listen();
00190     s.setNonBlocking();
00191     cerr<<"Bound to local port "<<ep.port<<endl;
00192 
00193     vector<WSEvent> waitevents;
00194     vector<Socket *>readers, writers,errors;
00195     Socket* newClient=0;
00196 
00197     for(;;) {
00198       while(MT.schedule());             // housekeeping, let threads run
00199 
00200       SelectSocketMultiplex mult;
00201       mult.addReader(&s);               // make sure we listen on the main socket
00202       MT.getEvents(waitevents);         // get which events threads are waiting for
00203 
00204       /* add them to our SocketMultiplexor */
00205       for(vector<WSEvent>::const_iterator i=waitevents.begin();i!=waitevents.end();++i)
00206         if(i->what==WSEvent::Write) 
00207           mult.addWriter(i->who);
00208         else if(i->what==WSEvent::Read) 
00209           mult.addReader(i->who);
00210 
00211       /* and see if anything interesting happened */
00212       mult.run(readers,writers,errors);
00213       
00214       if(count(readers.begin(),readers.end(),&s)==1 && (newClient=s.accept())) { // activity on the main socket
00215         newClient->setNonBlocking();                                             // just in case
00216         MT.makeThread(connection,(void *)newClient);                             // spawn new thread for newClient
00217       }
00218 
00219       WSEvent ws;
00220 
00221       /* send Events for all read requests that were fullfilled */
00222       ws.what=WSEvent::Read;
00223       for(vector<Socket *>::iterator i=readers.begin();i<readers.end();++i) {
00224         if(*i==&s)
00225           continue;
00226         ws.who=*i;
00227         MT.sendEvent(ws);
00228       }
00229       /* send Events for all write requests that were fullfilled */
00230       ws.what=WSEvent::Write;
00231       for(vector<Socket *>::iterator i=writers.begin();i<writers.end();++i) {
00232         ws.who=*i;
00233         MT.sendEvent(ws);
00234       }
00235     }
00236   }
00237   catch(NetworkError &ne) {
00238     cerr<<"Fatal error: "<<ne<<endl;
00239   }
00240   catch(exception &e) {
00241     cerr<<"STL Exception: "<<e.what()<<endl;
00242   }
00243 }
00244 

Generated on Sun Feb 8 12:07:52 2004 for MTasker by doxygen 1.3.5