mirror of
https://github.com/ashinn/chibi-scheme.git
synced 2025-05-20 14:19:18 +02:00
Adding send and receive support, with an example of how to use them with udp.
This commit is contained in:
parent
d1eeea1a66
commit
c8f61c8893
5 changed files with 108 additions and 2 deletions
22
examples/echo-server-udp.scm
Executable file
22
examples/echo-server-udp.scm
Executable file
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/env chibi-scheme
|
||||
|
||||
(import (scheme base) (chibi net))
|
||||
|
||||
(define (get-udp-address-info host service)
|
||||
(let ((hints (make-address-info address-family/inet
|
||||
socket-type/datagram
|
||||
ip-proto/udp)))
|
||||
(get-address-info host service hints)))
|
||||
|
||||
;; create and bind a udp socket
|
||||
(let* ((addr (get-udp-address-info #f 5556))
|
||||
(sock (socket (address-info-family addr)
|
||||
(address-info-socket-type addr)
|
||||
(address-info-protocol addr))))
|
||||
(bind sock (address-info-address addr) (address-info-address-length addr))
|
||||
;; for every packet we receive, just send it back
|
||||
(let lp ()
|
||||
(cond
|
||||
((receive sock 512 0 addr)
|
||||
=> (lambda (bv) (send sock bv 0 addr))))
|
||||
(lp)))
|
|
@ -24,6 +24,44 @@ sexp sexp_accept (sexp ctx, sexp self, int sock, struct sockaddr* addr, socklen_
|
|||
return sexp_make_fileno(ctx, sexp_make_fixnum(res), SEXP_FALSE);
|
||||
}
|
||||
|
||||
/* likewise sendto and recvfrom should suspend the thread gracefully */
|
||||
|
||||
sexp sexp_sendto (sexp ctx, sexp self, int sock, const void* buffer, size_t len, int flags, struct sockaddr* addr, socklen_t addr_len) {
|
||||
#if SEXP_USE_GREEN_THREADS
|
||||
sexp f;
|
||||
#endif
|
||||
ssize_t res;
|
||||
res = sendto(sock, buffer, len, flags, addr, addr_len);
|
||||
#if SEXP_USE_GREEN_THREADS
|
||||
if (res < 0 && errno == EWOULDBLOCK) {
|
||||
f = sexp_global(ctx, SEXP_G_THREADS_BLOCKER);
|
||||
if (sexp_opcodep(f)) {
|
||||
((sexp_proc2)sexp_opcode_func(f))(ctx, f, 1, sexp_make_fixnum(sock));
|
||||
return sexp_global(ctx, SEXP_G_IO_BLOCK_ERROR);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return sexp_make_fixnum(res);
|
||||
}
|
||||
|
||||
sexp sexp_recvfrom (sexp ctx, sexp self, int sock, void* buffer, size_t len, int flags, struct sockaddr* addr, socklen_t addr_len) {
|
||||
#if SEXP_USE_GREEN_THREADS
|
||||
sexp f;
|
||||
#endif
|
||||
ssize_t res;
|
||||
res = recvfrom(sock, buffer, len, flags, addr, &addr_len);
|
||||
#if SEXP_USE_GREEN_THREADS
|
||||
if (res < 0 && errno == EWOULDBLOCK) {
|
||||
f = sexp_global(ctx, SEXP_G_THREADS_BLOCKER);
|
||||
if (sexp_opcodep(f)) {
|
||||
((sexp_proc2)sexp_opcode_func(f))(ctx, f, 1, sexp_make_fixnum(sock));
|
||||
return sexp_global(ctx, SEXP_G_IO_BLOCK_ERROR);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return sexp_make_fixnum(res);
|
||||
}
|
||||
|
||||
/* If we're listening on a socket from Scheme, we most likely want it */
|
||||
/* to be non-blocking. */
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
;; Copyright (c) 2010-2012 Alex Shinn. All rights reserved.
|
||||
;; BSD-style license: http://synthcode.com/license.txt
|
||||
|
||||
;;> \subsubsubsection{\scheme{(make-address-info family socktype proto [hints])}}
|
||||
;;> \procedure{(make-address-info family socktype proto [hints])}
|
||||
|
||||
(define (make-address-info family socktype proto . o)
|
||||
(%make-address-info family socktype proto (if (pair? o) (car o) 0)))
|
||||
|
||||
;;> \subsubsubsection{\scheme{(get-address-info host service [addrinfo])}}
|
||||
;;> \procedure{(get-address-info host service [addrinfo])}
|
||||
|
||||
;;> Create and return a new addrinfo structure for the given host
|
||||
;;> and service. \var{host} should be a string and \var{service} a
|
||||
|
@ -106,3 +106,38 @@
|
|||
(define (get-socket-option socket level name)
|
||||
(let ((res (getsockopt socket level name)))
|
||||
(and (pair? res) (car res))))
|
||||
|
||||
;;> Sends the bytevector \var{bv} to \var{socket} with sendto and
|
||||
;;> returns the number of bytes sent, or a negative value on error.
|
||||
;;> If \var{addrinfo} is unspecified, \var{socket} must previously
|
||||
;;> have had a default address specified with \scheme{connect}.
|
||||
|
||||
(define (send socket bv . o)
|
||||
(let* ((flags (if (pair? o) (car o) 0))
|
||||
(addrinfo (and (pair? o) (pair? (cdr o)) (cadr o)))
|
||||
(sockaddr (and addrinfo (address-info-address addrinfo)))
|
||||
(sockaddr-len (if addrinfo (address-info-address-length addrinfo) 0)))
|
||||
(%send socket bv flags sockaddr sockaddr-len)))
|
||||
|
||||
;;> Recieves data from \var{socket} to fill the bytevector \var{bv} by
|
||||
;;> calling recvfrom. Returns the number of bytes read, or a negative
|
||||
;;> value on error. If \var{addrinfo} is unspecified, \var{socket}
|
||||
;;> must previously have had a default address specified with
|
||||
;;> \scheme{connect}.
|
||||
|
||||
(define (receive! socket bv . o)
|
||||
(let* ((flags (if (pair? o) (car o) 0))
|
||||
(addrinfo (and (pair? o) (pair? (cdr o)) (cadr o)))
|
||||
(sockaddr (and addrinfo (address-info-address addrinfo)))
|
||||
(sockaddr-len (if addrinfo (address-info-address-length addrinfo) 0)))
|
||||
(%receive! socket bv flags sockaddr sockaddr-len)))
|
||||
|
||||
;;> Shortcut for \scheme{receive}, returning a newly created
|
||||
;;> bytevector of length \var{n} on success and \scheme{#f} on
|
||||
;;> failure.
|
||||
|
||||
(define (receive socket n . o)
|
||||
(let* ((bv (make-bytevector n))
|
||||
(m (apply receive! socket bv o)))
|
||||
(and (>= m 0)
|
||||
(subbytes bv 0 m))))
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
socket connect bind accept listen open-socket-pair
|
||||
sockaddr-name sockaddr-port make-sockaddr
|
||||
with-net-io open-net-io make-listener-socket
|
||||
send receive! receive
|
||||
address-info-family address-info-socket-type address-info-protocol
|
||||
address-info-address address-info-address-length address-info-next
|
||||
address-family/unix address-family/inet address-family/unspecified
|
||||
|
|
|
@ -51,6 +51,16 @@
|
|||
|
||||
(define-c int connect (fileno sockaddr int))
|
||||
|
||||
(define-c sexp (%send "sexp_sendto")
|
||||
((value ctx sexp) (value self sexp)
|
||||
fileno bytevector (value (bytevector-length arg3) size_t) int
|
||||
(maybe-null sockaddr) socklen_t))
|
||||
|
||||
(define-c sexp (%receive! "sexp_recvfrom")
|
||||
((value ctx sexp) (value self sexp)
|
||||
fileno bytevector (value (bytevector-length arg3) size_t) int
|
||||
(maybe-null sockaddr) socklen_t))
|
||||
|
||||
;;> Returns a list of 2 new sockets, the input and output end of a new
|
||||
;;> pipe, respectively.
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue