(* Copyright (C) 2002-2006, 2008 Henry Cejtin, Matthew Fluet, Suresh * Jagannathan, and Stephen Weeks. * * MLton is released under a BSD-style license. * See the file MLton-LICENSE for details. *) structure NetHostDB: NET_HOST_DB_EXTRA = struct structure Prim = PrimitiveFFI.NetHostDB (* network byte order (big-endian) *) type pre_in_addr = Word8.word array type in_addr = Word8.word vector val preInAddrToWord8Array = fn a => a val inAddrToWord8Vector = fn v => v val inAddrLen = C_Size.toInt Prim.inAddrSize fun newInAddr () = let val ia: pre_in_addr = Array.array (inAddrLen, 0wx0: Word8.word) fun finish () = Array.vector ia in (ia, finish) end fun any () = let val (wa, finish) = newInAddr () fun loop (i, acc) = if i >= inAddrLen then () else let val w = Word8.castFromSysWord (C_Int.castToSysWord acc) val () = Array.update (wa, (inAddrLen - 1) - i, w) in loop (i + 1, C_Int.>> (acc, 0w4)) end in loop (0, Prim.INADDR_ANY) ; finish () end structure AddrFamily = Net.AddrFamily type addr_family = AddrFamily.t datatype entry = T of {name: string, aliases: string list, addrType: addr_family, addrs: in_addr list} local fun make s (T r) = s r in val name = make #name val aliases = make #aliases val addrType = make #addrType val addrs = make #addrs end fun addr entry = hd (addrs entry) local fun get (i: C_Int.t): entry option = if i <> C_Int.zero then let val name = CUtil.C_String.toString (Prim.getEntryName ()) val numAliases = Prim.getEntryAliasesNum () fun fill (n, aliases) = if C_Int.< (n, numAliases) then let val alias = CUtil.C_String.toString (Prim.getEntryAliasesN n) in fill (C_Int.+ (n, 1), alias::aliases) end else List.rev aliases val aliases = fill (0, []) val addrType = Prim.getEntryAddrType () val length = Prim.getEntryLength () val numAddrs = Prim.getEntryAddrsNum () fun fill (n, addrs) = if C_Int.< (n, numAddrs) then let val addr = Word8Array.array (C_Int.toInt length, 0wx0) val _ = Prim.getEntryAddrsN (n, Word8Array.toPoly addr) val addr = Word8Vector.toPoly (Word8Array.vector addr) in fill (C_Int.+ (n, 1), addr::addrs) end else List.rev addrs val addrs = fill (0, []) in SOME (T {name = name, aliases = aliases, addrType = AddrFamily.fromRep addrType, addrs = addrs}) end else NONE in fun getByAddr in_addr = get (Prim.getByAddress (in_addr, C_Socklen.fromInt (Vector.length in_addr))) fun getByName name = get (Prim.getByName (NullString.nullTerm name)) end fun getHostName () = let val n = 128 val buf = CharArray.array (n, #"\000") val () = Posix.Error.SysCall.simple (fn () => Prim.getHostName (CharArray.toPoly buf, C_Size.fromInt n)) in case CharArray.findi (fn (_, c) => c = #"\000") buf of NONE => CharArray.vector buf | SOME (i, _) => CharArraySlice.vector (CharArraySlice.slice (buf, 0, SOME i)) end fun scan reader state = let fun scanW state = case reader state of SOME (#"0", state') => (case reader state' of NONE => SOME (0w0, state') | SOME (c, state'') => if Char.isDigit c then StringCvt.wdigits StringCvt.OCT reader state' else if c = #"x" orelse c = #"X" then StringCvt.wdigits StringCvt.HEX reader state'' else SOME (0w0, state')) | _ => StringCvt.wdigits StringCvt.DEC reader state fun loop (n, state, acc) = if n <= 0 then List.rev acc else let fun finish (w, state) = case reader state of SOME (#".", state') => loop (n - 1, state', (w, state)::acc) | _ => List.rev ((w, state)::acc) in case scanW state of SOME (w, state') => finish (w, state') | NONE => List.rev acc end val l = loop (4, state, []) fun get1 w = (Word8.fromLarge (Word.toLarge (Word.andb (w, 0wxFF))), Word.>>(w, 0w8)) fun get2 w = let val (a,w) = get1 w val (b,w) = get1 w in (a,b,w) end fun get3 w = let val (a,b,w) = get2 w val (c,w) = get1 w in (a,b,c,w) end fun get4 w = let val (a,b,c,w) = get3 w val (d,w) = get1 w in (a,b,c,d,w) end fun try l = case l of [] => NONE | [(w, statew)] => let val (d,c,b,a,w) = get4 w in if w = 0wx0 then SOME (Vector.fromList [a,b,c,d], statew) else NONE end | [(x, statex), (w, statew)] => let val (d,c,b,w) = get3 w val (a,x) = get1 x in if w = 0wx0 andalso x = 0wx0 then SOME (Vector.fromList [a,b,c,d], statew) else try [(x, statex)] end | [(y, statey), (x, statex), (w, statew)] => let val (d,c,w) = get2 w val (b,x) = get1 x val (a,y) = get1 y in if w = 0wx0 andalso x = 0wx0 andalso y = 0wx0 then SOME (Vector.fromList [a,b,c,d], statew) else try [(y, statey), (x, statex)] end | [(z, statez), (y, statey), (x, statex), (w, statew)] => let val (d,w) = get1 w val (c,x) = get1 x val (b,y) = get1 y val (a,z) = get1 z in if w = 0wx0 andalso x = 0wx0 andalso y = 0wx0 andalso z = 0wx0 then SOME (Vector.fromList [a,b,c,d], statew) else try [(z, statez), (y, statey), (x, statex)] end | _ => NONE in try l end fun fromString s = StringCvt.scanString scan s fun toString in_addr = String.concatWith "." (Vector.foldr (fn (w,ss) => (Word8.fmt StringCvt.DEC w)::ss) [] in_addr) end