<commit_before>;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; indent-tabs-mode: nil -*-
;;;
;;; --- IP address classes and main methods.
;;;

(in-package :net.sockets)

;;;; Class Definitions

(defclass address ()
  ((name :initarg :name :reader address-name :type vector))
  (:documentation "Base class for all socket address classes."))

(defclass inet-address (address) ()
  (:documentation "Base class for IPv4 and IPv6 addresses."))

(defclass ipv4-address (inet-address) ()
  (:documentation "IPv4 address.  Its low-level representation
can be accessed as vector of type IPV4-ARRAY through the
ADDRESS-NAME reader."))

(defclass ipv6-address (inet-address) ()
  (:documentation "IPv6 address.  Its low-level representation
can be accessed as vector of type IPV6-ARRAY through the
ADDRESS-NAME reader."))

(defclass local-address (address)
  ((abstract :initform nil :initarg :abstract
             :reader abstract-address-p :type boolean))
  (:documentation "UNIX socket address."))
(unset-method-docstring #'abstract-address-p () '(local-address))
(set-function-docstring 'abstract-address-p "Return T if ADDRESS is a LOCAL-ADDRESS that lives in the abstract namespace.")

(defmethod make-load-form ((address inet-address) &optional env)
  (declare (ignore env))
  `(make-instance ,(class-of address)
                  :name ,(address-name address)))

(defmethod make-load-form ((address local-address) &optional env)
  (declare (ignore env))
  `(make-instance ,(class-of address)
                  :name ,(address-name address)
                  :abstract ,(abstract-address-p address)))

;;;; Conversion functions for SOCKADDR_* structs

(defun sockaddr-in->sockaddr (sin)
  (with-foreign-slots ((addr port) sin sockaddr-in)
    (values (make-instance 'ipv4-address
                           :name (integer-to-vector (ntohl addr)))
            (ntohs port))))

(defun sockaddr-in6->sockaddr (sin6)
  (with-foreign-slots ((addr port) sin6 sockaddr-in6)
    (values (make-instance 'ipv6-address
                           :name (in6-addr-to-ipv6-array addr))
            (ntohs port))))

(defun sockaddr-un->sockaddr (sun)
  (with-foreign-slots ((path) sun sockaddr-un)
    (let ((name (make-string (1- unix-path-max)))
          (abstract nil))
      (cond ((zerop (mem-aref path :uint8 0))
             ;; abstract address
             (setf abstract t)
             (loop :for sindex :from 0 :below (1- unix-path-max)
                   :for pindex :from 1 :below unix-path-max
                   :do (setf (schar name sindex)
                             (code-char (mem-aref path :uint8 pindex)))))
            (t
             ;; address is in the filesystem
             (setf name (foreign-string-to-lisp path))))
      (make-instance 'local-address
                     :name name
                     :abstract abstract))))

(defun sockaddr-storage->sockaddr (ss)
  (with-foreign-slots ((family) ss sockaddr-storage)
    (switch (family :test #'=)
      (af-inet (sockaddr-in->sockaddr ss))
      (af-inet6 (sockaddr-in6->sockaddr ss))
      (af-local (sockaddr-un->sockaddr ss)))))

(defun sockaddr->sockaddr-storage (ss sockaddr &optional (port 0))
  (etypecase sockaddr
    (ipv4-address (make-sockaddr-in ss (address-name sockaddr) port))
    (ipv6-address (make-sockaddr-in6 ss (address-name sockaddr) port))
    (local-address (make-sockaddr-un ss (address-name sockaddr)))))

(defun sockaddr-size (ss)
  (with-foreign-slots ((family) ss sockaddr-storage)
    (switch (family :test #'=)
      (af-inet  size-of-sockaddr-in)
      (af-inet6 size-of-sockaddr-in6)
      (af-local size-of-sockaddr-un))))

;;;; Conversion functions

(defun integer-to-dotted (integer)
  "Convert a 32-bit unsigned integer to a dotted string."<commit_msg>Clearer SOCKADDR-UN->SOCKADDR.<commit_after>;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; indent-tabs-mode: nil -*-
;;;
;;; --- IP address classes and main methods.
;;;

(in-package :net.sockets)

;;;; Class Definitions

(defclass address ()
  ((name :initarg :name :reader address-name :type vector))
  (:documentation "Base class for all socket address classes."))

(defclass inet-address (address) ()
  (:documentation "Base class for IPv4 and IPv6 addresses."))

(defclass ipv4-address (inet-address) ()
  (:documentation "IPv4 address.  Its low-level representation
can be accessed as vector of type IPV4-ARRAY through the
ADDRESS-NAME reader."))

(defclass ipv6-address (inet-address) ()
  (:documentation "IPv6 address.  Its low-level representation
can be accessed as vector of type IPV6-ARRAY through the
ADDRESS-NAME reader."))

(defclass local-address (address)
  ((abstract :initform nil :initarg :abstract
             :reader abstract-address-p :type boolean))
  (:documentation "UNIX socket address."))
(unset-method-docstring #'abstract-address-p () '(local-address))
(set-function-docstring 'abstract-address-p "Return T if ADDRESS is a LOCAL-ADDRESS that lives in the abstract namespace.")

(defmethod make-load-form ((address inet-address) &optional env)
  (declare (ignore env))
  `(make-instance ,(class-of address)
                  :name ,(address-name address)))

(defmethod make-load-form ((address local-address) &optional env)
  (declare (ignore env))
  `(make-instance ,(class-of address)
                  :name ,(address-name address)
                  :abstract ,(abstract-address-p address)))

;;;; Conversion functions for SOCKADDR_* structs

(defun sockaddr-in->sockaddr (sin)
  (with-foreign-slots ((addr port) sin sockaddr-in)
    (values (make-instance 'ipv4-address
                           :name (integer-to-vector (ntohl addr)))
            (ntohs port))))

(defun sockaddr-in6->sockaddr (sin6)
  (with-foreign-slots ((addr port) sin6 sockaddr-in6)
    (values (make-instance 'ipv6-address
                           :name (in6-addr-to-ipv6-array addr))
            (ntohs port))))

(defun parse-abstract-un-path (path)
  (let ((name (make-string (1- unix-path-max) :element-type 'base-char)))
    (dotimes (i (1- unix-path-max))
      (setf (schar name i) (code-char (mem-aref path :uint8 i))))
    (values name t)))

(defun parse-concrete-un-path (path)
  (values (foreign-string-to-lisp path) nil))

(defun sockaddr-un->sockaddr (sun)
  (with-foreign-slots ((path) sun sockaddr-un)
    (multiple-value-bind (name abstract)
        (if (zerop (mem-aref path :uint8 0))
            (parse-abstract-un-path (inc-pointer path 1))
            (parse-concrete-un-path path))
      (make-instance 'local-address :name name :abstract abstract))))

(defun sockaddr-storage->sockaddr (ss)
  (with-foreign-slots ((family) ss sockaddr-storage)
    (switch (family :test #'=)
      (af-inet (sockaddr-in->sockaddr ss))
      (af-inet6 (sockaddr-in6->sockaddr ss))
      (af-local (sockaddr-un->sockaddr ss)))))

(defun sockaddr->sockaddr-storage (ss sockaddr &optional (port 0))
  (etypecase sockaddr
    (ipv4-address (make-sockaddr-in ss (address-name sockaddr) port))
    (ipv6-address (make-sockaddr-in6 ss (address-name sockaddr) port))
    (local-address (make-sockaddr-un ss (address-name sockaddr)))))

(defun sockaddr-size (ss)
  (with-foreign-slots ((family) ss sockaddr-storage)
    (switch (family :test #'=)
      (af-inet  size-of-sockaddr-in)
      (af-inet6 size-of-sockaddr-in6)
      (af-local size-of-sockaddr-un))))

;;;; Conversion functions

(defun integer-to-dotted (integer)
  "Convert a 32-bit unsigned integer to a dotted string."
{'fraction_non_alphanumeric': 0.1434134550825836, 'fraction_numerical': 0.008728346985363233, 'mean_word_length': 3.0923076923076924, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 20, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4406337', 'n_tokens_mistral': 2444, 'n_tokens_neox': 2374, 'n_words': 660}