1
2
3
4
5
6 using System;
7 using System.IO;
8
9 namespace System.Net.Sockets
10 {
11 public enum ShutdownMode : int
12 {
13 receive = 0, send = 1, both = 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& node, const 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& node, int port) : this(node, ToString(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(handle, that.handle);
55 Swap(connected, that.connected);
56 Swap(shutdown, that.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(handle, errorId);
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(handle, errorId);
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& node, int port)
108 {
109 if (Error())
110 {
111 return Result<bool>(ErrorId(GetErrorId()));
112 }
113 return Connect(node, ToString(port));
114 }
115 [nodiscard]
116 public Result<bool> Connect(const string& node, const 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(handle, port, errorId);
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(handle, backlog, errorId);
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(handle, errorId);
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(handle, mode, errorId);
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* buffer, int count)
204 {
205 if (Error())
206 {
207 return Result<int>(ErrorId(GetErrorId()));
208 }
209 int errorId = 0;
210 int result = RtmSendSocket(handle, buffer, count, 0, errorId);
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* buffer, int 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(p, count);
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* buffer, int count)
241 {
242 if (Error())
243 {
244 return Result<int>(ErrorId(GetErrorId()));
245 }
246 int errorId = 0;
247 int result = RtmReceiveSocket(handle, buffer, count, 0, errorId);
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 }