Permalink
Browse files

Bug with IOS not playing is corrected : connection was closed after t…

…he OPTION request.

Updated traces in RTSPPacket, added a class RTSPResponse.
Rewritten run() in LaunchThread and RTSPResponder.
  • Loading branch information...
1 parent 9354b24 commit 287dc1368421c7000412c32ddae99a1b70058973 @jblezoray jblezoray committed Jun 28, 2011
Showing with 165 additions and 137 deletions.
  1. BIN Binaries/Rplay.jar
  2. +58 −23 src/LaunchThread.java
  3. +5 −1 src/RTSPPacket.java
  4. +71 −113 src/RTSPResponder.java
  5. +31 −0 src/RTSPResponse.java
View
BIN Binaries/Rplay.jar
Binary file not shown.
View
81 src/LaunchThread.java
@@ -1,19 +1,24 @@
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
+import java.net.ServerSocket;
+import java.net.Socket;
import java.net.SocketException;
+import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
+import com.apple.dnssd.DNSSDException;
+
/**
* LaunchThread class which starts services
* @author bencall
*
*/
public class LaunchThread extends Thread{
- private RTSPResponder repondeur;
- private BonjourEmitter emetteur;
+ private BonjourEmitter emitter;
private String name;
+ private boolean stopThread = false;
/**
* Constructor
@@ -24,9 +29,7 @@ public LaunchThread(String name){
this.name = name;
}
-
- public void run(){
- int port = 5000;
+ private byte[] getHardwareAdress() {
byte[] hwAddr = null;
InetAddress local;
@@ -36,38 +39,70 @@ public void run(){
if (ni != null) {
hwAddr = ni.getHardwareAddress();
}
- } catch (UnknownHostException e1) {
- e1.printStackTrace();
+ } catch (UnknownHostException e) {
+ e.printStackTrace();
} catch (SocketException e) {
e.printStackTrace();
}
-
+ return hwAddr;
+ }
+
+
+ private String getStringHardwareAdress(byte[] hwAddr) {
StringBuilder sb = new StringBuilder();
for (byte b : hwAddr) {
sb.append(String.format("%02x", b));
}
+ return sb.toString();
+ }
+
+
+ public void run(){
+ System.out.println("service started.");
+ int port = 5000;
+ ServerSocket servSock = null;
try {
- // DNS Emitter (Bonjour)
- repondeur = new RTSPResponder(port, hwAddr);
- emetteur = new BonjourEmitter(name, sb.toString(), repondeur.getPort());
-
- repondeur.start();
+ // We listen for new connections
+ try {
+ servSock = new ServerSocket(port);
+ } catch (IOException e) {
+ servSock = new ServerSocket();
+ }
+ // DNS Emitter (Bonjour)
+ byte[] hwAddr = getHardwareAdress();
+ emitter = new BonjourEmitter(name, getStringHardwareAdress(hwAddr), port);
+
+ servSock.setSoTimeout(1000);
+ while (!stopThread) {
+ try {
+ Socket socket = servSock.accept();
+ System.out.println("got connection from " + socket.toString());
+ new RTSPResponder(hwAddr, socket).start();
+ } catch(SocketTimeoutException e) {
+ // ignore
+ }
+ }
- } catch (Exception e) {
- // Bonjour error
- e.printStackTrace();
+ } catch (DNSSDException e) {
+ throw new RuntimeException(e);
+
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+
+ } finally {
+ try {
+ servSock.close(); // will stop all RTSPResponders.
+ emitter.stop();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
}
+ System.out.println("service stopped");
}
public synchronized void stopThread(){
- emetteur.stop();
-
- try {
- repondeur.stopThread();
- } catch (IOException e) {
- e.printStackTrace();
- }
+ stopThread = true;
}
}
View
6 src/RTSPPacket.java
@@ -73,7 +73,6 @@ public String getDirectory(){
}
public int getCode(){
-
return 200;
}
@@ -84,4 +83,9 @@ public String valueOfHeader(String headerName){
}
return headerContent.elementAt(i);
}
+
+ @Override
+ public String toString() {
+ return " < " + rawPacket.replaceAll("\r\n", "\r\n < ");
+ }
}
View
184 src/RTSPResponder.java
@@ -5,14 +5,13 @@
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.StringReader;
-import java.net.ServerSocket;
+import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.security.KeyPair;
import java.security.Security;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import java.net.InetSocketAddress;
import javax.crypto.Cipher;
@@ -28,15 +27,15 @@
*/
public class RTSPResponder extends Thread{
- private ServerSocket sock; // Initial socket
private Socket socket; // Connected socket
private int[] fmtp;
private byte[] aesiv, aeskey; // ANNOUNCE request infos
private AudioServer serv; // Audio listener
byte[] hwAddr;
- boolean stopThread = false;
+ private BufferedReader in;
+ private static final Pattern completedPacket = Pattern.compile("(.*)\r\n\r\n");
- private String key =
+ private static final String key =
"-----BEGIN RSA PRIVATE KEY-----\n"
+"MIIEpQIBAAKCAQEA59dE8qLieItsH1WgjrcFRKj6eUWqi+bGLOX1HL3U3GhC/j0Qg90u3sG/1CUt\n"
+"wC5vOYvfDmFI6oSFXi5ELabWJmT2dKHzBJKa3k9ok+8t9ucRqMd6DZHJ2YCCLlDRKSKv6kDqnw4U\n"
@@ -61,45 +60,18 @@
+"2gG0N5hvJpzwwhbhXqFKA4zaaSrw622wDniAK5MlIE0tIAKKP4yxNGjoD2QYjhBGuhvkWKaXTyY=\n"
+"-----END RSA PRIVATE KEY-----\n";
- /**
- *
- * @param port Will try to use the defined port. If not possible, check getPort() to know which port was taken.
- * @throws IOException
- */
- public RTSPResponder(int port, byte[] hwAddr) throws IOException{
+ public RTSPResponder(byte[] hwAddr, Socket socket) throws IOException {
this.hwAddr = hwAddr;
-
- // Try to take the given port. If not possible, take another. If not possible: ERROR
- try {
- sock = new ServerSocket(5000);
- } catch (IOException e) {
- sock = new ServerSocket();
- }
- }
-
-
- public void stopThread() throws IOException{
- stopThread = true;
- if(serv != null){
- serv.stop();
- }
- sock.close();
- }
-
-
- /**
- * @return port number
- */
- public int getPort(){
- return sock.getLocalPort();
+ this.socket = socket;
+ in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
- public void handlePacket(RTSPPacket packet){
+ public RTSPResponse handlePacket(RTSPPacket packet){
// We init the response holder
- StringBuilder response = new StringBuilder("RTSP/1.0 200 OK\r\n");
- response.append("Audio-Jack-Status: connected; type=analog\r\n");
- response.append("CSeq: "+ packet.valueOfHeader("CSeq")+"\r\n");
+ RTSPResponse response = new RTSPResponse("RTSP/1.0 200 OK");
+ response.append("Audio-Jack-Status", "connected; type=analog");
+ response.append("CSeq", packet.valueOfHeader("CSeq"));
// Apple Challenge-Response field if needed
String challenge;
@@ -143,21 +115,16 @@ public void handlePacket(RTSPPacket packet){
ret = ret.replace("=", "").replace("\r", "").replace("\n", "");
// Write
- response.append("Apple-Response: " + ret + "\r\n");
-
+ response.append("Apple-Response", ret);
}
// Paquet request
String REQ = packet.getReq();
- if(REQ.contentEquals("OPTIONS")){ // OPTIONS
- System.out.println("REQUEST: OPTIONS");
-
+ if(REQ.contentEquals("OPTIONS")){
// The response field
- response.append("Public: ANNOUNCE, SETUP, RECORD, PAUSE, FLUSH, TEARDOWN, OPTIONS, GET_PARAMETER, SET_PARAMETER\r\n");
+ response.append("Public", "ANNOUNCE, SETUP, RECORD, PAUSE, FLUSH, TEARDOWN, OPTIONS, GET_PARAMETER, SET_PARAMETER");
- } else if (REQ.contentEquals("ANNOUNCE")){ // ANNOUNCE
- System.out.println("REQUEST: ANNOUNCE");
-
+ } else if (REQ.contentEquals("ANNOUNCE")){
// Nothing to do here. Juste get the keys and values
Pattern p = Pattern.compile("^a=([^:]+):(.+)", Pattern.MULTILINE);
Matcher m = p.matcher(packet.getContent());
@@ -178,7 +145,6 @@ public void handlePacket(RTSPPacket packet){
}
} else if (REQ.contentEquals("SETUP")){
- System.out.println("REQUEST: SETUP");
int controlPort = 0;
int timingPort = 0;
@@ -201,10 +167,10 @@ public void handlePacket(RTSPPacket packet){
// Launching audioserver
serv = new AudioServer(new AudioSession(aesiv, aeskey, fmtp, controlPort, timingPort));
- response.append("Transport: " + packet.valueOfHeader("Transport") + ";server_port=" + serv.getServerPort() + "\r\n");
+ response.append("Transport", packet.valueOfHeader("Transport") + ";server_port=" + serv.getServerPort());
// ??? Why ???
- response.append("Session: DEADBEEF\r\n");
+ response.append("Session", "DEADBEEF");
} else if (REQ.contentEquals("RECORD")){
// Headers
// Range: ntp=0-
@@ -216,7 +182,7 @@ public void handlePacket(RTSPPacket packet){
serv.flush();
} else if (REQ.contentEquals("TEARDOWN")){
- response.append("Connection: close\r\n");
+ response.append("Connection", "close");
} else if (REQ.contentEquals("SET_PARAMETER")){
// Timing port
@@ -233,30 +199,8 @@ public void handlePacket(RTSPPacket packet){
}
// We close the response
- response.append("\r\n");
-
- System.out.println(packet.getRawPacket());
- System.out.println(response.toString());
-
- // Write the packet to the wire
- BufferedWriter oStream;
- try {
- oStream = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
- oStream.write(response.toString());
- oStream.flush();
-
- // Don't know why, but connection must be closed after the OPTIONS request
- if(REQ.contentEquals("OPTIONS") || REQ.contentEquals("TEARDOWN") ){
- socket.close();
- socket = null;
- }
-
- // We listen for a new connection or new data
- this.run();
-
- } catch (IOException e) {
- e.printStackTrace();
- }
+ response.finalize();
+ return response;
}
/**
@@ -292,7 +236,7 @@ public void handlePacket(RTSPPacket packet){
try{
Security.addProvider(new BouncyCastleProvider());
- // La cl� RSA
+ // La clef RSA
PEMReader pemReader = new PEMReader(new StringReader(key));
KeyPair pObj = (KeyPair) pemReader.readObject();
@@ -312,47 +256,61 @@ public void handlePacket(RTSPPacket packet){
* Thread to listen packets
*/
public void run() {
- boolean fin = stopThread;
try {
-
- // Socket & Streams
- // Socket init
- if(socket == null && !stopThread){
- socket = sock.accept();
- }
-
- if(socket != null){
- BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
-
- String packet = "";
- while(!fin){
- // Buffer
+ do {
+ System.out.println("listening packets ... ");
+ // feed buffer until packet completed
+ StringBuffer packet = new StringBuffer();
+ int ret = 0;
+ do {
char[] buffer = new char[4096];
- in.read(buffer);
- String temp = new String(buffer);
- packet = packet + temp;
-
- // If packet completed
- Pattern p = Pattern.compile("(.*)\r\n\r\n");
- Matcher m = p.matcher(packet);
- if(m.find()){
- //System.out.println(packet);
- // We handle the packet
- RTSPPacket paquet = new RTSPPacket(packet);
- this.handlePacket(paquet);
- packet = "";
- break;
- }
-
- synchronized(this){
- fin = stopThread;
+ ret = in.read(buffer);
+ packet.append(new String(buffer));
+ } while (ret!=-1 && !completedPacket.matcher(packet.toString()).find());
+
+ if (ret!=-1) {
+ // We handle the packet
+ RTSPPacket request = new RTSPPacket(packet.toString());
+ RTSPResponse response = this.handlePacket(request);
+ System.out.println(request.toString());
+ System.out.println(response.toString());
+
+ // Write the response to the wire
+ try {
+ BufferedWriter oStream = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
+ oStream.write(response.getRawPacket());
+ oStream.flush();
+ } catch (IOException e) {
+ e.printStackTrace();
}
+
+ if("TEARDOWN".equals(request.getReq())){
+ socket.close();
+ socket = null;
+ }
+ } else {
+ socket.close();
+ socket = null;
}
- in.close();
- socket.close();
- }
+ } while (socket!=null);
+
} catch (IOException e) {
e.printStackTrace();
- }
+
+ } finally {
+ try {
+ if (in!=null) in.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ if (socket!=null) socket.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ System.out.println("connection ended.");
}
+
}
View
31 src/RTSPResponse.java
@@ -0,0 +1,31 @@
+
+public class RTSPResponse {
+
+ private StringBuilder response = new StringBuilder();
+
+ public RTSPResponse(String header) {
+ response.append(header + "\r\n");
+ }
+
+ public void append(String key, String value) {
+ response.append(key + ": " + value + "\r\n");
+ }
+
+ /**
+ * close the response
+ */
+ public void finalize() {
+ response.append("\r\n");
+ }
+
+
+ public String getRawPacket() {
+ return response.toString();
+ }
+
+ @Override
+ public String toString() {
+ return " > " + response.toString().replaceAll("\r\n", "\r\n > ");
+ }
+
+}

0 comments on commit 287dc13

Please sign in to comment.