001: /*
002: * Copyright (c) 2001 by Matt Welsh and The Regents of the University of
003: * California. All rights reserved.
004: *
005: * Permission to use, copy, modify, and distribute this software and its
006: * documentation for any purpose, without fee, and without written agreement is
007: * hereby granted, provided that the above copyright notice and the following
008: * two paragraphs appear in all copies of this software.
009: *
010: * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
011: * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
012: * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
013: * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
014: *
015: * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
016: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
017: * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
018: * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
019: * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
020: *
021: * Author: Matt Welsh <mdw@cs.berkeley.edu>
022: *
023: */
024:
025: package seda.sandStorm.lib.http;
026:
027: import seda.sandStorm.api.*;
028: import seda.sandStorm.lib.aSocket.*;
029: import seda.sandStorm.core.*;
030: import seda.sandStorm.main.*;
031:
032: import java.util.*;
033: import java.io.*;
034: import java.net.*;
035:
036: /**
037: * An httpServer is a SandStorm stage which accepts incoming HTTP
038: * connections. The server has a client sink associated with it, onto
039: * which httpConnection and httpRequest events are pushed. When a
040: * connection is closed, a SinkClosedEvent is pushed, with the
041: * sink pointer set to the httpConnection that closed.
042: *
043: * @author Matt Welsh (mdw@cs.berkeley.edu)
044: * @see httpConnection
045: * @see httpRequest
046: */
047: public class httpServer implements EventHandlerIF, httpConst {
048:
049: private static final boolean DEBUG = false;
050:
051: // These are protected to allow subclasses to use them
052: protected int listenPort;
053: protected ATcpServerSocket servsock;
054: protected ManagerIF mgr;
055: protected SinkIF mySink, clientSink;
056:
057: // ATcpConnection -> httpConnection
058: private Hashtable connTable;
059:
060: private static int num_svrs = 0;
061:
062: /**
063: * Create an HTTP server listening for incoming connections on
064: * the default port of 8080.
065: */
066: public httpServer(ManagerIF mgr, SinkIF clientSink)
067: throws Exception {
068: this (mgr, clientSink, DEFAULT_HTTP_PORT);
069: }
070:
071: /**
072: * Create an HTTP server listening for incoming connections on
073: * the given listenPort.
074: */
075: public httpServer(ManagerIF mgr, SinkIF clientSink, int listenPort)
076: throws Exception {
077: this .mgr = mgr;
078: this .clientSink = clientSink;
079: this .listenPort = listenPort;
080:
081: this .connTable = new Hashtable();
082:
083: // Create the stage and register it
084: String sname = "httpServer " + num_svrs + " <port "
085: + listenPort + ">";
086: // Disable the RT controller for this stage
087: mgr.getConfig().putBoolean(
088: "stages." + sname + ".rtController.enable", false);
089: mgr.createStage(sname, this , null);
090: num_svrs++;
091: }
092:
093: /**
094: * The Sandstorm stage initialization method.
095: */
096: public void init(ConfigDataIF config) throws Exception {
097: mySink = config.getStage().getSink();
098:
099: servsock = new ATcpServerSocket(listenPort, mySink,
100: WRITE_CLOG_THRESHOLD);
101: }
102:
103: /**
104: * The Sandstorm stage destroy method.
105: */
106: public void destroy() {
107: }
108:
109: /**
110: * The main event handler.
111: */
112: public void handleEvent(QueueElementIF qel) {
113: if (DEBUG)
114: System.err.println("httpServer got qel: " + qel);
115:
116: if (qel instanceof ATcpInPacket) {
117: ATcpInPacket pkt = (ATcpInPacket) qel;
118:
119: if (DEBUG) {
120: System.err
121: .println("httpServer got packet: -----------------------");
122: String s = new String(pkt.getBytes());
123: System.err.println(s
124: + "\n----------------------------------");
125: }
126:
127: httpConnection hc = (httpConnection) connTable.get(pkt
128: .getConnection());
129: if (hc == null)
130: return; // Connection may have been closed
131:
132: try {
133: hc.parsePacket(pkt);
134: } catch (IOException ioe) {
135: //System.err.println("httpServer: Got IOException during packet processing for connection "+hc+": "+ioe);
136: //ioe.printStackTrace();
137: // XXX Should close connection
138: }
139:
140: } else if (qel instanceof ATcpConnection) {
141: ATcpConnection conn = (ATcpConnection) qel;
142: httpConnection hc = new httpConnection(conn, this ,
143: clientSink);
144: connTable.put(conn, hc);
145:
146: // Profile the connection if profiling enabled
147: ProfilerIF profiler = mgr.getProfiler();
148: SandstormConfig cfg = mgr.getConfig();
149: if ((profiler != null)
150: && cfg.getBoolean("global.profile.sockets"))
151: profiler.add(conn.toString(), conn);
152: conn.startReader(mySink);
153:
154: } else if (qel instanceof aSocketErrorEvent) {
155: System.err.println("httpServer got error: "
156: + qel.toString());
157:
158: } else if (qel instanceof SinkDrainedEvent) {
159: // Ignore
160:
161: } else if (qel instanceof SinkCloggedEvent) {
162: // Some connection is clogged; tell the user
163: SinkCloggedEvent sce = (SinkCloggedEvent) qel;
164: httpConnection hc = (httpConnection) connTable
165: .get(sce.sink);
166: if (hc != null)
167: clientSink
168: .enqueue_lossy(new SinkCloggedEvent(hc, null));
169:
170: } else if (qel instanceof SinkClosedEvent) {
171: // Some connection closed; tell the user
172: SinkClosedEvent sce = (SinkClosedEvent) qel;
173: httpConnection hc = (httpConnection) connTable
174: .get(sce.sink);
175: if (hc != null) {
176: clientSink.enqueue_lossy(new SinkClosedEvent(hc));
177: cleanupConnection(hc);
178: }
179:
180: } else if (qel instanceof ATcpListenSuccessEvent) {
181: clientSink.enqueue_lossy(qel);
182: }
183: }
184:
185: public void handleEvents(QueueElementIF[] qelarr) {
186: for (int i = 0; i < qelarr.length; i++) {
187: handleEvent(qelarr[i]);
188: }
189: }
190:
191: void cleanupConnection(httpConnection hc) {
192: connTable.remove(hc.getConnection());
193: }
194:
195: public String toString() {
196: return "httpServer [listen=" + listenPort + "]";
197: }
198:
199: /**
200: * Register a sink to receive incoming packets on this
201: * connection.
202: */
203: public void registerSink(SinkIF sink) {
204: this .clientSink = sink;
205: }
206:
207: /**
208: * Suspend acceptance of new connections on this server.
209: * This request will not be effective immediately.
210: */
211: public void suspendAccept() {
212: servsock.suspendAccept();
213: }
214:
215: /**
216: * Resume acceptance of new connections on this server.
217: * This request will not be effective immediately.
218: */
219: public void resumeAccept() {
220: servsock.resumeAccept();
221: }
222:
223: // Return my sink so that httpConnection can redirect
224: // packet completions to it
225: SinkIF getSink() {
226: return mySink;
227: }
228:
229: /**
230: * Return the server socket being used by this httpServer.
231: */
232: public ATcpServerSocket getServerSocket() {
233: return servsock;
234: }
235:
236: }
|