namespace edu.neu.ccs.demeterf.http.server{ using edu.neu.ccs.demeterf.http.classes; using System.IO; using System.Net; using System.Net.Sockets; using edu.neu.ccs.demeterf.lib; using System.Threading; using System; /** Represents the Listening/Dispatch portion of an HTTP Server. Given a Map of Paths * to Methods, it is responsible for calling methods when given a specific request. */ public class ServerThread{ static void p(String s){ Factory.p(s); } /** Set to true in order to get Output for Server/Dispatch descisions. */ public static void setVerbose(bool v){ Factory.setVerbose(v); } private Socket socket; private ServerDispatch dispatch; private List servants = List.create(); private bool single = false; private bool done = false; private Thread current; /** Create a ServerThread... */ public ServerThread(int port, bool sing, ServerDispatch disp){ socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socket.Bind(new IPEndPoint(IPAddress.Any, port)); dispatch = disp; single = sing; current = new Thread(run); current.Start(); } /** Run!! */ public void run(){ socket.Listen(10); while (!done) { try { p("Waiting for connection..."); Socket req = socket.Accept(); p("Got One from: " + req.RemoteEndPoint); DispatchThread t = new DispatchThread(req, dispatch, this); addServant(t); t.start(); try{ if(single)t.join(); }catch(Exception ie){ } } catch(Exception e) { if (!done) { Console.WriteLine(" ServerThread Exception: " + e.Message + "\n" + e.StackTrace); done = true; } } } } /** Add a Servant Thread to the List */ void addServant(DispatchThread t){ lock(this){ servants = servants.push(t); } } /** Remove a Servant Thread from the List */ void removeServant(DispatchThread t){ lock(this){ servants = servants.remove(t); } } /** Await the completion of all Servant Threads */ public void waitServants(){ lock(this){ p("Waiting for Servants..."); while(!servants.isEmpty()){ try{ current.Join(1000); }catch(Exception ie){} p("Still Waiting..."); } p("Done"); } } /** Kill the Server listening thread, though workers will continue/complete */ public void shutdown(){ done = true; socket.Close(); waitServants(); } /** Handles the dispatch of a Request to a Server Method */ private class DispatchThread{ Socket sock; ServerDispatch dispatch; ServerThread parent; Thread thread; public DispatchThread(Socket s, ServerDispatch disp, ServerThread p) { sock = s; dispatch = disp; parent = p; thread = new Thread(run); } public void start(){ thread.Start(); } public void join(){ thread.Join(); } public void run(){ p("In Dispatch Thread..."); HTTPReq req = null; try { req = HTTPReq.fromSocket(sock); }catch(Exception e){ try{ sock.Close(); }catch(Exception ee){} this.parent.removeServant(this); throw e; } try{ HTTPResp res = dispatch.handle(req, sock); res.toSocket(sock); sock.Close(); }catch(Exception e){ parent.removeServant(this); throw e; } parent.removeServant(this); } } } }