cl-rw

Layered streams for Common Lisp
git clone https://logand.com/git/cl-rw.git/
Log | Files | Refs

net.lisp (5593B)


      1 ;;; Copyright (C) 2013, 2014 Tomas Hlavaty <tom@logand.com>
      2 ;;;
      3 ;;; Permission is hereby granted, free of charge, to any person
      4 ;;; obtaining a copy of this software and associated documentation
      5 ;;; files (the "Software"), to deal in the Software without
      6 ;;; restriction, including without limitation the rights to use, copy,
      7 ;;; modify, merge, publish, distribute, sublicense, and/or sell copies
      8 ;;; of the Software, and to permit persons to whom the Software is
      9 ;;; furnished to do so, subject to the following conditions:
     10 ;;;
     11 ;;; The above copyright notice and this permission notice shall be
     12 ;;; included in all copies or substantial portions of the Software.
     13 ;;;
     14 ;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     15 ;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     16 ;;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     17 ;;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
     18 ;;; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     19 ;;; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     20 ;;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     21 ;;; DEALINGS IN THE SOFTWARE.
     22 
     23 (defpackage :rw.net
     24   (:use :cl)
     25   (:export :curl
     26            :download-rss
     27            :make-openssl-client
     28            :make-gnutls-client
     29            :wget))
     30 
     31 (in-package :rw.net)
     32 
     33 (defun network-interfaces ()
     34   #-linux
     35   (error "TODO rw.net::network-interfaces not ported")
     36   #+linux
     37   (sort (loop
     38            for d in (directory "/sys/class/net/*.*")
     39            collect (let ((x (pathname-directory d)))
     40                      (ecase (car x)
     41                        (:absolute (car (last x))))))
     42         #'string<))
     43 
     44 ;;(network-interfaces)
     45 
     46 (defun virtual-network-interface-p (name)
     47   #-linux
     48   (error "TODO rw.net::virtual-network-interface-p not ported")
     49   #+linux
     50   (let ((d (directory (merge-pathnames name "/sys/class/net/"))))
     51     (assert d)
     52     (assert (not (cdr d)))
     53     (let ((x (pathname-directory (car d))))
     54       (ecase (car x)
     55         (:absolute (and (find "virtual" x :test #'equal) t))))))
     56 
     57 ;;(virtual-network-interface-p "enp4s0f0")
     58 ;;(virtual-network-interface-p "tun0")
     59 
     60 (defun wget (url &key request-file response-file content-type)
     61   (rw.os:run-command
     62    "wget"
     63    `("-q"
     64      ,@ (when request-file
     65           `("--post-file" ,(namestring request-file)))
     66      ,@ (when response-file
     67           `("-O" ,(namestring response-file)))
     68      ,@ (when content-type
     69           `("--header" ,(format nil "Content-Type:~a" content-type)))
     70      ,url)
     71    '((1 . "Generic panic code")
     72      (2 . "Parse panic")
     73      (3 . "File I/O panic")
     74      (4 . "Network failure")
     75      (5 . "SSL verification failure")
     76      (6 . "Username/password authentication failure")
     77      (7 . "Protocol panics")
     78      (8 . "Server issued an panic response"))))
     79 
     80 ;;(wget "http://localhost:631/printers/" :response-file "/tmp/a.html")
     81 ;;(rw.xml:parse-xml #p"/tmp/a.html")
     82 
     83 (defun curl (url &key request-file response-file content-type)
     84   (rw.os:run-command
     85    "curl"
     86    `("-s"
     87      ,@ (when request-file
     88           `("--data-binary" ,(format nil "@~a" request-file)))
     89      ,@ (when response-file
     90           `("-o" ,response-file))
     91      ,@ (when content-type
     92           `("-H" ,(format nil "Content-Type:~a" content-type)))
     93      ,url)))
     94 
     95 ;;(curl "http://localhost:631/printers/" :response-file "/tmp/printers.html")
     96 ;;(curl "http://localhost:631/jobs/82" :response-file "/tmp/job-status.html")
     97 
     98 (defun download-rss (url)
     99   (let ((body (nth-value 4 (rw.http:client url))))
    100     (when body
    101       (let ((rss (rw.xml:parse-xml body))) ;; TODO parse directly from socket/stream?
    102         (when rss
    103           (assert (eq :rss (if (atom rss) (car rss) (caar rss))))
    104           rss)))))
    105 
    106 ;;(download-rss "http://www.spiegel.de/international/index.rss")
    107 (defun make-openssl-client (host port &key starttls)
    108   (rw.os:make-program :stream :stream "openssl"
    109                       `("s_client"
    110                         "-quiet"
    111                         "-verify_return_error"
    112                         "-no_ssl2" "-no_ssl3" "-no_tls1" "-no_tls1_1"
    113                         "-connect" ,(format nil "~a:~d" host port)
    114                         ,@ (ecase starttls
    115                              ((nil))
    116                              #+nil ;; TODO starttls
    117                              ((:smtp :pop3 :imap :ftp :xmpp)
    118                               `("-starttls" ,(string-downcase starttls)))))
    119                       nil))
    120 
    121 #+nil
    122 (rw.os:with-program-io (i o (make-openssl-client "wikipedia.org" 443))
    123   (write-string "GET / HTTP/1.0" i)
    124   (write-char #\return i)
    125   (write-char #\linefeed i)
    126   (write-char #\return i)
    127   (write-char #\linefeed i)
    128   (finish-output i)
    129   (rw:till (rw:peek-reader (rw:char-reader o))))
    130 
    131 (defun make-gnutls-client (host port &key starttls) ;; TODO remove junk output
    132   (rw.os:make-program :stream :stream "gnutls-cli"
    133                       `("--crlf"
    134                         "-p" ,(format nil "~d" port) ,host
    135                         ,@ (ecase starttls
    136                              ((nil))
    137                              #+nil ;; TODO starttls
    138                              ((:smtp :pop3 :imap :ftp #+nil :xmpp)
    139                               `("-starttls"
    140                                 ,(format nil "-~(~a~)" starttls)))))
    141                       nil))
    142 
    143 ;;- Simple Client Mode:
    144 #+nil
    145 (rw.os:with-program-io (i o (make-gnutls-client "wikipedia.org" 443))
    146   (write-string "GET / HTTP/1.0" i)
    147   (write-char #\return i)
    148   (write-char #\linefeed i)
    149   (write-char #\return i)
    150   (write-char #\linefeed i)
    151   (finish-output i)
    152   (rw:till (rw:peek-reader (rw:char-reader o))))