socket_cache.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. # Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
  2. #
  3. # Permission to use, copy, modify, and distribute this software for any
  4. # purpose with or without fee is hereby granted, provided that the above
  5. # copyright notice and this permission notice appear in all copies.
  6. #
  7. # THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
  8. # DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
  9. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
  10. # INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
  11. # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
  12. # FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
  13. # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  14. # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. """
  16. Here's the cache for sockets from socket creator.
  17. """
  18. class SocketError(Exception):
  19. """
  20. Exception raised when the socket creator is unable to create requested
  21. socket. Possible reasons might be the address it should be bound to
  22. is already taken, the permissions are insufficient, the address family
  23. is not supported on this computer and many more.
  24. """
  25. pass
  26. class ShareError(Exception):
  27. """
  28. The requested socket is already taken by other component and the sharing
  29. parameters don't allow sharing with the new request.
  30. """
  31. pass
  32. class Cache:
  33. """
  34. This is the cache for sockets from socket creator. The purpose of cache
  35. is to hold the sockets that were requested, until they are no longer
  36. needed. One reason is, the socket is created before it is sent over the
  37. unix domain socket in boss, so we need to keep it somewhere for a while.
  38. The other reason is, a single socket might be requested multiple times.
  39. So we keep it here in case someone else might ask for it.
  40. Each socket kept here has a reference count and when it drops to zero,
  41. it is removed from cache and closed.
  42. This is expected to be part of Boss, it is not a general utility class.
  43. """
  44. def __init__(self, creator):
  45. """
  46. Initialization. The creator is the socket creator object
  47. (isc.bind10.sockcreator.Creator) which will be used to create yet
  48. uncached sockets.
  49. """
  50. # Full implementation and tests are in #1427. This is just because
  51. # of a boss test.
  52. self._creator = creator
  53. def get_token(self, protocol, address, port, share_mode, share_name):
  54. """
  55. This requests a token representing a socket. The socket is either
  56. found in the cache already or requested from the creator at this time
  57. (and cached for later time).
  58. The parameters are:
  59. - protocol: either 'UDP' or 'TCP'
  60. - address: the IPAddr object representing the address to bind to
  61. - port: integer saying which port to bind to
  62. - share_mode: either 'NO', 'SAMEAPP' or 'ANY', specifying how the
  63. socket can be shared with others. See bin/bind10/creatorapi.txt
  64. for details.
  65. - share_name: the name of application, in case of 'SAMEAPP' share
  66. mode. Only requests with the same name can share the socket.
  67. If the call is successful, it returns a string token which can be
  68. used to pick up the socket later. The socket is created with reference
  69. count zero and if it isn't picked up soon enough (the time yet has to
  70. be set), it will be removed and the token is invalid.
  71. It can fail in various ways. Explicitly listed exceptions are:
  72. - SocketError: this one is thrown if the socket creator couldn't provide
  73. the socket and it is not yet cached (it belongs to other application,
  74. for example).
  75. - ShareError: the socket is already in the cache, but it can't be
  76. shared due to share_mode and share_name combination (both the request
  77. restrictions and of all copies of socket handed out are considered,
  78. so it can be raised even if you call it with share_mode 'ANY').
  79. - isc.bind10.sockcreator.CreatorError: fatal creator errors are
  80. propagated. Thay should cause the boss to exit if ever encountered.
  81. Note that it isn't guaranteed the tokens would be unique and they
  82. should be used as an opaque handle only.
  83. """
  84. pass
  85. def get_socket(self, token, application):
  86. """
  87. This returns the socket created by get_token. The token should be the
  88. one returned from previous call from get_token. The token can be used
  89. only once to receive the socket.
  90. The application is a token representing the application that requested
  91. it. It is not clear now if that would be the PID of application, it's
  92. address on message bus or filehandle of the unix domain socket used
  93. to request it, but the same application handle should be used in case
  94. the application crashes to call drop_application.
  95. In case the token is considered invalid (it doesn't come from the
  96. get_token, it was already used, the socket wasn't picked up soon
  97. enough, ...), it raises ValueError.
  98. """
  99. pass
  100. def drop_socket(self, token):
  101. """
  102. This signals the application no longer uses the socket which was
  103. requested by the given token. It decreases the reference count for
  104. the socket and closes and removes the cached copy if it was the last
  105. one.
  106. It raises ValueError if the token doesn't exist.
  107. """
  108. pass
  109. def drop_application(self, application):
  110. """
  111. This signals the application terminated and all socket it picked up
  112. should be considered unused by it now. It effectively calls drop_socket
  113. on each of the sockets the application picked up and didn't drop yet.
  114. If the application is invalid (no get_socket was successful with this
  115. value of application), it raises ValueError.
  116. """
  117. pass