ua_session_manager.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. #include "ua_session_manager.h"
  5. #include "ua_server_internal.h"
  6. UA_StatusCode
  7. UA_SessionManager_init(UA_SessionManager *sm, UA_Server *server) {
  8. LIST_INIT(&sm->sessions);
  9. sm->currentSessionCount = 0;
  10. sm->server = server;
  11. return UA_STATUSCODE_GOOD;
  12. }
  13. void UA_SessionManager_deleteMembers(UA_SessionManager *sm) {
  14. session_list_entry *current, *temp;
  15. LIST_FOREACH_SAFE(current, &sm->sessions, pointers, temp) {
  16. LIST_REMOVE(current, pointers);
  17. UA_Session_deleteMembersCleanup(&current->session, sm->server);
  18. UA_free(current);
  19. }
  20. }
  21. /* Delayed callback to free the session memory */
  22. static void
  23. removeSessionCallback(UA_Server *server, void *entry) {
  24. session_list_entry *sentry = (session_list_entry*)entry;
  25. UA_Session_deleteMembersCleanup(&sentry->session, server);
  26. UA_free(sentry);
  27. }
  28. static UA_StatusCode
  29. removeSession(UA_SessionManager *sm, session_list_entry *sentry) {
  30. /* Deactivate the session */
  31. sentry->session.activated = false;
  32. /* Add a delayed callback to remove the session when the currently
  33. * scheduled jobs have completed */
  34. UA_StatusCode retval = UA_Server_delayedCallback(sm->server, removeSessionCallback, sentry);
  35. if(retval != UA_STATUSCODE_GOOD) {
  36. UA_LOG_WARNING_SESSION(sm->server->config.logger, &sentry->session,
  37. "Could not remove session with error code %s",
  38. UA_StatusCode_name(retval));
  39. return retval; /* Try again next time */
  40. }
  41. /* Detach the session and make the capacity available */
  42. LIST_REMOVE(sentry, pointers);
  43. UA_atomic_add(&sm->currentSessionCount, (UA_UInt32)-1);
  44. return UA_STATUSCODE_GOOD;
  45. }
  46. void
  47. UA_SessionManager_cleanupTimedOut(UA_SessionManager *sm,
  48. UA_DateTime nowMonotonic) {
  49. session_list_entry *sentry, *temp;
  50. LIST_FOREACH_SAFE(sentry, &sm->sessions, pointers, temp) {
  51. /* Session has timed out? */
  52. if(sentry->session.validTill >= nowMonotonic)
  53. continue;
  54. UA_LOG_INFO_SESSION(sm->server->config.logger, &sentry->session,
  55. "Session has timed out");
  56. sm->server->config.accessControl.closeSession(&sentry->session.sessionId,
  57. sentry->session.sessionHandle);
  58. removeSession(sm, sentry);
  59. }
  60. }
  61. UA_Session *
  62. UA_SessionManager_getSessionByToken(UA_SessionManager *sm, const UA_NodeId *token) {
  63. session_list_entry *current = NULL;
  64. LIST_FOREACH(current, &sm->sessions, pointers) {
  65. /* Token does not match */
  66. if(!UA_NodeId_equal(&current->session.authenticationToken, token))
  67. continue;
  68. /* Session has timed out */
  69. if(UA_DateTime_nowMonotonic() > current->session.validTill) {
  70. UA_LOG_INFO_SESSION(sm->server->config.logger, &current->session,
  71. "Client tries to use a session that has timed out");
  72. return NULL;
  73. }
  74. /* Ok, return */
  75. return &current->session;
  76. }
  77. /* Session not found */
  78. UA_LOG_INFO(sm->server->config.logger, UA_LOGCATEGORY_SESSION,
  79. "Try to use Session with token " UA_PRINTF_GUID_FORMAT " but is not found",
  80. UA_PRINTF_GUID_DATA(token->identifier.guid));
  81. return NULL;
  82. }
  83. UA_Session *
  84. UA_SessionManager_getSessionById(UA_SessionManager *sm, const UA_NodeId *sessionId) {
  85. session_list_entry *current = NULL;
  86. LIST_FOREACH(current, &sm->sessions, pointers) {
  87. /* Token does not match */
  88. if(!UA_NodeId_equal(&current->session.sessionId, sessionId))
  89. continue;
  90. /* Session has timed out */
  91. if(UA_DateTime_nowMonotonic() > current->session.validTill) {
  92. UA_LOG_INFO_SESSION(sm->server->config.logger, &current->session,
  93. "Client tries to use a session that has timed out");
  94. return NULL;
  95. }
  96. /* Ok, return */
  97. return &current->session;
  98. }
  99. /* Session not found */
  100. UA_LOG_INFO(sm->server->config.logger, UA_LOGCATEGORY_SESSION,
  101. "Try to use Session with identifier " UA_PRINTF_GUID_FORMAT " but is not found",
  102. UA_PRINTF_GUID_DATA(sessionId->identifier.guid));
  103. return NULL;
  104. }
  105. /* Creates and adds a session. But it is not yet attached to a secure channel. */
  106. UA_StatusCode
  107. UA_SessionManager_createSession(UA_SessionManager *sm, UA_SecureChannel *channel,
  108. const UA_CreateSessionRequest *request, UA_Session **session) {
  109. if(sm->currentSessionCount >= sm->server->config.maxSessions)
  110. return UA_STATUSCODE_BADTOOMANYSESSIONS;
  111. session_list_entry *newentry = (session_list_entry *)UA_malloc(sizeof(session_list_entry));
  112. if(!newentry)
  113. return UA_STATUSCODE_BADOUTOFMEMORY;
  114. UA_atomic_add(&sm->currentSessionCount, 1);
  115. UA_Session_init(&newentry->session);
  116. newentry->session.sessionId = UA_NODEID_GUID(1, UA_Guid_random());
  117. newentry->session.authenticationToken = UA_NODEID_GUID(1, UA_Guid_random());
  118. if(request->requestedSessionTimeout <= sm->server->config.maxSessionTimeout &&
  119. request->requestedSessionTimeout > 0)
  120. newentry->session.timeout = request->requestedSessionTimeout;
  121. else
  122. newentry->session.timeout = sm->server->config.maxSessionTimeout;
  123. UA_Session_updateLifetime(&newentry->session);
  124. LIST_INSERT_HEAD(&sm->sessions, newentry, pointers);
  125. *session = &newentry->session;
  126. return UA_STATUSCODE_GOOD;
  127. }
  128. UA_StatusCode
  129. UA_SessionManager_removeSession(UA_SessionManager *sm, const UA_NodeId *token) {
  130. session_list_entry *current;
  131. LIST_FOREACH(current, &sm->sessions, pointers) {
  132. if(UA_NodeId_equal(&current->session.authenticationToken, token))
  133. break;
  134. }
  135. if(!current)
  136. return UA_STATUSCODE_BADSESSIONIDINVALID;
  137. return removeSession(sm, current);
  138. }