PageRenderTime 41ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/deskshare/applet/src/main/java/org/bigbluebutton/deskshare/client/net/NetworkStreamSender.java

http://github.com/bigbluebutton/bigbluebutton
Java | 302 lines | 231 code | 36 blank | 35 comment | 36 complexity | f76c33f23776b1ac725b179da01cfab7 MD5 | raw file
Possible License(s): LGPL-3.0
  1. /**
  2. *
  3. * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
  4. *
  5. * Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
  6. *
  7. * This program is free software; you can redistribute it and/or modify it under the
  8. * terms of the GNU Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2.1 of the License, or (at your option) any later
  10. * version.
  11. *
  12. * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
  13. * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
  14. * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License along
  17. * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
  18. *
  19. **/
  20. package org.bigbluebutton.deskshare.client.net;
  21. import java.io.IOException;
  22. import java.net.InetSocketAddress;
  23. import java.net.Socket;
  24. import java.net.UnknownHostException;
  25. import java.util.concurrent.BlockingQueue;
  26. import java.util.concurrent.ExecutorService;
  27. import java.util.concurrent.Executors;
  28. import java.util.concurrent.LinkedBlockingQueue;
  29. import net.jcip.annotations.ThreadSafe;
  30. import org.bigbluebutton.deskshare.client.ExitCode;
  31. import org.bigbluebutton.deskshare.client.blocks.BlockManager;
  32. import org.bigbluebutton.deskshare.common.Dimension;
  33. @ThreadSafe
  34. public class NetworkStreamSender implements NextBlockRetriever, NetworkStreamListener {
  35. public static final String NAME = "NETWORKSTREAMSENDER: ";
  36. private ExecutorService executor;
  37. private final BlockingQueue<Message> blockDataQ = new LinkedBlockingQueue<Message>();
  38. private final int numThreads;
  39. private final String host;
  40. private final int port;
  41. private final String room;
  42. private final boolean httpTunnel;
  43. private final boolean useSVC2;
  44. private NetworkSocketStreamSender[] socketSenders;
  45. private NetworkHttpStreamSender[] httpSenders;
  46. private boolean tunneling = false;
  47. private boolean stopped = true;
  48. private int numRunningThreads = 0;
  49. private Dimension screenDim;
  50. private Dimension blockDim;
  51. private BlockManager blockManager;
  52. private NetworkConnectionListener listener;
  53. private final SequenceNumberGenerator seqNumGenerator = new SequenceNumberGenerator();
  54. public NetworkStreamSender(BlockManager blockManager, String host, int port,
  55. String room, Dimension screenDim, Dimension blockDim, boolean httpTunnel, boolean useSVC2) {
  56. this.blockManager = blockManager;
  57. this.host = host;
  58. this.port = port;
  59. this.room = room;
  60. this.screenDim = screenDim;
  61. this.blockDim = blockDim;
  62. this.httpTunnel = httpTunnel;
  63. this.useSVC2 = useSVC2;
  64. //numThreads = Runtime.getRuntime().availableProcessors() * 3;
  65. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  66. // Use one thread per row of tiles
  67. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  68. numThreads = screenDim.getHeight() / blockDim.getHeight();
  69. System.out.println(NAME + "Starting up " + numThreads + " sender threads.");
  70. executor = Executors.newFixedThreadPool(numThreads);
  71. }
  72. public void addNetworkConnectionListener(NetworkConnectionListener listener) {
  73. this.listener = listener;
  74. }
  75. private void notifyNetworkConnectionListener(ExitCode reason) {
  76. if (listener != null) listener.networkConnectionException(reason);
  77. }
  78. private boolean trySocketConnection(String host, int port) {
  79. try {
  80. Socket socket = new Socket();
  81. InetSocketAddress endpoint = new InetSocketAddress(host, port);
  82. socket.connect(endpoint, 5000);
  83. socket.close();
  84. return true;
  85. } catch (UnknownHostException e) {
  86. System.out.println("Unknown host [" + host + "]");
  87. } catch (IOException e) {
  88. System.out.println("Cannot connect to [" + host + ":" + port + "]");
  89. }
  90. return false;
  91. }
  92. public boolean connect() {
  93. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  94. // If the requested server port is nonzero, then try to connect to the
  95. // requested port. Otherwise, tunnel the connection to the web server.
  96. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  97. if ((port != 0) && trySocketConnection(host, port)) {
  98. socketSenders = new NetworkSocketStreamSender[numThreads];
  99. for (int i = 0; i < numThreads; i++) {
  100. try {
  101. createSender(i);
  102. numRunningThreads++;
  103. } catch (ConnectionException e) {
  104. System.out.println("Failed to connect using socket.");
  105. }
  106. }
  107. } else {
  108. if (httpTunnel) {
  109. System.out.println(NAME + "Trying http tunneling");
  110. numRunningThreads = 0;
  111. if (tryHttpTunneling()) {
  112. tunneling = true;
  113. System.out.println(NAME + "Will use http tunneling");
  114. httpSenders = new NetworkHttpStreamSender[numThreads];
  115. for (int i = 0; i < numThreads; i++) {
  116. try {
  117. createHttpSender(i);
  118. numRunningThreads++;
  119. } catch (ConnectionException e) {
  120. System.out.println("Failed to connect using http.");
  121. }
  122. }
  123. }
  124. }
  125. }
  126. if (numRunningThreads != numThreads) {
  127. try {
  128. stop();
  129. } catch (ConnectionException e) {
  130. System.out.println("Failed to stop deskshare applet.");
  131. }
  132. return false;
  133. }
  134. return true;
  135. }
  136. private void createSender(int i) throws ConnectionException {
  137. socketSenders[i] = new NetworkSocketStreamSender(i, this, room, screenDim, blockDim, seqNumGenerator, useSVC2);
  138. socketSenders[i].addListener(this);
  139. socketSenders[i].connect(host, port);
  140. }
  141. private void createHttpSender(int i) throws ConnectionException {
  142. httpSenders[i] = new NetworkHttpStreamSender(i, this, room, screenDim, blockDim, seqNumGenerator, useSVC2);
  143. httpSenders[i].addListener(this);
  144. httpSenders[i].connect(host);
  145. }
  146. public void send(Message message) {
  147. boolean added = blockDataQ.offer(message);
  148. System.out.println("Offered to queue: res="+added+" size="+blockDataQ.size()+" remaining_capacity="+blockDataQ.remainingCapacity());
  149. }
  150. public void start() {
  151. System.out.println(NAME + "Starting network sender.");
  152. if (tunneling) {
  153. // NEW
  154. httpSenders[0].sendStartStreamMessage();
  155. for (int i = 0; i < numRunningThreads; i++) {
  156. executor.execute(httpSenders[i]);
  157. }
  158. } else {
  159. for (int i = 0; i < numRunningThreads; i++) {
  160. try {
  161. socketSenders[i].sendStartStreamMessage();
  162. executor.execute(socketSenders[i]);
  163. } catch (ConnectionException e) {
  164. // TODO Auto-generated catch block
  165. e.printStackTrace();
  166. }
  167. }
  168. }
  169. stopped = false;
  170. }
  171. private volatile boolean clearQ = true;
  172. public void stop() throws ConnectionException {
  173. stopped = true;
  174. System.out.println(NAME + "Stopping network sender");
  175. // NEW
  176. if (tunneling) {
  177. if (httpSenders == null)
  178. return;
  179. if (httpSenders[0] != null)
  180. httpSenders[0].disconnect();
  181. }
  182. if (socketSenders == null)
  183. return;
  184. for (int i = 0; i < numRunningThreads; i++) {
  185. try {
  186. if (tunneling) {
  187. if (httpSenders[i] != null)
  188. httpSenders[i].stopProcessingBlocks();
  189. } else {
  190. //socketSenders[i].disconnect();
  191. if (clearQ) {
  192. clearQ = false;
  193. blockDataQ.clear();
  194. }
  195. send(new PoisonMessage());
  196. // LRP changed 06-06-2012
  197. Thread.yield();
  198. //Thread.sleep(1000);
  199. socketSenders[i].disconnect();
  200. }
  201. } catch (Exception e) {
  202. e.printStackTrace();
  203. }
  204. }
  205. System.out.println("Shutting down executor");
  206. executor.shutdownNow();
  207. System.out.println("Shutting down executor [DONE]");
  208. httpSenders = null;
  209. socketSenders = null;
  210. }
  211. private boolean tryHttpTunneling() {
  212. NetworkHttpStreamSender httpSender = new NetworkHttpStreamSender(0, this, room, screenDim, blockDim, seqNumGenerator, useSVC2);
  213. try {
  214. httpSender.connect(host);
  215. return true;
  216. } catch (ConnectionException e) {
  217. System.out.println(NAME + "Problem connecting to " + host);
  218. }
  219. return false;
  220. }
  221. public void blockSent(int position) {
  222. blockManager.blockSent(position);
  223. }
  224. public EncodedBlockData getBlockToSend(int position) {
  225. return blockManager.getBlock(position).encode();
  226. }
  227. public Message getNextMessageToSend() throws InterruptedException {
  228. try {
  229. return (Message) blockDataQ.take();
  230. } catch (InterruptedException e) {
  231. if (!stopped)
  232. e.printStackTrace();
  233. throw e;
  234. }
  235. }
  236. @Override
  237. public void networkException(int id, ExitCode reason) {
  238. try {
  239. numRunningThreads--;
  240. if (tunneling) {
  241. // httpSenders[id].disconnect();
  242. System.out.println(NAME + "Failed to use http tunneling. Stopping.");
  243. stop();
  244. notifyNetworkConnectionListener(reason);
  245. } else {
  246. socketSenders[id].disconnect();
  247. }
  248. if (numRunningThreads < 1) {
  249. System.out.println(NAME + "No more sender threads. Stopping.");
  250. stop();
  251. notifyNetworkConnectionListener(reason);
  252. } else {
  253. System.out.println(NAME + "Sender thread stopped. " + numRunningThreads + " sender threads remaining.");
  254. }
  255. } catch (ConnectionException e) {
  256. // TODO Auto-generated catch block
  257. e.printStackTrace();
  258. if (numRunningThreads < 1) {
  259. System.out.println(NAME + "No more sender threads. Stopping.");
  260. notifyNetworkConnectionListener(reason);
  261. } else {
  262. System.out.println(NAME + "Sender thread stopped. " + numRunningThreads + " sender threads remaining.");
  263. }
  264. }
  265. }
  266. }