/* * Copyright 2015-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package sockslib.server; import sockslib.common.Credentials; import sockslib.common.SocksException; import sockslib.common.net.MonitorSocketWrapper; import sockslib.common.net.NetworkMonitor; import sockslib.server.msg.ReadableMessage; import sockslib.server.msg.WritableMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.net.SocketAddress; import java.util.HashMap; import java.util.Map; /** * The class <code>SocksSession</code> represents * * @author Youchao Feng * @version 1.0 * @date Apr 5, 2015 10:21:36 AM */ public class SocksSession implements Session { private static final Logger logger = LoggerFactory.getLogger(SocksSession.class); private Socket socket; private long id; private InputStream inputStream; private OutputStream outputStream; private Map<Long, Session> sessions; private SocketAddress clientAddress; private Map<Object, Object> attributes; private NetworkMonitor networkMonitor; private Credentials credentials; public SocksSession() { } public SocksSession(Socket socket) { this(0, socket, null); } public SocksSession(long id, Socket socket, Map<Long, Session> sessions) { if (!socket.isConnected()) { throw new IllegalArgumentException("Socket should be a connected socket"); } if (socket instanceof MonitorSocketWrapper) { networkMonitor = new NetworkMonitor(); ((MonitorSocketWrapper) socket).addMonitor(networkMonitor); } this.id = id; this.socket = socket; this.sessions = sessions; try { this.inputStream = this.socket.getInputStream(); this.outputStream = this.socket.getOutputStream(); } catch (IOException e) { logger.error(e.getMessage(), e); } clientAddress = socket.getRemoteSocketAddress(); attributes = new HashMap<Object, Object>(); } @Override public Socket getSocket() { return socket; } @Override public void write(byte[] bytes) throws SocksException, IOException { write(bytes, 0, bytes.length); } @Override public void write(WritableMessage message) throws SocksException, IOException { write(message.getBytes()); } @Override public int read(byte[] bytes) throws SocksException, IOException { return inputStream.read(bytes); } @Override public int read(ReadableMessage message) throws SocksException, IOException { message.read(inputStream); return message.getLength(); } @Override public long getId() { return id; } @Override public void close() { try { if (inputStream != null) { inputStream.close(); } if (outputStream != null) { outputStream.close(); } if (socket != null && !socket.isClosed()) { socket.close(); } } catch (IOException e) { logger.error(e.getMessage(), e); } finally { sessions.remove(id); } } @Override public InputStream getInputStream() { return inputStream; } @Override public OutputStream getOutputStream() { return outputStream; } @Override public void write(byte[] bytes, int offset, int length) throws SocksException, IOException { outputStream.write(bytes, offset, length); outputStream.flush(); } @Override public Map<Long, Session> getManagedSessions() { return sessions; } @Override public SocketAddress getClientAddress() { return clientAddress; } @Override public void setAttribute(Object key, Object value) { attributes.put(key, value); } @Override public Object getAttribute(Object key) { return attributes.get(key); } @Override public Map<Object, Object> getAttributes() { return attributes; } @Override public void clearAllAttributes() { attributes.clear(); } @Override public boolean isClose() { try { socket.sendUrgentData(0); return false; } catch (IOException expected) { return true; } } @Override public boolean isConnected() { return socket.isConnected(); } @Override public NetworkMonitor getNetworkMonitor() { return networkMonitor; } @Override public String toString() { return "SESSION[" + id + "]" + "@" + clientAddress; } }