mirror of
https://github.com/janet-lang/janet
synced 2024-12-26 08:20:27 +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:
parent
7037532943
commit
6e8584e8e0
@ -259,8 +259,9 @@ static int janet_get_sockettype(Janet *argv, int32_t argc, int32_t n) {
|
||||
}
|
||||
|
||||
/* Needs argc >= offset + 2 */
|
||||
/* For unix paths, just rertuns a single sockaddr and sets *is_unix to 1, otherwise 0 */
|
||||
static struct addrinfo *janet_get_addrinfo(Janet *argv, int32_t offset, int socktype, int passive, int *is_unix) {
|
||||
/* For unix paths, just rertuns a single sockaddr and sets *is_unix to 1,
|
||||
* 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. */
|
||||
#ifndef JANET_WINDOWS
|
||||
if (janet_keyeq(argv[offset], "unix")) {
|
||||
@ -285,12 +286,29 @@ static struct addrinfo *janet_get_addrinfo(Janet *argv, int32_t offset, int sock
|
||||
}
|
||||
#endif
|
||||
/* Get host and port */
|
||||
const char *host = janet_getcstring(argv, offset);
|
||||
const char *port;
|
||||
if (janet_checkint(argv[offset + 1])) {
|
||||
port = (const char *)janet_to_string(argv[offset + 1]);
|
||||
char *host = NULL, *port = NULL;
|
||||
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])) {
|
||||
port = (char *)janet_to_string(argv[offset + 1]);
|
||||
} else {
|
||||
port = (char *)janet_optcstring(argv, offset + 2, offset + 1, NULL);
|
||||
}
|
||||
err = "could not get address info: %s";
|
||||
} else {
|
||||
port = janet_optcstring(argv, offset + 2, offset + 1, NULL);
|
||||
/* 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 */
|
||||
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;
|
||||
int status = getaddrinfo(host, port, &hints, &ai);
|
||||
if (status) {
|
||||
janet_panicf("could not get address info: %s", gai_strerror(status));
|
||||
janet_panicf(err, gai_strerror(status));
|
||||
}
|
||||
*is_unix = 0;
|
||||
return ai;
|
||||
@ -322,7 +340,7 @@ JANET_CORE_FN(cfun_net_sockaddr,
|
||||
int socktype = janet_get_sockettype(argv, argc, 2);
|
||||
int is_unix = 0;
|
||||
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
|
||||
/* no unix domain socket support on windows yet */
|
||||
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 "
|
||||
"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. ") {
|
||||
janet_arity(argc, 2, 3);
|
||||
janet_arity(argc, 2, 4);
|
||||
|
||||
int socktype = janet_get_sockettype(argv, argc, 2);
|
||||
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 */
|
||||
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 */
|
||||
#ifdef JANET_WINDOWS
|
||||
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*/
|
||||
int socktype = janet_get_sockettype(argv, argc, 2);
|
||||
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;
|
||||
#ifndef JANET_WINDOWS
|
||||
|
Loading…
Reference in New Issue
Block a user