1    Introduction

1.1    Overview

std.lib.network is part of the standard foundation library set. This page collects the public API reference for the namespace.

2    Walkthrough

2.1    Local host information

std.lib.network returns information about the local machine: host address, IP, and hostname.

query local host details

^{:refer std.lib.network/local-host :added "3.0"}
(local-host)
=> java.net.Inet4Address

^{:refer std.lib.network/local-ip :added "3.0"}
(local-ip)
=> string?

^{:refer std.lib.network/local-hostname :added "3.0"}
(local-hostname)
=> string?

2.2    Port availability

port:check-available, port:get-available, and wait-for-port help allocate and synchronise ports.

check and find available ports

^{:refer std.lib.network/port:check-available :added "4.0"}
(port:check-available 51311)
=> anything

^{:refer std.lib.network/port:get-available :added "4.0"}
(port:get-available [51312 51313])
=> number?

3    API



ip-score ^

[ip]

NONE
(defn- ip-score
  [^String ip]
  (cond (clojure.string/starts-with? ip "192.168.") 0
        (clojure.string/starts-with? ip "10.")      1
        (and (clojure.string/starts-with? ip "172.")
             (let [n (try (Integer/parseInt (second (clojure.string/split ip #"\.") 0))
                          (catch Throwable _ 0))]
               (<= 16 n 31)))                        2
        :else                                        3))
link

local-host ^

[]
Added 3.0

returns the current host

v 3.0
(defn ^java.net.Inet4Address local-host
  ([]
   (java.net.InetAddress/getLocalHost)))
link
(local-host) ;; #object[java.net.Inet4Address 0x4523dee "chapterhouse.base.local/127.0.0.1"] => java.net.Inet4Address

local-hostname ^

[]
Added 3.0

returns the current host name

v 3.0
(defn local-hostname
  ([]
   (.getHostName (local-host))))
link
(local-hostname) ;; "chapterhouse.base.local" => string?

local-ip ^

[]
Added 3.0

returns the current ip

v 3.0
(defn local-ip
  ([]
   (.getHostAddress (local-host))))
link
(local-ip) ;; "127.0.0.1" => string?

local-ip-lan ^

[]
Added 4.0

returns a non-loopback lan ip

v 4.0
(defn local-ip-lan
  []
  (->> (NetworkInterface/getNetworkInterfaces)
       (enumeration-seq)
       (filter (fn [^NetworkInterface ni]
                 (and (.isUp ni)
                      (not (.isLoopback ni))
                      (not (.isPointToPoint ni)))))
       (mapcat (fn [^NetworkInterface ni]
                 (enumeration-seq (.getInetAddresses ni))))
       (filter (fn [^InetAddress addr]
                 (and (instance? java.net.Inet4Address addr)
                      (not (.isLoopbackAddress addr))
                      (not (.isLinkLocalAddress addr)))))
       (map #(.getHostAddress ^InetAddress %))
       (sort-by ip-score)
       first))
link
(local-ip-lan) => (any nil? string?)

local-shortname ^

[]
Added 3.0

returns the current host short name

v 3.0
(defn local-shortname
  ([]
   (-> (local-hostname)
       (clojure.string/split #"\.")
       first)))
link
(local-shortname) ;; "chapterhouse" => string?

port:check-available ^

[port]
Added 4.0

check that port is available

v 4.0
(defn port:check-available
  ([port]
   (try
     (with-open [^ServerSocket s (ServerSocket. port)]
       (.setReuseAddress s true)
       (.getLocalPort s))
     (catch Throwable t
       false))))
link
(port:check-available 51311) => anything

port:get-available ^

[ports]
Added 4.0

get first available port from a range

v 4.0
(defn port:get-available
  ([ports]
   (reduce (fn [_ i]
             (if (port:check-available i) (reduced i)))
           nil ports)))
link
(port:get-available [51312 51313]) => number?

socket ^

[port] [host port]
Added 3.0

creates a new socket

v 3.0
(defn ^Socket socket
  ([^long port]
   (socket nil port))
  ([^String host ^long port]
   (Socket. (or host "localhost") port)))
link
(h/suppress (with-open [s ^java.net.Socket (socket 51311)] s)) => (any nil? java.net.Socket)

socket:address ^

[socket]
Added 3.0

gets the remote socket address

v 3.0
(defn socket:address
  ([^Socket socket]
   (str (.getInetAddress socket))))
link
(with-open [s (java.net.ServerSocket. 0)] (with-open [c (socket (.getLocalPort s))] (socket:address c))) => "localhost/127.0.0.1"

socket:local-address ^

[socket]
Added 3.0

getst the local socket address

v 3.0
(defn socket:local-address
  ([^Socket socket]
   (str (.getLocalAddress socket))))
link
(with-open [s (java.net.ServerSocket. 0)] (with-open [c (socket (.getLocalPort s))] (socket:local-address c))) => "/127.0.0.1"

socket:local-port ^

[socket]
Added 3.0

gets the local socket port

v 3.0
(defn socket:local-port
  ([^Socket socket]
   (.getLocalPort socket)))
link
(with-open [s (java.net.ServerSocket. 0)] (with-open [c (socket (.getLocalPort s))] (socket:local-port c))) => number?

socket:port ^

[socket]
Added 3.0

gets the remote socket port

v 3.0
(defn socket:port
  ([^Socket socket]
   (.getPort socket)))
link
(with-open [s (java.net.ServerSocket. 0)] (with-open [c (socket (.getLocalPort s))] (socket:port c))) => number?

wait-for-port ^

[host port] [host port {:keys [timeout pause], :as opts}]
Added 3.0

waits for a port to be ready

v 3.0
(defn wait-for-port
  ([host port]
   (wait-for-port host port {}))
  ([host port {:keys [timeout pause] :as opts}]
   (let [t0 (time/time-ms)]
     (loop [retries 0]
       (let [[retry? timeout?]
             (try (env/close (socket host port))
                  [false false]
                  (catch ConnectException _
                    (if (or (nil? timeout)
                            (< (time/elapsed-ms t0) timeout))
                      [true false]
                      [false true])))]
         (cond retry?
               (do (Thread/sleep (long (or pause 100)))
                   (recur (inc retries)))

               :else
               (let [data {:host host
                           :port port
                           :elapsed (time/elapsed-ms t0)
                           :retries retries}]
                 (if timeout?
                   (throw (ex-info "Timed out" data))
                   data))))))))
link
(wait-for-port "localhost" 51313 {:timeout 1000}) => (throws)

4    std.lib.network: A Comprehensive Summary

The std.lib.network namespace provides a collection of utility functions for network-related operations in Clojure, primarily focusing on local host information, socket management, and port availability checks. It leverages Java's java.net package to offer convenient wrappers for common networking tasks.

Key Features and Concepts:

  1. Local Host Information:n local-host: Returns the java.net.Inet4Address object representing the local host.n local-ip: Retrieves the IP address of the local host as a string.n local-hostname: Returns the full hostname of the local machine.n local-shortname: Extracts the short name (first part) of the local hostname.nn2. Socket Management:n socket: Creates a new java.net.Socket object, allowing connection to a specified host and port.n socket:port: Gets the remote port number of a connected socket.n socket:local-port: Gets the local port number of a connected socket.n socket:address: Returns the remote IP address of a connected socket.n socket:local-address: Returns the local IP address of a connected socket.nn3. Port Availability and Waiting:n port:check-available: Checks if a given port is available for use by attempting to bind a ServerSocket to it.n port:get-available: Finds the first available port from a provided list of ports.n wait-for-port: Blocks execution until a specified port on a given host becomes available, with configurable timeout and pause intervals. This is useful for synchronizing services during startup or testing.nn4. Component Protocol Integration:n * The java.net.Socket class is extended to implement the std.protocol.component/IComponent and std.protocol.component/IComponentQuery protocols. This allows Socket objects to be managed as components within the foundation-base ecosystem, enabling standardized lifecycle management (-start, -stop, -kill) and status querying (-started?, -stopped?, -remote?).

Usage and Importance:

std.lib.network is a vital module for any application within the foundation-base project that needs to interact with network resources. It simplifies common networking tasks, from identifying local machine details to managing socket connections and ensuring port availability. The integration with the std.protocol.component allows network resources to be treated as first-class components, promoting a consistent and manageable approach to resource lifecycle within the larger system.