package com.jcumulus.server.rtmfp; /** * jCumulus is a Java port of Cumulus OpenRTMP * * Copyright 2011 OpenRTMFP * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License received along this program for more * details (or else see http://www.gnu.org/licenses/). * * * This file is a part of jCumulus. */ import com.jcumulus.server.rtmfp.client.*; import com.jcumulus.server.rtmfp.packet.*; import com.jcumulus.server.rtmfp.pipe.C; import com.jcumulus.server.rtmfp.publisher.E; import com.jcumulus.server.rtmfp.publisher.F; import com.jcumulus.server.rtmfp.stream.B; import com.google.common.base.Strings; import java.net.SocketAddress; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.log4j.Logger; import org.jboss.netty.channel.Channel; public class ServerSession implements ISession { private static final Logger J = Logger.getLogger(ServerSession.class); int O; int D; protected Peer M; boolean I; boolean F; byte H; K S; K K; protected final B N; Channel Q; com.jcumulus.server.rtmfp.pipe.B G; short A; boolean U; int B; int E; Map L; com.jcumulus.server.rtmfp.publisher.FlowWriter R; int P; Map C; Map T; public ServerSession(int i, int j, byte abyte0[], byte abyte1[]) { this(i, j, abyte0, abyte1, new Peer()); } public ServerSession(int i, int j, byte abyte0[], byte abyte1[], Peer p) { N = new B(); G = new com.jcumulus.server.rtmfp.pipe.B(); A = 0; U = false; L = new HashMap(); P = 1; C = new HashMap(); T = new HashMap(); H = 0; F = false; I = false; O = i; D = j; M = p; M.A(new ClientHandler()); S = new K(abyte0, com.jcumulus.server.rtmfp.K.Encryption.DECRYPT); K = new K(abyte1, com.jcumulus.server.rtmfp.K.Encryption.ENCRYPT); N.E(11); N.C(com.jcumulus.server.rtmfp.N.G); } public I A(byte abyte0[]) { I i = (I)T.get(abyte0); if(i == null) { i = new I(); T.put(abyte0, i); } return i; } public void A(Channel channel, SocketAddress socketaddress) { Q = channel; M.A(socketaddress); } public void A(AudioPacket a) { if(!com.jcumulus.server.rtmfp.N.A(S, a)) { J.error((new StringBuilder()).append("Decrypt error on session ").append(O).toString()); return; } else { B(a); return; } } protected void A(B b) { if(Q == null) { J.error((new StringBuilder()).append("Impossible to send on a null socket for session ").append(O).toString()); return; } B b1 = com.jcumulus.server.rtmfp.N.A(K, b); if(b1 != null) { com.jcumulus.server.rtmfp.N.A(b1, D); Q.write(b1.E(), M.L()); } } public boolean A(com.jcumulus.server.rtmfp.publisher.FlowWriter h) { return R == h; } public void B(com.jcumulus.server.rtmfp.publisher.FlowWriter h) { while(++P == 0 || C.get(Integer.valueOf(P)) != null) ; h.B(P); if(L.size() > 0) h.C(((E[])L.values().toArray(new E[L.size()]))[0].D()); C.put(Integer.valueOf(P), h); } public com.jcumulus.server.rtmfp.stream.B A(byte paramByte, int paramInt, com.jcumulus.server.rtmfp.publisher.FlowWriter paramH) { if (this.U) synchronized (this.N) { this.N.B(11); this.N.C(this.N.C()); return this.N; } this.R = paramH; int i = paramInt + 3; if (i > this.N.D()) { A(false); if (i > this.N.D()) { J.error("Message truncated because exceeds maximum UDP packet size on session " + this.O); i = this.N.D(); } this.R = null; } synchronized (this.N) { this.N.C(this.N.C() + i); this.N.B(paramByte); this.N.A((short)paramInt); return this.N; } } private void D() { if(F) return; B++; synchronized(N) { N.B((byte)12); N.A((short)0); } A(false); if(B == 10 || G.A(0x15752a00L)) C(); } private void A(String s) { if(U) return; synchronized(N) { N.B(11); } Integer integer; for(Iterator iterator = C.keySet().iterator(); iterator.hasNext(); ((com.jcumulus.server.rtmfp.publisher.FlowWriter)C.get(integer)).I()) integer = (Integer)iterator.next(); this.M.A((com.jcumulus.server.rtmfp.publisher.FlowWriter)null); this.M.J(); this.U = true; if(!Strings.isNullOrEmpty(s)) { J.warn((new StringBuilder()).append("Session failed id : ").append(s).toString()); M.E(s); D(); } } public void C() { if(F) return; M.O(); M.C(); U = true; M.A((com.jcumulus.server.rtmfp.publisher.FlowWriter)null); M.J(); E e; for(Iterator iterator = L.values().iterator(); iterator.hasNext(); e.C()) e = (E)iterator.next(); L.clear(); com.jcumulus.server.rtmfp.publisher.FlowWriter h; for(Iterator iterator1 = C.values().iterator(); iterator1.hasNext(); h.F()) h = (com.jcumulus.server.rtmfp.publisher.FlowWriter)iterator1.next(); C.clear(); F = true; J.info((new StringBuilder()).append("Session ").append(O).append(" died").toString()); } protected void B(AudioPacket a) { if(F) return; if(!U && M.K()) A(""); if(M.N().size() == 0) { J.error((new StringBuilder()).append("Session ").append(O).append(" has no any addresses!").toString()); M.N().add(M.L().toString()); } G.A(); byte byte0 = (byte)(a.L() | 0xfffffff0); A = a.E(); if(byte0 == -3) { short word0 = com.jcumulus.server.rtmfp.N.A(G.getTime()); short word1 = a.E(); M.A((short)(word1 <= word0 ? word0 - word1 : 0)); } else if(byte0 != -7) J.warn("Packet marker unknown : marker"); byte byte1 = 0; E e = null; int i = 0; int j = 0; byte byte2 = a.I() <= 0 ? -1 : a.L(); boolean flag = false; do { if(byte2 == -1) break; short word2 = a.E(); AudioPacket a1 = new AudioPacket(a.G(), word2); switch(byte2) { case 112: // 'p' break; case 12: // '\f' A("failed on client side"); break; case 76: // 'L' C(); return; case 1: // '\001' if(!M.M()) A("Timeout connection client"); else A((byte)65, 0, null); // fall through case 65: // 'A' E = 0; break; case 94: // '^' int k = a1.J(); com.jcumulus.server.rtmfp.publisher.FlowWriter h = (com.jcumulus.server.rtmfp.publisher.FlowWriter)C.get(Integer.valueOf(k)); if(h != null) h.D((new StringBuilder()).append("FlowWriter rejected on session ").append(O).toString()); else J.warn((new StringBuilder()).append("FlowWriter ").append(k).append(" unfound for failed signal on session ").append(O).toString()); break; case 24: // '\030' A("ack negative from server"); break; case 81: // 'Q' int l = a1.J(); com.jcumulus.server.rtmfp.publisher.FlowWriter h1 = (com.jcumulus.server.rtmfp.publisher.FlowWriter)C.get(Integer.valueOf(l)); if(h1 != null) h1.A(a1); else J.warn((new StringBuilder()).append("FlowWriter ").append(l).append(" unfound for acknowledgment on session").append(O).toString()); break; case 16: // '\020' byte1 = a1.L(); int i1 = a1.J(); i = a1.J() - 1; j = a1.J() - 1; if(U) break; e = (E)L.get(Integer.valueOf(i1)); if((byte1 & com.jcumulus.server.rtmfp.publisher.E.N.intValue()) != 0) { byte abyte0[] = a1.F(a1.L() & 0xff); if(e == null) e = A(i1, abyte0); if(a1.L() > 0) { if(a1.L() != 10) J.warn((new StringBuilder()).append("Unknown fullduplex header part for the flow '").append(i1).append("'").toString()); else a1.J(); byte byte3; for(byte3 = a1.L(); byte3 > 0 && a1.I() > 0; byte3 = a1.L()) { J.warn((new StringBuilder()).append("Unknown message part on flow '").append(i1).append("'").toString()); a1.D(byte3); } if(byte3 > 0) J.error("Bad header message part, finished before scheduled"); } } if(e == null) J.warn((new StringBuilder()).append("Flow ").append(i1).append(" unfound").toString()); // fall through case 17: // '\021' i++; j++; if(byte2 == 17) byte1 = a1.L(); if(e == null) break; e.A(i, j, a1, byte1); if(!Strings.isNullOrEmpty(e.G()) || M.K()) { A(e.G()); e = null; } break; default: J.error((new StringBuilder()).append("Message type '").append(byte2).append("' unknown").toString()); break; } a.D(word2); byte2 = a.I() <= 0 ? -1 : a.L(); if(e != null && byte2 != 17) { e.F(); if(e.B()) L.remove(Integer.valueOf(e.D())); e = null; } } while(true); A((byte)74, true); } private E A(int i, byte abyte0[]) { if(F) { J.error((new StringBuilder()).append("Session ").append(i).append(" is died, no more Flow creation possible").toString()); return null; } Object obj = (E)L.get(Integer.valueOf(i)); if(obj != null) { J.warn((new StringBuilder()).append("Flow ").append(i).append(" has already been created").toString()); return ((E) (obj)); } if(com.jcumulus.server.rtmfp.pipe.C.B(abyte0, com.jcumulus.server.rtmfp.publisher.F.S)) obj = new F(i, M, this); else if(com.jcumulus.server.rtmfp.pipe.C.B(abyte0, com.jcumulus.server.rtmfp.publisher.C.Q)) obj = new com.jcumulus.server.rtmfp.publisher.C(i, M, this); else if(com.jcumulus.server.rtmfp.pipe.C.A(com.jcumulus.server.rtmfp.publisher.A.Z, abyte0)) obj = new com.jcumulus.server.rtmfp.publisher.A(i, abyte0, M, this); else J.error((new StringBuilder()).append("New unknown flow '").append(Arrays.toString(abyte0)).append("' on session ").append(O).toString()); if(obj != null) { J.debug((new StringBuilder()).append("New flow ").append(i).append(" on session ").append(O).toString()); L.put(Integer.valueOf(i), obj); } return ((E) (obj)); } public void A(boolean flag) { A((byte)74, flag); } protected void A(byte byte0, boolean flag) { R = null; if(F) return; if(N.A() >= com.jcumulus.server.rtmfp.N.C) { if(G.A(0x1c9c380L)) flag = false; byte byte1 = 0; if(flag) byte0 += 4; else byte1 = 2; B b1; synchronized(N) { b1 = N.F(); N.B(11); N.C(com.jcumulus.server.rtmfp.N.G); } if(b1 != null) { b1.C(0); b1.G(byte1); b1.F(6); b1.B(byte0); b1.A(com.jcumulus.server.rtmfp.N.A()); if(flag) b1.A((short)(A + com.jcumulus.server.rtmfp.N.A(G.B()))); A(b1); } } } public boolean A() { return U; } public B B() { N.C(com.jcumulus.server.rtmfp.N.G); return N; } }