Как использовать Clozure CL только в сети IPv6?

Я пытался заменить SBCL на Clozure CL при работе только в сети IPv6, но обнаружил такую ​​ошибку:

MIGRATIONS> (ignore-errors (ccl:make-socket :remote-host "ya.ru" :remote-port 443))
NIL
#<CCL:NO-APPLICABLE-METHOD-EXISTS #x302005215E5D>
MIGRATIONS> (ignore-errors (ccl:make-socket :remote-host "ya.ru" :remote-port 443 :address-family :internet))
NIL
#<CCL:NO-APPLICABLE-METHOD-EXISTS #x3020052549AD>
MIGRATIONS> (ignore-errors (ccl:make-socket :remote-host "ya.ru" :remote-port 443 :address-family :internet6))
#<BASIC-TCP-STREAM ISO-8859-1 (SOCKET/16) #x3020051D4A9D>

Проблема в том, что многие библиотеки при использовании CCL:MAKE-TCP-SOCKET не указывайте адрес-семью или не указывайте :internet,

Есть ли способ патча ccl:make-socket во время выполнения переопределить этот параметр?

2 ответа

Посоветуйте функцию

Несколько реализаций Common Lisp позволяют рекомендовать (-> исправление) нормальных функций. Консультирование - это нестандартная функция, и различные реализации предоставляют ее немного по-разному. Связанный механизм стандартизирован для универсальных функций CLOS с методами:before,:after и:around.

Цель состоит в том, чтобы добавить один или несколько исправлений к функции после ее определения и без изменения исходного исходного кода.

Обычно для этого требуется, чтобы вызов функции для этой функции не был встроенным.

Макрос ADVISE в Clozure Common Lisp

Функции исправления в Clozure CL можно выполнить с помощью макроса ADVISE, Смотрите документацию для консультирования.

Допустим, у нас есть функция FOOBAR:

? (defun foobar (a b &key c (d :foobar)) (list a b c d))
FOOBAR

FOOBAR вызывается внутри TEST:

? (defun test (a) (foobar a 20 :c 30))
TEST

? (test 10)
(10 20 30 :FOOBAR)

Теперь мы хотим патч FOOBAR такой, что назвал арг :D вызывается с другим значением.

Мы изменяем arglist для вставки нового именованного аргумента после двух обязательных аргументов:

? (advise foobar (let ((arglist (list* (first arglist)
                                       (second arglist)
                                       :d :ipv6
                                       (cddr arglist))))
                   (:do-it))   ; calling the original function
          :when :around     ; advise around it
          :name :ipv6)      ; the name of this advise
#<Compiled-function (CCL::ADVISED 'FOOBAR) (Non-Global)  #x3020010D1CCF>

Теперь мы можем позвонить нашим TEST функция, и она будет вызывать рекомендованную функцию FOOBAR,

? (test 10)
(10 20 30 :IPV6)

Посоветуйте для CCL:MAKE-SOCKET

Вы могли бы написать аналогичный совет для CCL:MAKE-SOCKET,

Непроверенные:

(advise ccl:make-socket (let ((arglist (list* :address-family
                                              :internet6
                                              arglist)))
                          (:do-it))
        :when :around
        :name :internet6)

Это можно сделать!

Сначала сделайте копию оригинальной розетки

(IN-PACKAGE :ccl)
(DEFPARAMETER original-make-socket #'make-socket)

Затем переопределите make-socket. Примечание. Вам нужно будет предоставить полную спецификацию для всех параметров ключевых слов. На самом деле, я использовал только те из вашего вопроса для демонстрации.

(defun make-socket (&key (remote-host "defau.lt") 
                         (remote-port 443) 
                         (address-family :internet6))
  (declare (ignore address-family))
  (format t "Calling new make-socket with address-family as internet6!")
  (funcall original-make-socket 
           :remote-host remote-host 
           :remote-port remote-port 
           :address-family :internet6))

Это будет сигнализировать о постоянной ошибке.

Тип :go в ответ, чтобы продолжить. Это успешно исправит make-socket.

Теперь любые вызовы make-socket будут соответствовать новому определению. Пытаться:

(IN-PACKAGE :cl-user)
(ccl:make-socket :remote-host "ya.ru" :remote-port 443 :address-family :IRRELEVANT)

Другой способ сделать это - переопределить глобальную переменную. *warn-if-redefine-kernel* перед переопределением make-socket.

(setf *warn-if-redefine-kernel* nil)

Это позволит избежать продолжительного сигнала об ошибке и исправить патч функции ядра.

Другие вопросы по тегам