1 // =================================
  2 // Copyright (c) 2024 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using System;
  7 using System.IO;
  8 
  9 namespace System.Net.Sockets
 10 {
 11     public enum ShutdownMode : int
 12     {
 13         receive = 0send = 1both = 2
 14     }
 15 
 16     public class TcpSocket : IOBase
 17     {
 18         public TcpSocket() : handle(null)connected(false)shutdown(false)
 19         {
 20             int errorId = 0;
 21             handle = RtmCreateSocket(errorId);
 22             if (errorId != 0)
 23             {
 24                 SetErrorId(errorId);
 25             }
 26         }
 27         public TcpSocket(const string& nodeconst string& service) : handle(null)connected(false)shutdown(false)
 28         {
 29             int errorId = 0;
 30             handle = RtmConnectSocket(node.Chars()service.Chars()errorId);
 31             if (errorId != 0)
 32             {
 33                 SetErrorId(errorId);
 34             }
 35             else
 36             {
 37                 connected = true;
 38             }
 39         }
 40         public TcpSocket(const string& nodeint port) : this(nodeToString(port))
 41         {
 42         }
 43         public TcpSocket(void* handle_) : handle(handle_)connected(true)shutdown(false)
 44         {
 45         }
 46         public TcpSocket(TcpSocket&& that) : handle(that.handle)connected(that.connected)shutdown(that.shutdown)
 47         {
 48             that.handle = null;
 49             that.connected = false;
 50             that.shutdown = false;
 51         }
 52         public void operator=(TcpSocket&& that)
 53         {
 54             Swap(handlethat.handle);
 55             Swap(connectedthat.connected);
 56             Swap(shutdownthat.shutdown);
 57         }
 58         public override ~TcpSocket()
 59         {
 60             if (handle != null)
 61             {
 62                 if (connected && !shutdown)
 63                 {
 64                     auto result = Shutdown(ShutdownMode.both);
 65                 }
 66                 if (connected)
 67                 {
 68                     int errorId = 0;
 69                     RtmCloseSocket(handleerrorId);
 70                 }
 71                 RtmDestroySocket(handle);
 72             }
 73         }
 74         [nodiscard]
 75         public Result<bool> Close()
 76         {
 77             if (Error())
 78             {
 79                 return Result<bool>(ErrorId(GetErrorId()));
 80             }
 81             if (handle != null)
 82             {
 83                 if (connected && !shutdown)
 84                 {
 85                     auto result = Shutdown(ShutdownMode.both);
 86                     if (result.Error())
 87                     {
 88                         return result;
 89                     }
 90                 }
 91                 if (connected)
 92                 {
 93                     int errorId = 0;
 94                     RtmCloseSocket(handleerrorId);
 95                     if (errorId != 0)
 96                     {
 97                         SetErrorId(errorId);
 98                         return Result<bool>(ErrorId(errorId));
 99                     }
100                 }
101                 handle = null;
102                 connected = false;
103             }
104             return Result<bool>(true);
105         }
106         [nodiscard]
107         public Result<bool> Connect(const string& nodeint port)
108         {
109             if (Error())
110             {
111                 return Result<bool>(ErrorId(GetErrorId()));
112             }
113             return Connect(nodeToString(port));
114         }
115         [nodiscard]
116         public Result<bool> Connect(const string& nodeconst string& service)
117         {
118             if (Error())
119             {
120                 return Result<bool>(ErrorId(GetErrorId()));
121             }
122             auto result = Close();
123             if (result.Error())
124             {
125                 return Result<bool>(ErrorId(result.GetErrorId()));
126             }
127             int errorId = 0;
128             handle = RtmConnectSocket(node.Chars()service.Chars()errorId);
129             if (errorId != 0)
130             {
131                 SetErrorId(errorId);
132                 return Result<bool>(ErrorId(errorId));
133             }
134             connected = true;
135             return Result<bool>(true);
136         }
137         [nodiscard]
138         public Result<bool> Bind(int port)
139         {
140             if (Error())
141             {
142                 return Result<bool>(ErrorId(GetErrorId()));
143             }
144             int errorId = 0;
145             RtmBindSocket(handleporterrorId);
146             if (errorId != 0)
147             {
148                 SetErrorId(errorId);
149                 return Result<bool>(ErrorId(errorId));
150             }
151             return Result<bool>(true);
152         }
153         [nodiscard]
154         public Result<bool> Listen(int backlog)
155         {
156             if (Error())
157             {
158                 return Result<bool>(ErrorId(GetErrorId()));
159             }
160             int errorId = 0;
161             RtmListenSocket(handlebacklogerrorId);
162             if (errorId != 0)
163             {
164                 SetErrorId(errorId);
165                 return Result<bool>(ErrorId(errorId));
166             }
167             return Result<bool>(true);
168         }
169         [nodiscard]
170         public Result<TcpSocket> Accept()
171         {
172             if (Error())
173             {
174                 return Result<TcpSocket>(ErrorId(GetErrorId()));
175             }
176             int errorId = 0;
177             void* acceptedHandle = RtmAcceptSocket(handleerrorId);
178             if (errorId != 0)
179             {
180                 SetErrorId(errorId);
181                 return Result<TcpSocket>(ErrorId(errorId));
182             }
183             return Result<TcpSocket>(TcpSocket(acceptedHandle));
184         }
185         [nodiscard]
186         public Result<bool> Shutdown(ShutdownMode mode)
187         {
188             if (Error())
189             {
190                 return Result<bool>(ErrorId(GetErrorId()));
191             }
192             int errorId = 0;
193             RtmShutdownSocket(handlemodeerrorId);
194             if (errorId != 0)
195             {
196                 SetErrorId(errorId);
197                 return Result<bool>(ErrorId(errorId));
198             }
199             shutdown = true;
200             return Result<bool>(true);
201         }
202         [nodiscard]
203         public Result<int> Send(byte* bufferint count)
204         {
205             if (Error())
206             {
207                 return Result<int>(ErrorId(GetErrorId()));
208             }
209             int errorId = 0;
210             int result = RtmSendSocket(handlebuffercount0errorId);
211             if (errorId != 0)
212             {
213                 SetErrorId(errorId);
214                 return Result<int>(ErrorId(errorId));
215             }
216             return Result<int>(result);
217         }
218         [nodiscard]
219         public Result<bool> SendAll(byte* bufferint count)
220         {
221             if (Error())
222             {
223                 return Result<bool>(ErrorId(GetErrorId()));
224             }
225             byte* p = buffer;
226             while (count > 0)
227             {
228                 Result<int> bytesSentResult = Send(pcount);
229                 if (bytesSentResult.Error())
230                 {
231                     return Result<bool>(ErrorId(bytesSentResult.GetErrorId()));
232                 }
233                 int bytesSent = bytesSentResult.Value();
234                 p = p + bytesSent;
235                 count = count - bytesSent;
236             }
237             return Result<bool>(true);
238         }
239         [nodiscard]
240         public Result<int> Receive(byte* bufferint count)
241         {
242             if (Error())
243             {
244                 return Result<int>(ErrorId(GetErrorId()));
245             }
246             int errorId = 0;
247             int result = RtmReceiveSocket(handlebuffercount0errorId);
248             if (errorId != 0)
249             {
250                 SetErrorId(errorId);
251                 return Result<int>(ErrorId(errorId));
252             }
253             return Result<int>(result);
254         }
255         private void* handle;
256         private bool connected;
257         private bool shutdown;
258     }
259 
260 }