/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.smscserver.impl; import java.net.SocketAddress; import java.security.cert.Certificate; import java.util.Date; import java.util.Set; import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantLock; import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLSession; import org.apache.mina.core.filterchain.IoFilterChain; import org.apache.mina.core.future.CloseFuture; import org.apache.mina.core.future.ReadFuture; import org.apache.mina.core.future.WriteFuture; import org.apache.mina.core.service.IoHandler; import org.apache.mina.core.service.IoService; import org.apache.mina.core.service.TransportMetadata; import org.apache.mina.core.session.AbstractIoSession; import org.apache.mina.core.session.IdleStatus; import org.apache.mina.core.session.IoSession; import org.apache.mina.core.session.IoSessionConfig; import org.apache.mina.core.write.WriteRequest; import org.apache.mina.core.write.WriteRequestQueue; import org.apache.mina.filter.ssl.SslFilter; import org.apache.smscserver.ServerSmscStatistics; import org.apache.smscserver.SmscServerContext; import org.apache.smscserver.listener.Listener; import org.apache.smscserver.smsclet.SmscIoSession; import org.apache.smscserver.smsclet.SmscRequest; import org.apache.smscserver.smsclet.SmscRuntimeException; import org.apache.smscserver.smsclet.SmscSession; import org.apache.smscserver.smsclet.User; import org.slf4j.LoggerFactory; /** * <strong>Internal class, do not use directly.</strong> * * @author hceylan * */ public class DefaultSmscIoSession implements SmscIoSession { private static final String ATTRIBUTE_SESSION_ID = SmscIoSession.ATTRIBUTE_PREFIX + "session-id"; private static final String ATTRIBUTE_USER = SmscIoSession.ATTRIBUTE_PREFIX + "user"; private static final String ATTRIBUTE_BIND_TIME = SmscIoSession.ATTRIBUTE_PREFIX + "bind-time"; private static final String ATTRIBUTE_FAILED_BINDS = SmscIoSession.ATTRIBUTE_PREFIX + "failed-binds"; private static final String ATTRIBUTE_LISTENER = SmscIoSession.ATTRIBUTE_PREFIX + "listener"; private static final String ATTRIBUTE_MAX_IDLE_TIME = SmscIoSession.ATTRIBUTE_PREFIX + "max-idle-time"; private static final String ATTRIBUTE_LAST_ACCESS_TIME = SmscIoSession.ATTRIBUTE_PREFIX + "last-access-time"; private static final String ATTRIBUTE_CACHED_REMOTE_ADDRESS = SmscIoSession.ATTRIBUTE_PREFIX + "cached-remote-address"; private final IoSession wrappedSession; private final SmscServerContext serverContext; private SmscRequest request; private final ReentrantLock lock; private final AtomicInteger sequenceNumber = new AtomicInteger(); public DefaultSmscIoSession(IoSession wrappedSession, SmscServerContext context) { this.wrappedSession = wrappedSession; this.serverContext = context; this.lock = new ReentrantLock(); } public void clearUser() { DefaultSmscStatistics statistics = (DefaultSmscStatistics) this.serverContext.getSmscStatistics(); statistics.setUnbind(this); this.setAttribute(DefaultSmscIoSession.ATTRIBUTE_USER, null); this.serverContext.getDeliveryManager().closeBoundSession(this); } /** * {@inheritDoc} * */ public CloseFuture close() { return this.wrappedSession.close(); } /** * {@inheritDoc} * */ public CloseFuture close(boolean immediately) { return this.wrappedSession.close(immediately); } /** * {@inheritDoc} * */ public boolean containsAttribute(Object key) { return this.wrappedSession.containsAttribute(key); } /** * {@inheritDoc} * */ @SuppressWarnings("deprecation") public Object getAttachment() { return this.wrappedSession.getAttachment(); } /** * {@inheritDoc} * */ public Object getAttribute(Object key) { return this.wrappedSession.getAttribute(key); } /** * {@inheritDoc} * */ public Object getAttribute(Object key, Object defaultValue) { return this.wrappedSession.getAttribute(key, defaultValue); } /** * {@inheritDoc} * */ public Set<Object> getAttributeKeys() { return this.wrappedSession.getAttributeKeys(); } public Date getBindTime() { return (Date) this.getAttribute(DefaultSmscIoSession.ATTRIBUTE_BIND_TIME); } /** * {@inheritDoc} * */ public int getBothIdleCount() { return this.wrappedSession.getBothIdleCount(); } public Certificate[] getClientCertificates() { if (this.getFilterChain().contains(SslFilter.class)) { SslFilter sslFilter = (SslFilter) this.getFilterChain().get(SslFilter.class); SSLSession sslSession = sslFilter.getSslSession(this); if (sslSession != null) { try { return sslSession.getPeerCertificates(); } catch (SSLPeerUnverifiedException e) { // ignore, certificate will not be available to the session } } } // no certificates available return null; } /** * {@inheritDoc} * */ public CloseFuture getCloseFuture() { return this.wrappedSession.getCloseFuture(); } /** * {@inheritDoc} * */ public IoSessionConfig getConfig() { return this.wrappedSession.getConfig(); } /** * {@inheritDoc} * */ public long getCreationTime() { return this.wrappedSession.getCreationTime(); } /** * {@inheritDoc} * */ public Object getCurrentWriteMessage() { return this.wrappedSession.getCurrentWriteMessage(); } /** * {@inheritDoc} * */ public WriteRequest getCurrentWriteRequest() { return this.wrappedSession.getCurrentWriteRequest(); } public int getFailedBinds() { return (Integer) this.getAttribute(DefaultSmscIoSession.ATTRIBUTE_FAILED_BINDS, 0); } /** * {@inheritDoc} * */ public IoFilterChain getFilterChain() { return this.wrappedSession.getFilterChain(); } /** * {@inheritDoc} * */ public IoHandler getHandler() { return this.wrappedSession.getHandler(); } /** * {@inheritDoc} * */ public long getId() { return this.wrappedSession.getId(); } /** * {@inheritDoc} * */ public int getIdleCount(IdleStatus status) { return this.wrappedSession.getIdleCount(status); } public Date getLastAccessTime() { return (Date) this.getAttribute(DefaultSmscIoSession.ATTRIBUTE_LAST_ACCESS_TIME); } /** * {@inheritDoc} * */ public long getLastBothIdleTime() { return this.wrappedSession.getLastBothIdleTime(); } /** * {@inheritDoc} * */ public long getLastIdleTime(IdleStatus status) { return this.wrappedSession.getLastIdleTime(status); } /** * {@inheritDoc} * */ public long getLastIoTime() { return this.wrappedSession.getLastIoTime(); } /** * {@inheritDoc} * */ public long getLastReaderIdleTime() { return this.wrappedSession.getLastReaderIdleTime(); } /** * {@inheritDoc} * */ public long getLastReadTime() { return this.wrappedSession.getLastReadTime(); } /** * {@inheritDoc} * */ public long getLastWriterIdleTime() { return this.wrappedSession.getLastWriterIdleTime(); } /** * {@inheritDoc} * */ public long getLastWriteTime() { return this.wrappedSession.getLastWriteTime(); } public Listener getListener() { return (Listener) this.getAttribute(DefaultSmscIoSession.ATTRIBUTE_LISTENER); } /** * {@inheritDoc} * */ public SocketAddress getLocalAddress() { return this.wrappedSession.getLocalAddress(); } public int getMaxIdleTime() { return (Integer) this.getAttribute(DefaultSmscIoSession.ATTRIBUTE_MAX_IDLE_TIME, 0); } /** * {@inheritDoc} * */ public int getNextSequnce() { return this.sequenceNumber.incrementAndGet(); } /** * {@inheritDoc} * */ public long getReadBytes() { return this.wrappedSession.getReadBytes(); } /** * {@inheritDoc} * */ public double getReadBytesThroughput() { return this.wrappedSession.getReadBytesThroughput(); } /** * {@inheritDoc} * */ public int getReaderIdleCount() { return this.wrappedSession.getReaderIdleCount(); } /** * {@inheritDoc} * */ public long getReadMessages() { return this.wrappedSession.getReadMessages(); } /** * {@inheritDoc} * */ public double getReadMessagesThroughput() { return this.wrappedSession.getReadMessagesThroughput(); } /** * {@inheritDoc} * */ public SocketAddress getRemoteAddress() { // when closing a socket, the remote address might be reset to null // therefore, we attempt to keep a cached copy around SocketAddress address = this.wrappedSession.getRemoteAddress(); if ((address == null) && this.containsAttribute(DefaultSmscIoSession.ATTRIBUTE_CACHED_REMOTE_ADDRESS)) { return (SocketAddress) this.getAttribute(DefaultSmscIoSession.ATTRIBUTE_CACHED_REMOTE_ADDRESS); } else { this.setAttribute(DefaultSmscIoSession.ATTRIBUTE_CACHED_REMOTE_ADDRESS, address); return address; } } /** * {@inheritDoc} * */ public long getScheduledWriteBytes() { return this.wrappedSession.getScheduledWriteBytes(); } /** * {@inheritDoc} * */ public int getScheduledWriteMessages() { return this.wrappedSession.getScheduledWriteMessages(); } /** * {@inheritDoc} * */ public IoService getService() { return this.wrappedSession.getService(); } /** * {@inheritDoc} * */ public SocketAddress getServiceAddress() { return this.wrappedSession.getServiceAddress(); } /** * @return */ public UUID getSessionId() { synchronized (this.wrappedSession) { if (!this.wrappedSession.containsAttribute(DefaultSmscIoSession.ATTRIBUTE_SESSION_ID)) { this.wrappedSession.setAttribute(DefaultSmscIoSession.ATTRIBUTE_SESSION_ID, UUID.randomUUID()); } return (UUID) this.wrappedSession.getAttribute(DefaultSmscIoSession.ATTRIBUTE_SESSION_ID); } } public SmscSession getSmscletSession() { return new DefaultSmscSession(this); } /** * {@inheritDoc} * */ public TransportMetadata getTransportMetadata() { return this.wrappedSession.getTransportMetadata(); } public User getUser() { return (User) this.getAttribute(DefaultSmscIoSession.ATTRIBUTE_USER); } /** * {@inheritDoc} * */ public WriteRequestQueue getWriteRequestQueue() { return this.wrappedSession.getWriteRequestQueue(); } /** * {@inheritDoc} * */ public int getWriterIdleCount() { return this.wrappedSession.getWriterIdleCount(); } /** * {@inheritDoc} * */ public long getWrittenBytes() { return this.wrappedSession.getWrittenBytes(); } /** * {@inheritDoc} * */ public double getWrittenBytesThroughput() { return this.wrappedSession.getWrittenBytesThroughput(); } /** * {@inheritDoc} * */ public long getWrittenMessages() { return this.wrappedSession.getWrittenMessages(); } /** * {@inheritDoc} * */ public double getWrittenMessagesThroughput() { return this.wrappedSession.getWrittenMessagesThroughput(); } public synchronized void increaseFailedBinds() { int failedBinds = (Integer) this.getAttribute(DefaultSmscIoSession.ATTRIBUTE_FAILED_BINDS, 0); failedBinds++; this.setAttribute(DefaultSmscIoSession.ATTRIBUTE_FAILED_BINDS, failedBinds); } /** * Increase the number of bytes read on the data connection * * @param increment * The number of bytes written */ public void increaseReadDataBytes(int increment) { if (this.wrappedSession instanceof AbstractIoSession) { ((AbstractIoSession) this.wrappedSession).increaseReadBytes(increment, System.currentTimeMillis()); } } /** * Increase the number of bytes written on the data connection * * @param increment * The number of bytes written */ public void increaseWrittenDataBytes(int increment) { if (this.wrappedSession instanceof AbstractIoSession) { ((AbstractIoSession) this.wrappedSession).increaseScheduledWriteBytes(increment); ((AbstractIoSession) this.wrappedSession).increaseWrittenBytes(increment, System.currentTimeMillis()); } } /** * {@inheritDoc} * */ public boolean isBothIdle() { return this.wrappedSession.isBothIdle(); } /** * Is bound */ public boolean isBound() { return this.containsAttribute(DefaultSmscIoSession.ATTRIBUTE_USER); } /** * {@inheritDoc} * */ public boolean isClosing() { return this.wrappedSession.isClosing(); } /** * {@inheritDoc} * */ public boolean isConnected() { return this.wrappedSession.isConnected(); } /** * {@inheritDoc} * */ public boolean isIdle(IdleStatus status) { return this.wrappedSession.isIdle(status); } /** * {@inheritDoc} * */ public boolean isReaderIdle() { return this.wrappedSession.isReaderIdle(); } /** * {@inheritDoc} * */ public boolean isReadSuspended() { return this.wrappedSession.isReadSuspended(); } /** * Indicates whether the control socket for this session is secure, that is, running over SSL/TLS * * @return true if the control socket is secured */ public boolean isSecure() { return this.getFilterChain().contains(SslFilter.class); } /** * {@inheritDoc} * */ public boolean isWriterIdle() { return this.wrappedSession.isWriterIdle(); } /** * {@inheritDoc} * */ public boolean isWriteSuspended() { return this.wrappedSession.isWriteSuspended(); } /** * {@inheritDoc} * */ public synchronized boolean lock() { long timeout = this.serverContext.getSessionLockTimeout(); try { return this.lock.tryLock(timeout, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { throw new SmscRuntimeException("Unable to acquire lock"); } } /** * {@inheritDoc} * */ public ReadFuture read() { return this.wrappedSession.read(); } public void reinitialize() { this.unbindUser(); this.removeAttribute(DefaultSmscIoSession.ATTRIBUTE_USER); this.removeAttribute(DefaultSmscIoSession.ATTRIBUTE_BIND_TIME); } /** * {@inheritDoc} * */ public Object removeAttribute(Object key) { return this.wrappedSession.removeAttribute(key); } /** * {@inheritDoc} * */ public boolean removeAttribute(Object key, Object value) { return this.wrappedSession.removeAttribute(key, value); } /** * {@inheritDoc} * */ public boolean replaceAttribute(Object key, Object oldValue, Object newValue) { return this.wrappedSession.replaceAttribute(key, oldValue, newValue); } /** * {@inheritDoc} * */ public void resumeRead() { this.wrappedSession.resumeRead(); } /** * {@inheritDoc} * */ public void resumeWrite() { this.wrappedSession.resumeWrite(); } /** * {@inheritDoc} * */ @SuppressWarnings("deprecation") public Object setAttachment(Object attachment) { return this.wrappedSession.setAttachment(attachment); } /** * {@inheritDoc} * */ public Object setAttribute(Object key) { return this.wrappedSession.setAttribute(key); } /** * {@inheritDoc} * */ public Object setAttribute(Object key, Object value) { return this.wrappedSession.setAttribute(key, value); } /** * {@inheritDoc} * */ public Object setAttributeIfAbsent(Object key) { return this.wrappedSession.setAttributeIfAbsent(key); } /** * {@inheritDoc} * */ public Object setAttributeIfAbsent(Object key, Object value) { return this.wrappedSession.setAttributeIfAbsent(key, value); } /** * {@inheritDoc} * */ public void setCurrentWriteRequest(WriteRequest currentWriteRequest) { this.wrappedSession.setCurrentWriteRequest(currentWriteRequest); } public void setListener(Listener listener) { this.setAttribute(DefaultSmscIoSession.ATTRIBUTE_LISTENER, listener); } public void setMaxIdleTime(int maxIdleTime) { this.setAttribute(DefaultSmscIoSession.ATTRIBUTE_MAX_IDLE_TIME, maxIdleTime); int listenerTimeout = this.getListener().getIdleTimeout(); // the listener timeout should be the upper limit, unless set to unlimited // if the user limit is set to be unlimited, use the listener value is the threshold // (already used as the default for all sessions) // else, if the user limit is less than the listener idle time, use the user limit if ((listenerTimeout <= 0) || ((maxIdleTime > 0) && (maxIdleTime < listenerTimeout))) { this.wrappedSession.getConfig().setBothIdleTime(maxIdleTime); } } public void setRequest(SmscRequest request) { if (this.request != null) { throw new SmscRuntimeException("SmscIOSession " + this.wrappedSession.getId() + " already bound to the request " + this.request.getId()); } this.request = request; } public void setUser(User user, boolean receiver) { DefaultSmscStatistics statistics = (DefaultSmscStatistics) this.serverContext.getSmscStatistics(); this.setAttribute(DefaultSmscIoSession.ATTRIBUTE_USER, user); statistics.setBind(this); if (receiver) { this.serverContext.getDeliveryManager().newBoundSession(this); } } /** * {@inheritDoc} * */ public void startDelivery() { // TODO Auto-generated method stub } /** * {@inheritDoc} * */ public void stopDelivery() { // TODO Auto-generated method stub } /** * {@inheritDoc} * */ public void suspendRead() { this.wrappedSession.suspendRead(); } /** * {@inheritDoc} * */ public void suspendWrite() { this.wrappedSession.suspendWrite(); } public void unbindUser() { if (((ServerSmscStatistics) this.serverContext.getSmscStatistics()) != null) { ((ServerSmscStatistics) this.serverContext.getSmscStatistics()).setUnbind(this); LoggerFactory.getLogger(this.getClass()).debug("Statistics unbind decreased due to user unbind"); } else { LoggerFactory.getLogger(this.getClass()).warn( "Statistics not available in session, can not decrease unbind count"); } } public synchronized void unlock() { this.lock.unlock(); } public void updateLastAccessTime() { this.setAttribute(DefaultSmscIoSession.ATTRIBUTE_LAST_ACCESS_TIME, new Date()); } /** * {@inheritDoc} * */ public void updateThroughput(long currentTime, boolean force) { this.wrappedSession.updateThroughput(currentTime, force); } /** * {@inheritDoc} * */ public WriteFuture write(Object message) { if (this.request == null) { throw new SmscRuntimeException("Illegal write from unbound SmscIOSession " + this.wrappedSession.getId()); } return this.wrappedSession.write(message); } /** * {@inheritDoc} * */ public WriteFuture write(Object message, SocketAddress destination) { if (this.request == null) { throw new SmscRuntimeException("Illegal write from unbound SmscIOSession " + this.wrappedSession.getId()); } return this.wrappedSession.write(message, destination); } }