package net.i2p.sam; /* * free (adj.): unencumbered; not under the control of others * Written by human in 2004 and released into the public domain * with no warranty of any kind, either expressed or implied. * It probably won't make your computer catch on fire, or eat * your children, but it might. Use at your own risk. * */ import java.io.IOException; import java.nio.channels.SocketChannel; import java.util.Properties; import net.i2p.data.DataFormatException; import net.i2p.util.Log; /** * Class able to handle a SAM version 2 client connection. * * @author mkvore */ class SAMv2Handler extends SAMv1Handler implements SAMRawReceiver, SAMDatagramReceiver, SAMStreamReceiver { /** * Create a new SAM version 2 handler. This constructor expects * that the SAM HELLO message has been still answered (and * stripped) from the socket input stream. * * @param s Socket attached to a SAM client * @param verMajor SAM major version to manage (should be 2) * @param verMinor SAM minor version to manage */ public SAMv2Handler(SocketChannel s, int verMajor, int verMinor, SAMBridge parent) throws SAMException, IOException { this(s, verMajor, verMinor, new Properties(), parent); } /** * Create a new SAM version 2 handler. This constructor expects * that the SAM HELLO message has been still answered (and * stripped) from the socket input stream. * * @param s Socket attached to a SAM client * @param verMajor SAM major version to manage (should be 2) * @param verMinor SAM minor version to manage * @param i2cpProps properties to configure the I2CP connection (host, port, etc) */ public SAMv2Handler(SocketChannel s, int verMajor, int verMinor, Properties i2cpProps, SAMBridge parent) throws SAMException, IOException { super(s, verMajor, verMinor, i2cpProps, parent); } @Override public boolean verifVersion() { return (verMajor == 2); } SAMStreamSession newSAMStreamSession(String destKeystream, String direction, Properties props ) throws IOException, DataFormatException, SAMException { return new SAMv2StreamSession(destKeystream, direction, props, this) ; } /* Parse and execute a STREAM message */ @Override protected boolean execStreamMessage ( String opcode, Properties props ) { if ( getStreamSession() == null ) { _log.error ( "STREAM message received, but no STREAM session exists" ); return false; } if ( opcode.equals ( "SEND" ) ) { return execStreamSend ( props ); } else if ( opcode.equals ( "CONNECT" ) ) { return execStreamConnect ( props ); } else if ( opcode.equals ( "CLOSE" ) ) { return execStreamClose ( props ); } else if ( opcode.equals ( "RECEIVE") ) { return execStreamReceive( props ); } else { if (_log.shouldLog(Log.DEBUG)) _log.debug ( "Unrecognized RAW message opcode: \"" + opcode + "\"" ); return false; } } private boolean execStreamReceive ( Properties props ) { if (props.isEmpty()) { if (_log.shouldLog(Log.DEBUG)) _log.debug ( "No parameters specified in STREAM RECEIVE message" ); return false; } int id; { String strid = props.getProperty ( "ID" ); if ( strid == null ) { if (_log.shouldLog(Log.DEBUG)) _log.debug ( "ID not specified in STREAM RECEIVE message" ); return false; } try { id = Integer.parseInt ( strid ); } catch ( NumberFormatException e ) { if (_log.shouldLog(Log.DEBUG)) _log.debug ( "Invalid STREAM RECEIVE ID specified: " + strid ); return false; } } boolean nolimit = false; long limit = 0; { String strsize = props.getProperty ( "LIMIT" ); if ( strsize == null ) { if (_log.shouldLog(Log.DEBUG)) _log.debug ( "Limit not specified in STREAM RECEIVE message" ); return false; } if ( strsize.equals( "NONE" ) ) { nolimit = true ; } else { try { limit = Long.parseLong ( strsize ); } catch ( NumberFormatException e ) { if (_log.shouldLog(Log.DEBUG)) _log.debug ( "Invalid STREAM RECEIVE size specified: " + strsize ); return false; } if ( limit < 0 ) { if (_log.shouldLog(Log.DEBUG)) _log.debug ( "Specified limit (" + limit + ") is out of protocol limits" ); return false; } } } getStreamSession().setReceiveLimit ( id, limit, nolimit ) ; return true; } }