⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sslchannel.java

📁 Examples to create your Conferencing System in .NET, C# VOIP & Video Conferencing Systems using H.32
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
	 * Raises an event when there is space available for 
	 * writing more data to this socket.
	 */
	public void registerForWrite() throws IOException {
		checkChannelStillValid();
		if (!appWriteInterestSet) {
			log.fine("Activating write interest");
			appWriteInterestSet = true;
			if (initialHandshake) {
				return;
			} else {
				// Check if we can write now
				if (netData.hasRemaining()) {
					assert channelWriteInterestSet : "Write interest should be active";
					// The buffer is full, the application can't write anymore.
					// The write interest must be set...
				} else {
					assert !channelWriteInterestSet : 
						"Write interest should not be active";
					// netData is empty. But don't fire the write event right 
					// now. Instead, register with the SecureChannelManager and 
					// wait for the SelectorThread to call for these events.
					st.getSscManager().registerForWrite(this);
				}
			}
		}
	}	

	/**
	 * Cancel the write interest.
	 */
	public void unregisterForWrite() throws IOException {
		checkChannelStillValid();
		appWriteInterestSet = false;
		st.getSscManager().unregisterForWrite(this);
	}

	/**
	 * Called from the SSLChannelManager when it's time for launching 
	 * the application events
	 */
	void fireReadEvent() {
		appReadInterestSet = false;
		listener.handleRead();
	}
	
	/**
	 * Called from the SSLChannelManager when it's time for launching 
	 * the application events
	 */
	void fireWriteEvent() {
		appWriteInterestSet = false;
		listener.handleWrite();
	}
	
	private void doShutdown() throws IOException {
//		log.fine("");
		assert !netData.hasRemaining() : "Buffer was not empty.";
		// Either shutdown was initiated now or we are on the middle
		// of shutting down and this method was called after emptying 
		// the out buffer
		
		// If the engine has nothing else to do, close the socket. If
		// this socket is dead because of an exception, close it
		// immediately
		if (asynchException != null || engine.isOutboundDone()) {
			log.fine("Outbound is done. Closing socket");
			try {
				// If no data was produced by the call to wrap, shutdown is complete
				sc.close();
			} catch (IOException e) {	/* Ignore. */ }
			return;
		}
		
		// The engine has more things to send 
		/*
		 * By RFC 2616, we can "fire and forget" our close_notify
		 * message, so that's what we'll do here.
		 */
		netData.clear();
		try {
			SSLEngineResult res = engine.wrap(dummy, netData);
			log.info("Wrapping:\n" + res);
		} catch (SSLException e1) {
			// Problems with the engine. Probably it is dead. So close 
			// the socket and forget about it. 
			log.warning("Error during shutdown.\n" + e1.toString());
			try {
				sc.close();
			} catch (IOException e) {	/* Ignore. */ }
			return;
		}
		netData.flip();
		flushData();
	}

	/**
	 *
	 */
	public void close() throws IOException {
		log.fine("Shutting down SSL Channel");
		if (shutdown) {
			log.fine("Shutdown already in progress");
			return;
		}
		// Initiate the shutdown process
		shutdown = true;
		closed = true;
		// We don't need it anymore
		asynchException = null;
		engine.closeOutbound();
		if (netData.hasRemaining()) {
			// If this method is called after an exception, we should
			// close the socket regardless having some data to send.
			assert channelWriteInterestSet : "Data to be sent but no write interest.";
			log.fine("There is some data left to be sent. Waiting: " + netData);
			// We are waiting to send the data
			return;
		} else {
			doShutdown();
		}
	}

	private void finishInitialHandshake() throws IOException {
		// Only during the initial handshake is it necessary to check
		// these flags
		initialHandshake = false;
		// Activate interest
		if (appReadInterestSet) {
			// We are not sure that there is data left to be read on the
			// socket. Therefore, wait for a selector event.
			selectorRegisterForRead();
		}
		if (appWriteInterestSet) {
			assert !netData.hasRemaining() : "There is data left to send after handshake!";
			// We don't need to register with the selector, since we
			// know that the netData buffer is empty after the handshake.
			// Just send the write event to the application.
			st.getSscManager().registerForWrite(this);
		}	
	}
	
	private void doHandshake() throws IOException {
		while (true) {
			SSLEngineResult res;
			log.fine(hsStatus.toString());
			switch (hsStatus) {
			case FINISHED:
				if (initialHandshake) {
					finishInitialHandshake();
				}
				return;
				
			case NEED_TASK:
				doTasks();
				// The hs status was updated, so go back to the switch
				break;
				
			case NEED_UNWRAP:
				readAndUnwrap();
				// During normal operation a call to readAndUnwrap() that results in underflow
				// does not cause the channel to activate read interest with the selector.
				// Therefore, if we are at the initial handshake, we must activate the read
				// insterest explicitily.
				if (initialHandshake && 
						status == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
					selectorRegisterForRead();
				}
				return;

			case NEED_WRAP:
				// First make sure that the out buffer is completely empty. Since we
				// cannot call wrap with data left on the buffer
				if (netData.hasRemaining()) {
					assert channelWriteInterestSet : 
						"Write interest should be active: " + netData;
					return;
				}
				
				// Prepare to write
				netData.clear();
				res = engine.wrap(dummy, netData);
				log.info("Wrapping:\n" + res);
				assert res.bytesProduced() != 0 : "No net data produced during handshake wrap.";
				assert res.bytesConsumed() == 0 : "App data consumed during handshake wrap.";
				hsStatus = res.getHandshakeStatus();
				netData.flip();
				
				// Now send the data and come back here only when 
				// the data is all sent
				if (!flushData()) {
					// There is data left to be send. Wait for it
					return;
				}
				// All data was sent. Break from the switch but don't 
				// exit this method. It will loop again, since there may be more
				// operations that can be done without blocking.
				break;

			case NOT_HANDSHAKING:
				assert false : "doHandshake() should never reach the NOT_HANDSHAKING state";
				return;
			}
		}
	}

	/**
	 * Called from the selector thread.
	 */
	public void handleRead() {
		assert initialHandshake || appReadInterestSet :
			"Trying to read when there is no read interest set";
		assert channelReadInterestSet : "Method called when no read interest was set";
		channelReadInterestSet = false;
		// log.fine("");
		try {
			if (initialHandshake) {
				doHandshake();

			} else if (shutdown) {
				doShutdown();

			} else {
				// The read interest is always set when this method is called					
				assert appReadInterestSet : "handleRead() called without read interest being set";

				int bytesUnwrapped = readAndUnwrap();
				if (bytesUnwrapped == -1) {
					// End of stream. 
					assert engine.isInboundDone() : 
						"End of stream but engine inbound is not closed";

					// We must inform the client of the EOF
					st.getSscManager().registerForRead(this);

				} else if (bytesUnwrapped == 0) {
					// Must read more data
					selectorRegisterForRead();

				} else {
					// There is data to be read by the application. Notify it.
					st.getSscManager().registerForRead(this);
				}
			}
		} catch (IOException e) {
			handleAsynchException(e);
		}
	}

	/**
	 * Tries to write the data on the netData buffer to the socket.
	 * If not all data is sent, the write interest is activated with
	 * the selector thread.
	 * 
	 * @return True if all data was sent. False otherwise.
	 */
	private boolean flushData() throws IOException {		
		assert netData.hasRemaining() : "Trying to write but netData buffer is empty";
		int written;
		try {
			written = sc.write(netData);
		} catch (IOException ioe) {
			// Clear the buffer. If write failed, the socket is dead. Clearing
			// the buffer indicates that no more write should be attempted.
			netData.position(netData.limit());
			throw ioe;
		}
		log.fine("Written to socket: " + written);	
		if (netData.hasRemaining()) {
			// The buffer is not empty. Register again with the selector
			selectorRegisterForWrite();
			return false;
		}  else {
			return true;
		}
	}
		
	/**
	 * Called from the selector thread.
	 */
	public void handleWrite() {
		assert channelWriteInterestSet : "Write event when no write interest set";		
		channelWriteInterestSet = false;
		// log.fine("");
		try {
			if (flushData()) {
				// The buffer was sent completely
				if (initialHandshake) {
					doHandshake();

				} else if (shutdown) {
					doShutdown();

				} else {
					// If the listener is interested in writing, 
					// prepare to fire the event.
					if (appWriteInterestSet) {
						st.getSscManager().registerForWrite(this);
					}
				}
			} else {
				// There is still more data to be sent. Wait for another
				// write event. Calling flush data already resulted in the
				// write interest being reactivated.
			}
		} catch (IOException e) {
			handleAsynchException(e);
		}
	}

	private void handleAsynchException(IOException e) {		
		// Will be sent back to the application next time a public 
		// method is called
		asynchException = e;
		// If the application has any interest set, fire an event.
		// Otherwise, the event will be fired next time a public method
		// is called.
		if (appWriteInterestSet) {
			st.getSscManager().registerForWrite(this);
		}
		if (appReadInterestSet) {
			st.getSscManager().registerForRead(this);
		}
		// We won't be sending any more data.
		engine.closeOutbound();
	}

	private void selectorRegisterForRead() throws IOException {
		log.fine("");
		if (channelReadInterestSet) {
			return;
		}
		channelReadInterestSet = true;
		st.addChannelInterestNow(sc, SelectionKey.OP_READ);
	}

	private void selectorRegisterForWrite() throws IOException {
		log.fine("");
		if (channelWriteInterestSet) {
			return;
		}
		channelWriteInterestSet = true;
		st.addChannelInterestNow(sc, SelectionKey.OP_WRITE);
	}

	/**
	 * Execute delegated tasks in the main thread. These are compute
	 * intensive tasks, so there's no point in scheduling them in a different
	 * thread.
	 */
	private void doTasks() {
		Runnable task;
		while ((task = engine.getDelegatedTask()) != null) {
			task.run();
		}
		hsStatus = engine.getHandshakeStatus();
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -