_sendfile.py 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. # -*- coding: utf-8 -
  2. #
  3. # This file is part of gunicorn released under the MIT license.
  4. # See the NOTICE for more information.
  5. import errno
  6. import os
  7. import sys
  8. try:
  9. import ctypes
  10. import ctypes.util
  11. except MemoryError:
  12. # selinux execmem denial
  13. # https://bugzilla.redhat.com/show_bug.cgi?id=488396
  14. raise ImportError
  15. SUPPORTED_PLATFORMS = (
  16. 'darwin',
  17. 'freebsd',
  18. 'dragonfly',
  19. 'linux2')
  20. if sys.platform not in SUPPORTED_PLATFORMS:
  21. raise ImportError("sendfile isn't supported on this platform")
  22. _libc = ctypes.CDLL(ctypes.util.find_library("c"), use_errno=True)
  23. _sendfile = _libc.sendfile
  24. def sendfile(fdout, fdin, offset, nbytes):
  25. if sys.platform == 'darwin':
  26. _sendfile.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_uint64,
  27. ctypes.POINTER(ctypes.c_uint64), ctypes.c_voidp,
  28. ctypes.c_int]
  29. _nbytes = ctypes.c_uint64(nbytes)
  30. result = _sendfile(fdin, fdout, offset, _nbytes, None, 0)
  31. if result == -1:
  32. e = ctypes.get_errno()
  33. if e == errno.EAGAIN and _nbytes.value is not None:
  34. return _nbytes.value
  35. raise OSError(e, os.strerror(e))
  36. return _nbytes.value
  37. elif sys.platform in ('freebsd', 'dragonfly',):
  38. _sendfile.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_uint64,
  39. ctypes.c_uint64, ctypes.c_voidp,
  40. ctypes.POINTER(ctypes.c_uint64), ctypes.c_int]
  41. _sbytes = ctypes.c_uint64()
  42. result = _sendfile(fdin, fdout, offset, nbytes, None, _sbytes, 0)
  43. if result == -1:
  44. e = ctypes.get_errno()
  45. if e == errno.EAGAIN and _sbytes.value is not None:
  46. return _sbytes.value
  47. raise OSError(e, os.strerror(e))
  48. return _sbytes.value
  49. else:
  50. _sendfile.argtypes = [ctypes.c_int, ctypes.c_int,
  51. ctypes.POINTER(ctypes.c_uint64), ctypes.c_size_t]
  52. _offset = ctypes.c_uint64(offset)
  53. sent = _sendfile(fdout, fdin, _offset, nbytes)
  54. if sent == -1:
  55. e = ctypes.get_errno()
  56. raise OSError(e, os.strerror(e))
  57. return sent