1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using System;
  7 
  8 namespace System.Net.Sockets
  9 {
 10     public enum ShutdownMode : int
 11     {
 12         receive = 0send = 1both = 2
 13     }
 14     
 15     public enum ConnectOptions : int
 16     {
 17         none = 0useTls = 1 << 0
 18     }
 19     
 20     public class SocketException : Exception
 21     {
 22         public nothrow SocketException(const string& message_) : base(message_)
 23         {
 24         }
 25     }
 26 
 27     public class TcpSocket
 28     {
 29         public TcpSocket() : handle(null)connected(false)shutdown(false)
 30         {
 31             int errorStringHandle = -1;
 32             handle = RtCreateSocket(errorStringHandle);
 33             if (handle == null)
 34             {
 35                 string errorMessage = RtGetError(errorStringHandle);
 36                 RtDisposeError(errorStringHandle);
 37                 throw SocketException(errorMessage);
 38             }
 39         }
 40         public TcpSocket(const string& nodeconst string& serviceConnectOptions options) : handle(null)connected(false)shutdown(false)
 41         {
 42             int errorStringHandle = -1;
 43             handle = RtConnectSocket(node.Chars()service.Chars()cast<int>(options)errorStringHandle);
 44             if (handle == null)
 45             {
 46                 string errorMessage = RtGetError(errorStringHandle);
 47                 RtDisposeError(errorStringHandle);
 48                 throw SocketException(errorMessage);
 49             }
 50             else
 51             {
 52                 connected = true;
 53             }
 54         }
 55         public TcpSocket(const string& nodeconst string& service) : this(nodeserviceConnectOptions.none)
 56         {
 57         }
 58         public nothrow TcpSocket(void* handle_) : handle(handle_)connected(true)shutdown(false)
 59         {
 60         }
 61         suppress TcpSocket(const TcpSocket&);
 62         suppress void operator=(const TcpSocket&);
 63         public nothrow TcpSocket(TcpSocket&& that) : handle(that.handle)connected(that.connected)shutdown(that.shutdown)
 64         {
 65             that.handle = null;
 66             that.connected = false;
 67             that.shutdown = false;
 68         }
 69         public nothrow void operator=(TcpSocket&& that)
 70         {
 71             Swap(handlethat.handle);
 72             Swap(connectedthat.connected);
 73             Swap(shutdownthat.shutdown);
 74         }
 75         public ~TcpSocket()
 76         {
 77             if (handle != null)
 78             {
 79                 if (connected && !shutdown)
 80                 {
 81                     try
 82                     {
 83                         Shutdown(ShutdownMode.both);
 84                     }
 85                     catch (const Exception& ex)
 86                     {
 87                     }
 88                 }
 89                 if (connected)
 90                 {
 91                     int errorStringHandle = -1;
 92                     RtCloseSocket(handleerrorStringHandle);
 93                 }
 94                 RtDestroySocket(handle);
 95             }
 96         }
 97         public void Close()
 98         {
 99             if (handle != null)
100             {
101                 if (connected && !shutdown)
102                 {
103                     Shutdown(ShutdownMode.both);
104                 }
105                 int errorStringHandle = -1;
106                 if (!RtCloseSocket(handleerrorStringHandle))
107                 {
108                     string errorMessage = RtGetError(errorStringHandle);
109                     RtDisposeError(errorStringHandle);
110                     throw SocketException(errorMessage);
111                 }
112                 handle = null;
113                 connected = false;
114             }
115         }
116         public void Connect(const string& nodeconst string& service)
117         {
118             Connect(nodeserviceConnectOptions.none);
119         }
120         public void Connect(const string& nodeconst string& serviceConnectOptions options)
121         {
122             Close();
123             int errorStringHandle = -1;
124             handle = RtConnectSocket(node.Chars()service.Chars()cast<int>(options)errorStringHandle);
125             if (handle == null)
126             {
127                 string errorMessage = RtGetError(errorStringHandle);
128                 RtDisposeError(errorStringHandle);
129                 throw SocketException(errorMessage);
130             }
131             else
132             {
133                 connected = true;
134             }
135         }
136         public void Bind(int port)
137         {
138             int errorStringHandle = -1;
139             if (!RtBindSocket(handleporterrorStringHandle))
140             {
141                 string errorMessage = RtGetError(errorStringHandle);
142                 RtDisposeError(errorStringHandle);
143                 throw SocketException(errorMessage);
144             }
145         }
146         public void Listen(int backLog)
147         {
148             int errorStringHandle = -1;
149             if (!RtListenSocket(handlebackLogerrorStringHandle))
150             {
151                 string errorMessage = RtGetError(errorStringHandle);
152                 RtDisposeError(errorStringHandle);
153                 throw SocketException(errorMessage);
154             }
155         }
156         public TcpSocket Accept()
157         {
158             int errorStringHandle = -1;
159             void* acceptedHandle = RtAcceptSocket(handleerrorStringHandle);
160             if (acceptedHandle == null)
161             {
162                 string errorMessage = RtGetError(errorStringHandle);
163                 RtDisposeError(errorStringHandle);
164                 throw SocketException(errorMessage);
165             }
166             return TcpSocket(acceptedHandle);
167         }
168         public void Shutdown(ShutdownMode mode)
169         {
170             shutdown = true;
171             int errorStringHandle = -1;
172             if (!RtShutdownSocket(handlecast<int>(mode)errorStringHandle))
173             {
174                 string errorMessage = RtGetError(errorStringHandle);
175                 RtDisposeError(errorStringHandle);
176                 throw SocketException(errorMessage);
177             }
178         }
179         public int Send(byte* bufferint count)
180         {
181             int errorStringHandle = -1;
182             int result = RtSendSocket(handlebuffercount0errorStringHandle);
183             if (result < 0)
184             {
185                 string errorMessage = RtGetError(errorStringHandle);
186                 RtDisposeError(errorStringHandle);
187                 throw SocketException(errorMessage);
188             }
189             return result;
190         }
191         public int Receive(byte* bufferint count)
192         {
193             int errorStringHandle = -1;
194             int result = RtReceiveSocket(handlebuffercount0errorStringHandle);
195             if (result < 0)
196             {
197                 string errorMessage = RtGetError(errorStringHandle);
198                 RtDisposeError(errorStringHandle);
199                 throw SocketException(errorMessage);
200             }
201             return result;
202         }
203         private void* handle;
204         private bool connected;
205         private bool shutdown;
206     }
207 
208     public void Write(TcpSocket& socketconst string& str)
209     {
210         int size = cast<int>(str.Length());
211         byte[4] buffer;
212         MemoryWriter writer(&buffer[0]4);
213         writer.Write(size);
214         int bytesToSend = 4;
215         int offset = 0;
216         while (bytesToSend > 0)
217         {
218             int bytesSent = socket.Send(&buffer[0] + offsetbytesToSend);
219             bytesToSend = bytesToSend - bytesSent;
220             offset = offset + bytesSent;
221         }
222         byte* p = cast<byte*>(cast<void*>(str.Chars()));
223         int count = size;
224         while (count > 0)
225         {
226             int bytesSent = socket.Send(pcount);
227             p = p + bytesSent;
228             count = count - bytesSent;
229         }
230     }
231 
232     public string ReadStr(TcpSocket& socket)
233     {
234         byte[4] buffer;
235         int bytesToReceive = 4;
236         int offset = 0;
237         int bytesReceived = socket.Receive(&buffer[offset]bytesToReceive);
238         if (bytesReceived == 0)
239         {
240             return string();
241         }
242         bytesToReceive = bytesToReceive - bytesReceived;
243         offset = offset + bytesReceived;
244         while (bytesToReceive > 0)
245         {
246             bytesReceived = socket.Receive(&buffer[offset]bytesToReceive);
247             if (bytesReceived == 0)
248             {
249                 return string();
250             }
251             bytesToReceive = bytesToReceive - bytesReceived;
252             offset = offset + bytesReceived;
253         }
254         MemoryReader reader(&buffer[0]4);
255         int size = reader.ReadInt();
256         if (size == 0)
257         {
258             return string();
259         }
260         UniquePtr<byte> mem(cast<byte*>(MemAlloc(size)));
261         offset = 0;
262         bytesToReceive = size;
263         bytesReceived = socket.Receive(mem.Get() + offsetbytesToReceive);
264         if (bytesReceived == 0)
265         {
266             return string();
267         }
268         bytesToReceive = bytesToReceive - bytesReceived;
269         offset = offset + bytesReceived;
270         while (bytesToReceive > 0)
271         {
272             bytesReceived = socket.Receive(mem.Get() + offsetbytesToReceive);
273             if (bytesReceived == 0)
274             {
275                 return string();
276             }
277             bytesToReceive = bytesToReceive - bytesReceived;
278             offset = offset + bytesReceived;
279         }
280         string s(cast<const char*>(cast<void*>(mem.Get()))size);
281         return s;
282     }
283 }