ISCSIServer.Logout.cs 4.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. /* Copyright (C) 2012-2016 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
  2. *
  3. * You can redistribute this program and/or modify it under the terms of
  4. * the GNU Lesser Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. */
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Net;
  10. using System.Text;
  11. using Utilities;
  12. namespace ISCSI.Server
  13. {
  14. public partial class ISCSIServer
  15. {
  16. private ISCSIPDU GetLogoutResponsePDU(LogoutRequestPDU request, ConnectionParameters connection)
  17. {
  18. Log(Severity.Verbose, "[{0}] Logour Request", connection.ConnectionIdentifier);
  19. if (connection.Session.IsDiscovery && request.ReasonCode != LogoutReasonCode.CloseTheSession)
  20. {
  21. // RFC 3720: Discovery-session: The target MUST ONLY accept [..] logout request with the reason "close the session"
  22. RejectPDU reject = new RejectPDU();
  23. reject.Reason = RejectReason.ProtocolError;
  24. reject.Data = ByteReader.ReadBytes(request.GetBytes(), 0, 48);
  25. return reject;
  26. }
  27. else
  28. {
  29. List<ConnectionState> connectionsToClose = new List<ConnectionState>();
  30. if (request.ReasonCode == LogoutReasonCode.CloseTheSession)
  31. {
  32. connectionsToClose = m_connectionManager.GetSessionConnections(connection.Session);
  33. }
  34. else if (request.ReasonCode == LogoutReasonCode.CloseTheConnection)
  35. {
  36. // RFC 3720: A Logout for a CID may be performed on a different transport connection when the TCP connection for the CID has already been terminated.
  37. ConnectionState existingConnection = m_connectionManager.FindConnection(connection.Session, request.CID);
  38. if (existingConnection != null)
  39. {
  40. connectionsToClose.Add(existingConnection);
  41. }
  42. else
  43. {
  44. return ServerResponseHelper.GetLogoutResponsePDU(request, LogoutResponse.CIDNotFound);
  45. }
  46. }
  47. else if (request.ReasonCode == LogoutReasonCode.RemoveTheConnectionForRecovery)
  48. {
  49. return ServerResponseHelper.GetLogoutResponsePDU(request, LogoutResponse.ConnectionRecoveryNotSupported);
  50. }
  51. else
  52. {
  53. // Unknown LogoutRequest ReasonCode
  54. RejectPDU reject = new RejectPDU();
  55. reject.Reason = RejectReason.ProtocolError;
  56. reject.Data = ByteReader.ReadBytes(request.GetBytes(), 0, 48);
  57. return reject;
  58. }
  59. foreach (ConnectionState connectionToClose in connectionsToClose)
  60. {
  61. // Wait for pending I/O to complete.
  62. connectionToClose.RunningSCSICommands.WaitUntilZero();
  63. if (connectionToClose.ConnectionParameters != connection)
  64. {
  65. SocketUtils.ReleaseSocket(connectionToClose.ClientSocket);
  66. }
  67. m_connectionManager.RemoveConnection(connectionToClose);
  68. }
  69. if (request.ReasonCode == LogoutReasonCode.CloseTheSession)
  70. {
  71. Log(Severity.Verbose, "[{0}] Session has been closed", connection.Session.SessionIdentifier);
  72. m_sessionManager.RemoveSession(connection.Session, SessionTerminationReason.Logout);
  73. }
  74. return ServerResponseHelper.GetLogoutResponsePDU(request, LogoutResponse.ClosedSuccessfully);
  75. // connection will be closed after a LogoutResponsePDU has been sent.
  76. }
  77. }
  78. }
  79. }