/* * Created on 22.04.2004 * */ package multimonster.mediaproxy.plugin; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; import java.rmi.RemoteException; import java.util.StringTokenizer; import javax.ejb.CreateException; import javax.ejb.RemoveException; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import multimonster.common.Action; import multimonster.common.ConnectionAddress; import multimonster.common.FormatId; import multimonster.common.ProtocolId; import multimonster.common.Session; import multimonster.common.media.MOIdentifier; import multimonster.common.pipe.Pipe; import multimonster.common.pipe.PipeClosedException; import multimonster.common.resource.ResourceRequestIdentifier; import multimonster.common.util.EjbCreator; import multimonster.common.util.EjbHomeGetter; import multimonster.mediaproxy.MediaProxyPlugin; import multimonster.mediaproxy.ProxyInitObjects; import multimonster.mediaproxy.exceptions.MediaProxyException; import multimonster.mediaproxy.interfaces.MediaProxyImpl; import multimonster.mediaproxy.interfaces.MediaProxyImplHome; import org.apache.log4j.Logger; /** * The helper class for the HttpProxy */ public class HttpProxyHandler implements Runnable{ private Logger log = Logger.getLogger(this.getClass()); private Socket socket; private MediaProxyPlugin parent; private ConnectionAddress ca = null; /** * */ public HttpProxyHandler(Socket socket, MediaProxyPlugin parent, ConnectionAddress ca) { super(); this.socket = socket; this.parent = parent; this.ca = ca; } /* * (non-Javadoc) * * @see java.lang.Runnable#run() */ public void run() { InputStream in = null; OutputStream out = null; InputStreamReader inStream = null; DataOutputStream outStream = null; BufferedReader inBufferedReader = null; Context context = null; MediaProxyImplHome mediaProxyHome = null; MediaProxyImpl mediaProxyFacade = null; ProxyInitObjects pio = null; Pipe pipeToTransporter = null; ResourceRequestIdentifier rrId = null; Session session = null; MOIdentifier mOId = null; FormatId fId = null; ProtocolId protocolId = null; Action action = null; String errorText = ""; log.debug("thread is running, waiting for connection..."); try { in = socket.getInputStream(); inStream = new InputStreamReader(in); inBufferedReader = new BufferedReader(inStream); } catch (IOException e3) { errorText = "Couldn't get InputStream of socket: " + e3.getMessage(); log.error(errorText); cleanup( inBufferedReader, outStream, socket, pipeToTransporter, mediaProxyFacade, rrId, true); return; } try { out = socket.getOutputStream(); outStream = new DataOutputStream(out); } catch (IOException e4) { errorText = "Couldn't OutputStream of socket: " + e4.getMessage(); log.error(errorText); cleanup( inBufferedReader, outStream, socket, pipeToTransporter, mediaProxyFacade, rrId, true); return; } InetAddress remoteIp = socket.getInetAddress(); if (remoteIp == null) { errorText = "No remote-IP, socket isn't connected."; log.error(errorText); cleanup( inBufferedReader, outStream, socket, pipeToTransporter, mediaProxyFacade, rrId, true); return; } // log.debug("Remote IP=" + remoteIp.getHostAddress()); /* parse request to check session, mOId, format */ try { parseClientRequest(inBufferedReader); } catch (MediaProxyException e5) { errorText = e5.getMessage(); log.error(errorText); cleanup( inBufferedReader, outStream, socket, pipeToTransporter, mediaProxyFacade, rrId, true); return; } // now the values are check by the parser, I can use them: session = ca.getSession(); mOId = ca.getMOId(); fId = ca.getFormatId(); /* mapping to internal protocol between proxy and transporter * this proxy needs a transporter which speaks "mmSimple"! */ protocolId = new ProtocolId(ProtocolId.pId_mmSimple); action = new Action(Action.A_USE); /* init */ // trying to get MediaProxyEJB try { context = new InitialContext(); mediaProxyHome = EjbHomeGetter.getMediaProxyHome(context); mediaProxyFacade = EjbCreator.createMediaProxy(mediaProxyHome, context); } catch (NamingException e) { errorText = e.getMessage(); log.error(errorText); cleanup( inBufferedReader, outStream, socket, pipeToTransporter, mediaProxyFacade, rrId, true); return; } catch (RemoteException e) { errorText = e.getMessage(); log.error(errorText); cleanup( inBufferedReader, outStream, socket, pipeToTransporter, mediaProxyFacade, rrId, true); return; } catch (CreateException e) { errorText = e.getMessage(); log.error(errorText); cleanup( inBufferedReader, outStream, socket, pipeToTransporter, mediaProxyFacade, rrId, true); return; } try { /* * call MediaProxyFacade to prepare for output and get Pipe from * Transporter and ResourceRequestId */ pio = mediaProxyFacade.initWork( session, mOId, fId, protocolId, action, false); mediaProxyFacade.remove(); } catch (RemoteException e) { errorText = e.getMessage(); log.error(errorText); cleanup( inBufferedReader, outStream, socket, pipeToTransporter, mediaProxyFacade, rrId, true); return; } catch (RemoveException e) { errorText = e.getMessage(); log.error(errorText); cleanup( inBufferedReader, outStream, socket, pipeToTransporter, mediaProxyFacade, rrId, true); return; } catch (MediaProxyException e) { errorText = e.getMessage(); log.error(errorText); cleanup( inBufferedReader, outStream, socket, pipeToTransporter, mediaProxyFacade, rrId, true); return; } if (pio == null) { errorText = "Didn't get InitObjects to do my work."; log.error(errorText); cleanup( inBufferedReader, outStream, socket, pipeToTransporter, mediaProxyFacade, rrId, true); return; } if ((rrId = pio.getRrId()) == null) { errorText = "Didn't get ResourceRequestIdentifier."; log.error(errorText); cleanup( inBufferedReader, outStream, socket, pipeToTransporter, mediaProxyFacade, rrId, true); return; } log.debug("rrID is ok: " +rrId); if ((pipeToTransporter = pio.getPipeToTransporter()) == null) { errorText = "Didn't get pipeToTransporter."; log.error(errorText); cleanup( inBufferedReader, outStream, socket, pipeToTransporter, mediaProxyFacade, rrId, true); return; } /* do data exchange */ transmitOutputData(pipeToTransporter, inBufferedReader, outStream); cleanup( inBufferedReader, outStream, socket, pipeToTransporter, mediaProxyFacade, rrId, false); } /** * Cleansup every established connection, either to the client or to the * transporter. * * @param in * @param out * @param socket * @param pipeToTransporter * @param mediaProxyFacade */ private void cleanup( BufferedReader in, DataOutputStream out, Socket socket, Pipe pipeToTransporter, MediaProxyImpl mediaProxyFacade, ResourceRequestIdentifier rrId, boolean errorOccured) { String http_error_msg = "HTTP/1.1 400 Bad Request\r\n\r\nERROR"; String errorText = ""; log.debug("finished, closing socket, pipe and cleaning up."); try { if (out != null) { if (errorOccured) { // try to inform client, about the error out.writeBytes(http_error_msg); } out.close(); } if (in != null) { in.close(); } if (socket != null) { socket.close(); } } catch (IOException e1) { errorText = "Error on cleaning up socket: " + e1.getMessage(); log.error(errorText); } finally { if (pipeToTransporter != null) { pipeToTransporter.close(); } try { /* call MediaProxyFacade to indicate the finished request */ if (mediaProxyFacade != null) { if (rrId != null){ mediaProxyFacade.requestFinished(rrId); } mediaProxyFacade.remove(); } } catch (RemoteException e) { errorText = "Error calling remote object: " + e.getMessage(); log.error(errorText); return; } catch (RemoveException e) { errorText = "Couldn't remove MediaProxy: " + e.getMessage(); log.error(errorText); return; } catch (MediaProxyException e) { errorText = e.getMessage(); log.error(errorText); return; } } } /** * Parses the client request and checks if it's equal to the expected * request as it is stored in the ConnectionAddress. * * @param in * @param mOId * @param format * @param protocol * @param session * @param action */ private void parseClientRequest(BufferedReader in) throws MediaProxyException { // get the request string: // String request = ""; String parsed_sessionId = ""; int parsed_mOId = 0; String parsed_formatId = ""; String errorText = ""; try { // now it's a buffered reader: request = in.readLine(); } catch (IOException e5) { log.info("Could not read anymore from client."); } if (request == null) { errorText = "Client-request was null"; throw new MediaProxyException(errorText); } log.debug("read request: " +request); StringTokenizer to_parse = new StringTokenizer(request, "/"); try { to_parse.nextToken(); // "GET " parsed_sessionId = to_parse.nextToken(); // sessionID parsed_mOId = Integer.parseInt(to_parse.nextToken()); // mOId parsed_formatId = to_parse.nextToken(); // format to_parse.nextToken(); // filename } catch (Exception e) { errorText = "Couldn't parse request string: " + e.getMessage(); throw new MediaProxyException(errorText); } /* check if parsed request is ok */ if (parent .getConnectionAddress() .getSession() .getId() .compareTo(parsed_sessionId) != 0) { errorText = "Expected different sessionId (" + parent.getConnectionAddress().getSession().getId() + "), but got " + parsed_sessionId + "."; throw new MediaProxyException(errorText); } else if ( parent.getConnectionAddress().getMOId().getMoNumber() != parsed_mOId) { errorText = "Expected different mOId (" + parent.getConnectionAddress().getMOId().getMoNumber() + "), but got " + parsed_mOId + "."; throw new MediaProxyException(errorText); } else if ( parent .getConnectionAddress() .getFormatId() .getId() .compareTo( parsed_formatId) != 0) { errorText = "Expected different formatNumber (" + parent .getConnectionAddress() .getFormatId() .getId() + "), but got " + parsed_formatId + "."; throw new MediaProxyException(errorText); } log.debug( "Request parsed, is ok, as expected: sessionID=" + parsed_sessionId + ", moid=" + parsed_mOId + ", format=" + parsed_formatId); return; } /** * Does the actual data transmit from transporter to client. * * @param pipeToTransporter * @param in * @param out */ private void transmitOutputData( Pipe pipeToTransporter, BufferedReader in, DataOutputStream out) { String CRLF = "\r\n"; byte[] bytesOut; int bytesOutCounter = 0; boolean proxying = true; String clientRequest = ""; //get the segment-size to read out of pipe int PIPE_SEGMENT_SIZE = Pipe.getPipeSegmentSize(); try { String httpHeader = ""; String httpHeader_statusLine = ""; String httpHeader_contentType = ""; httpHeader_statusLine = "HTTP/1.1 200 OK"; //httpHeader_contentType = "Content-Type: application/octet-stream"; httpHeader_contentType = "Content-Type: video/mpeg"; httpHeader = httpHeader_statusLine +CRLF +httpHeader_contentType +CRLF +CRLF; // writing HTTP header to client out.write(httpHeader.getBytes()); bytesOutCounter += httpHeader.length(); log.debug("HTTP header: " +httpHeader.length() +" bytes."); while (proxying) { // read data from transporter bytesOut = pipeToTransporter.read(PIPE_SEGMENT_SIZE); // write it to the client out.write(bytesOut); // count written bytes bytesOutCounter += bytesOut.length; if (bytesOut.length < PIPE_SEGMENT_SIZE) { // this was the rest of data in the pipe, now we're // finished proxying = false; } // get controlling info from client if (in.ready()) { clientRequest = in.readLine(); // log.debug( // "Got controlling-client-request: " + clientRequest); if (clientRequest.endsWith("stop")) { /* abort transmission */ log.info("client wants to abort transmission."); proxying = false; } else { } } } } catch (PipeClosedException e6) { log.info( "Pipe from Transporter was closed, wrote " + bytesOutCounter + " bytes."); } catch (IOException e) { log.info( "Couldn't write to client anymore, wrote " + bytesOutCounter + " bytes."); } log.debug( "Transmit finished, " + bytesOutCounter + " wrote to client."); return; } }