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