2121import android .util .Log ;
2222import android .util .SparseArray ;
2323
24+ import org .jetbrains .annotations .NotNull ;
25+
2426import tech .httptoolkit .android .TagKt ;
2527import tech .httptoolkit .android .vpn .socket .DataConst ;
2628import tech .httptoolkit .android .vpn .socket .ICloseSession ;
@@ -89,7 +91,7 @@ public Session getSession(int ip, int port, int srcIp, int srcPort) {
8991
9092 @ Nullable
9193 public Session getSessionByKey (String key ) {
92- if (table .containsKey (key )){
94+ if (table .containsKey (key )) {
9395 return table .get (key );
9496 }
9597
@@ -126,92 +128,64 @@ public void closeSession(@NonNull Session session){
126128 session .getSourcePort ());
127129 }
128130
129- @ Nullable
130- public Session createNewUDPSession (int ip , int port , int srcIp , int srcPort ) {
131+ @ NotNull
132+ public Session createNewUDPSession (int ip , int port , int srcIp , int srcPort ) throws IOException {
131133 String keys = Session .getSessionKey (ip , port , srcIp , srcPort );
132134
133- if (table .containsKey (keys ))
135+ if (table .containsKey (keys )) {
136+ // For TCP, we freak out if you try to create an already existing session.
137+ // With UDP though, it's totally fine:
134138 return table .get (keys );
139+ }
135140
136141 Session session = new Session (srcIp , srcPort , ip , port , this );
137142
138143 DatagramChannel channel ;
139144
140- try {
141- channel = DatagramChannel .open ();
142- channel .socket ().setSoTimeout (0 );
143- channel .configureBlocking (false );
144- } catch (IOException e ) {
145- e .printStackTrace ();
146- return null ;
147- }
145+ channel = DatagramChannel .open ();
146+ channel .socket ().setSoTimeout (0 );
147+ channel .configureBlocking (false );
148148 protector .protect (channel .socket ());
149149
150150 session .setChannel (channel );
151151
152- //initiate connection to reduce latency
152+ // Initiate connection early to reduce latency
153153 String ips = PacketUtil .intToIPAddress (ip );
154154 String sourceIpAddress = PacketUtil .intToIPAddress (srcIp );
155155 SocketAddress socketAddress = new InetSocketAddress (ips , port );
156156 Log .d (TAG ,"initialized connection to remote UDP server: " + ips + ":" +
157157 port + " from " + sourceIpAddress + ":" + srcPort );
158158
159- try {
160- channel .connect (socketAddress );
161- session .setConnected (channel .isConnected ());
162- } catch (IOException e ) {
163- e .printStackTrace ();
164- return null ;
165- }
166-
167- try {
168- nioService .registerSession (session );
169- } catch (ClosedChannelException e ) {
170- e .printStackTrace ();
171- Log .e (TAG ,"failed to register udp channel with selector: " + e .getMessage ());
172- return null ;
173- }
159+ channel .connect (socketAddress );
160+ session .setConnected (channel .isConnected ());
174161
175- if (table .containsKey (keys )) {
176- try {
177- channel .close ();
178- } catch (IOException e ) {
179- e .printStackTrace ();
180- return null ;
181- }
182- } else {
183- table .put (keys , session );
184- }
162+ nioService .registerSession (session );
163+ table .put (keys , session );
185164
186165 Log .d (TAG ,"new UDP session successfully created." );
187166 return session ;
188167 }
189168
190- @ Nullable
191- public Session createNewTCPSession (int ip , int port , int srcIp , int srcPort ){
169+ @ NotNull
170+ public Session createNewTCPSession (int ip , int port , int srcIp , int srcPort ) throws IOException {
192171 String key = Session .getSessionKey (ip , port , srcIp , srcPort );
193172 if (table .containsKey (key )) {
194- Log .e (TAG , "Session " + key + " was already created." );
195- return null ;
173+ // This can happen if we receive two SYN packets somehow. That shouldn't happen, especially
174+ // given that our connection is local & should be 100% reliable, but it does. We probably
175+ // should RST, for now we just throw here (and so drop the packet entirely).
176+ throw new IllegalArgumentException ("Can't create duplicate session" );
196177 }
197178
198179 Session session = new Session (srcIp , srcPort , ip , port , this );
199180
200181 SocketChannel channel ;
201- try {
202- channel = SocketChannel .open ();
203- channel .socket ().setKeepAlive (true );
204- channel .socket ().setTcpNoDelay (true );
205- channel .socket ().setSoTimeout (0 );
206- channel .socket ().setReceiveBufferSize (DataConst .MAX_RECEIVE_BUFFER_SIZE );
207- channel .configureBlocking (false );
208- } catch (SocketException e ) {
209- Log .e (TAG , e .toString ());
210- return null ;
211- } catch (IOException e ) {
212- Log .e (TAG ,"Failed to create SocketChannel: " + e .getMessage ());
213- return null ;
214- }
182+ channel = SocketChannel .open ();
183+ channel .socket ().setKeepAlive (true );
184+ channel .socket ().setTcpNoDelay (true );
185+ channel .socket ().setSoTimeout (0 );
186+ channel .socket ().setReceiveBufferSize (DataConst .MAX_RECEIVE_BUFFER_SIZE );
187+ channel .configureBlocking (false );
188+
215189 String ips = PacketUtil .intToIPAddress (ip );
216190 Log .d (TAG ,"created new SocketChannel for " + key );
217191
@@ -220,42 +194,20 @@ public Session createNewTCPSession(int ip, int port, int srcIp, int srcPort){
220194
221195 session .setChannel (channel );
222196
223- //initiate connection to reduce latency
224- // Use the real address, unless tcpPortRedirection defines a different
197+ // Initiate connection straight away, to reduce latency
198+ // We use the real address, unless tcpPortRedirection redirects us to a different
225199 // target address for traffic on this port.
226200 SocketAddress socketAddress = tcpPortRedirection .get (port ) != null
227201 ? tcpPortRedirection .get (port )
228202 : new InetSocketAddress (ips , port );
229203
230- Log .d (TAG ,"initiate connecting to remote tcp server: " + socketAddress .toString ());
231- boolean connected ;
232- try {
233- connected = channel .connect (socketAddress );
234- } catch (IOException e ) {
235- Log .e (TAG , e .toString ());
236- return null ;
237- }
238-
204+ Log .d (TAG ,"Initiate connecting to remote tcp server: " + socketAddress .toString ());
205+ boolean connected = channel .connect (socketAddress );
239206 session .setConnected (connected );
240207
241- try {
242- nioService .registerSession (session );
243- } catch (ClosedChannelException e ) {
244- e .printStackTrace ();
245- Log .e (TAG ,"Failed to register channel with selector: " + e .getMessage ());
246- return null ;
247- }
208+ nioService .registerSession (session );
209+ table .put (key , session );
248210
249- if (table .containsKey (key )) {
250- try {
251- channel .close ();
252- } catch (IOException e ) {
253- e .printStackTrace ();
254- }
255- return null ;
256- } else {
257- table .put (key , session );
258- }
259211 return session ;
260212 }
261213
0 commit comments