Skip to content

Commit 4cc05c3

Browse files
authored
Merge pull request #1058 from robgjansen/syscall-socketpair
Add support for socketpair syscall
2 parents b963f5e + 8b11ec8 commit 4cc05c3

12 files changed

Lines changed: 155 additions & 52 deletions

File tree

src/main/host/descriptor/channel.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "main/core/support/object_counter.h"
1616
#include "main/core/worker.h"
1717
#include "main/host/descriptor/descriptor.h"
18+
#include "main/host/descriptor/descriptor_types.h"
1819
#include "main/host/descriptor/transport.h"
1920
#include "main/host/host.h"
2021
#include "main/utility/utility.h"
@@ -33,7 +34,8 @@ struct _Channel {
3334
};
3435

3536
static Channel* _channel_fromDescriptor(Descriptor* descriptor) {
36-
utility_assert(descriptor_getType(descriptor) == DT_PIPE);
37+
utility_assert(descriptor_getType(descriptor) == DT_PIPE ||
38+
descriptor_getType(descriptor) == DT_UNIXSOCKET);
3739
return (Channel*)descriptor;
3840
}
3941

@@ -154,11 +156,11 @@ TransportFunctionTable channel_functions = {
154156
channel_close, channel_free, channel_sendUserData, channel_receiveUserData,
155157
MAGIC_VALUE};
156158

