regarding non-existent packages in #+ and #- feature tests.
* new feature: command line options --no-sysinit, --no-userinit to
inhibit loading the corresponding init files
+ * new feature: add a generic function SOCKET-SEND to SB-BSD-SOCKETS,
+ for sending data through UDP sockets (thanks to François-René Rideau)
* minor incompatible change: SIGPIPE is ignored and "Broken pipe"
error is signalled instead (thanks to François-René Rideau)
* bug fix: LISTEN sometimes returned T even in cases where no data was
(:integer msg-peek "MSG_PEEK")
(:integer msg-trunc "MSG_TRUNC")
(:integer msg-waitall "MSG_WAITALL")
+ (:integer msg-eor "MSG_EOR")
+ (:integer msg-dontroute "MSG_DONTROUTE")
+ (:integer msg-dontwait "MSG_DONTWAIT")
+ (:integer msg-nosignal "MSG_NOSIGNAL")
+#+linux (:integer msg-confirm "MSG_CONFIRM")
+#+linux (:integer msg-more "MSG_MORE")
;; for socket-receive
(:type socklen-t "socklen_t")
+ (:type size-t "size_t")
+ (:type ssize-t "ssize_t")
#|
;;; stat is nothing to do with sockets, but I keep it around for testing
(integer proto "int" "p_proto")))
(:function getprotobyname ("getprotobyname" (* protoent)
(name c-string)))
+ (:function getprotobynumber ("getprotobynumber" (* protoent)
+ (proto int)))
(:integer inaddr-any "INADDR_ANY")
(:structure in-addr ("struct in_addr"
((array (unsigned 8)) addr "u_int32_t" "s_addr")))
(integer type "int" "h_addrtype")
(integer length "int" "h_length")
((* (* (unsigned 8))) addresses "char **" "h_addr_list")))
+ (:structure msghdr ("struct msghdr"
+ (c-string-pointer name "void *" "msg_name")
+ (integer namelen "socklen_t" "msg_namelen")
+ ((* t) iov "struct iovec" "msg_iov")
+ (integer iovlen "size_t" "msg_iovlen")
+ ((* t) control "void *" "msg_control")
+ (integer controllen "socklen_t" "msg_controllen")
+ (integer flags "int" "msg_flags")))
(:function socket ("socket" int
(domain int)
(type int)
(:function bind ("bind" int
(sockfd int)
(my-addr (* t)) ; KLUDGE: sockaddr-in or sockaddr-un?
- (addrlen int)))
+ (addrlen socklen-t)))
(:function listen ("listen" int
(socket int)
(backlog int)))
(:function accept ("accept" int
(socket int)
(my-addr (* t)) ; KLUDGE: sockaddr-in or sockaddr-un?
- (addrlen int :in-out)))
+ (addrlen socklen-t :in-out)))
(:function getpeername ("getpeername" int
(socket int)
(her-addr (* t)) ; KLUDGE: sockaddr-in or sockaddr-un?
- (addrlen int :in-out)))
+ (addrlen socklen-t :in-out)))
(:function getsockname ("getsockname" int
(socket int)
(my-addr (* t)) ; KLUDGE: sockaddr-in or sockaddr-un?
- (addrlen int :in-out)))
+ (addrlen socklen-t :in-out)))
(:function connect ("connect" int
(socket int)
(his-addr (* t)) ; KLUDGE: sockaddr-in or sockaddr-un?
- (addrlen int )))
-
+ (addrlen socklen-t)))
(:function close ("close" int
(fd int)))
- (:function recvfrom ("recvfrom" int
+ (:function recvfrom ("recvfrom" ssize-t
(socket int)
(buf (* t))
(len integer)
(flags int)
(sockaddr (* t)) ; KLUDGE: sockaddr-in or sockaddr-un?
(socklen (* socklen-t))))
+ (:function recvmsg ("recvmsg" ssize-t
+ (socket int)
+ (msg (* msghdr))
+ (flags int)))
+ (:function send ("send" ssize-t
+ (socket int)
+ (buf (* t))
+ (len size-t)
+ (flags int)))
+ (:function sendto ("sendto" int
+ (socket int)
+ (buf (* t))
+ (len size-t)
+ (flags int)
+ (sockaddr (* t)) ; KLUDGE: sockaddr-in or sockaddr-un?
+ (socklen socklen-t)))
+ (:function sendmsg ("sendmsg" int
+ (socket int)
+ (msg (* msghdr))
+ (flags int)))
(:function gethostbyname ("gethostbyname" (* hostent) (name c-string)))
(:function gethostbyaddr ("gethostbyaddr" (* hostent)
(addr (* t))
(len int)
(af int)))
+;;; should be using getaddrinfo instead?
(:function setsockopt ("setsockopt" int
(socket int)
(level int)
(optname int)
(optval (* t))
- (optlen int)))
+ (optlen int))) ;;; should be socklen-t!
(:function fcntl ("fcntl" int
(fd int)
(cmd int)
(level int)
(optname int)
(optval (* t))
- (optlen (* int)))))
+ (optlen (* int))))) ;;; should be socklen-t!
)
@include fun-sb-bsd-sockets-socket-receive.texinfo
+@include fun-sb-bsd-sockets-socket-send.texinfo
+
@include fun-sb-bsd-sockets-socket-listen.texinfo
@include fun-sb-bsd-sockets-socket-open-p.texinfo
(bits-of-sockaddr socket sockaddr)))))))
(sb-alien:free-alien copy-buffer))))))
+(defmacro with-vector-sap ((name vector) &body body)
+ `(sb-sys:with-pinned-objects (,vector)
+ (let ((,name (sb-sys:vector-sap ,vector)))
+ ,@body)))
+
+(defgeneric socket-send (socket buffer length
+ &key
+ address
+ external-format
+ oob eor dontroute dontwait nosignal
+ #+linux confirm #+linux more)
+ (:documentation
+ "Send LENGTH octets from BUFFER into SOCKET, using sendto(2). If BUFFER
+is a string, it will converted to octets according to EXTERNAL-FORMAT. If
+LENGTH is NIL, the length of the octet buffer is used. The format of ADDRESS
+depends on the socket type (for example for INET domain sockets it would
+be a list of an IP address and a port). If no socket address is provided,
+send(2) will be called instead. Returns the number of octets written."))
+
+(defmethod socket-send ((socket socket) buffer length
+ &key
+ address
+ (external-format :default)
+ oob eor dontroute dontwait nosignal
+ #+linux confirm #+linux more)
+ (let* ((flags
+ (logior (if oob sockint::MSG-OOB 0)
+ (if eor sockint::MSG-EOR 0)
+ (if dontroute sockint::MSG-DONTROUTE 0)
+ (if dontwait sockint::MSG-DONTWAIT 0)
+ (if nosignal sockint::MSG-NOSIGNAL 0)
+ #+linux (if confirm sockint::MSG-CONFIRM 0)
+ #+linux (if more sockint::MSG-MORE 0)))
+ (buffer (etypecase buffer
+ (string
+ (sb-ext:string-to-octets buffer
+ :external-format external-format
+ :null-terminate nil))
+ ((simple-array (unsigned-byte 8))
+ buffer)
+ ((array (unsigned-byte 8))
+ (make-array (length buffer)
+ :element-type '(unsigned-byte 8)
+ :initial-contents buffer))))
+ (len (with-vector-sap (buffer-sap buffer)
+ (unless length
+ (setf length (length buffer)))
+ (if address
+ (with-sockaddr-for (socket sockaddr address)
+ (sb-alien:with-alien ((sa-len sockint::socklen-t
+ (size-of-sockaddr socket)))
+ (sockint::sendto (socket-file-descriptor socket)
+ buffer-sap
+ length
+ flags
+ sockaddr
+ sa-len)))
+ (sockint::send (socket-file-descriptor socket)
+ buffer-sap
+ length
+ flags)))))
+ (cond
+ ((and (= len -1)
+ (member (sb-unix::get-errno)
+ '(sockint::EAGAIN sockint::EINTR)))
+ nil)
+ ((= len -1)
+ (socket-error "sendto"))
+ (t len))))
+
(defgeneric socket-listen (socket backlog)
(:documentation "Mark SOCKET as willing to accept incoming connections. BACKLOG
defines the maximum length that the queue of pending connections may
;;; checkins which aren't released. (And occasionally for internal
;;; versions, especially for internal versions off the main CVS
;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
-"0.9.11.33"
+"0.9.11.34"