001package edu.wpi.first.wpilibj.networktables2.server; 002 003import edu.wpi.first.wpilibj.networktables2.connection.BadMessageException; 004import java.io.*; 005 006import edu.wpi.first.wpilibj.networktables2.*; 007import edu.wpi.first.wpilibj.networktables2.connection.*; 008import edu.wpi.first.wpilibj.networktables2.stream.*; 009import edu.wpi.first.wpilibj.networktables2.thread.*; 010import edu.wpi.first.wpilibj.networktables2.type.*; 011 012/** 013 * Object that adapts messages from a client to the server 014 * 015 * @author Mitchell 016 * 017 */ 018public class ServerConnectionAdapter implements ConnectionAdapter, IncomingEntryReceiver, FlushableOutgoingEntryReceiver{ 019 020 private final ServerNetworkTableEntryStore entryStore; 021 private final IncomingEntryReceiver transactionReceiver; 022 private final ServerAdapterManager adapterListener; 023 /** 024 * the connection this adapter uses 025 */ 026 public final NetworkTableConnection connection; 027 private final NTThread readThread; 028 029 private ServerConnectionState connectionState; 030 private void gotoState(ServerConnectionState newState){ 031 if(connectionState!=newState){ 032 System.out.println(this+" entered connection state: "+newState); 033 connectionState = newState; 034 } 035 } 036 037 /** 038 * Create a server connection adapter for a given stream 039 * 040 * @param stream 041 * @param transactionPool 042 * @param entryStore 043 * @param transactionReceiver 044 * @param adapterListener 045 * @param threadManager 046 */ 047 public ServerConnectionAdapter(final IOStream stream, final ServerNetworkTableEntryStore entryStore, final IncomingEntryReceiver transactionReceiver, final ServerAdapterManager adapterListener, final NetworkTableEntryTypeManager typeManager, final NTThreadManager threadManager) { 048 connection = new NetworkTableConnection(stream, typeManager); 049 this.entryStore = entryStore; 050 this.transactionReceiver = transactionReceiver; 051 this.adapterListener = adapterListener; 052 053 gotoState(ServerConnectionState.GOT_CONNECTION_FROM_CLIENT); 054 readThread = threadManager.newBlockingPeriodicThread(new ConnectionMonitorThread(this, connection), "Server Connection Reader Thread"); 055 } 056 057 058 public void badMessage(BadMessageException e) { 059 gotoState(new ServerConnectionState.Error(e)); 060 adapterListener.close(this, true); 061 } 062 public void ioException(IOException e) { 063 if(e instanceof EOFException) 064 gotoState(ServerConnectionState.CLIENT_DISCONNECTED); 065 else 066 gotoState(new ServerConnectionState.Error(e)); 067 adapterListener.close(this, false); 068 } 069 070 071 /** 072 * stop the read thread and close the stream 073 */ 074 public void shutdown(boolean closeStream) { 075 readThread.stop(); 076 if(closeStream) 077 connection.close(); 078 } 079 080 public void keepAlive() throws IOException { 081 //just let it happen 082 } 083 084 public void clientHello(char protocolRevision) throws IOException { 085 if(connectionState!=ServerConnectionState.GOT_CONNECTION_FROM_CLIENT) 086 throw new BadMessageException("A server should not receive a client hello after it has already connected/entered an error state"); 087 if(protocolRevision!=NetworkTableConnection.PROTOCOL_REVISION){ 088 connection.sendProtocolVersionUnsupported(); 089 throw new BadMessageException("Client Connected with bad protocol revision: 0x"+Integer.toHexString(protocolRevision)); 090 } 091 else{ 092 entryStore.sendServerHello(connection); 093 gotoState(ServerConnectionState.CONNECTED_TO_CLIENT); 094 } 095 } 096 097 public void protocolVersionUnsupported(char protocolRevision) throws IOException { 098 throw new BadMessageException("A server should not receive a protocol version unsupported message"); 099 } 100 101 public void serverHelloComplete() throws IOException { 102 throw new BadMessageException("A server should not receive a server hello complete message"); 103 } 104 105 public void offerIncomingAssignment(NetworkTableEntry entry) { 106 transactionReceiver.offerIncomingAssignment(entry); 107 } 108 109 public void offerIncomingUpdate(NetworkTableEntry entry, char sequenceNumber, Object value) { 110 transactionReceiver.offerIncomingUpdate(entry, sequenceNumber, value); 111 } 112 113 public NetworkTableEntry getEntry(char id) { 114 return entryStore.getEntry(id); 115 } 116 117 public void offerOutgoingAssignment(NetworkTableEntry entry) { 118 try { 119 if(connectionState==ServerConnectionState.CONNECTED_TO_CLIENT) 120 connection.sendEntryAssignment(entry); 121 } catch (IOException e) { 122 ioException(e); 123 } 124 } 125 public void offerOutgoingUpdate(NetworkTableEntry entry) { 126 try { 127 if(connectionState==ServerConnectionState.CONNECTED_TO_CLIENT) 128 connection.sendEntryUpdate(entry); 129 } catch (IOException e) { 130 ioException(e); 131 } 132 } 133 134 135 public void flush() { 136 try { 137 connection.flush(); 138 } catch (IOException e) { 139 ioException(e); 140 } 141 } 142 143 /** 144 * @return the state of the connection 145 */ 146 public ServerConnectionState getConnectionState() { 147 return connectionState; 148 } 149 150 public void ensureAlive() { 151 try { 152 connection.sendKeepAlive(); 153 } catch (IOException e) { 154 ioException(e); 155 } 156 } 157 158}