package posix-socket

  1. Overview
  2. Docs

Source file posix_socket.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
open Ctypes
include Posix_socket_types
include Posix_socket_stubs.Def (Posix_socket_generated_stubs)
include Posix_eai_errno_is_native_impl

type sockaddr_storage = unit

let sockaddr_storage () = to_voidp (allocate_n char ~count:sockaddr_storage_len)

type socket_type = int

let socket_type_t = int
let from_sockaddr_storage t ptr = from_voidp t (to_voidp ptr)

exception Error of error

let strerror err = strerror (int_of_error err)

let () =
  Printexc.register_printer (function
    | Error err -> Some (Printf.sprintf "Posix_socket.Error(%s)" (strerror err))
    | _ -> None)

module Addrinfo = Types.Addrinfo

module Sockaddr = struct
  include Types.Sockaddr

  let from_sockaddr_storage = from_sockaddr_storage t
end

type sockaddr = Sockaddr.t structure

let sockaddr_t = Sockaddr.t

type in_port = Unsigned.uint16

let in_port_t = uint16_t

module SockaddrInet = struct
  include Types.SockaddrInet

  let from_sockaddr_storage = from_sockaddr_storage t
end

type sockaddr_in = SockaddrInet.t structure

let sockaddr_in_t = SockaddrInet.t

module SockaddrInet6 = struct
  include Types.SockaddrInet6

  let from_sockaddr_storage = from_sockaddr_storage t
end

type sockaddr_in6 = SockaddrInet6.t structure

let sockaddr_in6_t = SockaddrInet6.t

let sockaddr_len s =
  if is_null s then 0
  else (
    match !@(s |-> Sockaddr.sa_family) with
      | id when id = af_inet -> sizeof sockaddr_in_t
      | id when id = af_inet6 -> sizeof sockaddr_in6_t
      | id ->
          failwith
            (Printf.sprintf "Unsupported socket family: %x"
               (Sa_family.to_int id)))

let getnameinfo sockaddr_ptr =
  let s = allocate_n char ~count:ni_maxhost in
  let p = allocate_n char ~count:ni_maxserv in
  match
    getnameinfo sockaddr_ptr
      (Socklen.of_int (sockaddr_len sockaddr_ptr))
      s
      (Socklen.of_int ni_maxhost)
      p
      (Socklen.of_int ni_maxserv)
      (ni_numerichost lor ni_numericserv)
  with
    | 0 ->
        let host =
          let length =
            Unsigned.Size_t.to_int
              (strnlen s (Unsigned.Size_t.of_int ni_maxhost))
          in
          string_from_ptr s ~length
        in
        let port =
          let length =
            Unsigned.Size_t.to_int
              (strnlen p (Unsigned.Size_t.of_int ni_maxserv))
          in
          let port = string_from_ptr p ~length in
          try int_of_string port
          with _ -> (
            match getservbyname p null with
              | ptr when is_null ptr -> failwith "getnameinfo"
              | ptr ->
                  Unsigned.UInt16.to_int
                    (ntohs !@(ptr |-> Types.Servent.s_port)))
        in
        (host, port)
    | n -> raise (Error (error_of_int n))

let getaddrinfo =
  let get_sockaddr p =
    let finalise () = ignore (Sys.opaque_identity p) in
    let rec get_ptrs ~cur p =
      if is_null !@p then List.rev cur
      else (
        let addrinfo = !@p in
        let sockaddr = !@(addrinfo |-> Types.Addrinfo.ai_addr) in
        Gc.finalise_last finalise sockaddr;
        get_ptrs ~cur:(sockaddr :: cur) (addrinfo |-> Types.Addrinfo.ai_next))
    in
    get_ptrs ~cur:[] p
  in
  fun ?hints ?port host ->
    let port =
      match port with
        | Some (`Int port) ->
            let s = string_of_int port in
            let c = CArray.of_string s in
            CArray.start c
        | Some (`String s) ->
            let c = CArray.of_string s in
            CArray.start c
        | None -> from_voidp char null
    in
    let p =
      allocate_n
        ~finalise:(fun p ->
          let p = !@p in
          if not (is_null p) then freeaddrinfo p)
        (ptr Addrinfo.t) ~count:1
    in
    let hints =
      Option.value ~default:(from_voidp Types.Addrinfo.t null) hints
    in
    match getaddrinfo host port hints p with
      | 0 -> get_sockaddr p
      | n -> raise (Error (error_of_int n))

external alloc_sockaddr : _ Cstubs_internals.fatptr -> int -> Unix.sockaddr
  = "posix_socket_alloc_sockaddr"

let fatptr = function Cstubs_internals.CPointer s -> s
let to_unix_sockaddr s = alloc_sockaddr (fatptr s) (sockaddr_len s)

external get_sockaddr : Unix.sockaddr -> _ Cstubs_internals.fatptr -> unit
  = "posix_socket_get_sockaddr"

let from_unix_sockaddr s =
  let storage = sockaddr_storage () in
  get_sockaddr s (fatptr storage);
  Sockaddr.from_sockaddr_storage storage