PageRenderTime 51ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/projects/jgroups-2.10.0/src/org/jgroups/blocks/BasicConnectionTable.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 850 lines | 638 code | 134 blank | 78 comment | 153 complexity | 1bb496b42ac501328c9c40cc9692c8ba MD5 | raw file
  1. package org.jgroups.blocks;
  2. import org.jgroups.logging.Log;
  3. import org.jgroups.logging.LogFactory;
  4. import org.jgroups.Address;
  5. import org.jgroups.Global;
  6. import org.jgroups.Version;
  7. import org.jgroups.stack.IpAddress;
  8. import org.jgroups.util.*;
  9. import java.io.*;
  10. import java.net.InetAddress;
  11. import java.net.ServerSocket;
  12. import java.net.Socket;
  13. import java.net.SocketException;
  14. import java.util.*;
  15. import java.util.Map.Entry;
  16. import java.util.concurrent.BlockingQueue;
  17. import java.util.concurrent.LinkedBlockingQueue;
  18. import java.util.concurrent.atomic.AtomicInteger;
  19. import java.util.concurrent.locks.Lock;
  20. import java.util.concurrent.locks.ReentrantLock;
  21. /**
  22. * Shared class for TCP connection tables.
  23. * @author Scott Marlow
  24. */
  25. public abstract class BasicConnectionTable {
  26. private ThreadFactory factory;
  27. final Map<Address,Connection> conns=new HashMap<Address,Connection>(); // keys: Addresses (peer address), values: Connection
  28. Receiver receiver=null;
  29. boolean use_send_queues=false; // max number of messages in a send queue
  30. int send_queue_size=10000;
  31. InetAddress bind_addr=null;
  32. Address local_addr=null; // bind_addr + port of srv_sock
  33. int srv_port=7800;
  34. int recv_buf_size=120000;
  35. int send_buf_size=60000;
  36. final Vector<ConnectionListener> conn_listeners=new Vector<ConnectionListener>(); // listeners to be notified when a conn is established/torn down
  37. Reaper reaper=null; // closes conns that have been idle for more than n secs
  38. long reaper_interval=60000; // reap unused conns once a minute
  39. long conn_expire_time=300000; // connections can be idle for 5 minutes before they are reaped
  40. int sock_conn_timeout=1000; // max time in millis to wait for Socket.connect() to return
  41. int peer_addr_read_timeout=2000; // max time in milliseconds to block on reading peer address
  42. final ThreadGroup thread_group=new ThreadGroup(Util.getGlobalThreadGroup(), "ConnectionTable");
  43. protected final Log log= LogFactory.getLog(getClass());
  44. final byte[] cookie={'b', 'e', 'l', 'a'};
  45. boolean use_reaper=false; // by default we don't reap idle conns
  46. static final int backlog=20; // 20 conn requests are queued by ServerSocket (addtl will be discarded)
  47. volatile ServerSocket srv_sock=null;
  48. boolean tcp_nodelay=false;
  49. int linger=-1;
  50. protected SocketFactory socket_factory=new DefaultSocketFactory();
  51. /**
  52. * The address which will be broadcast to the group (the externally visible address which this host should
  53. * be contacted on). If external_addr is null, it will default to the same address that the server socket is bound to.
  54. */
  55. InetAddress external_addr=null;
  56. int max_port=0; // maximum port to bind to (if < srv_port, no limit)
  57. Thread acceptor=null; // continuously calls srv_sock.accept()
  58. boolean running=false;
  59. /** Total number of Connections created for this connection table */
  60. static AtomicInteger conn_creations=new AtomicInteger(0);
  61. final static long MAX_JOIN_TIMEOUT=Global.THREAD_SHUTDOWN_WAIT_TIME;
  62. protected BasicConnectionTable() {
  63. factory = new DefaultThreadFactory(new ThreadGroup(Util.getGlobalThreadGroup(),"ConnectionTable"),"Connection Table", false);
  64. }
  65. public final void setReceiver(Receiver r) {
  66. receiver=r;
  67. }
  68. public void addConnectionListener(ConnectionListener l) {
  69. if(l != null && !conn_listeners.contains(l))
  70. conn_listeners.addElement(l);
  71. }
  72. public void removeConnectionListener(ConnectionListener l) {
  73. if(l != null) conn_listeners.removeElement(l);
  74. }
  75. public Address getLocalAddress() {
  76. if(local_addr == null)
  77. local_addr=bind_addr != null ? new IpAddress(bind_addr, srv_port) : null;
  78. return local_addr;
  79. }
  80. public int getSendBufferSize() {
  81. return send_buf_size;
  82. }
  83. public void setSendBufferSize(int send_buf_size) {
  84. this.send_buf_size=send_buf_size;
  85. }
  86. public int getReceiveBufferSize() {
  87. return recv_buf_size;
  88. }
  89. public void setReceiveBufferSize(int recv_buf_size) {
  90. this.recv_buf_size=recv_buf_size;
  91. }
  92. public int getSocketConnectionTimeout() {
  93. return sock_conn_timeout;
  94. }
  95. public void setSocketConnectionTimeout(int sock_conn_timeout) {
  96. this.sock_conn_timeout=sock_conn_timeout;
  97. }
  98. public int getPeerAddressReadTimeout() {
  99. return peer_addr_read_timeout;
  100. }
  101. public void setPeerAddressReadTimeout(int peer_addr_read_timeout) {
  102. this.peer_addr_read_timeout=peer_addr_read_timeout;
  103. }
  104. public int getNumConnections() {
  105. return conns.size();
  106. }
  107. public static int getNumberOfConnectionCreations() {
  108. return conn_creations.intValue();
  109. }
  110. public boolean getTcpNodelay() {
  111. return tcp_nodelay;
  112. }
  113. public void setTcpNodelay(boolean tcp_nodelay) {
  114. this.tcp_nodelay=tcp_nodelay;
  115. }
  116. public int getLinger() {
  117. return linger;
  118. }
  119. public void setLinger(int linger) {
  120. this.linger=linger;
  121. }
  122. public void setThreadFactory(ThreadFactory factory){
  123. this.factory = factory;
  124. }
  125. public ThreadFactory getThreadFactory(){
  126. return factory;
  127. }
  128. public SocketFactory getSocketFactory() {
  129. return socket_factory;
  130. }
  131. public void setSocketFactory(SocketFactory socket_factory) {
  132. this.socket_factory=socket_factory;
  133. }
  134. public boolean getUseSendQueues() {return use_send_queues;}
  135. public void setUseSendQueues(boolean flag) {this.use_send_queues=flag;}
  136. public int getSendQueueSize() {
  137. return send_queue_size;
  138. }
  139. public void setSendQueueSize(int send_queue_size) {
  140. this.send_queue_size=send_queue_size;
  141. }
  142. public void start() throws Exception {
  143. running=true;
  144. }
  145. public void stop() {
  146. running=false;
  147. // 1. Stop the reaper
  148. if(reaper != null)
  149. reaper.stop();
  150. // 2. close the server socket (this also stops the acceptor thread)
  151. if(srv_sock != null) {
  152. try {
  153. ServerSocket tmp=srv_sock;
  154. srv_sock=null;
  155. socket_factory.close(tmp);
  156. if(acceptor != null)
  157. Util.interruptAndWaitToDie(acceptor);
  158. }
  159. catch(Exception e) {
  160. }
  161. }
  162. // 3. then close the connections
  163. Collection<Connection> connsCopy=null;
  164. synchronized(conns) {
  165. connsCopy=new LinkedList<Connection>(conns.values());
  166. conns.clear();
  167. }
  168. for(Connection conn:connsCopy) {
  169. conn.destroy();
  170. }
  171. connsCopy.clear();
  172. local_addr=null;
  173. }
  174. /**
  175. Remove <code>addr</code>from connection table. This is typically triggered when a member is suspected.
  176. */
  177. public void removeConnection(Address addr) {
  178. Connection conn;
  179. synchronized(conns) {
  180. conn=conns.remove(addr);
  181. }
  182. if(conn != null) {
  183. try {
  184. conn.destroy(); // won't do anything if already destroyed
  185. }
  186. catch(Exception e) {
  187. }
  188. }
  189. if(log.isTraceEnabled()) log.trace("removed " + addr + ", connections are " + toString());
  190. }
  191. /**
  192. * Calls the receiver callback. We do not serialize access to this method, and it may be called concurrently
  193. * by several Connection handler threads. Therefore the receiver needs to be reentrant.
  194. */
  195. public void receive(Address sender, byte[] data, int offset, int length) {
  196. if(receiver != null) {
  197. receiver.receive(sender, data, offset, length);
  198. }
  199. else
  200. if(log.isErrorEnabled()) log.error("receiver is null (not set) !");
  201. }
  202. public String toString() {
  203. StringBuilder ret=new StringBuilder();
  204. Address key;
  205. Connection val;
  206. Entry<Address,Connection> entry;
  207. HashMap<Address,Connection> copy;
  208. synchronized(conns) {
  209. copy=new HashMap<Address,Connection>(conns);
  210. }
  211. ret.append("local_addr=" + local_addr).append("\n");
  212. ret.append("connections (" + copy.size() + "):\n");
  213. for(Iterator<Entry<Address,Connection>> it=copy.entrySet().iterator(); it.hasNext();) {
  214. entry=it.next();
  215. key=entry.getKey();
  216. val=entry.getValue();
  217. ret.append(key + ": " + val + '\n');
  218. }
  219. ret.append('\n');
  220. return ret.toString();
  221. }
  222. void notifyConnectionOpened(Address peer) {
  223. if(peer == null) return;
  224. for(int i=0; i < conn_listeners.size(); i++)
  225. conn_listeners.elementAt(i).connectionOpened(peer);
  226. }
  227. void notifyConnectionClosed(Address peer) {
  228. if(peer == null) return;
  229. for(int i=0; i < conn_listeners.size(); i++)
  230. conn_listeners.elementAt(i).connectionClosed(peer);
  231. }
  232. void addConnection(Address peer, Connection c) {
  233. synchronized (conns) {
  234. conns.put(peer, c);
  235. }
  236. if(reaper != null && !reaper.isRunning())
  237. reaper.start();
  238. }
  239. public void send(Address dest, byte[] data, int offset, int length) throws Exception {
  240. Connection conn;
  241. if(dest == null) {
  242. if(log.isErrorEnabled())
  243. log.error("destination is null");
  244. return;
  245. }
  246. if(data == null) {
  247. log.warn("data is null; discarding packet");
  248. return;
  249. }
  250. if(!running) {
  251. if(log.isWarnEnabled())
  252. log.warn("connection table is not running, discarding message to " + dest);
  253. return;
  254. }
  255. if(dest.equals(local_addr)) {
  256. receive(local_addr, data, offset, length);
  257. return;
  258. }
  259. // 1. Try to obtain correct Connection (or create one if not yet existent)
  260. try {
  261. conn=getConnection(dest);
  262. if(conn == null) return;
  263. }
  264. catch(Throwable ex) {
  265. throw new Exception("connection to " + dest + " could not be established", ex);
  266. }
  267. // 2. Send the message using that connection
  268. try {
  269. conn.send(data, offset, length);
  270. }
  271. catch(Throwable ex) {
  272. if(log.isTraceEnabled())
  273. log.trace("sending msg to " + dest + " failed (" + ex.getClass().getName() + "); removing from connection table", ex);
  274. removeConnection(dest);
  275. }
  276. }
  277. abstract Connection getConnection(Address dest) throws Exception;
  278. /**
  279. * Removes all connections from ConnectionTable which are not in current_mbrs
  280. * @param current_mbrs
  281. */
  282. public void retainAll(Collection<Address> current_mbrs) {
  283. if(current_mbrs == null) return;
  284. HashMap<Address,Connection> copy;
  285. synchronized(conns) {
  286. copy=new HashMap<Address,Connection>(conns);
  287. conns.keySet().retainAll(current_mbrs);
  288. }
  289. copy.keySet().removeAll(current_mbrs);
  290. //destroy orphaned connection i.e. connections
  291. //to members that are not in current view
  292. for(Connection orphanConnection:copy.values()){
  293. if (log.isTraceEnabled())
  294. log.trace("At " + local_addr + " destroying orphan to "
  295. + orphanConnection.getPeerAddress());
  296. orphanConnection.destroy();
  297. }
  298. copy.clear();
  299. }
  300. /** Used for message reception. */
  301. public interface Receiver {
  302. void receive(Address sender, byte[] data, int offset, int length);
  303. }
  304. /** Used to be notified about connection establishment and teardown. */
  305. public interface ConnectionListener {
  306. void connectionOpened(Address peer_addr);
  307. void connectionClosed(Address peer_addr);
  308. }
  309. class Connection implements Runnable {
  310. Socket sock=null; // socket to/from peer (result of srv_sock.accept() or new Socket())
  311. String sock_addr=null; // used for Thread.getName()
  312. DataOutputStream out=null; // for sending messages
  313. DataInputStream in=null; // for receiving messages
  314. Thread receiverThread=null; // thread for receiving messages
  315. Address peer_addr=null; // address of the 'other end' of the connection
  316. final Lock send_lock=new ReentrantLock(); // serialize send()
  317. long last_access=System.currentTimeMillis(); // last time a message was sent or received
  318. /** Bounded queue of data to be sent to the peer of this connection */
  319. BlockingQueue<byte[]> send_queue=null;
  320. Sender sender=null;
  321. boolean is_running=false;
  322. private String getSockAddress() {
  323. if(sock_addr != null)
  324. return sock_addr;
  325. if(sock != null) {
  326. StringBuilder sb;
  327. sb=new StringBuilder();
  328. sb.append(sock.getLocalAddress().getHostAddress()).append(':').append(sock.getLocalPort());
  329. sb.append(" - ").append(sock.getInetAddress().getHostAddress()).append(':').append(sock.getPort());
  330. sock_addr=sb.toString();
  331. }
  332. return sock_addr;
  333. }
  334. Connection(Socket s, Address peer_addr) {
  335. sock=s;
  336. this.peer_addr=peer_addr;
  337. if(use_send_queues) {
  338. send_queue=new LinkedBlockingQueue<byte[]>(send_queue_size);
  339. sender=new Sender();
  340. }
  341. try {
  342. // out=new DataOutputStream(sock.getOutputStream());
  343. // in=new DataInputStream(sock.getInputStream());
  344. // The change to buffered input and output stream yielded a 400% performance gain !
  345. // bela Sept 7 2006
  346. out=new DataOutputStream(new BufferedOutputStream(sock.getOutputStream()));
  347. in=new DataInputStream(new BufferedInputStream(sock.getInputStream()));
  348. if(sender != null)
  349. sender.start();
  350. conn_creations.incrementAndGet();
  351. }
  352. catch(Exception ex) {
  353. if(log.isErrorEnabled()) log.error("exception is " + ex);
  354. }
  355. }
  356. boolean established() {
  357. return receiverThread != null;
  358. }
  359. void setPeerAddress(Address peer_addr) {
  360. this.peer_addr=peer_addr;
  361. }
  362. Address getPeerAddress() {return peer_addr;}
  363. void updateLastAccessed() {
  364. last_access=System.currentTimeMillis();
  365. }
  366. void init() {
  367. is_running=true;
  368. if(receiverThread == null || !receiverThread.isAlive()) {
  369. // Roland Kurmann 4/7/2003, put in thread_group
  370. receiverThread=getThreadFactory().newThread(thread_group,this, "ConnectionTable.Connection.Receiver [" + getSockAddress() + "]");
  371. receiverThread.start();
  372. if(log.isTraceEnabled())
  373. log.trace("receiver started: " + receiverThread);
  374. }
  375. }
  376. /**
  377. * Returns true if underlying socket to peer is closed
  378. *
  379. * @return
  380. */
  381. boolean isSocketClosed() {
  382. return !(sock != null && sock.isConnected());
  383. }
  384. void destroy() {
  385. if(log.isTraceEnabled()) log.trace("destroyed " + this);
  386. is_running=false;
  387. closeSocket(); // should terminate handler as well
  388. if(sender != null)
  389. sender.stop();
  390. Thread tmp=receiverThread;
  391. receiverThread=null;
  392. if(tmp != null) {
  393. Util.interruptAndWaitToDie(tmp);
  394. }
  395. conn_creations.decrementAndGet();
  396. }
  397. /**
  398. *
  399. * @param data Guaranteed to be non null
  400. * @param offset
  401. * @param length
  402. */
  403. void send(byte[] data, int offset, int length) {
  404. if(!is_running) {
  405. if(log.isWarnEnabled())
  406. log.warn("Connection is not running, discarding message");
  407. return;
  408. }
  409. if(use_send_queues) {
  410. try {
  411. // we need to copy the byte[] buffer here because the original buffer might get changed meanwhile
  412. byte[] tmp=new byte[length];
  413. System.arraycopy(data, offset, tmp, 0, length);
  414. send_queue.put(tmp);
  415. }
  416. catch(InterruptedException e) {
  417. Thread.currentThread().interrupt();
  418. }
  419. }
  420. else
  421. _send(data, offset, length, true);
  422. }
  423. /**
  424. * Sends data using the 'out' output stream of the socket
  425. * @param data
  426. * @param offset
  427. * @param length
  428. * @param acquire_lock
  429. */
  430. private void _send(byte[] data, int offset, int length, boolean acquire_lock) {
  431. if(acquire_lock)
  432. send_lock.lock();
  433. try {
  434. doSend(data, offset, length);
  435. updateLastAccessed();
  436. }
  437. catch(InterruptedException iex) {
  438. Thread.currentThread().interrupt(); // set interrupt flag again
  439. }
  440. catch(Throwable ex) {
  441. if(log.isErrorEnabled()) log.error("failed sending data to " + peer_addr + ": " + ex);
  442. }
  443. finally {
  444. if(acquire_lock)
  445. send_lock.unlock();
  446. }
  447. }
  448. void doSend(byte[] data, int offset, int length) throws Exception {
  449. try {
  450. // we're using 'double-writes', sending the buffer to the destination in 2 pieces. this would
  451. // ensure that, if the peer closed the connection while we were idle, we would get an exception.
  452. // this won't happen if we use a single write (see Stevens, ch. 5.13).
  453. if(out != null) {
  454. out.writeInt(length); // write the length of the data buffer first
  455. Util.doubleWrite(data, offset, length, out);
  456. out.flush(); // may not be very efficient (but safe)
  457. }
  458. }
  459. catch(Exception ex) {
  460. removeConnection(peer_addr);
  461. throw ex;
  462. }
  463. }
  464. /**
  465. * Reads the peer's address. First a cookie has to be sent which has to match my own cookie, otherwise
  466. * the connection will be refused
  467. */
  468. Address readPeerAddress(Socket client_sock) throws Exception {
  469. Address client_peer_addr=null;
  470. byte[] input_cookie=new byte[cookie.length];
  471. int client_port=client_sock != null? client_sock.getPort() : 0;
  472. short version;
  473. InetAddress client_addr=client_sock != null? client_sock.getInetAddress() : null;
  474. int timeout=client_sock.getSoTimeout();
  475. client_sock.setSoTimeout(peer_addr_read_timeout);
  476. try {
  477. if(in != null) {
  478. initCookie(input_cookie);
  479. // read the cookie first
  480. in.readFully(input_cookie, 0, input_cookie.length);
  481. if(!matchCookie(input_cookie))
  482. throw new SocketException("ConnectionTable.Connection.readPeerAddress(): cookie sent by " +
  483. client_peer_addr + " does not match own cookie; terminating connection");
  484. // then read the version
  485. version=in.readShort();
  486. if(Version.isBinaryCompatible(version) == false) {
  487. if(log.isWarnEnabled())
  488. log.warn(new StringBuilder("packet from ").append(client_addr).append(':').append(client_port).
  489. append(" has different version (").append(Version.print(version)).append(") from ours (").
  490. append(Version.printVersion()).append("). This may cause problems").toString());
  491. }
  492. client_peer_addr=new IpAddress();
  493. client_peer_addr.readFrom(in);
  494. updateLastAccessed();
  495. }
  496. return client_peer_addr;
  497. }
  498. finally {
  499. client_sock.setSoTimeout(timeout);
  500. }
  501. }
  502. /**
  503. * Send the cookie first, then the our port number. If the cookie doesn't match the receiver's cookie,
  504. * the receiver will reject the connection and close it.
  505. */
  506. void sendLocalAddress(Address local_addr) {
  507. if(local_addr == null) {
  508. if(log.isWarnEnabled()) log.warn("local_addr is null");
  509. return;
  510. }
  511. if(out != null) {
  512. try {
  513. // write the cookie
  514. out.write(cookie, 0, cookie.length);
  515. // write the version
  516. out.writeShort(Version.version);
  517. local_addr.writeTo(out);
  518. out.flush(); // needed ?
  519. updateLastAccessed();
  520. }
  521. catch(Throwable t) {
  522. if(log.isErrorEnabled()) log.error("exception is " + t);
  523. }
  524. }
  525. }
  526. void initCookie(byte[] c) {
  527. if(c != null)
  528. for(int i=0; i < c.length; i++)
  529. c[i]=0;
  530. }
  531. boolean matchCookie(byte[] input) {
  532. if(input == null || input.length < cookie.length) return false;
  533. for(int i=0; i < cookie.length; i++)
  534. if(cookie[i] != input[i]) return false;
  535. return true;
  536. }
  537. String printCookie(byte[] c) {
  538. if(c == null) return "";
  539. return new String(c);
  540. }
  541. public void run() {
  542. while(receiverThread != null && receiverThread.equals(Thread.currentThread()) && is_running) {
  543. try {
  544. if(in == null) {
  545. if(log.isErrorEnabled()) log.error("input stream is null !");
  546. break;
  547. }
  548. int len=in.readInt();
  549. byte[] buf=new byte[len];
  550. in.readFully(buf, 0, len);
  551. updateLastAccessed();
  552. receive(peer_addr, buf, 0, len); // calls receiver.receive(msg)
  553. }
  554. catch(OutOfMemoryError mem_ex) {
  555. if(log.isWarnEnabled()) log.warn("dropped invalid message, closing connection");
  556. break; // continue;
  557. }
  558. catch(IOException io_ex) {
  559. //this is very common occurrence, hence log under trace level
  560. if(log.isTraceEnabled()) log.trace("Exception while read blocked for data from peer ", io_ex);
  561. notifyConnectionClosed(peer_addr);
  562. break;
  563. }
  564. catch(Throwable e) {
  565. if(log.isWarnEnabled()) log.warn("Problem encountered while receiving message from peer " + peer_addr, e);
  566. }
  567. }
  568. if(log.isTraceEnabled())
  569. log.trace("ConnectionTable.Connection.Receiver terminated");
  570. receiverThread=null;
  571. closeSocket();
  572. // remove(peer_addr);
  573. }
  574. public String toString() {
  575. StringBuilder ret=new StringBuilder();
  576. InetAddress local=null, remote=null;
  577. String local_str, remote_str;
  578. Socket tmp_sock=sock;
  579. if(tmp_sock == null)
  580. ret.append("<null socket>");
  581. else {
  582. //since the sock variable gets set to null we want to make
  583. //make sure we make it through here without a nullpointer exception
  584. local=tmp_sock.getLocalAddress();
  585. remote=tmp_sock.getInetAddress();
  586. local_str=local != null ? Util.shortName(local) : "<null>";
  587. remote_str=remote != null ? Util.shortName(remote) : "<null>";
  588. ret.append('<' + local_str + ':' + tmp_sock.getLocalPort() +
  589. " --> " + remote_str + ':' + tmp_sock.getPort() + "> (" +
  590. ((System.currentTimeMillis() - last_access) / 1000) + " secs old)");
  591. }
  592. tmp_sock=null;
  593. return ret.toString();
  594. }
  595. void closeSocket() {
  596. Util.close(sock); // should actually close in/out (so we don't need to close them explicitly)
  597. sock=null;
  598. Util.close(out); // flushes data
  599. // removed 4/22/2003 (request by Roland Kurmann)
  600. // out=null;
  601. Util.close(in);
  602. }
  603. class Sender implements Runnable {
  604. Thread senderThread;
  605. private boolean is_it_running=false;
  606. void start() {
  607. if(senderThread == null || !senderThread.isAlive()) {
  608. senderThread=getThreadFactory().newThread(thread_group,this, "ConnectionTable.Connection.Sender local_addr=" + local_addr + " [" + getSockAddress() + "]");
  609. senderThread.setDaemon(true);
  610. is_it_running=true;
  611. senderThread.start();
  612. if(log.isTraceEnabled())
  613. log.trace("sender thread started: " + senderThread);
  614. }
  615. }
  616. void stop() {
  617. is_it_running=false;
  618. if(send_queue != null)
  619. send_queue.clear();
  620. if(senderThread != null) {
  621. Thread tmp=senderThread;
  622. senderThread=null;
  623. Util.interruptAndWaitToDie(tmp);
  624. }
  625. }
  626. boolean isRunning() {
  627. return is_it_running && senderThread != null;
  628. }
  629. public void run() {
  630. byte[] data;
  631. while(senderThread != null && senderThread.equals(Thread.currentThread()) && is_it_running) {
  632. try {
  633. data=send_queue.take();
  634. if(data == null)
  635. continue;
  636. // we don't need to serialize access to 'out' as we're the only thread sending messages
  637. _send(data, 0, data.length, false);
  638. }
  639. catch(InterruptedException e) {
  640. ;
  641. }
  642. }
  643. is_it_running=false;
  644. if(log.isTraceEnabled())
  645. log.trace("ConnectionTable.Connection.Sender thread terminated");
  646. }
  647. }
  648. }
  649. class Reaper implements Runnable {
  650. Thread t=null;
  651. Reaper() {
  652. ;
  653. }
  654. // return true if we have zero connections
  655. private boolean haveZeroConnections() {
  656. synchronized(conns) {
  657. return conns.isEmpty();
  658. }
  659. }
  660. public void start() {
  661. if(haveZeroConnections())
  662. return;
  663. if(t != null && !t.isAlive())
  664. t=null;
  665. if(t == null) {
  666. //RKU 7.4.2003, put in threadgroup
  667. t=getThreadFactory().newThread(thread_group, this, "ConnectionTable.ReaperThread");
  668. t.setDaemon(true); // will allow us to terminate if all remaining threads are daemons
  669. t.start();
  670. }
  671. }
  672. public void stop() {
  673. Thread tmp=t;
  674. if(t != null)
  675. t=null;
  676. if(tmp != null) {
  677. Util.interruptAndWaitToDie(tmp);
  678. }
  679. }
  680. public boolean isRunning() {
  681. return t != null;
  682. }
  683. public void run() {
  684. Connection connection;
  685. Entry<Address,Connection> entry;
  686. long curr_time;
  687. if(log.isDebugEnabled()) log.debug("connection reaper thread was started. Number of connections=" +
  688. conns.size() + ", reaper_interval=" + reaper_interval + ", conn_expire_time=" +
  689. conn_expire_time);
  690. while(!haveZeroConnections() && t != null && t.equals(Thread.currentThread())) {
  691. Util.sleep(reaper_interval);
  692. if(t == null || !Thread.currentThread().equals(t))
  693. break;
  694. synchronized(conns) {
  695. curr_time=System.currentTimeMillis();
  696. for(Iterator<Entry<Address,Connection>> it=conns.entrySet().iterator(); it.hasNext();) {
  697. entry=it.next();
  698. connection=entry.getValue();
  699. if(log.isTraceEnabled()) log.trace("connection is " +
  700. ((curr_time - connection.last_access) / 1000) + " seconds old (curr-time=" +
  701. curr_time + ", last_access=" + connection.last_access + ')');
  702. if(connection.last_access + conn_expire_time < curr_time) {
  703. if(log.isTraceEnabled()) log.trace("connection " + connection +
  704. " has been idle for too long (conn_expire_time=" + conn_expire_time +
  705. "), will be removed");
  706. connection.destroy();
  707. it.remove();
  708. }
  709. }
  710. }
  711. }
  712. if(log.isDebugEnabled()) log.debug("reaper terminated");
  713. t=null;
  714. }
  715. }
  716. }