package piaf

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file sendfile.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
exception Darwin_specific_unix_error of (Unix.error * int)

let () =
  Callback.register_exception
    "sendfile_exn_unix_error"
    (Darwin_specific_unix_error (Unix.E2BIG, 0));
  Printexc.register_printer (function
    | Darwin_specific_unix_error (unix_error, len) ->
      let msg =
        (* Copied from
           https://github.com/ocaml/ocaml/blob/trunk/otherlibs/unix/unix_unix.ml *)
        match unix_error with
        | E2BIG -> "E2BIG"
        | EACCES -> "EACCES"
        | EAGAIN -> "EAGAIN"
        | EBADF -> "EBADF"
        | EBUSY -> "EBUSY"
        | ECHILD -> "ECHILD"
        | EDEADLK -> "EDEADLK"
        | EDOM -> "EDOM"
        | EEXIST -> "EEXIST"
        | EFAULT -> "EFAULT"
        | EFBIG -> "EFBIG"
        | EINTR -> "EINTR"
        | EINVAL -> "EINVAL"
        | EIO -> "EIO"
        | EISDIR -> "EISDIR"
        | EMFILE -> "EMFILE"
        | EMLINK -> "EMLINK"
        | ENAMETOOLONG -> "ENAMETOOLONG"
        | ENFILE -> "ENFILE"
        | ENODEV -> "ENODEV"
        | ENOENT -> "ENOENT"
        | ENOEXEC -> "ENOEXEC"
        | ENOLCK -> "ENOLCK"
        | ENOMEM -> "ENOMEM"
        | ENOSPC -> "ENOSPC"
        | ENOSYS -> "ENOSYS"
        | ENOTDIR -> "ENOTDIR"
        | ENOTEMPTY -> "ENOTEMPTY"
        | ENOTTY -> "ENOTTY"
        | ENXIO -> "ENXIO"
        | EPERM -> "EPERM"
        | EPIPE -> "EPIPE"
        | ERANGE -> "ERANGE"
        | EROFS -> "EROFS"
        | ESPIPE -> "ESPIPE"
        | ESRCH -> "ESRCH"
        | EXDEV -> "EXDEV"
        | EWOULDBLOCK -> "EWOULDBLOCK"
        | EINPROGRESS -> "EINPROGRESS"
        | EALREADY -> "EALREADY"
        | ENOTSOCK -> "ENOTSOCK"
        | EDESTADDRREQ -> "EDESTADDRREQ"
        | EMSGSIZE -> "EMSGSIZE"
        | EPROTOTYPE -> "EPROTOTYPE"
        | ENOPROTOOPT -> "ENOPROTOOPT"
        | EPROTONOSUPPORT -> "EPROTONOSUPPORT"
        | ESOCKTNOSUPPORT -> "ESOCKTNOSUPPORT"
        | EOPNOTSUPP -> "EOPNOTSUPP"
        | EPFNOSUPPORT -> "EPFNOSUPPORT"
        | EAFNOSUPPORT -> "EAFNOSUPPORT"
        | EADDRINUSE -> "EADDRINUSE"
        | EADDRNOTAVAIL -> "EADDRNOTAVAIL"
        | ENETDOWN -> "ENETDOWN"
        | ENETUNREACH -> "ENETUNREACH"
        | ENETRESET -> "ENETRESET"
        | ECONNABORTED -> "ECONNABORTED"
        | ECONNRESET -> "ECONNRESET"
        | ENOBUFS -> "ENOBUFS"
        | EISCONN -> "EISCONN"
        | ENOTCONN -> "ENOTCONN"
        | ESHUTDOWN -> "ESHUTDOWN"
        | ETOOMANYREFS -> "ETOOMANYREFS"
        | ETIMEDOUT -> "ETIMEDOUT"
        | ECONNREFUSED -> "ECONNREFUSED"
        | EHOSTDOWN -> "EHOSTDOWN"
        | EHOSTUNREACH -> "EHOSTUNREACH"
        | ELOOP -> "ELOOP"
        | EOVERFLOW -> "EOVERFLOW"
        | EUNKNOWNERR x -> Printf.sprintf "EUNKNOWNERR %d" x
      in

      Some
        (Format.asprintf "Sendfile(Unix_error): %s; remaining len: %d" msg len)
    | _ -> None)

external sendfile :
   src:Unix.file_descr
  -> dst:Unix.file_descr
  -> off:int
  -> len:int
  -> int
  = "ocaml_sendfile_sendfile_stub"

let sendfile_once_exn ?(off = 0) ~len ~src dst =
  try sendfile ~src ~dst ~off ~len with
  | Darwin_specific_unix_error (unix_err, _) ->
    raise (Unix.Unix_error (unix_err, "sendfile", ""))

let sendfile_once ?(off = 0) ~len ~src dst =
  try Ok (sendfile_once_exn ~src ~off ~len dst) with
  | Unix.Unix_error (unix_err, _, _msg) -> Error unix_err

let sendfile_exn ?(off = 0) ?len ~src dst =
  let rec sendfile_exn ~off ~len ~src dst =
    match sendfile ~src ~off ~len ~dst with
    | c when c = len -> len
    | c -> sendfile_exn ~src ~off:(off + c) ~len:(len - c) dst
    | exception Unix.Unix_error ((EINTR | EAGAIN), _, _) ->
      sendfile_exn ~src ~off ~len dst
    | exception Darwin_specific_unix_error ((EINTR | EAGAIN), sent) ->
      (* Darwin systems signal the number of bytes partially sent on EINTR /
         EAGAIN. *)
      sendfile_exn ~src ~off:(off + sent) ~len:(len - sent) dst
    | exception Darwin_specific_unix_error (unix_err, _) ->
      raise (Unix.Unix_error (unix_err, "sendfile", ""))
  in
  let len =
    match len with Some len -> len | None -> (Unix.fstat src).st_size - off
  in
  let _sent = sendfile_exn ~off ~len ~src dst in
  (* If we're here, we sent the whole file correctly, so we return the total
     length sent. *)
  len

let sendfile ?off ?len ~src dst =
  try Ok (sendfile_exn ~src ?off ?len dst) with
  | Unix.Unix_error (unix_err, _, _msg) -> Error unix_err
OCaml

Innovation. Community. Security.