| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -2,40 +2,712 @@
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// Licensed under GPLv2 or any later version
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// Refer to the license.txt file included.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include "common/platform.h"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#if EMU_PLATFORM == PLATFORM_WINDOWS
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include <winsock2.h>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include <ws2tcpip.h>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#else
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include <sys/socket.h>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include <netinet/in.h>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include <netdb.h>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include <arpa/inet.h>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include <fcntl.h>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include <poll.h>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include "common/log.h"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include "common/scope_exit.h"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include "core/hle/hle.h"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include "core/hle/service/soc_u.h"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include <unordered_map>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#if EMU_PLATFORM == PLATFORM_WINDOWS
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#    define WSAEAGAIN      WSAEWOULDBLOCK
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#    define WSAEMULTIHOP   -1 // Invalid dummy value
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#    define ERRNO(x)       WSA##x
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#    define GET_ERRNO      WSAGetLastError()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#    define poll(x, y, z)  WSAPoll(x, y, z);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#else
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#    define ERRNO(x)       x
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#    define GET_ERRNO      errno
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#    define closesocket(x) close(x)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static const s32 SOCKET_ERROR_VALUE = -1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// Namespace SOC_U
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				namespace SOC_U {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				/// Holds the translation from system network errors to 3DS network errors
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static const std::unordered_map<int, int> error_map = { {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { E2BIG, 1 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(EACCES), 2 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(EADDRINUSE), 3 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(EADDRNOTAVAIL), 4 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(EAFNOSUPPORT), 5 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(EAGAIN), 6 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(EALREADY), 7 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(EBADF), 8 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { EBADMSG, 9 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { EBUSY, 10 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ECANCELED, 11 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ECHILD, 12 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(ECONNABORTED), 13 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(ECONNREFUSED), 14 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(ECONNRESET), 15 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { EDEADLK, 16 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(EDESTADDRREQ), 17 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { EDOM, 18 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(EDQUOT), 19 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { EEXIST, 20 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(EFAULT), 21 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { EFBIG, 22 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(EHOSTUNREACH), 23 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { EIDRM, 24 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { EILSEQ, 25 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(EINPROGRESS), 26 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(EINTR), 27 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(EINVAL), 28 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { EIO, 29 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(EISCONN), 30 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { EISDIR, 31 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(ELOOP), 32 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(EMFILE), 33 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { EMLINK, 34 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(EMSGSIZE), 35 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(EMULTIHOP), 36 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(ENAMETOOLONG), 37 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(ENETDOWN), 38 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(ENETRESET), 39 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(ENETUNREACH), 40 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ENFILE, 41 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(ENOBUFS), 42 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ENODATA, 43 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ENODEV, 44 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ENOENT, 45 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ENOEXEC, 46 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ENOLCK, 47 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ENOLINK, 48 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ENOMEM, 49 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ENOMSG, 50 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(ENOPROTOOPT), 51 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ENOSPC, 52 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ENOSR, 53 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ENOSTR, 54 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ENOSYS, 55 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(ENOTCONN), 56 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ENOTDIR, 57 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(ENOTEMPTY), 58 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(ENOTSOCK), 59 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ENOTSUP, 60 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ENOTTY, 61 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ENXIO, 62 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(EOPNOTSUPP), 63 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { EOVERFLOW, 64 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { EPERM, 65 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { EPIPE, 66 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { EPROTO, 67 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(EPROTONOSUPPORT), 68 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(EPROTOTYPE), 69 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERANGE, 70 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { EROFS, 71 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ESPIPE, 72 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ESRCH, 73 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(ESTALE), 74 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ETIME, 75 },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    { ERRNO(ETIMEDOUT), 76 }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				/// Converts a network error from platform-specific to 3ds-specific
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static int TranslateError(int error) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    auto found = error_map.find(error);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (found != error_map.end())
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return -found->second;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return error;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				/// Holds information about a particular socket
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				struct SocketHolder {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 socket_fd; ///< The socket descriptor
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    bool blocking; ///< Whether the socket is blocking or not, it is only read on Windows.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				/// Structure to represent the 3ds' pollfd structure, which is different than most implementations
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				struct CTRPollFD {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 fd; ///< Socket handle
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    union Events {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        u32 hex; ///< The complete value formed by the flags
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        BitField<0, 1, u32> pollin;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        BitField<1, 1, u32> pollpri;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        BitField<2, 1, u32> pollhup;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        BitField<3, 1, u32> pollerr;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        BitField<4, 1, u32> pollout;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        BitField<5, 1, u32> pollnval;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        Events& operator=(const Events& other) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            hex = other.hex;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            return *this;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        /// Translates the resulting events of a Poll operation from platform-specific to 3ds specific
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        static Events TranslateTo3DS(u32 input_event) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            Events ev = {};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            if (input_event & POLLIN)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                ev.pollin = 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            if (input_event & POLLPRI)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                ev.pollpri = 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            if (input_event & POLLHUP)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                ev.pollhup = 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            if (input_event & POLLERR)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                ev.pollerr = 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            if (input_event & POLLOUT)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                ev.pollout = 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            if (input_event & POLLNVAL)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                ev.pollnval = 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            return ev;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        /// Translates the resulting events of a Poll operation from 3ds specific to platform specific
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        static u32 TranslateToPlatform(Events input_event) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            u32 ret = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            if (input_event.pollin)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                ret |= POLLIN;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            if (input_event.pollpri)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                ret |= POLLPRI;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            if (input_event.pollhup)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                ret |= POLLHUP;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            if (input_event.pollerr)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                ret |= POLLERR;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            if (input_event.pollout)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                ret |= POLLOUT;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            if (input_event.pollnval)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                ret |= POLLNVAL;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            return ret;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    };
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    Events events; ///< Events to poll for (input)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    Events revents; ///< Events received (output)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    /// Converts a platform-specific pollfd to a 3ds specific structure
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    static CTRPollFD FromPlatform(pollfd const& fd) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        CTRPollFD result;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        result.events.hex = Events::TranslateTo3DS(fd.events).hex;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        result.revents.hex = Events::TranslateTo3DS(fd.revents).hex;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        result.fd = static_cast<u32>(fd.fd);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return result;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    /// Converts a 3ds specific pollfd to a platform-specific structure
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    static pollfd ToPlatform(CTRPollFD const& fd) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        pollfd result;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        result.events = Events::TranslateToPlatform(fd.events);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        result.revents = Events::TranslateToPlatform(fd.revents);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        result.fd = fd.fd;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return result;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				/// Union to represent the 3ds' sockaddr structure
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				union CTRSockAddr {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    /// Structure to represent a raw sockaddr
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    struct {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        u8 len; ///< The length of the entire structure, only the set fields count
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        u8 sa_family; ///< The address family of the sockaddr
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        u8 sa_data[0x1A]; ///< The extra data, this varies, depending on the address family
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    } raw;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    /// Structure to represent the 3ds' sockaddr_in structure
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    struct CTRSockAddrIn {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        u8 len; ///< The length of the entire structure
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        u8 sin_family; ///< The address family of the sockaddr_in
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        u16 sin_port; ///< The port associated with this sockaddr_in
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        u32 sin_addr; ///< The actual address of the sockaddr_in
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    } in;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    /// Convert a 3DS CTRSockAddr to a platform-specific sockaddr
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    static sockaddr ToPlatform(CTRSockAddr const& ctr_addr) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        sockaddr result;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        result.sa_family = ctr_addr.raw.sa_family;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        memset(result.sa_data, 0, sizeof(result.sa_data));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // We can not guarantee ABI compatibility between platforms so we copy the fields manually
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        switch (result.sa_family) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        case AF_INET:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            sockaddr_in* result_in = reinterpret_cast<sockaddr_in*>(&result);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            result_in->sin_port = ctr_addr.in.sin_port;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            result_in->sin_addr.s_addr = ctr_addr.in.sin_addr;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            memset(result_in->sin_zero, 0, sizeof(result_in->sin_zero));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        default:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            _dbg_assert_msg_(Service_SOC, false, "Unhandled address family (sa_family) in CTRSockAddr::ToPlatform");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return result;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    /// Convert a platform-specific sockaddr to a 3DS CTRSockAddr
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    static CTRSockAddr FromPlatform(sockaddr const& addr) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        CTRSockAddr result;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        result.raw.sa_family = static_cast<u8>(addr.sa_family);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // We can not guarantee ABI compatibility between platforms so we copy the fields manually
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        switch (result.raw.sa_family) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        case AF_INET:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            sockaddr_in const* addr_in = reinterpret_cast<sockaddr_in const*>(&addr);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            result.raw.len = sizeof(CTRSockAddrIn);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            result.in.sin_port = addr_in->sin_port;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            result.in.sin_addr = addr_in->sin_addr.s_addr;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        default:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            _dbg_assert_msg_(Service_SOC, false, "Unhandled address family (sa_family) in CTRSockAddr::ToPlatform");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return result;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				/// Holds info about the currently open sockets
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static std::unordered_map<u32, SocketHolder> open_sockets;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				/// Close all open sockets
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static void CleanupSockets() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    for (auto sock : open_sockets)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        closesocket(sock.second.socket_fd);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    open_sockets.clear();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static void Socket(Service::Interface* self) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32* cmd_buffer = Kernel::GetCommandBuffer();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 domain = cmd_buffer[1]; // Address family
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 type = cmd_buffer[2];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 protocol = cmd_buffer[3];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // Only 0 is allowed according to 3dbrew, using 0 will let the OS decide which protocol to use
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (protocol != 0) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        cmd_buffer[1] = UnimplementedFunction(ErrorModule::SOC).raw; // TODO(Subv): Correct error code
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (domain != AF_INET) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        cmd_buffer[1] = UnimplementedFunction(ErrorModule::SOC).raw; // TODO(Subv): Correct error code
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (type != SOCK_DGRAM && type != SOCK_STREAM) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        cmd_buffer[1] = UnimplementedFunction(ErrorModule::SOC).raw; // TODO(Subv): Correct error code
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 socket_handle = static_cast<u32>(::socket(domain, type, protocol));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (socket_handle != SOCKET_ERROR_VALUE)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        open_sockets[socket_handle] = { socket_handle, true };
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    int result = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (socket_handle == SOCKET_ERROR_VALUE)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        result = TranslateError(GET_ERRNO);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[1] = result;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[2] = socket_handle;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static void Bind(Service::Interface* self) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32* cmd_buffer = Kernel::GetCommandBuffer();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 socket_handle = cmd_buffer[1];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 len = cmd_buffer[2];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    CTRSockAddr* ctr_sock_addr = reinterpret_cast<CTRSockAddr*>(Memory::GetPointer(cmd_buffer[6]));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (ctr_sock_addr == nullptr) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        cmd_buffer[1] = -1; // TODO(Subv): Correct code
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    sockaddr sock_addr = CTRSockAddr::ToPlatform(*ctr_sock_addr);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    int res = ::bind(socket_handle, &sock_addr, std::max<u32>(sizeof(sock_addr), len));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    int result = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (res != 0)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        result = TranslateError(GET_ERRNO);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[2] = res;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[1] = result;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static void Fcntl(Service::Interface* self) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32* cmd_buffer = Kernel::GetCommandBuffer();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 socket_handle = cmd_buffer[1];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 ctr_cmd = cmd_buffer[2];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 ctr_arg = cmd_buffer[3];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    int result = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 posix_ret = 0; // TODO: Check what hardware returns for F_SETFL (unspecified by POSIX)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    SCOPE_EXIT({
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            cmd_buffer[1] = result;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            cmd_buffer[2] = posix_ret;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    });
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (ctr_cmd == 3) { // F_GETFL
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#if EMU_PLATFORM == PLATFORM_WINDOWS
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        posix_ret = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        auto iter = open_sockets.find(socket_handle);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if (iter != open_sockets.end() && iter->second.blocking == false)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            posix_ret |= 4; // O_NONBLOCK
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#else
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        int ret = ::fcntl(socket_handle, F_GETFL, 0);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if (ret == SOCKET_ERROR_VALUE) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            result = TranslateError(GET_ERRNO);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            posix_ret = -1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        posix_ret = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if (ret & O_NONBLOCK)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            posix_ret |= 4; // O_NONBLOCK
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    } else if (ctr_cmd == 4) { // F_SETFL
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#if EMU_PLATFORM == PLATFORM_WINDOWS
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        unsigned long tmp = (ctr_arg & 4 /* O_NONBLOCK */) ? 1 : 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        int ret = ioctlsocket(socket_handle, FIONBIO, &tmp);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if (ret == SOCKET_ERROR_VALUE) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            result = TranslateError(GET_ERRNO);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            posix_ret = -1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        auto iter = open_sockets.find(socket_handle);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if (iter != open_sockets.end())
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            iter->second.blocking = (tmp == 0);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#else
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        int flags = ::fcntl(socket_handle, F_GETFL, 0);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if (flags == SOCKET_ERROR_VALUE) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            result = TranslateError(GET_ERRNO);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            posix_ret = -1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        flags &= ~O_NONBLOCK;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if (ctr_arg & 4) // O_NONBLOCK
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            flags |= O_NONBLOCK;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        int ret = ::fcntl(socket_handle, F_SETFL, flags);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if (ret == SOCKET_ERROR_VALUE) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            result = TranslateError(GET_ERRNO);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            posix_ret = -1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    } else {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        LOG_ERROR(Service_SOC, "Unsupported command (%d) in fcntl call");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        result = TranslateError(EINVAL); // TODO: Find the correct error
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        posix_ret = -1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static void Listen(Service::Interface* self) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32* cmd_buffer = Kernel::GetCommandBuffer();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 socket_handle = cmd_buffer[1];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 backlog = cmd_buffer[2];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    int ret = ::listen(socket_handle, backlog);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    int result = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (ret != 0)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        result = TranslateError(GET_ERRNO);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[2] = ret;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[1] = result;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static void Accept(Service::Interface* self) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // TODO(Subv): Calling this function on a blocking socket will block the emu thread, 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // preventing graceful shutdown when closing the emulator, this can be fixed by always 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // performing nonblocking operations and spinlock until the data is available
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32* cmd_buffer = Kernel::GetCommandBuffer();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 socket_handle = cmd_buffer[1];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    socklen_t max_addr_len = static_cast<socklen_t>(cmd_buffer[2]);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    sockaddr addr;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    socklen_t addr_len = sizeof(addr);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 ret = static_cast<u32>(::accept(socket_handle, &addr, &addr_len));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (ret != SOCKET_ERROR_VALUE)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        open_sockets[ret] = { ret, true };
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    int result = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (ret == SOCKET_ERROR_VALUE) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        result = TranslateError(GET_ERRNO);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    } else {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        CTRSockAddr ctr_addr = CTRSockAddr::FromPlatform(addr);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        Memory::WriteBlock(cmd_buffer[0x104 >> 2], (const u8*)&ctr_addr, max_addr_len);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[2] = ret;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[1] = result;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static void GetHostId(Service::Interface* self) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32* cmd_buffer = Kernel::GetCommandBuffer();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    char name[128];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    gethostname(name, sizeof(name));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    hostent* host = gethostbyname(name);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    in_addr* addr = reinterpret_cast<in_addr*>(host->h_addr);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[2] = addr->s_addr;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[1] = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static void Close(Service::Interface* self) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32* cmd_buffer = Kernel::GetCommandBuffer();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 socket_handle = cmd_buffer[1];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    int ret = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    open_sockets.erase(socket_handle);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    ret = closesocket(socket_handle);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    int result = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (ret != 0)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        result = TranslateError(GET_ERRNO);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[2] = ret;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[1] = result;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static void SendTo(Service::Interface* self) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32* cmd_buffer = Kernel::GetCommandBuffer();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 socket_handle = cmd_buffer[1];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 len = cmd_buffer[2];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 flags = cmd_buffer[3];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 addr_len = cmd_buffer[4];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u8* input_buff = Memory::GetPointer(cmd_buffer[8]);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    CTRSockAddr* ctr_dest_addr = reinterpret_cast<CTRSockAddr*>(Memory::GetPointer(cmd_buffer[10]));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (ctr_dest_addr == nullptr) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        cmd_buffer[1] = -1; // TODO(Subv): Find the right error code
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    int ret = -1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (addr_len > 0) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        sockaddr dest_addr = CTRSockAddr::ToPlatform(*ctr_dest_addr);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        ret = ::sendto(socket_handle, (const char*)input_buff, len, flags, &dest_addr, sizeof(dest_addr));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    } else {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        ret = ::sendto(socket_handle, (const char*)input_buff, len, flags, nullptr, 0);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    int result = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (ret == SOCKET_ERROR_VALUE)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        result = TranslateError(GET_ERRNO);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[2] = ret;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[1] = result;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static void RecvFrom(Service::Interface* self) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // TODO(Subv): Calling this function on a blocking socket will block the emu thread, 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // preventing graceful shutdown when closing the emulator, this can be fixed by always 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // performing nonblocking operations and spinlock until the data is available
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32* cmd_buffer = Kernel::GetCommandBuffer();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 socket_handle = cmd_buffer[1];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 len = cmd_buffer[2];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 flags = cmd_buffer[3];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    socklen_t addr_len = static_cast<socklen_t>(cmd_buffer[4]);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u8* output_buff = Memory::GetPointer(cmd_buffer[0x104 >> 2]);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    sockaddr src_addr;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    socklen_t src_addr_len = sizeof(src_addr);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    int ret = ::recvfrom(socket_handle, (char*)output_buff, len, flags, &src_addr, &src_addr_len);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (cmd_buffer[0x1A0 >> 2] != 0) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        CTRSockAddr* ctr_src_addr = reinterpret_cast<CTRSockAddr*>(Memory::GetPointer(cmd_buffer[0x1A0 >> 2]));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        *ctr_src_addr = CTRSockAddr::FromPlatform(src_addr);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    int result = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    int total_received = ret;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (ret == SOCKET_ERROR_VALUE) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        result = TranslateError(GET_ERRNO);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        total_received = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[1] = result;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[2] = ret;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[3] = total_received;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static void Poll(Service::Interface* self) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32* cmd_buffer = Kernel::GetCommandBuffer();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 nfds = cmd_buffer[1];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    int timeout = cmd_buffer[2];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    CTRPollFD* input_fds = reinterpret_cast<CTRPollFD*>(Memory::GetPointer(cmd_buffer[6]));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    CTRPollFD* output_fds = reinterpret_cast<CTRPollFD*>(Memory::GetPointer(cmd_buffer[0x104 >> 2]));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // The 3ds_pollfd and the pollfd structures may be different (Windows/Linux have different sizes)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // so we have to copy the data
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    pollfd* platform_pollfd = new pollfd[nfds];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    for (unsigned current_fds = 0; current_fds < nfds; ++current_fds)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        platform_pollfd[current_fds] = CTRPollFD::ToPlatform(input_fds[current_fds]);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    int ret = ::poll(platform_pollfd, nfds, timeout);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // Now update the output pollfd structure
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    for (unsigned current_fds = 0; current_fds < nfds; ++current_fds)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        output_fds[current_fds] = CTRPollFD::FromPlatform(platform_pollfd[current_fds]);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    delete[] platform_pollfd;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    int result = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (ret == SOCKET_ERROR_VALUE)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        result = TranslateError(GET_ERRNO);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[1] = result;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[2] = ret;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static void GetSockName(Service::Interface* self) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32* cmd_buffer = Kernel::GetCommandBuffer();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 socket_handle = cmd_buffer[1];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    socklen_t ctr_len = cmd_buffer[2];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    CTRSockAddr* ctr_dest_addr = reinterpret_cast<CTRSockAddr*>(Memory::GetPointer(cmd_buffer[0x104 >> 2]));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    sockaddr dest_addr;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    socklen_t dest_addr_len = sizeof(dest_addr);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    int ret = ::getsockname(socket_handle, &dest_addr, &dest_addr_len);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (ctr_dest_addr != nullptr) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        *ctr_dest_addr = CTRSockAddr::FromPlatform(dest_addr);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    } else {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        cmd_buffer[1] = -1; // TODO(Subv): Verify error
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    int result = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (ret != 0)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        result = TranslateError(GET_ERRNO);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[2] = ret;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[1] = result;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static void Shutdown(Service::Interface* self) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32* cmd_buffer = Kernel::GetCommandBuffer();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 socket_handle = cmd_buffer[1];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    int how = cmd_buffer[2];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    int ret = ::shutdown(socket_handle, how);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    int result = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (ret != 0)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        result = TranslateError(GET_ERRNO);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[2] = ret;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[1] = result;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static void GetPeerName(Service::Interface* self) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32* cmd_buffer = Kernel::GetCommandBuffer();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 socket_handle = cmd_buffer[1];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    socklen_t len = cmd_buffer[2];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    CTRSockAddr* ctr_dest_addr = reinterpret_cast<CTRSockAddr*>(Memory::GetPointer(cmd_buffer[0x104 >> 2]));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    sockaddr dest_addr;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    socklen_t dest_addr_len = sizeof(dest_addr);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    int ret = ::getpeername(socket_handle, &dest_addr, &dest_addr_len);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (ctr_dest_addr != nullptr) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        *ctr_dest_addr = CTRSockAddr::FromPlatform(dest_addr);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    } else {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        cmd_buffer[1] = -1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    int result = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (ret != 0)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        result = TranslateError(GET_ERRNO);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[2] = ret;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[1] = result;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static void Connect(Service::Interface* self) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // TODO(Subv): Calling this function on a blocking socket will block the emu thread, 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // preventing graceful shutdown when closing the emulator, this can be fixed by always 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // performing nonblocking operations and spinlock until the data is available
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32* cmd_buffer = Kernel::GetCommandBuffer();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 socket_handle = cmd_buffer[1];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    socklen_t len = cmd_buffer[2];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    CTRSockAddr* ctr_input_addr = reinterpret_cast<CTRSockAddr*>(Memory::GetPointer(cmd_buffer[6]));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (ctr_input_addr == nullptr) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        cmd_buffer[1] = -1; // TODO(Subv): Verify error
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    sockaddr input_addr = CTRSockAddr::ToPlatform(*ctr_input_addr);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    int ret = ::connect(socket_handle, &input_addr, sizeof(input_addr));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    int result = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (ret != 0)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        result = TranslateError(GET_ERRNO);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[2] = ret;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[1] = result;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static void InitializeSockets(Service::Interface* self) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // TODO(Subv): Implement
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#if EMU_PLATFORM == PLATFORM_WINDOWS
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    WSADATA data;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    WSAStartup(MAKEWORD(2, 2), &data);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32* cmd_buffer = Kernel::GetCommandBuffer();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[1] = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static void ShutdownSockets(Service::Interface* self) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // TODO(Subv): Implement
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    CleanupSockets();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#if EMU_PLATFORM == PLATFORM_WINDOWS
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    WSACleanup();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32* cmd_buffer = Kernel::GetCommandBuffer();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmd_buffer[1] = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				const Interface::FunctionInfo FunctionTable[] = {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00010044, nullptr,                       "InitializeSockets"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x000200C2, nullptr,                       "socket"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00030082, nullptr,                       "listen"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00040082, nullptr,                       "accept"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00050084, nullptr,                       "bind"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00060084, nullptr,                       "connect"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00010044, InitializeSockets,             "InitializeSockets"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x000200C2, Socket,                        "Socket"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00030082, Listen,                        "Listen"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00040082, Accept,                        "Accept"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00050084, Bind,                          "Bind"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00060084, Connect,                       "Connect"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00070104, nullptr,                       "recvfrom_other"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00080102, nullptr,                       "recvfrom"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00080102, RecvFrom,                      "RecvFrom"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00090106, nullptr,                       "sendto_other"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x000A0106, nullptr,                       "sendto"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x000B0042, nullptr,                       "close"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x000C0082, nullptr,                       "shutdown"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x000D0082, nullptr,                       "gethostbyname"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x000E00C2, nullptr,                       "gethostbyaddr"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x000A0106, SendTo,                        "SendTo"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x000B0042, Close,                         "Close"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x000C0082, Shutdown,                      "Shutdown"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x000D0082, nullptr,                       "GetHostByName"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x000E00C2, nullptr,                       "GetHostByAddr"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x000F0106, nullptr,                       "unknown_resolve_ip"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00110102, nullptr,                       "getsockopt"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00120104, nullptr,                       "setsockopt"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x001300C2, nullptr,                       "fcntl"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00140084, nullptr,                       "poll"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00150042, nullptr,                       "sockatmark"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00160000, nullptr,                       "gethostid"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00170082, nullptr,                       "getsockname"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00180082, nullptr,                       "getpeername"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00190000, nullptr,                       "ShutdownSockets"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00110102, nullptr,                       "GetSockOpt"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00120104, nullptr,                       "SetSockOpt"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x001300C2, Fcntl,                         "Fcntl"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00140084, Poll,                          "Poll"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00150042, nullptr,                       "SockAtMark"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00160000, GetHostId,                     "GetHostId"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00170082, GetSockName,                   "GetSockName"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00180082, GetPeerName,                   "GetPeerName"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x00190000, ShutdownSockets,               "ShutdownSockets"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x001A00C0, nullptr,                       "GetNetworkOpt"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x001B0040, nullptr,                       "ICMPSocket"},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {0x001C0104, nullptr,                       "ICMPPing"},
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -52,4 +724,11 @@ Interface::Interface() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    Register(FunctionTable, ARRAY_SIZE(FunctionTable));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				Interface::~Interface() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    CleanupSockets();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#if EMU_PLATFORM == PLATFORM_WINDOWS
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    WSACleanup();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				} // namespace
 | 
			
		
		
	
	
		
			
				
					
					| 
						 
							
							
							
						 
					 | 
				
			
			 | 
			 | 
			
				 
 |