1
0
mirror of https://github.com/janet-lang/janet synced 2024-12-27 00:40:26 +00:00

Add bind option to net/connect

This will allow us to set the address we use for outgoing connections.

Builds, haven't checked it passes current tests, haven't checked it
actually works either.
This commit is contained in:
llmII 2021-09-06 08:54:24 -05:00
parent 7037532943
commit 6e8584e8e0
No known key found for this signature in database
GPG Key ID: E3AD2E259F58A9A0

View File

@ -259,8 +259,9 @@ static int janet_get_sockettype(Janet *argv, int32_t argc, int32_t n) {
} }
/* Needs argc >= offset + 2 */ /* Needs argc >= offset + 2 */
/* For unix paths, just rertuns a single sockaddr and sets *is_unix to 1, otherwise 0 */ /* For unix paths, just rertuns a single sockaddr and sets *is_unix to 1,
static struct addrinfo *janet_get_addrinfo(Janet *argv, int32_t offset, int socktype, int passive, int *is_unix) { * otherwise 0. Also, ignores is_bind when is a unix socket. */
static struct addrinfo *janet_get_addrinfo(Janet *argv, int32_t offset, int socktype, int passive, int *is_unix, int is_bind) {
/* Unix socket support - not yet supported on windows. */ /* Unix socket support - not yet supported on windows. */
#ifndef JANET_WINDOWS #ifndef JANET_WINDOWS
if (janet_keyeq(argv[offset], "unix")) { if (janet_keyeq(argv[offset], "unix")) {
@ -285,12 +286,29 @@ static struct addrinfo *janet_get_addrinfo(Janet *argv, int32_t offset, int sock
} }
#endif #endif
/* Get host and port */ /* Get host and port */
const char *host = janet_getcstring(argv, offset); char *host = NULL, *port = NULL;
const char *port; char *err = NULL;
/* if is_bind is set, skip offsets and ports! */
if (!is_bind) {
host = (char *)janet_getcstring(argv, offset);
if (janet_checkint(argv[offset + 1])) { if (janet_checkint(argv[offset + 1])) {
port = (const char *)janet_to_string(argv[offset + 1]); port = (char *)janet_to_string(argv[offset + 1]);
} else { } else {
port = janet_optcstring(argv, offset + 2, offset + 1, NULL); port = (char *)janet_optcstring(argv, offset + 2, offset + 1, NULL);
}
err = "could not get address info: %s";
} else {
/* when is_bind is set, we're performing a connect, but wanting to
* specify from where we connect, and in general don't care about a
* port */
int32_t current_offset = 3;
if (janet_keyeq(argv[current_offset], "stream") ||
janet_keyeq(argv[current_offset], "datagram")) {
current_offset = 4;
}
host = (char *)janet_getcstring(argv, current_offset);
port = NULL;
err = "could not get address info for connect bind: %s";
} }
/* getaddrinfo */ /* getaddrinfo */
struct addrinfo *ai = NULL; struct addrinfo *ai = NULL;
@ -301,7 +319,7 @@ static struct addrinfo *janet_get_addrinfo(Janet *argv, int32_t offset, int sock
hints.ai_flags = passive ? AI_PASSIVE : 0; hints.ai_flags = passive ? AI_PASSIVE : 0;
int status = getaddrinfo(host, port, &hints, &ai); int status = getaddrinfo(host, port, &hints, &ai);
if (status) { if (status) {
janet_panicf("could not get address info: %s", gai_strerror(status)); janet_panicf(err, gai_strerror(status));
} }
*is_unix = 0; *is_unix = 0;
return ai; return ai;
@ -322,7 +340,7 @@ JANET_CORE_FN(cfun_net_sockaddr,
int socktype = janet_get_sockettype(argv, argc, 2); int socktype = janet_get_sockettype(argv, argc, 2);
int is_unix = 0; int is_unix = 0;
int make_arr = (argc >= 3 && janet_truthy(argv[3])); int make_arr = (argc >= 3 && janet_truthy(argv[3]));
struct addrinfo *ai = janet_get_addrinfo(argv, 0, socktype, 0, &is_unix); struct addrinfo *ai = janet_get_addrinfo(argv, 0, socktype, 0, &is_unix, 0);
#ifndef JANET_WINDOWS #ifndef JANET_WINDOWS
/* no unix domain socket support on windows yet */ /* no unix domain socket support on windows yet */
if (is_unix) { if (is_unix) {
@ -361,11 +379,11 @@ JANET_CORE_FN(cfun_net_connect,
"Open a connection to communicate with a server. Returns a duplex stream " "Open a connection to communicate with a server. Returns a duplex stream "
"that can be used to communicate with the server. Type is an optional keyword " "that can be used to communicate with the server. Type is an optional keyword "
"to specify a connection type, either :stream or :datagram. The default is :stream. ") { "to specify a connection type, either :stream or :datagram. The default is :stream. ") {
janet_arity(argc, 2, 3); janet_arity(argc, 2, 4);
int socktype = janet_get_sockettype(argv, argc, 2); int socktype = janet_get_sockettype(argv, argc, 2);
int is_unix = 0; int is_unix = 0;
struct addrinfo *ai = janet_get_addrinfo(argv, 0, socktype, 0, &is_unix); struct addrinfo *ai = janet_get_addrinfo(argv, 0, socktype, 0, &is_unix, 0);
/* Create socket */ /* Create socket */
JSock sock = JSOCKDEFAULT; JSock sock = JSOCKDEFAULT;
@ -401,6 +419,35 @@ JANET_CORE_FN(cfun_net_connect,
} }
} }
/* TODO: check if need bind and bind! */
ai = NULL;
if (argc >= 3 && is_unix == 0) {
if (argc == 4 ||
(!janet_keyeq(argv[3], "stream") &&
!janet_keyeq(argv[3], "datagram"))) {
ai = janet_get_addrinfo(argv, 0, socktype, 0, &is_unix, 1);
}
}
/* Check all addrinfos in a loop for the first that we can bind to. */
struct addrinfo *rp = NULL;
for (rp = ai; rp != NULL; rp = rp->ai_next) {
#ifdef JANET_WINDOWS
sock = WSASocketW(rp->ai_family, rp->ai_socktype | JSOCKFLAGS, rp->ai_protocol, NULL, 0, WSA_FLAG_OVERLAPPED);
#else
sock = socket(rp->ai_family, rp->ai_socktype | JSOCKFLAGS, rp->ai_protocol);
#endif
if (!JSOCKVALID(sock)) continue;
/* Bind */
if (bind(sock, rp->ai_addr, (int) rp->ai_addrlen) == 0) break;
JSOCKCLOSE(sock);
}
freeaddrinfo(ai);
if (NULL == rp) {
janet_panic("could not bind to any sockets");
}
/* Connect to socket */ /* Connect to socket */
#ifdef JANET_WINDOWS #ifdef JANET_WINDOWS
int status = WSAConnect(sock, addr, addrlen, NULL, NULL, NULL, NULL); int status = WSAConnect(sock, addr, addrlen, NULL, NULL, NULL, NULL);
@ -502,7 +549,7 @@ JANET_CORE_FN(cfun_net_listen,
/* Get host, port, and handler*/ /* Get host, port, and handler*/
int socktype = janet_get_sockettype(argv, argc, 2); int socktype = janet_get_sockettype(argv, argc, 2);
int is_unix = 0; int is_unix = 0;
struct addrinfo *ai = janet_get_addrinfo(argv, 0, socktype, 1, &is_unix); struct addrinfo *ai = janet_get_addrinfo(argv, 0, socktype, 1, &is_unix, 0);
JSock sfd = JSOCKDEFAULT; JSock sfd = JSOCKDEFAULT;
#ifndef JANET_WINDOWS #ifndef JANET_WINDOWS