aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/WinSockHelper.cs
blob: 9df180235342580d33438cf3aaf8c223820e22bb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
using System;
using System.Collections.Generic;
using System.Net.Sockets;

namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
{
    static class WinSockHelper
    {
        private static readonly Dictionary<WsaError, LinuxError> _errorMap = new()
        {
            // WSAEINTR
            { WsaError.WSAEINTR,           LinuxError.EINTR },
            // WSAEWOULDBLOCK
            { WsaError.WSAEWOULDBLOCK,     LinuxError.EWOULDBLOCK },
            // WSAEINPROGRESS
            { WsaError.WSAEINPROGRESS,     LinuxError.EINPROGRESS },
            // WSAEALREADY
            { WsaError.WSAEALREADY,        LinuxError.EALREADY },
            // WSAENOTSOCK
            { WsaError.WSAENOTSOCK,        LinuxError.ENOTSOCK },
            // WSAEDESTADDRREQ
            { WsaError.WSAEDESTADDRREQ,    LinuxError.EDESTADDRREQ },
            // WSAEMSGSIZE
            { WsaError.WSAEMSGSIZE,        LinuxError.EMSGSIZE },
            // WSAEPROTOTYPE
            { WsaError.WSAEPROTOTYPE,      LinuxError.EPROTOTYPE },
            // WSAENOPROTOOPT
            { WsaError.WSAENOPROTOOPT,     LinuxError.ENOPROTOOPT },
            // WSAEPROTONOSUPPORT
            { WsaError.WSAEPROTONOSUPPORT, LinuxError.EPROTONOSUPPORT },
            // WSAESOCKTNOSUPPORT
            { WsaError.WSAESOCKTNOSUPPORT, LinuxError.ESOCKTNOSUPPORT },
            // WSAEOPNOTSUPP
            { WsaError.WSAEOPNOTSUPP,      LinuxError.EOPNOTSUPP },
            // WSAEPFNOSUPPORT
            { WsaError.WSAEPFNOSUPPORT,    LinuxError.EPFNOSUPPORT },
            // WSAEAFNOSUPPORT
            { WsaError.WSAEAFNOSUPPORT,    LinuxError.EAFNOSUPPORT },
            // WSAEADDRINUSE
            { WsaError.WSAEADDRINUSE,      LinuxError.EADDRINUSE },
            // WSAEADDRNOTAVAIL
            { WsaError.WSAEADDRNOTAVAIL,   LinuxError.EADDRNOTAVAIL },
            // WSAENETDOWN
            { WsaError.WSAENETDOWN,        LinuxError.ENETDOWN },
            // WSAENETUNREACH
            { WsaError.WSAENETUNREACH,     LinuxError.ENETUNREACH },
            // WSAENETRESET
            { WsaError.WSAENETRESET,       LinuxError.ENETRESET },
            // WSAECONNABORTED
            { WsaError.WSAECONNABORTED,    LinuxError.ECONNABORTED },
            // WSAECONNRESET
            { WsaError.WSAECONNRESET,      LinuxError.ECONNRESET },
            // WSAENOBUFS
            { WsaError.WSAENOBUFS,         LinuxError.ENOBUFS },
            // WSAEISCONN
            { WsaError.WSAEISCONN,         LinuxError.EISCONN },
            // WSAENOTCONN
            { WsaError.WSAENOTCONN,        LinuxError.ENOTCONN },
            // WSAESHUTDOWN
            { WsaError.WSAESHUTDOWN,       LinuxError.ESHUTDOWN },
            // WSAETOOMANYREFS
            { WsaError.WSAETOOMANYREFS,    LinuxError.ETOOMANYREFS },
            // WSAETIMEDOUT
            { WsaError.WSAETIMEDOUT,       LinuxError.ETIMEDOUT },
            // WSAECONNREFUSED
            { WsaError.WSAECONNREFUSED,    LinuxError.ECONNREFUSED },
            // WSAELOOP
            { WsaError.WSAELOOP,           LinuxError.ELOOP },
            // WSAENAMETOOLONG
            { WsaError.WSAENAMETOOLONG,    LinuxError.ENAMETOOLONG },
            // WSAEHOSTDOWN
            { WsaError.WSAEHOSTDOWN,       LinuxError.EHOSTDOWN },
            // WSAEHOSTUNREACH
            { WsaError.WSAEHOSTUNREACH,    LinuxError.EHOSTUNREACH },
            // WSAENOTEMPTY
            { WsaError.WSAENOTEMPTY,       LinuxError.ENOTEMPTY },
            // WSAEUSERS
            { WsaError.WSAEUSERS,          LinuxError.EUSERS },
            // WSAEDQUOT
            { WsaError.WSAEDQUOT,          LinuxError.EDQUOT },
            // WSAESTALE
            { WsaError.WSAESTALE,          LinuxError.ESTALE },
            // WSAEREMOTE
            { WsaError.WSAEREMOTE,         LinuxError.EREMOTE },
            // WSAEINVAL
            { WsaError.WSAEINVAL,          LinuxError.EINVAL },
            // WSAEFAULT
            { WsaError.WSAEFAULT,          LinuxError.EFAULT },
            // NOERROR
            { 0, 0 },
        };

        private static readonly Dictionary<int, LinuxError> _errorMapMacOs = new()
        {
            { 35, LinuxError.EAGAIN },
            { 11, LinuxError.EDEADLOCK },
            { 91, LinuxError.ENOMSG },
            { 90, LinuxError.EIDRM },
            { 77, LinuxError.ENOLCK },
            { 70, LinuxError.ESTALE },
            { 36, LinuxError.EINPROGRESS },
            { 37, LinuxError.EALREADY },
            { 38, LinuxError.ENOTSOCK },
            { 39, LinuxError.EDESTADDRREQ },
            { 40, LinuxError.EMSGSIZE },
            { 41, LinuxError.EPROTOTYPE },
            { 42, LinuxError.ENOPROTOOPT },
            { 43, LinuxError.EPROTONOSUPPORT },
            { 44, LinuxError.ESOCKTNOSUPPORT },
            { 45, LinuxError.EOPNOTSUPP },
            { 46, LinuxError.EPFNOSUPPORT },
            { 47, LinuxError.EAFNOSUPPORT },
            { 48, LinuxError.EADDRINUSE },
            { 49, LinuxError.EADDRNOTAVAIL },
            { 50, LinuxError.ENETDOWN },
            { 51, LinuxError.ENETUNREACH },
            { 52, LinuxError.ENETRESET },
            { 53, LinuxError.ECONNABORTED },
            { 54, LinuxError.ECONNRESET },
            { 55, LinuxError.ENOBUFS },
            { 56, LinuxError.EISCONN },
            { 57, LinuxError.ENOTCONN },
            { 58, LinuxError.ESHUTDOWN },
            { 60, LinuxError.ETIMEDOUT },
            { 61, LinuxError.ECONNREFUSED },
            { 64, LinuxError.EHOSTDOWN },
            { 65, LinuxError.EHOSTUNREACH },
            { 68, LinuxError.EUSERS },
            { 62, LinuxError.ELOOP },
            { 63, LinuxError.ENAMETOOLONG },
            { 66, LinuxError.ENOTEMPTY },
            { 69, LinuxError.EDQUOT },
            { 71, LinuxError.EREMOTE },
            { 78, LinuxError.ENOSYS },
            { 59, LinuxError.ETOOMANYREFS },
            { 92, LinuxError.EILSEQ },
            { 89, LinuxError.ECANCELED },
            { 84, LinuxError.EOVERFLOW },
        };

        private static readonly Dictionary<BsdSocketOption, SocketOptionName> _soSocketOptionMap = new()
        {
            { BsdSocketOption.SoDebug,       SocketOptionName.Debug },
            { BsdSocketOption.SoReuseAddr,   SocketOptionName.ReuseAddress },
            { BsdSocketOption.SoKeepAlive,   SocketOptionName.KeepAlive },
            { BsdSocketOption.SoDontRoute,   SocketOptionName.DontRoute },
            { BsdSocketOption.SoBroadcast,   SocketOptionName.Broadcast },
            { BsdSocketOption.SoUseLoopBack, SocketOptionName.UseLoopback },
            { BsdSocketOption.SoLinger,      SocketOptionName.Linger },
            { BsdSocketOption.SoOobInline,   SocketOptionName.OutOfBandInline },
            { BsdSocketOption.SoReusePort,   SocketOptionName.ReuseAddress },
            { BsdSocketOption.SoSndBuf,      SocketOptionName.SendBuffer },
            { BsdSocketOption.SoRcvBuf,      SocketOptionName.ReceiveBuffer },
            { BsdSocketOption.SoSndLoWat,    SocketOptionName.SendLowWater },
            { BsdSocketOption.SoRcvLoWat,    SocketOptionName.ReceiveLowWater },
            { BsdSocketOption.SoSndTimeo,    SocketOptionName.SendTimeout },
            { BsdSocketOption.SoRcvTimeo,    SocketOptionName.ReceiveTimeout },
            { BsdSocketOption.SoError,       SocketOptionName.Error },
            { BsdSocketOption.SoType,        SocketOptionName.Type },
        };

        private static readonly Dictionary<BsdSocketOption, SocketOptionName> _ipSocketOptionMap = new()
        {
            { BsdSocketOption.IpOptions,              SocketOptionName.IPOptions },
            { BsdSocketOption.IpHdrIncl,              SocketOptionName.HeaderIncluded },
            { BsdSocketOption.IpTtl,                  SocketOptionName.IpTimeToLive },
            { BsdSocketOption.IpMulticastIf,          SocketOptionName.MulticastInterface },
            { BsdSocketOption.IpMulticastTtl,         SocketOptionName.MulticastTimeToLive },
            { BsdSocketOption.IpMulticastLoop,        SocketOptionName.MulticastLoopback },
            { BsdSocketOption.IpAddMembership,        SocketOptionName.AddMembership },
            { BsdSocketOption.IpDropMembership,       SocketOptionName.DropMembership },
            { BsdSocketOption.IpDontFrag,             SocketOptionName.DontFragment },
            { BsdSocketOption.IpAddSourceMembership,  SocketOptionName.AddSourceMembership },
            { BsdSocketOption.IpDropSourceMembership, SocketOptionName.DropSourceMembership },
        };

        private static readonly Dictionary<BsdSocketOption, SocketOptionName> _tcpSocketOptionMap = new()
        {
            { BsdSocketOption.TcpNoDelay,   SocketOptionName.NoDelay },
            { BsdSocketOption.TcpKeepIdle,  SocketOptionName.TcpKeepAliveTime },
            { BsdSocketOption.TcpKeepIntvl, SocketOptionName.TcpKeepAliveInterval },
            { BsdSocketOption.TcpKeepCnt,   SocketOptionName.TcpKeepAliveRetryCount },
        };

        public static LinuxError ConvertError(WsaError errorCode)
        {
            if (OperatingSystem.IsMacOS())
            {
                if (_errorMapMacOs.TryGetValue((int)errorCode, out LinuxError errno))
                {
                    return errno;
                }
            }
            else
            {
                if (_errorMap.TryGetValue(errorCode, out LinuxError errno))
                {
                    return errno;
                }
            }

            return (LinuxError)errorCode;
        }

        public static bool TryConvertSocketOption(BsdSocketOption option, SocketOptionLevel level, out SocketOptionName name)
        {
            var table = level switch
            {
                SocketOptionLevel.Socket => _soSocketOptionMap,
                SocketOptionLevel.IP => _ipSocketOptionMap,
                SocketOptionLevel.Tcp => _tcpSocketOptionMap,
                _ => null,
            };

            if (table == null)
            {
                name = default;
                return false;
            }

            return table.TryGetValue(option, out name);
        }
    }
}