package multimonster.mediaproxy.plugin;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.rmi.RemoteException;
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 of the RawSocketInputProxy.
*/
public class RawSocketInputProxyHandler implements Runnable {
private Logger log = Logger.getLogger(this.getClass());
private Socket socket;
private MediaProxyPlugin parent;
ConnectionAddress ca = null;
/**
*
*/
public RawSocketInputProxyHandler(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;
DataOutputStream outStream = null;
BufferedReader inBufferedReader = null;
MediaProxyImpl mediaProxyFacade = null;
Pipe pipeToTransporter = null;
ResourceRequestIdentifier rrId = null;
String errorText = "";
log.debug("thread is running, waiting for connection...");
try {
in = socket.getInputStream();
} 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;
}
doWork(in, outStream);
cleanup(inBufferedReader, outStream, socket, pipeToTransporter,
mediaProxyFacade, rrId, false);
}
/**
* Runs the Proxy.
*
* @param file
* @param link
*/
public void doWork(InputStream inStream, DataOutputStream out) {
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;
int transferredBytes = 0;
String errorText = "";
log.debug("InputProxy starts work...");
// now the values are check by the parser, I can use them:
if (ca == null) {
errorText = "Connection Adress is null, should be set at init, creating it from the parsed link...";
log.warn(errorText);
}
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(pipeToTransporter, mediaProxyFacade, rrId, true);
return;
} catch (RemoteException e) {
errorText = e.getMessage();
log.error(errorText);
cleanup(pipeToTransporter, mediaProxyFacade, rrId, true);
return;
} catch (CreateException e) {
errorText = e.getMessage();
log.error(errorText);
cleanup(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, true);
mediaProxyFacade.remove();
} catch (RemoteException e) {
errorText = e.getMessage();
log.error(errorText);
cleanup(pipeToTransporter, mediaProxyFacade, rrId, true);
return;
} catch (RemoveException e) {
errorText = e.getMessage();
log.error(errorText);
cleanup(pipeToTransporter, mediaProxyFacade, rrId, true);
return;
} catch (MediaProxyException e) {
errorText = e.getMessage();
log.error(errorText);
cleanup(pipeToTransporter, mediaProxyFacade, rrId, true);
return;
}
if (pio == null) {
errorText = "Didn't get InitObjects to do my work.";
log.error(errorText);
cleanup(pipeToTransporter, mediaProxyFacade, rrId, true);
return;
}
if ((rrId = pio.getRrId()) == null) {
errorText = "Didn't get ResourceRequestIdentifier.";
log.error(errorText);
cleanup(pipeToTransporter, mediaProxyFacade, rrId, true);
return;
}
if ((pipeToTransporter = pio.getPipeToTransporter()) == null) {
errorText = "Didn't get pipeToTransporter.";
log.error(errorText);
cleanup(pipeToTransporter, mediaProxyFacade, rrId, true);
return;
}
log
.debug("Initialization finshed, got Pipe from Transporter and ResourceRequestIdentifier.");
/* do data exchange */
log.debug("starting work.");
transferredBytes = transmitInputData(pipeToTransporter, inStream);
try {
out.writeUTF("successfully transferred " + transferredBytes
+ " bytes.");
} catch (IOException e1) {
log.error("Couldn't write to client through socket.");
}
cleanup(pipeToTransporter, mediaProxyFacade, rrId, false);
return;
}
private void cleanup(Pipe pipeToTransporter,
MediaProxyImpl mediaProxyFacade, ResourceRequestIdentifier rrId,
boolean errorOccured) {
cleanup(null, null, null, pipeToTransporter, mediaProxyFacade, rrId,
errorOccured);
}
/**
* Cleans up 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) {
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;
}
}
}
/**
* Does the actual data transmit from client to transporter.
*
* @param pipeToTransporter
* @param in
* @param out
*/
private int transmitInputData(Pipe pipeToTransporter, InputStream inStream) {
int bytesInCounter = 0;
int bytesOutCounter = 0;
//get the segment-size to read out of pipe
int PIPE_SEGMENT_SIZE = Pipe.getPipeSegmentSize();
log.debug("transmitInputData called, starting reading HTTP-Stream...");
try {
//transfer data
byte[] data = new byte[PIPE_SEGMENT_SIZE];
int read = 1;
while ((read = inStream.read(data)) > 0) {
bytesInCounter += read;
pipeToTransporter.write(data);
bytesOutCounter += data.length;
}
/*
* int nextBlockSize = Math.min(PIPE_SEGMENT_SIZE,
* inStream.available());
*
* while (nextBlockSize > 0){ byte[] data = new
* byte[nextBlockSize];
*
* bytesInCounter += inStream.read(data, 0, nextBlockSize);
*
* pipeToTransporter.write(data); bytesOutCounter +=
* data.length;
*
* nextBlockSize = Math.min(512, inStream.available());
}
*/
// byte[] bytesIn = new byte[PIPE_SEGMENT_SIZE];
// byte[] tmpBuff;
//
// while (!socket.isInputShutdown()) {
//
// bytesInCounter = inStream.read(bytesIn);
//
// if (bytesInCounter == -1){
// //EOF is reached
// break;
// }
//
// if (bytesInCounter < bytesIn.length){
//
// tmpBuff = new byte[bytesInCounter];
//
// for (int i=0; i<bytesInCounter; i++){
// tmpBuff[i] = bytesIn[i];
// }
// bytesIn = tmpBuff;
//
// }
//
// // write data to transporter
// pipeToTransporter.write(bytesIn);
//
// // count written bytes
// bytesOutCounter += bytesIn.length;
// //log.debug("Wrote " +bytesOutCounter +" bytes to Transporter.");
// }
} catch (PipeClosedException e6) {
log.info("Pipe to Transporter was closed, wrote " + bytesOutCounter
+ " bytes.");
} catch (IOException e6) {
log.info("File was closed, wrote " + bytesOutCounter + " bytes.");
}
log.debug("Transmit finished, " + bytesOutCounter
+ " wrote to Transporter.");
return bytesOutCounter;
}
}