package luv

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

Source file DNS.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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
(* This file is part of Luv, released under the MIT license. See LICENSE.md for
   details, or visit https://github.com/aantron/luv/blob/master/LICENSE.md. *)



module Addr_info =
struct
  module Request =
  struct
    type t = [ `Addr_info ] Request.t

    let make () =
      Request.allocate C.Types.DNS.Addr_info.Request.t
  end

  module Flag =
  struct
    type t = [
      | `PASSIVE
      | `CANONNAME
      | `NUMERICHOST
      | `NUMERICSERV
      | `V4MAPPED
      | `ALL
      | `ADDRCONFIG
    ]

    let to_c = let open C.Types.DNS.Addr_info.Flag in function
      | `PASSIVE -> passive
      | `CANONNAME -> canonname
      | `NUMERICHOST -> numerichost
      | `NUMERICSERV -> numericserv
      | `V4MAPPED -> v4mapped
      | `ALL -> all
      | `ADDRCONFIG -> addrconfig
  end

  type t = {
    family : Sockaddr.Address_family.t;
    socktype : Sockaddr.Socket_type.t;
    protocol : int;
    addr : Sockaddr.t;
    canonname : string option;
  }
end

module Name_info =
struct
  module Request =
  struct
    type t = [ `Name_info ] Request.t

    let make () =
      Request.allocate C.Types.DNS.Name_info.t
  end

  module Flag =
  struct
    type t = [
      | `NAMEREQD
      | `DGRAM
      | `NOFQDN
      | `NUMERICHOST
      | `NUMERICSERV
    ]

    let to_c = let open C.Types.DNS.Name_info.Flag in function
      | `NAMEREQD -> namereqd
      | `DGRAM -> dgram
      | `NOFQDN -> nofqdn
      | `NUMERICHOST -> numerichost
      | `NUMERICSERV -> numericserv
  end
end

let rec addrinfo_list_to_ocaml addrinfo =
  if Ctypes.is_null addrinfo then
    []
  else begin
    let module AI = C.Types.DNS.Addr_info in
    let addrinfo = Ctypes.(!@) addrinfo in
    let family =
      Sockaddr.Address_family.from_c (Ctypes.getf addrinfo AI.family) in
    let socktype =
      Sockaddr.Socket_type.from_c (Ctypes.getf addrinfo AI.socktype) in
    let addr =
      Sockaddr.copy_sockaddr
        (Ctypes.getf addrinfo AI.addrlen) (Ctypes.getf addrinfo AI.addr)
    in
    let ocaml_addrinfo = {
      Addr_info.family;
      socktype;
      protocol = Ctypes.getf addrinfo AI.protocol;
      addr;
      canonname = Ctypes.getf addrinfo AI.canonname;
    }
    in
    let next = Ctypes.getf addrinfo AI.next in
    ocaml_addrinfo::(addrinfo_list_to_ocaml next)
  end

module Async =
struct
  let getaddrinfo_trampoline =
    C.Functions.DNS.Addr_info.get_trampoline ()

  let getaddrinfo
      ?loop
      ?(request = Addr_info.Request.make ())
      ?family
      ?socktype
      ?protocol
      ?flags
      ?node
      ?service
      ()
      callback =

    let loop = Loop.or_default loop in

    let hints =
      let module AI = C.Types.DNS.Addr_info in
      match family, socktype, protocol, flags with
      | None, None, None, None ->
        Ctypes.(from_voidp AI.t null)
      | _ ->
        let hints = Ctypes.make AI.t in
        let family =
          match family with
          | Some family -> family
          | None -> `UNSPEC
        in
        let family = Sockaddr.Address_family.to_c family in
        Ctypes.setf hints AI.family family;
        begin match socktype with
        | Some socktype ->
          let socktype = Sockaddr.Socket_type.to_c socktype in
          Ctypes.setf hints AI.socktype socktype
        | None -> ()
        end;
        begin match protocol with
        | Some protocol -> Ctypes.setf hints AI.protocol protocol
        | None -> ()
        end;
        begin match flags with
        | Some flags ->
          let flags = Helpers.Bit_field.list_to_c Addr_info.Flag.to_c flags in
          Ctypes.setf hints AI.flags flags
        | None -> ()
        end;
        Ctypes.addr hints
    in

    let callback = Error.catch_exceptions callback in
    Request.set_callback request begin fun result ->
      result
      |> Error.to_result_f begin fun () ->
        let addrinfos =
          Ctypes.(getf (!@ request)) C.Types.DNS.Addr_info.Request.addrinfo in
        let result = addrinfo_list_to_ocaml addrinfos in
        C.Functions.DNS.Addr_info.free addrinfos;
        result
      end
      |> callback
    end;

    let immediate_result =
      C.Functions.DNS.Addr_info.getaddrinfo
        loop request getaddrinfo_trampoline node service hints
    in

    if immediate_result < 0 then begin
      Request.release request;
      callback (Error.result_from_c immediate_result)
    end

  let load_string request field' field_length =
    let bigstring =
      Ctypes.(bigarray_of_ptr
        array1 field_length Bigarray.Char (request |-> field'))
    in
    let rec find_terminator index =
      if Buffer.unsafe_get bigstring index = '\000' then index
      else find_terminator (index + 1)
    in
    Buffer.sub bigstring ~offset:0 ~length:(find_terminator 0)
    |> Buffer.to_string

  let getnameinfo_trampoline =
    C.Functions.DNS.Name_info.get_trampoline ()

  let getnameinfo
      ?loop
      ?(request = Name_info.Request.make ())
      ?(flags = [])
      address
      callback =

    let callback = Error.catch_exceptions callback in
    Request.set_callback request begin fun result ->
      result
      |> Error.to_result_f begin fun () ->
        let module NI = C.Types.DNS.Name_info in
        let host = load_string request NI.host NI.maxhost in
        let service = load_string request NI.service NI.maxserv in
        (host, service)
      end
      |> callback
    end;

    let flags = Helpers.Bit_field.list_to_c Name_info.Flag.to_c flags in

    let immediate_result =
      C.Functions.DNS.Name_info.getnameinfo
        (Loop.or_default loop)
        request
        getnameinfo_trampoline
        (Sockaddr.as_sockaddr address)
        flags
    in

    if immediate_result < 0 then begin
      Request.release request;
      callback (Error.result_from_c immediate_result)
    end
end

include Async
OCaml

Innovation. Community. Security.