PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/servers/diameter/core/jdiameter/impl/src/main/java/org/jdiameter/server/impl/app/auth/ServerAuthSessionImpl.java

http://mobicents.googlecode.com/
Java | 540 lines | 403 code | 45 blank | 92 comment | 52 complexity | 64fda97e9feaa8584b5d426f61afc3ec MD5 | raw file
Possible License(s): LGPL-3.0, GPL-3.0, LGPL-2.1, GPL-2.0, CC-BY-SA-3.0, CC0-1.0, Apache-2.0, BSD-3-Clause
  1. /*
  2. * JBoss, Home of Professional Open Source
  3. * Copyright 2006, Red Hat, Inc. and individual contributors
  4. * by the @authors tag. See the copyright.txt in the distribution for a
  5. * full listing of individual contributors.
  6. *
  7. * This is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU Lesser General Public License as
  9. * published by the Free Software Foundation; either version 2.1 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * This software is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this software; if not, write to the Free
  19. * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  20. * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  21. */
  22. package org.jdiameter.server.impl.app.auth;
  23. import static org.jdiameter.common.api.app.auth.ServerAuthSessionState.DISCONNECTED;
  24. import static org.jdiameter.common.api.app.auth.ServerAuthSessionState.IDLE;
  25. import static org.jdiameter.common.api.app.auth.ServerAuthSessionState.OPEN;
  26. import static org.jdiameter.server.impl.app.auth.Event.Type.RECEIVE_ASR_ANSWER;
  27. import static org.jdiameter.server.impl.app.auth.Event.Type.RECEIVE_AUTH_REQUEST;
  28. import static org.jdiameter.server.impl.app.auth.Event.Type.TIMEOUT_EXPIRES;
  29. import java.io.Serializable;
  30. import java.util.concurrent.locks.Lock;
  31. import java.util.concurrent.locks.ReentrantLock;
  32. import org.jdiameter.api.Answer;
  33. import org.jdiameter.api.EventListener;
  34. import org.jdiameter.api.IllegalDiameterStateException;
  35. import org.jdiameter.api.InternalException;
  36. import org.jdiameter.api.NetworkReqListener;
  37. import org.jdiameter.api.OverloadException;
  38. import org.jdiameter.api.Request;
  39. import org.jdiameter.api.RouteException;
  40. import org.jdiameter.api.app.AppAnswerEvent;
  41. import org.jdiameter.api.app.AppEvent;
  42. import org.jdiameter.api.app.AppRequestEvent;
  43. import org.jdiameter.api.app.AppSession;
  44. import org.jdiameter.api.app.StateChangeListener;
  45. import org.jdiameter.api.app.StateEvent;
  46. import org.jdiameter.api.auth.ServerAuthSession;
  47. import org.jdiameter.api.auth.ServerAuthSessionListener;
  48. import org.jdiameter.api.auth.events.AbortSessionAnswer;
  49. import org.jdiameter.api.auth.events.AbortSessionRequest;
  50. import org.jdiameter.api.auth.events.ReAuthRequest;
  51. import org.jdiameter.api.auth.events.SessionTermAnswer;
  52. import org.jdiameter.api.auth.events.SessionTermRequest;
  53. import org.jdiameter.client.api.ISessionFactory;
  54. import org.jdiameter.common.api.app.IAppSessionState;
  55. import org.jdiameter.common.api.app.auth.IAuthMessageFactory;
  56. import org.jdiameter.common.api.app.auth.IServerAuthActionContext;
  57. import org.jdiameter.common.api.app.auth.ServerAuthSessionState;
  58. import org.jdiameter.common.impl.app.AppAnswerEventImpl;
  59. import org.jdiameter.common.impl.app.auth.AbortSessionAnswerImpl;
  60. import org.jdiameter.common.impl.app.auth.AbortSessionRequestImpl;
  61. import org.jdiameter.common.impl.app.auth.AppAuthSessionImpl;
  62. import org.slf4j.Logger;
  63. import org.slf4j.LoggerFactory;
  64. /**
  65. * Server Authorization session implementation
  66. *
  67. * @author erick.svenson@yahoo.com
  68. * @author <a href="mailto:brainslog@gmail.com"> Alexandre Mendonca </a>
  69. * @author <a href="mailto:baranowb@gmail.com"> Bartosz Baranowski </a>
  70. */
  71. public class ServerAuthSessionImpl extends AppAuthSessionImpl implements ServerAuthSession, EventListener<Request, Answer>, NetworkReqListener {
  72. private static final long serialVersionUID = 1L;
  73. protected static final Logger logger = LoggerFactory.getLogger(ServerAuthSessionImpl.class);
  74. protected IServerAuthSessionData sessionData;
  75. // Session State Handling ---------------------------------------------------
  76. private Lock sendAndStateLock = new ReentrantLock();
  77. // Factories and Listeners --------------------------------------------------
  78. protected transient IAuthMessageFactory factory;
  79. protected transient IServerAuthActionContext context;
  80. protected transient ServerAuthSessionListener listener;
  81. // Ts Timer -----------------------------------------------------------------
  82. protected final static String TIMER_NAME_TS="AUTH_TS";
  83. // Constructors -------------------------------------------------------------
  84. public ServerAuthSessionImpl(IServerAuthSessionData sessionData,ISessionFactory sf, ServerAuthSessionListener lst, IAuthMessageFactory fct, StateChangeListener<AppSession> scListener,IServerAuthActionContext context, long tsTimeout, boolean stateless) {
  85. super(sf,sessionData);
  86. super.appId = fct.getApplicationId();
  87. this.listener = lst;
  88. this.factory = fct;
  89. this.context = context;
  90. this.sessionData = sessionData;
  91. this.sessionData.setStateless(stateless);
  92. this.sessionData.setTsTimeout(tsTimeout);
  93. super.addStateChangeNotification(scListener);
  94. }
  95. // ServerAuthSession Implementation methods ---------------------------------
  96. public void sendAuthAnswer(AppAnswerEvent appAnswerEvent) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException {
  97. send(null, appAnswerEvent);
  98. }
  99. public void sendReAuthRequest(ReAuthRequest reAuthRequest) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException {
  100. send(null, reAuthRequest);
  101. }
  102. public void sendAbortSessionRequest(AbortSessionRequest abortSessionRequest) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException {
  103. send(Event.Type.SEND_ASR_REQUEST, abortSessionRequest);
  104. }
  105. public void sendSessionTerminationAnswer(SessionTermAnswer sessionTermAnswer) throws InternalException, IllegalDiameterStateException, RouteException, OverloadException {
  106. send(null, sessionTermAnswer);
  107. }
  108. protected void send(Event.Type type, AppEvent event) throws InternalException {
  109. try {
  110. sendAndStateLock.lock();
  111. if (type != null) {
  112. handleEvent(new Event(type, event));
  113. }
  114. session.send(event.getMessage(), this);
  115. }
  116. catch (Exception e) {
  117. throw new InternalException(e);
  118. }
  119. finally {
  120. sendAndStateLock.unlock();
  121. }
  122. }
  123. public boolean isStateless() {
  124. return sessionData.isStateless();
  125. }
  126. @SuppressWarnings("unchecked")
  127. protected void setState(ServerAuthSessionState newState) {
  128. IAppSessionState oldState = sessionData.getServerAuthSessionState();
  129. sessionData.setServerAuthSessionState(newState);
  130. for (StateChangeListener i : stateListeners) {
  131. i.stateChanged(this,(Enum) oldState, (Enum) newState);
  132. }
  133. }
  134. @SuppressWarnings("unchecked")
  135. public <E> E getState(Class<E> eClass) {
  136. return eClass == ServerAuthSessionState.class ? (E) sessionData.getServerAuthSessionState() : null;
  137. }
  138. public boolean handleEvent(StateEvent event) throws InternalException, OverloadException {
  139. return isStateless() ? handleEventForStatelessSession(event) : handleEventForStatefullSession(event);
  140. }
  141. public boolean handleEventForStatelessSession(StateEvent event) throws InternalException, OverloadException {
  142. try {
  143. switch (sessionData.getServerAuthSessionState()) {
  144. case IDLE:
  145. switch ((Event.Type) event.getType()) {
  146. case RECEIVE_AUTH_REQUEST:
  147. // Current State: IDLE
  148. // Event: Service-specific authorization request received, and successfully processed
  149. // Action: Send service specific answer
  150. // New State: IDLE
  151. setState(IDLE);
  152. listener.doAuthRequestEvent(this, (AppRequestEvent) event.getData());
  153. break;
  154. default:
  155. logger.debug("Unknown event {}", event.getType());
  156. break;
  157. }
  158. break;
  159. }
  160. }
  161. catch (Throwable t) {
  162. throw new InternalException(t);
  163. }
  164. return true;
  165. }
  166. public boolean handleEventForStatefullSession(StateEvent event) throws InternalException, OverloadException {
  167. ServerAuthSessionState state = sessionData.getServerAuthSessionState();
  168. ServerAuthSessionState oldState = state;
  169. try {
  170. switch (state) {
  171. case IDLE: {
  172. switch ((Event.Type) event.getType()) {
  173. case RECEIVE_AUTH_REQUEST:
  174. try {
  175. // Current State: IDLE
  176. // Event: Service-specific authorization request received, and user is authorized
  177. // Action: Send successful service specific answer
  178. // New State: OPEN
  179. setState(OPEN);
  180. listener.doAuthRequestEvent(this, (AppRequestEvent) event.getData());
  181. }
  182. catch (Exception e) {
  183. setState(IDLE);
  184. }
  185. break;
  186. case RECEIVE_STR_REQUEST:
  187. try {
  188. // Current State: ANY
  189. // Event: STR Received
  190. // Action: Send STA, Cleanup
  191. // New State: IDLE
  192. setState(IDLE);
  193. listener.doSessionTerminationRequestEvent(this, (SessionTermRequest) event.getData());
  194. }
  195. catch (Exception e) {
  196. logger.debug("Can not handle event", e);
  197. }
  198. break;
  199. case SEND_ASR_REQUEST:
  200. setState(DISCONNECTED);
  201. break;
  202. case TIMEOUT_EXPIRES:
  203. if (context != null) {
  204. context.accessTimeoutElapses(this);
  205. }
  206. setState(IDLE);
  207. break;
  208. default:
  209. logger.debug("Unknown event {}", event.getType());
  210. break;
  211. }
  212. break;
  213. }
  214. case OPEN: {
  215. switch ((Event.Type) event.getType()) {
  216. case RECEIVE_AUTH_REQUEST:
  217. try {
  218. // Current State: OPEN
  219. // Event: Service-specific authorization request received, and user is authorized
  220. // Action: Send successful service specific answer
  221. // New State: OPEN
  222. listener.doAuthRequestEvent(this, (AppRequestEvent) event.getData());
  223. }
  224. catch (Exception e) {
  225. // Current State: OPEN
  226. // Event: Service-specific authorization request received, and user is not authorized
  227. // Action: Send failed service specific answer, Cleanup
  228. // New State: IDLE
  229. setState(IDLE);
  230. }
  231. break;
  232. case RECEIVE_STR_REQUEST:
  233. try {
  234. setState(IDLE);
  235. listener.doSessionTerminationRequestEvent(this, (SessionTermRequest) event.getData());
  236. }
  237. catch (Exception e) {
  238. logger.debug("Can not handle event", e);
  239. }
  240. break;
  241. case SEND_ASR_REQUEST:
  242. // Current State: OPEN
  243. // Event: Home server wants to terminate the service
  244. // Action: Send ASR
  245. // New State: DISCON
  246. setState(DISCONNECTED);
  247. break;
  248. case TIMEOUT_EXPIRES:
  249. // Current State: OPEN
  250. // Event: Authorization-Lifetime (and Auth-Grace-Period) expires on home server.
  251. // Action: Cleanup
  252. // New State: IDLE
  253. // Current State: OPEN
  254. // Event: Session-Timeout expires on home server
  255. // Action: Cleanup
  256. // New State: IDLE
  257. if (context != null) {
  258. context.accessTimeoutElapses(this);
  259. }
  260. setState(IDLE);
  261. break;
  262. default:
  263. logger.debug("Unknown event {}", event.getType());
  264. break;
  265. }
  266. break;
  267. }
  268. case DISCONNECTED: {
  269. switch ((Event.Type) event.getType()) {
  270. case SEND_ASR_FAILURE:
  271. // Current State: DISCON
  272. // Event: Failure to send ASR
  273. // Action: Wait, Re-send ASR
  274. // New State: DISCON
  275. setState(DISCONNECTED);
  276. break;
  277. case RECEIVE_ASR_ANSWER:
  278. // Current State: DISCON
  279. // Event: ASR successfully sent and ASA Received with Result-Code
  280. // Action: Cleanup
  281. // New State: IDLE
  282. setState(IDLE);
  283. listener.doAbortSessionAnswerEvent(this, (AbortSessionAnswer) event.getData());
  284. break;
  285. default:
  286. logger.debug("Unknown event {}", event.getType());
  287. break;
  288. }
  289. break;
  290. }
  291. default: {
  292. logger.debug("Unknown state {}", state);
  293. break;
  294. }
  295. }
  296. // post processing
  297. if (oldState != state) {
  298. if (OPEN.equals(state) && context != null) {
  299. if(context != null) {
  300. cancelTsTimer();
  301. startTsTimer();
  302. }
  303. // scheduler.schedule(new Runnable() {
  304. // public void run() {
  305. // if (context != null) {
  306. // try {
  307. // handleEvent(new Event(TIMEOUT_EXPIRES, null));
  308. // }
  309. // catch (Exception e) {
  310. // logger.debug("Can not handle event", e);
  311. // }
  312. // }
  313. // }
  314. // }, context.createAccessTimer(), TimeUnit.MILLISECONDS);
  315. }
  316. }
  317. }
  318. catch (Throwable t) {
  319. throw new InternalException(t);
  320. }
  321. return true;
  322. }
  323. public void receivedSuccessMessage(Request request, Answer answer) {
  324. AnswerDelivery rd = new AnswerDelivery();
  325. rd.session = this;
  326. rd.request = request;
  327. rd.answer = answer;
  328. super.scheduler.execute(rd);
  329. }
  330. public void timeoutExpired(Request request) {
  331. try {
  332. if (request.getCommandCode() == AbortSessionRequestImpl.code) {
  333. handleEvent(new Event(Event.Type.SEND_ASR_FAILURE, new AbortSessionRequestImpl(request)));
  334. }
  335. else {
  336. logger.debug("Timeout for unknown request {}", request);
  337. }
  338. }
  339. catch (Exception e) {
  340. logger.debug("Can not handle event", e);
  341. }
  342. }
  343. public Answer processRequest(Request request) {
  344. RequestDelivery rd = new RequestDelivery();
  345. rd.session = this;
  346. rd.request = request;
  347. super.scheduler.execute(rd);
  348. return null;
  349. }
  350. /* (non-Javadoc)
  351. * @see org.jdiameter.common.impl.app.AppSessionImpl#isReplicable()
  352. */
  353. @Override
  354. public boolean isReplicable() {
  355. return true;
  356. }
  357. protected void startTsTimer() {
  358. try {
  359. sendAndStateLock.lock();
  360. sessionData.setTsTimerId(super.timerFacility.schedule(sessionData.getSessionId(), TIMER_NAME_TS, sessionData.getTsTimeout()));
  361. }
  362. finally {
  363. sendAndStateLock.unlock();
  364. }
  365. }
  366. protected void cancelTsTimer() {
  367. try {
  368. sendAndStateLock.lock();
  369. Serializable tsTimerId = sessionData.getTsTimerId();
  370. if(tsTimerId != null) {
  371. super.timerFacility.cancel(tsTimerId);
  372. sessionData.setTsTimerId(null);
  373. }
  374. }
  375. finally {
  376. sendAndStateLock.unlock();
  377. }
  378. }
  379. /* (non-Javadoc)
  380. * @see org.jdiameter.common.impl.app.AppSessionImpl#onTimer(java.lang.String)
  381. */
  382. @Override
  383. public void onTimer(String timerName) {
  384. if(timerName.equals(TIMER_NAME_TS)) {
  385. try {
  386. sendAndStateLock.lock();
  387. sessionData.setTsTimerId(null);
  388. handleEvent(new Event(TIMEOUT_EXPIRES, null));
  389. }
  390. catch (Exception e) {
  391. logger.debug("Can not handle event", e);
  392. }
  393. finally {
  394. sendAndStateLock.unlock();
  395. }
  396. }
  397. }
  398. @Override
  399. public int hashCode() {
  400. final int prime = 31;
  401. int result = super.hashCode();
  402. result = prime * result + ((sessionData == null) ? 0 : sessionData.hashCode());
  403. return result;
  404. }
  405. @Override
  406. public boolean equals(Object obj) {
  407. if (this == obj)
  408. return true;
  409. if (!super.equals(obj))
  410. return false;
  411. if (getClass() != obj.getClass())
  412. return false;
  413. ServerAuthSessionImpl other = (ServerAuthSessionImpl) obj;
  414. if (sessionData == null) {
  415. if (other.sessionData != null)
  416. return false;
  417. }
  418. else if (!sessionData.equals(other.sessionData))
  419. return false;
  420. return true;
  421. }
  422. @Override
  423. public void release() {
  424. if (isValid()) {
  425. try {
  426. sendAndStateLock.lock();
  427. super.release();
  428. this.context = null;
  429. this.listener = null;
  430. }
  431. catch (Exception e) {
  432. logger.debug("Failed to release session", e);
  433. }
  434. finally {
  435. sendAndStateLock.unlock();
  436. }
  437. }
  438. else {
  439. logger.debug("Trying to release an already invalid session, with Session ID '{}'", getSessionId());
  440. }
  441. }
  442. private class RequestDelivery implements Runnable {
  443. ServerAuthSession session;
  444. Request request;
  445. public void run() {
  446. if (request != null) {
  447. if (request.getCommandCode() == factory.getAuthMessageCommandCode()) {
  448. try {
  449. sendAndStateLock.lock();
  450. handleEvent(new Event(RECEIVE_AUTH_REQUEST, factory.createAuthRequest(request)));
  451. }
  452. catch (Exception e) {
  453. logger.debug("Can not handle event", e);
  454. }
  455. finally {
  456. sendAndStateLock.unlock();
  457. }
  458. }
  459. else {
  460. try {
  461. listener.doOtherEvent(session, factory.createAuthRequest(request), null);
  462. }
  463. catch (Exception e) {
  464. logger.debug("Can not handle event", e);
  465. }
  466. }
  467. }
  468. }
  469. }
  470. private class AnswerDelivery implements Runnable {
  471. ServerAuthSession session;
  472. Answer answer;
  473. Request request;
  474. public void run() {
  475. try {
  476. sendAndStateLock.lock();
  477. if (request.getCommandCode() == factory.getAuthMessageCommandCode()) {
  478. handleEvent(new Event(RECEIVE_AUTH_REQUEST, factory.createAuthRequest(request)));
  479. }
  480. else if (request.getCommandCode() == AbortSessionRequestImpl.code) {
  481. handleEvent(new Event(RECEIVE_ASR_ANSWER, new AbortSessionAnswerImpl(answer)));
  482. }
  483. else {
  484. listener.doOtherEvent(session, factory.createAuthRequest(request), new AppAnswerEventImpl(answer));
  485. }
  486. }
  487. catch (Exception e) {
  488. logger.debug("Can not handle event", e);
  489. }
  490. finally {
  491. sendAndStateLock.unlock();
  492. }
  493. }
  494. }
  495. }