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
906922SysCallReturn 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
943974SysCallReturn 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+ }
0 commit comments