Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support connect() for tcp wrapper #2764

Merged
merged 2 commits into from
Feb 25, 2023
Merged

Conversation

stevenengler
Copy link
Contributor

The logic generally follows the logic from src/main/host/syscall/socket.c.

SysCallReturn syscallhandler_connect(SysCallHandler* sys,
const SysCallArgs* args) {
int sockfd = args->args[0].as_i64;
PluginPtr addrPtr = args->args[1].as_ptr; // const struct sockaddr*
socklen_t addrlen = args->args[2].as_u64;
trace("trying to connect on socket %i", sockfd);
/* Get and validate the socket. */
LegacySocket* socket_desc = NULL;
int errcode =
_syscallhandler_validateSocketHelper(sys, sockfd, &socket_desc);
if (errcode < 0) {
return syscallreturn_makeDoneErrno(-errcode);
}
utility_debugAssert(socket_desc);
/* TODO: we assume AF_INET here, change this when we support AF_UNIX */
// size_t unix_len = sizeof(struct sockaddr_un); // if sa_family==AF_UNIX
size_t inet_len = sizeof(struct sockaddr_in);
if (addrlen < inet_len) {
return syscallreturn_makeDoneErrno(EINVAL);
}
const struct sockaddr* addr =
process_getReadablePtr(_syscallhandler_getProcess(sys), addrPtr, addrlen);
if (!addr) {
debug("Couldn't read addr %p", (void*)addrPtr.val);
return syscallreturn_makeDoneErrno(EFAULT);
}
/* TODO: we assume AF_INET here, change this when we support AF_UNIX */
if (addr->sa_family != AF_INET && addr->sa_family != AF_UNSPEC) {
warning("connecting to address family %i, but we only support AF_INET",
(int)addr->sa_family);
return syscallreturn_makeDoneErrno(EAFNOSUPPORT);
} else if (!legacysocket_isFamilySupported(socket_desc, addr->sa_family)) {
return syscallreturn_makeDoneErrno(EAFNOSUPPORT);
}
/* TODO: update for AF_UNIX */
struct sockaddr_in* inet_addr = (struct sockaddr_in*)addr;
sa_family_t family = inet_addr->sin_family;
in_addr_t peerAddr = inet_addr->sin_addr.s_addr;
in_port_t peerPort = inet_addr->sin_port;
in_addr_t loopbackAddr = htonl(INADDR_LOOPBACK);
if (peerAddr == htonl(INADDR_ANY)) {
peerAddr = loopbackAddr;
}
/* make sure we will be able to route this later */
if (peerAddr != loopbackAddr) {
const Address* myAddress = host_getDefaultAddress(_syscallhandler_getHost(sys));
const Address* peerAddress = worker_resolveIPToAddress(peerAddr);
in_addr_t myAddr = htonl(address_toHostIP(myAddress));
if (!peerAddress || !worker_isRoutable(myAddr, peerAddr)) {
/* can't route it - there is no node with this address */
gchar* peerAddressString = address_ipToNewString(peerAddr);
warning("attempting to connect to address '%s:%u' for which no "
"host exists",
peerAddressString, ntohs(peerPort));
g_free(peerAddressString);
return syscallreturn_makeDoneErrno(ECONNREFUSED);
}
}
if (!legacysocket_isBound(socket_desc)) {
/* do an implicit bind to a random ephemeral port.
* use default interface unless the remote peer is on loopback */
in_addr_t bindAddr = (loopbackAddr == peerAddr)
? loopbackAddr
: host_getDefaultIP(_syscallhandler_getHost(sys));
errcode = _syscallhandler_bindHelper(
sys, socket_desc, bindAddr, 0, peerAddr, peerPort);
if (errcode < 0) {
return syscallreturn_makeDoneErrno(-errcode);
}
} else {
legacysocket_setPeerName(socket_desc, peerAddr, peerPort);
}
/* Now we are ready to connect. */
errcode = legacysocket_connectToPeer(
socket_desc, _syscallhandler_getHost(sys), peerAddr, peerPort, family);
LegacyFile* desc = (LegacyFile*)socket_desc;
if (legacyfile_getType(desc) == DT_TCPSOCKET && !(legacyfile_getFlags(desc) & O_NONBLOCK)) {
/* This is a blocking connect call. */
if (errcode == -EINPROGRESS) {
/* This is the first time we ever called connect, and so we
* need to wait for the 3-way handshake to complete.
* We will wait indefinitely for a success or failure. */
Trigger trigger = (Trigger){.type = TRIGGER_DESCRIPTOR,
.object = desc,
.status = STATUS_FILE_ACTIVE | STATUS_FILE_WRITABLE};
return syscallreturn_makeBlocked(
syscallcondition_new(trigger), legacyfile_supportsSaRestart(desc));
} else if (_syscallhandler_wasBlocked(sys) && errcode == -EISCONN) {
/* It was EINPROGRESS, but is now a successful blocking connect. */
errcode = 0;
}
}
/* Make sure we return valid error codes for connect. */
if (errcode == -ECONNRESET || errcode == -ENOTCONN) {
errcode = -EISCONN;
}
/* -EALREADY is well defined in man page, but Linux returns -EINPROGRESS. */
else if (errcode == -EALREADY) {
errcode = -EINPROGRESS;
}
/* Return 0, -EINPROGRESS, etc. now. */
return syscallreturn_makeDoneI64(errcode);
}

@stevenengler stevenengler self-assigned this Feb 24, 2023
@github-actions github-actions bot added the Component: Main Composing the core Shadow executable label Feb 24, 2023
@stevenengler stevenengler merged commit 1c2d436 into shadow:main Feb 25, 2023
@stevenengler stevenengler deleted the wrap-tcp-rust branch February 25, 2023 00:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Component: Main Composing the core Shadow executable
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants