package org.jdiameter.client.impl; import org.jdiameter.api.*; import org.jdiameter.client.api.IContainer; import org.jdiameter.client.api.IEventListener; import org.jdiameter.client.api.IMessage; import org.jdiameter.client.api.parser.IMessageParser; import org.jdiameter.client.impl.helpers.UIDGenerator; import org.jdiameter.common.impl.validation.DiameterMessageValidator; import static org.jdiameter.client.impl.helpers.Parameters.MessageTimeOut; import java.util.concurrent.*; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /* * Copyright (c) 2006 jDiameter. * https://jdiameter.dev.java.net/ * * License: GPL v3 * * e-mail: erick.svenson@yahoo.com * */ public abstract class BaseSessionImpl implements BaseSession { private static final long serialVersionUID = 1L; protected static UIDGenerator uid = new UIDGenerator(); protected final long creationTime = System.currentTimeMillis(); protected long lastAccessedTime = creationTime; protected boolean isValid = true; protected String sessionId; protected transient IContainer container; protected transient IMessageParser parser; protected NetworkReqListener reqListener; protected static final DiameterMessageValidator messageValidator = DiameterMessageValidator.getInstance(); public long getCreationTime() { return creationTime; } public long getLastAccessedTime() { return lastAccessedTime; } public boolean isValid() { return isValid; } public String generateSessionId() { long id = uid.nextLong(); long high32 = (id & 0xffffffff00000000L) >> 32; long low32 = (id & 0xffffffffL); return new StringBuffer().append(container.getMetaData().getLocalPeer().getUri().getFQDN()). append(";").append(high32).append(";").append(low32).toString(); } protected void genericSend(Message message, EventListener listener) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException { if (isValid) { long timeOut = container.getConfiguration().getLongValue(MessageTimeOut.ordinal(), (Long) MessageTimeOut.defValue()); genericSend(message, listener, timeOut, TimeUnit.MILLISECONDS); } else { throw new IllegalDiameterStateException("Session already released"); } } protected void genericSend(Message aMessage, EventListener listener, long timeout, TimeUnit timeUnit) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException { if ( isValid ) { lastAccessedTime = System.currentTimeMillis(); if(BaseSessionImpl.messageValidator.isOn()) { BaseSessionImpl.messageValidator.validate(aMessage); } IMessage message = (IMessage) aMessage; IEventListener localListener = createListenerWrapper(listener); if (message.isRequest()) { message.setListener(localListener); // Auto set system avps if (message.getAvps().getAvpByIndex(0).getCode() != Avp.SESSION_ID && sessionId != null) { message.getAvps().insertAvp(0, Avp.SESSION_ID, sessionId, true, false, false); } } if (message.getState() != IMessage.STATE_NOT_SENT && message.getState() != IMessage.STATE_ANSWERED) { throw new IllegalDiameterStateException("Illegal state"); } message.createTimer(container.getScheduledFacility(), timeout, timeUnit); try { container.sendMessage(message); } catch(RouteException e) { throw e; } catch (Exception e) { message.clearTimer(); throw new InternalException(e); } } else { throw new IllegalDiameterStateException("Session already released"); } } protected IEventListener createListenerWrapper(final EventListener listener) { return listener == null ? null : new MyEventListener(this, listener); } public Future<Message> send(final Message message) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException { MyFuture future = new MyFuture(); future.send(message); return future; } public Future<Message> send(Message message, long timeOut, TimeUnit timeUnit) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException { MyFuture future = new MyFuture(); future.send(message, timeOut, timeUnit); return future; } private class MyFuture implements Future<Message> { private boolean canceled; private boolean done; private boolean timeOut; private Lock lock = new ReentrantLock(); private CountDownLatch block = new CountDownLatch(1); private Message result; public boolean cancel(boolean mayInterruptIfRunning) { lock.lock(); try { canceled = true; done = false; block.countDown(); } finally { lock.unlock(); } return true; } public boolean isCancelled() { return canceled; } public boolean isDone() { return done; } public Message get() throws InterruptedException, ExecutionException { try { block.await(); } catch (Exception e) { throw new ExecutionException(e); } Message rc = canceled ? null : result; result = null; return rc; } public Message get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { try { block.await(); } catch (Exception e) { throw new ExecutionException(e); } if (timeOut) { throw new TimeoutException(); } Message rc = canceled ? null : result; result = null; return rc; } private IEventListener createListener() { return new IEventListener() { public void setValid(boolean value) { } public boolean isValid() { return !canceled; } public void receivedSuccessMessage(Message r, Message a) { lock.lock(); try { if (!canceled) { result = a; canceled = false; done = true; } block.countDown(); } finally { lock.unlock(); } } public void timeoutExpired(Message message) { lock.lock(); try { if (!canceled) { done = true; timeOut = true; } block.countDown(); } finally { lock.unlock(); } } }; } public void send(Message message) throws RouteException, OverloadException, IllegalDiameterStateException, InternalException { genericSend(message, createListener()); } public void send(Message message, long timeOut, TimeUnit timeUnit) throws RouteException, OverloadException, IllegalDiameterStateException, InternalException { genericSend(message, createListener(), timeOut, timeUnit); } } protected void appendAppId(ApplicationId appId, Message m) { // todo duplicate code look peerimpl 601 line if (appId == null) return; if (appId.getVendorId() == 0) { if (appId.getAcctAppId() != 0) { m.getAvps().addAvp(Avp.ACCT_APPLICATION_ID, appId.getAcctAppId(), true, false, true); } if (appId.getAuthAppId() != 0) { m.getAvps().addAvp(Avp.AUTH_APPLICATION_ID, appId.getAuthAppId(), true, false, true); } } else { AvpSet avp = m.getAvps().addGroupedAvp(Avp.VENDOR_SPECIFIC_APPLICATION_ID, true, false); avp.addAvp(Avp.VENDOR_ID, appId.getVendorId(), true, false, true); if (appId.getAuthAppId() != 0) { avp.addAvp(Avp.AUTH_APPLICATION_ID, appId.getAuthAppId(), true, false, true); } if (appId.getAcctAppId() != 0) { avp.addAvp(Avp.ACCT_APPLICATION_ID, appId.getAcctAppId(), true, false, true); } } } protected long getAppId(ApplicationId appId) { if (appId == null) { return 0; } // if (appId.getVendorId() == 0) { if (appId.getAcctAppId() != 0) { return appId.getAcctAppId(); } if (appId.getAuthAppId() != 0) { return appId.getAuthAppId(); } // } return appId.getVendorId(); } } class MyEventListener implements IEventListener { BaseSessionImpl session; EventListener listener; boolean isValid = true; public MyEventListener(BaseSessionImpl session, EventListener listener) { this.session = session; this.listener = listener; } public void setValid(boolean value) { isValid = value; if ( !isValid ) { session = null; listener = null; } } public boolean isValid() { return isValid; } public void receivedSuccessMessage(Message request, Message answer) { if (isValid) { session.lastAccessedTime = System.currentTimeMillis(); listener.receivedSuccessMessage(request, answer); } } public void timeoutExpired(Message message) { if (isValid) { session.lastAccessedTime = System.currentTimeMillis(); listener.timeoutExpired(message); } } public int hashCode() { return listener == null ? 0 :listener.hashCode(); } public boolean equals(Object obj) { return listener != null && listener.equals(obj); } public String toString() { return listener == null ? "null" : listener.toString(); } }