mirror of
https://github.com/janet-lang/janet
synced 2025-08-03 20:43:55 +00:00
Work on bug #1556
This commit is contained in:
parent
53bcc15207
commit
2e6001316a
@ -3877,8 +3877,8 @@
|
|||||||
(compwhen (dyn 'net/listen)
|
(compwhen (dyn 'net/listen)
|
||||||
(defn net/server
|
(defn net/server
|
||||||
"Start a server asynchronously with `net/listen` and `net/accept-loop`. Returns the new server stream."
|
"Start a server asynchronously with `net/listen` and `net/accept-loop`. Returns the new server stream."
|
||||||
[host port &opt handler type]
|
[host port &opt handler type no-reuse]
|
||||||
(def s (net/listen host port type))
|
(def s (net/listen host port type no-reuse))
|
||||||
(if handler
|
(if handler
|
||||||
(ev/go (fn [] (net/accept-loop s handler))))
|
(ev/go (fn [] (net/accept-loop s handler))))
|
||||||
s))
|
s))
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2024 Calvin Rose
|
* Copyright (c) 2025 Calvin Rose
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to
|
* of this software and associated documentation files (the "Software"), to
|
||||||
@ -1789,6 +1789,22 @@ void janet_stream_edge_triggered(JanetStream *stream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void janet_stream_level_triggered(JanetStream *stream) {
|
void janet_stream_level_triggered(JanetStream *stream) {
|
||||||
|
/* On macos, we seem to need to delete any registered events before re-registering without
|
||||||
|
* EV_CLEAR, otherwise the new event will still have EV_CLEAR set erroneously. This could be a
|
||||||
|
* kernel bug, but unfortunately the specification is vague here, esp. in regards to where and when
|
||||||
|
* EV_CLEAR is set automatically. */
|
||||||
|
struct kevent kevs[2];
|
||||||
|
int length = 0;
|
||||||
|
if (stream->flags & (JANET_STREAM_READABLE | JANET_STREAM_ACCEPTABLE)) {
|
||||||
|
EV_SETx(&kevs[length++], stream->handle, EVFILT_READ, EV_DELETE, 0, 0, stream);
|
||||||
|
}
|
||||||
|
if (stream->flags & JANET_STREAM_WRITABLE) {
|
||||||
|
EV_SETx(&kevs[length++], stream->handle, EVFILT_WRITE, EV_DELETE, 0, 0, stream);
|
||||||
|
}
|
||||||
|
int status;
|
||||||
|
do {
|
||||||
|
status = kevent(janet_vm.kq, kevs, length, NULL, 0, NULL);
|
||||||
|
} while (status == -1 && errno == EINTR);
|
||||||
janet_register_stream_impl(stream, 0);
|
janet_register_stream_impl(stream, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -554,7 +554,10 @@ JANET_CORE_FN(cfun_net_connect,
|
|||||||
int err = WSAGetLastError();
|
int err = WSAGetLastError();
|
||||||
freeaddrinfo(ai);
|
freeaddrinfo(ai);
|
||||||
#else
|
#else
|
||||||
int status = connect(sock, addr, addrlen);
|
int status;
|
||||||
|
do {
|
||||||
|
status = connect(sock, addr, addrlen);
|
||||||
|
} while (status == -1 && errno == EINTR);
|
||||||
int err = errno;
|
int err = errno;
|
||||||
if (is_unix) {
|
if (is_unix) {
|
||||||
janet_free(ai);
|
janet_free(ai);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2023 Calvin Rose & contributors
|
# Copyright (c) 2025 Calvin Rose & contributors
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
# of this software and associated documentation files (the "Software"), to
|
# of this software and associated documentation files (the "Software"), to
|
||||||
@ -199,7 +199,7 @@
|
|||||||
(assert s "made server 1")
|
(assert s "made server 1")
|
||||||
|
|
||||||
(defn test-echo [msg]
|
(defn test-echo [msg]
|
||||||
(with [conn (net/connect test-host test-port)]
|
(with [conn (assert (net/connect test-host test-port))]
|
||||||
(net/write conn msg)
|
(net/write conn msg)
|
||||||
(def res (net/read conn 1024))
|
(def res (net/read conn 1024))
|
||||||
(assert (= (string res) msg) (string "echo " msg))))
|
(assert (= (string res) msg) (string "echo " msg))))
|
||||||
@ -213,6 +213,7 @@
|
|||||||
|
|
||||||
# Test on both server and client
|
# Test on both server and client
|
||||||
# 504411e
|
# 504411e
|
||||||
|
(var iterations 0)
|
||||||
(defn names-handler
|
(defn names-handler
|
||||||
[stream]
|
[stream]
|
||||||
(defer (:close stream)
|
(defer (:close stream)
|
||||||
@ -220,21 +221,26 @@
|
|||||||
(ev/read stream 1)
|
(ev/read stream 1)
|
||||||
(def [host port] (net/localname stream))
|
(def [host port] (net/localname stream))
|
||||||
(assert (= host test-host) "localname host server")
|
(assert (= host test-host) "localname host server")
|
||||||
(assert (= port (scan-number test-port)) "localname port server")))
|
(assert (= port (scan-number test-port)) "localname port server")
|
||||||
|
(++ iterations)
|
||||||
|
(ev/write stream " ")))
|
||||||
|
|
||||||
# Test localname and peername
|
# Test localname and peername
|
||||||
# 077bf5eba
|
# 077bf5eba
|
||||||
(repeat 10
|
(repeat 10
|
||||||
(with [s (net/server test-host test-port names-handler)]
|
(with [s (net/server test-host test-port names-handler)]
|
||||||
(repeat 10
|
(repeat 10
|
||||||
(with [conn (net/connect test-host test-port)]
|
(with [conn (assert (net/connect test-host test-port))]
|
||||||
(def [host port] (net/peername conn))
|
(def [host port] (net/peername conn))
|
||||||
(assert (= host test-host) "peername host client ")
|
(assert (= host test-host) "peername host client ")
|
||||||
(assert (= port (scan-number test-port)) "peername port client")
|
(assert (= port (scan-number test-port)) "peername port client")
|
||||||
# let server close
|
(++ iterations)
|
||||||
(ev/write conn " "))))
|
(ev/write conn " ")
|
||||||
|
(ev/read conn 1))))
|
||||||
(gccollect))
|
(gccollect))
|
||||||
|
|
||||||
|
(assert (= iterations 200) "localname and peername not enough checks")
|
||||||
|
|
||||||
# Create pipe
|
# Create pipe
|
||||||
# 12f09ad2d
|
# 12f09ad2d
|
||||||
(var pipe-counter 0)
|
(var pipe-counter 0)
|
||||||
@ -422,7 +428,7 @@
|
|||||||
(assert (= result text) (string/format "expected %v, got %v" text result)))
|
(assert (= result text) (string/format "expected %v, got %v" text result)))
|
||||||
|
|
||||||
# Now do our telnet chat
|
# Now do our telnet chat
|
||||||
(def bob (net/connect test-host test-port :stream))
|
(def bob (assert (net/connect test-host test-port :stream)))
|
||||||
(expect-read bob "Whats your name?\n")
|
(expect-read bob "Whats your name?\n")
|
||||||
(if (= :mingw (os/which))
|
(if (= :mingw (os/which))
|
||||||
(net/write bob "bob")
|
(net/write bob "bob")
|
||||||
@ -432,7 +438,7 @@
|
|||||||
(file/flush fbob)
|
(file/flush fbob)
|
||||||
(:close fbob)))
|
(:close fbob)))
|
||||||
(expect-read bob "Welcome bob\n")
|
(expect-read bob "Welcome bob\n")
|
||||||
(def alice (net/connect test-host test-port))
|
(def alice (assert (net/connect test-host test-port)))
|
||||||
(expect-read alice "Whats your name?\n")
|
(expect-read alice "Whats your name?\n")
|
||||||
(net/write alice "alice")
|
(net/write alice "alice")
|
||||||
(expect-read alice "Welcome alice\n")
|
(expect-read alice "Welcome alice\n")
|
||||||
@ -446,7 +452,7 @@
|
|||||||
(expect-read bob "[alice]:hi\n")
|
(expect-read bob "[alice]:hi\n")
|
||||||
|
|
||||||
# Ted joins the chat server
|
# Ted joins the chat server
|
||||||
(def ted (net/connect test-host test-port))
|
(def ted (assert (net/connect test-host test-port)))
|
||||||
(expect-read ted "Whats your name?\n")
|
(expect-read ted "Whats your name?\n")
|
||||||
(net/write ted "ted")
|
(net/write ted "ted")
|
||||||
(expect-read ted "Welcome ted\n")
|
(expect-read ted "Welcome ted\n")
|
||||||
@ -485,9 +491,31 @@
|
|||||||
(ev/chan-close c)
|
(ev/chan-close c)
|
||||||
|
|
||||||
# soreuseport on unix domain sockets
|
# soreuseport on unix domain sockets
|
||||||
(compwhen (= :linux (os/which))
|
(compwhen (or (= :macos (os/which)) (= :linux (os/which)))
|
||||||
(assert-no-error "unix-domain socket reuseaddr"
|
(assert-no-error "unix-domain socket reuseaddr"
|
||||||
(let [s (net/listen :unix "./unix-domain-socket" :stream)]
|
(let [s (net/listen :unix "./unix-domain-socket" :stream)]
|
||||||
(:close s))))
|
(:close s))))
|
||||||
|
|
||||||
|
# net/accept-loop level triggering
|
||||||
|
(gccollect)
|
||||||
|
(def maxconn 50)
|
||||||
|
(var connect-count 0)
|
||||||
|
(defn level-trigger-handling
|
||||||
|
[conn &]
|
||||||
|
(with [conn conn]
|
||||||
|
(ev/write conn (ev/read conn 4096))
|
||||||
|
(++ connect-count)))
|
||||||
|
(def s (assert (net/server test-host test-port level-trigger-handling)))
|
||||||
|
(def cons @[])
|
||||||
|
(repeat maxconn (array/push cons (assert (net/connect test-host test-port))))
|
||||||
|
(assert (= maxconn (length cons)))
|
||||||
|
(defn do-connect [i]
|
||||||
|
(with [c (get cons i)]
|
||||||
|
(ev/write c "abc123")
|
||||||
|
(ev/read c 4096)))
|
||||||
|
(for i 0 maxconn (ev/spawn (do-connect i)))
|
||||||
|
(ev/sleep 0.1)
|
||||||
|
(assert (= maxconn connect-count))
|
||||||
|
(:close s)
|
||||||
|
|
||||||
(end-suite)
|
(end-suite)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user