157-
Channel* channel_new(ChannelType type) {
159+
Channel* channel_new(ChannelType type, DescriptorType dtype) {
158160
Channel* channel = g_new0(Channel, 1);
159161
MAGIC_INIT(channel);
160162

161-
transport_init(&(channel->super), &channel_functions, DT_PIPE);
163+
transport_init(&(channel->super), &channel_functions, dtype);
162164

163165
channel->type = type;
164166
channel->buffer = bytequeue_new(8192);

src/main/host/descriptor/channel.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#ifndef SHD_CHANNEL_H_
88
#define SHD_CHANNEL_H_
99

10+
#include "main/host/descriptor/descriptor_types.h"
11+
1012
#include <glib.h>
1113

1214
typedef enum _ChannelType ChannelType;
@@ -16,7 +18,7 @@ enum _ChannelType {
1618

1719
typedef struct _Channel Channel;
1820

19-
Channel* channel_new(ChannelType type);
21+
Channel* channel_new(ChannelType type, DescriptorType dtype);
2022
void channel_setLinkedChannel(Channel* channel, Channel* linkedChannel);
2123
Channel* channel_getLinkedChannel(Channel* channel);
2224

src/main/host/descriptor/descriptor_table.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,7 @@ void descriptortable_shutdownHelper(DescriptorTable* table) {
177177
/* tcp servers and their children holds refs to each other. make
178178
* sure they all get freed by removing the refs in one direction */
179179
tcp_clearAllChildrenIfServer((TCP*)desc);
180-
} else if (desc &&
181-
(desc->type == DT_SOCKETPAIR || desc->type == DT_PIPE)) {
180+
} else if (desc && (desc->type == DT_UNIXSOCKET || desc->type == DT_PIPE)) {
182181
/* we need to correctly update the linked channel refs */
183182
channel_setLinkedChannel((Channel*)desc, NULL);
184183
} else if (desc && desc->type == DT_EPOLL) {

src/main/host/descriptor/descriptor_types.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ enum _DescriptorType {
1717
DT_TCPSOCKET,
1818
DT_UDPSOCKET,
1919
DT_PIPE,
20-
DT_SOCKETPAIR,
20+
DT_UNIXSOCKET,
2121
DT_EPOLL,
2222
DT_TIMER,
2323
DT_FILE,

src/main/host/descriptor/transport.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
static Transport* _transport_fromDescriptor(Descriptor* descriptor) {
1616
utility_assert(descriptor_getType(descriptor) == DT_TCPSOCKET ||
1717
descriptor_getType(descriptor) == DT_UDPSOCKET ||
18+
descriptor_getType(descriptor) == DT_UNIXSOCKET ||
1819
descriptor_getType(descriptor) == DT_PIPE);
1920
return (Transport*)descriptor;
2021
}

src/main/host/syscall/socket.c

Lines changed: 124 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <sys/types.h>
1414

1515
#include "main/core/worker.h"
16+
#include "main/host/descriptor/channel.h"
1617
#include "main/host/descriptor/descriptor.h"
1718
#include "main/host/descriptor/socket.h"
1819
#include "main/host/descriptor/tcp.h"
@@ -66,7 +67,7 @@ static int _syscallhandler_validateSocketHelper(SysCallHandler* sys, int sockfd,
6667
}
6768

6869
DescriptorType type = descriptor_getType(desc);
69-
if (type != DT_TCPSOCKET && type != DT_UDPSOCKET) {
70+
if (type != DT_TCPSOCKET && type != DT_UDPSOCKET && type != DT_UNIXSOCKET) {
7071
info("descriptor %i with type %i is not a socket", sockfd, (int)type);
7172
return -ENOTSOCK;
7273
}
@@ -121,10 +122,9 @@ static int _syscallhandler_validateUDPSocketHelper(SysCallHandler* sys,
121122
return 0;
122123
}
123124

124-
static SysCallReturn
125-
_syscallhandler_getnameHelper(SysCallHandler* sys,
126-
struct sockaddr_in* inet_addr, PluginPtr addrPtr,
127-
PluginPtr addrlenPtr) {
125+
static SysCallReturn _syscallhandler_getnameHelper(SysCallHandler* sys, struct sockaddr* saddr,
126+
size_t slen, PluginPtr addrPtr,
127+
PluginPtr addrlenPtr) {
128128
if (!addrPtr.val || !addrlenPtr.val) {
129129
info("Cannot get name with NULL return address info.");
130130
return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -EFAULT};
@@ -134,14 +134,14 @@ _syscallhandler_getnameHelper(SysCallHandler* sys,
134134
process_getMutablePtr(sys->process, sys->thread, addrlenPtr, sizeof(*addrlen));
135135

136136
/* The result is truncated if they didn't give us enough space. */
137-
size_t retSize = MIN(*addrlen, sizeof(*inet_addr));
138-
*addrlen = (socklen_t)sizeof(*inet_addr);
137+
size_t retSize = MIN(*addrlen, slen);
138+
*addrlen = (socklen_t)slen;
139139

140140
if (retSize > 0) {
141141
/* Return the results */
142142
struct sockaddr* addr =
143143
process_getWriteablePtr(sys->process, sys->thread, addrPtr, retSize);
144-
memcpy(addr, inet_addr, retSize);
144+
memcpy(addr, saddr, retSize);
145145
}
146146

147147
return (SysCallReturn){.state = SYSCALL_DONE};
@@ -222,7 +222,8 @@ static SysCallReturn _syscallhandler_acceptHelper(SysCallHandler* sys,
222222

223223
/* check if they wanted to know where we got the data from */
224224
if (addrPtr.val) {
225-
_syscallhandler_getnameHelper(sys, &inet_addr, addrPtr, addrlenPtr);
225+
_syscallhandler_getnameHelper(
226+
sys, (struct sockaddr*)&inet_addr, sizeof(inet_addr), addrPtr, addrlenPtr);
226227
}
227228

228229
return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = accepted_fd};
@@ -499,7 +500,8 @@ SysCallReturn _syscallhandler_recvfromHelper(SysCallHandler* sys, int sockfd,
499500
/* check if they wanted to know where we got the data from */
500501
if (retval > 0 && srcAddrPtr.val) {
501502
debug("address info is requested in recv on socket %i", sockfd);
502-
_syscallhandler_getnameHelper(sys, &inet_addr, srcAddrPtr, addrlenPtr);
503+
_syscallhandler_getnameHelper(
504+
sys, (struct sockaddr*)&inet_addr, sizeof(inet_addr), srcAddrPtr, addrlenPtr);
503505
}
504506

505507
return (SysCallReturn){
@@ -889,18 +891,32 @@ SysCallReturn syscallhandler_getpeername(SysCallHandler* sys,
889891

890892
/* Get the name of the connected peer.
891893
* TODO: Needs to be updated when we support AF_UNIX. */
892-
struct sockaddr_in inet_addr = {.sin_family = AF_INET};
893-
gboolean hasName = socket_getPeerName(
894-
socket_desc, &inet_addr.sin_addr.s_addr, &inet_addr.sin_port);
895-
if (!hasName) {
896-
info("Socket %i has no peer name.", sockfd);
897-
return (SysCallReturn){
898-
.state = SYSCALL_DONE, .retval.as_i64 = -ENOTCONN};
894+
struct sockaddr saddr = {0};
895+
size_t slen = 0;
896+
897+
if (descriptor_getType((Descriptor*)socket_desc) == DT_UNIXSOCKET) {
898+
// TODO currently handles socketpair, but will need to be extended
899+
// in order to support traditional UNIX sockets
900+
struct sockaddr_un* unix_addr = (struct sockaddr_un*)&saddr;
901+
unix_addr->sun_family = AF_UNIX;
902+
slen = sizeof(unix_addr->sun_family);
903+
} else {
904+
struct sockaddr_in* inet_addr = (struct sockaddr_in*)&saddr;
905+
inet_addr->sin_family = AF_INET;
906+
907+
gboolean hasName =
908+
socket_getPeerName(socket_desc, &inet_addr->sin_addr.s_addr, &inet_addr->sin_port);
909+
if (!hasName) {
910+
info("Socket %i has no peer name.", sockfd);
911+
return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -ENOTCONN};
912+
}
913+
914+
slen = sizeof(*inet_addr);
899915
}
900916

901917
/* Use helper to write out the result. */
902918
return _syscallhandler_getnameHelper(
903-
sys, &inet_addr, args->args[1].as_ptr, args->args[2].as_ptr);
919+
sys, &saddr, slen, args->args[1].as_ptr, args->args[2].as_ptr);
904920
}
905921

906922
SysCallReturn syscallhandler_getsockname(SysCallHandler* sys,
@@ -920,24 +936,39 @@ SysCallReturn syscallhandler_getsockname(SysCallHandler* sys,
920936

921937
/* Get the name of the socket.
922938
* TODO: Needs to be updated when we support AF_UNIX. */
923-
struct sockaddr_in inet_addr = {.sin_family = AF_INET};
924-
gboolean hasName = socket_getSocketName(
925-
socket_desc, &inet_addr.sin_addr.s_addr, &inet_addr.sin_port);
926-
/* If !hasName, leave sin_addr and sin_port at their default 0 values. */
927-
928-
/* If we are bound to INADDR_ANY, we should instead return the address used
929-
* to communicate with the connected peer (if we have one). */
930-
if (inet_addr.sin_addr.s_addr == htonl(INADDR_ANY)) {
931-
in_addr_t peerIP = 0;
932-
if (socket_getPeerName(socket_desc, &peerIP, NULL) &&
933-
peerIP != htonl(INADDR_LOOPBACK)) {
934-
inet_addr.sin_addr.s_addr = host_getDefaultIP(sys->host);
939+
struct sockaddr saddr = {0};
940+
size_t slen = 0;
941+
942+
if (descriptor_getType((Descriptor*)socket_desc) == DT_UNIXSOCKET) {
943+
// TODO currently handles socketpair, but will need to be extended
944+
// in order to support traditional UNIX sockets
945+
struct sockaddr_un* unix_addr = (struct sockaddr_un*)&saddr;
946+
unix_addr->sun_family = AF_UNIX;
947+
slen = sizeof(unix_addr->sun_family);
948+
} else {
949+
struct sockaddr_in* inet_addr = (struct sockaddr_in*)&saddr;
950+
inet_addr->sin_family = AF_INET;
951+
952+
gboolean hasName =
953+
socket_getSocketName(socket_desc, &inet_addr->sin_addr.s_addr, &inet_addr->sin_port);
954+
/* If !hasName, leave sin_addr and sin_port at their default 0 values. */
955+
956+
/* If we are bound to INADDR_ANY, we should instead return the address used
957+
* to communicate with the connected peer (if we have one). */
958+
if (inet_addr->sin_addr.s_addr == htonl(INADDR_ANY)) {
959+
in_addr_t peerIP = 0;
960+
if (socket_getPeerName(socket_desc, &peerIP, NULL) &&
961+
peerIP != htonl(INADDR_LOOPBACK)) {
962+
inet_addr->sin_addr.s_addr = host_getDefaultIP(sys->host);
963+
}
935964
}
965+
966+
slen = sizeof(*inet_addr);
936967
}
937968

938969
/* Use helper to write out the result. */
939970
return _syscallhandler_getnameHelper(
940-
sys, &inet_addr, args->args[1].as_ptr, args->args[2].as_ptr);
971+
sys, &saddr, slen, args->args[1].as_ptr, args->args[2].as_ptr);
941972
}
942973

943974
SysCallReturn syscallhandler_getsockopt(SysCallHandler* sys,
@@ -1199,3 +1230,65 @@ SysCallReturn syscallhandler_socket(SysCallHandler* sys,
11991230

12001231
return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = sockfd};
12011232
}
1233+
1234+
SysCallReturn syscallhandler_socketpair(SysCallHandler* sys, const SysCallArgs* args) {
1235+
int domain = args->args[0].as_i64;
1236+
int type = args->args[1].as_i64;
1237+
int protocol = args->args[2].as_i64;
1238+
PluginPtr fdsPtr = args->args[3].as_ptr; // int [2]
1239+
1240+
debug("trying to create new socketpair");
1241+
1242+
/* Null pointer is invalid. */
1243+
if (!fdsPtr.val) {
1244+
debug("Null pointer is invalid.");
1245+
return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -EFAULT};
1246+
}
1247+
1248+
/* Only AF_UNIX (i.e., AF_LOCAL) is supported. */
1249+
if (domain != AF_UNIX) {
1250+
debug("Domain %d not supported", domain);
1251+
return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -EOPNOTSUPP};
1252+
}
1253+
1254+
/* Remove the two possible flags to get the type. */
1255+
int type_no_flags = type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC);
1256+
1257+
/* The below are warnings so the Shadow user knows that we don't support
1258+
* everything that Linux supports. */
1259+
if (type_no_flags != SOCK_STREAM && type_no_flags != SOCK_DGRAM) {
1260+
warning("unsupported socket type \"%i\", we only support SOCK_STREAM and SOCK_DGRAM",
1261+
type_no_flags);
1262+
return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -EPROTONOSUPPORT};
1263+
} else if (protocol != 0) {
1264+
warning("unsupported socket protocol \"%i\", we only support default protocol 0", protocol);
1265+
return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = -EPROTONOSUPPORT};
1266+
}
1267+
1268+
/* TODO: should we actually be running TCP/UDP internally (i.e., using already connected TCP/UDP
1269+
* sockets here) instead? */
1270+
Channel* socketA = channel_new(CT_NONE, DT_UNIXSOCKET);
1271+
Channel* socketB = channel_new(CT_NONE, DT_UNIXSOCKET);
1272+
channel_setLinkedChannel(socketA, socketB);
1273+
channel_setLinkedChannel(socketB, socketA);
1274+
1275+
/* Set any options that were given. */
1276+
if (type & SOCK_NONBLOCK) {
1277+
descriptor_addFlags((Descriptor*)socketA, O_NONBLOCK);
1278+
descriptor_addFlags((Descriptor*)socketB, O_NONBLOCK);
1279+
}
1280+
if (type & SOCK_CLOEXEC) {
1281+
descriptor_addFlags((Descriptor*)socketA, O_CLOEXEC);
1282+
descriptor_addFlags((Descriptor*)socketB, O_CLOEXEC);
1283+
}
1284+
1285+
/* Return the socket fds to the caller. */
1286+
int* sockfd = process_getWriteablePtr(sys->process, sys->thread, fdsPtr, 2 * sizeof(int));
1287+
1288+
sockfd[0] = process_registerDescriptor(sys->process, (Descriptor*)socketA);
1289+
sockfd[1] = process_registerDescriptor(sys->process, (Descriptor*)socketB);
1290+
1291+
debug("Created socketpair with fd %i and fd %i", sockfd[0], sockfd[1]);
1292+
1293+
return (SysCallReturn){.state = SYSCALL_DONE, .retval.as_i64 = 0};
1294+
}

src/main/host/syscall/socket.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ SYSCALL_HANDLER(sendto);
2121
SYSCALL_HANDLER(setsockopt);
2222
SYSCALL_HANDLER(shutdown);
2323
SYSCALL_HANDLER(socket);
24+
SYSCALL_HANDLER(socketpair);
2425

2526
/* Protected helper to allow read(sockfd) to redirect here. */
2627
SysCallReturn _syscallhandler_recvfromHelper(SysCallHandler* sys, int sockfd,

src/main/host/syscall/uio.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ _syscallhandler_readvHelper(SysCallHandler* sys, int fd, PluginPtr iovPtr,
158158
break;
159159
}
160160
case DT_TIMER:
161-
case DT_SOCKETPAIR:
161+
case DT_UNIXSOCKET:
162162
case DT_EPOLL:
163163
default: {
164164
warning(
@@ -277,7 +277,7 @@ _syscallhandler_writevHelper(SysCallHandler* sys, int fd, PluginPtr iovPtr,
277277
break;
278278
}
279279
case DT_TIMER:
280-
case DT_SOCKETPAIR:
280+
case DT_UNIXSOCKET:
281281
case DT_EPOLL:
282282
default: {
283283
warning(

src/main/host/syscall/unistd.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ static SysCallReturn _syscallhandler_pipeHelper(SysCallHandler* sys,
4646

4747
/* A pipe descriptor is simulated with our Channel object, where
4848
* one side is readonly, the other is writeonly. */
49-
Channel* pipeReader = channel_new(CT_READONLY);
50-
Channel* pipeWriter = channel_new(CT_WRITEONLY);
49+
Channel* pipeReader = channel_new(CT_READONLY, DT_PIPE);
50+
Channel* pipeWriter = channel_new(CT_WRITEONLY, DT_PIPE);
5151
channel_setLinkedChannel(pipeReader, pipeWriter);
5252
channel_setLinkedChannel(pipeWriter, pipeReader);
5353

@@ -146,7 +146,7 @@ static SysCallReturn _syscallhandler_readHelper(SysCallHandler* sys, int fd,
146146
// We already diverted these to the socket handler above.
147147
utility_assert(0);
148148
break;
149-
case DT_SOCKETPAIR:
149+
case DT_UNIXSOCKET:
150150
case DT_EPOLL:
151151
default:
152152
warning("write() not yet implemented for descriptor type %i",
@@ -237,7 +237,7 @@ static SysCallReturn _syscallhandler_writeHelper(SysCallHandler* sys, int fd,
237237
// We already diverted these to the socket handler above.
238238
utility_assert(0);
239239
break;
240-
case DT_SOCKETPAIR:
240+
case DT_UNIXSOCKET:
241241
case DT_EPOLL:
242242
default:
243243
warning("write(%d) not yet implemented for descriptor type %i", fd, (int)dType);

src/main/host/syscall_handler.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ SysCallReturn syscallhandler_make_syscall(SysCallHandler* sys,
281281
HANDLE(set_tid_address);
282282
HANDLE(shutdown);
283283
HANDLE(socket);
284+
HANDLE(socketpair);
284285
#ifdef SYS_statx
285286
HANDLE(statx);
286287
#endif

0 commit comments

Comments
 (0)