Как использовать 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 во время выполнения, чтобы переопределить этот параметр?


person Alexander Artemenko    schedule 04.09.2017    source источник


Ответы (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 вызывался с другим значением.

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

? (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)
person Rainer Joswig    schedule 08.09.2017

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

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

(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)

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

person Capstone    schedule 07.09.2017