SLikeNet 0.1.3

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
RakNetSocket2_WindowsStore8.cpp
Go to the documentation of this file.
1 /*
2 * Original work: Copyright (c) 2014, Oculus VR, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * RakNet License.txt file in the licenses directory of this source tree. An additional grant
7 * of patent rights can be found in the RakNet Patents.txt file in the same directory.
8 *
9 *
10 * Modified work: Copyright (c) 2016-2017, SLikeSoft UG (haftungsbeschränkt)
11 *
12 * This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
13 * license found in the license.txt file in the root directory of this source tree.
14 */
15
16 #include "slikenet/EmptyHeader.h"
17
18 #ifdef RAKNET_SOCKET_2_INLINE_FUNCTIONS
19
20 #ifndef RAKNETSOCKET2_WINDOWS_STORE_8
21 #define RAKNETSOCKET2_WINDOWS_STORE_8
22
23 #if defined(WINDOWS_STORE_RT)
24
25 #include <ppltasks.h>
26 #include <collection.h>
27 #include "slikenet/string.h"
28 #include "slikenet/linux_adapter.h"
29 #include "slikenet/osx_adapter.h"
30
31 using namespace Concurrency;
32 using namespace Platform;
33 using namespace Windows::ApplicationModel::Core;
34 using namespace Windows::Foundation;
35 using namespace Windows::Networking;
36 using namespace Windows::Networking::Sockets;
37 using namespace Windows::UI::Core;
38 using namespace Windows::UI::Xaml;
39 using namespace Windows::UI::Xaml::Controls;
40 using namespace Windows::UI::Xaml::Navigation;
41 using namespace Windows::Storage::Streams;
42 //using namespace Platform::Collections;
43 //using namespace Windows::Foundation::Collections;
44
45 namespace SLNet
46 {
47
48 public ref class OutputStreamAndDataWriter sealed
49 {
50 public:
51 // http://msdn.microsoft.com/en-us/library/windows/apps/hh755807.aspx
52 property IOutputStream ^outputStream;
53 /*
54 {
55 IOutputStream ^ get() {return outputStream;}
56 void set(IOutputStream ^ value) {outputStream = value;}
57 }
58 */
59 property DataWriter ^dataWriter;
60 /*
61 {
62 DataWriter ^ get() {return dataWriter;}
63 void set(DataWriter ^ value) {dataWriter = value;}
64 }
65 */
66 private:
67 };
68
69 public ref class ListenerContext sealed
70 {
71 public:
72 ListenerContext(Windows::Networking::Sockets::DatagramSocket^ listener);
73 void OnMessage(Windows::Networking::Sockets::DatagramSocket^ socket, Windows::Networking::Sockets::DatagramSocketMessageReceivedEventArgs^ eventArguments);
74 OutputStreamAndDataWriter ^GetOutputStreamAndDataWriter(uint64_t s_addr);
75
76 private:
77 ~ListenerContext();
78 // CRITICAL_SECTION lock;
79 SimpleMutex outputStreamMapMutex;
80 Windows::Networking::Sockets::DatagramSocket^ listener;
81 //Windows::Storage::Streams::IOutputStream^ outputStream;
82 //Windows::Networking::HostName^ hostName;
83 //Platform::String^ port;
84 // http://msdn.microsoft.com/en-us/library/windows/apps/hh700103.aspx
85 Platform::Collections::Map<uint64_t,OutputStreamAndDataWriter^>^ outputStreamMap;
86
87 void EchoMessage(Windows::Networking::Sockets::DatagramSocketMessageReceivedEventArgs^ eventArguments);
88 };
89 }
90
91 using namespace SLNet;
92
93 ListenerContext::ListenerContext(Windows::Networking::Sockets::DatagramSocket^ listener)
94 {
95 this->listener = listener;
96 // InitializeCriticalSectionEx(&lock, 0, 0);
97 outputStreamMap = ref new Platform::Collections::Map<uint64_t,OutputStreamAndDataWriter^>();
98 }
99
100 ListenerContext::~ListenerContext()
101 {
102 // The listener can be closed in two ways:
103 // - explicit: by using delete operator (the listener is closed even if there are outstanding references to it).
104 // - implicit: by removing last reference to it (i.e. falling out-of-scope).
105 // In this case this is the last reference to the listener so both will yield the same result.
106 delete listener;
107 listener = nullptr;
108
109 // DeleteCriticalSection(&lock);
110 }
111
112 OutputStreamAndDataWriter ^ListenerContext::GetOutputStreamAndDataWriter(uint64_t s_addr)
113 {
114 outputStreamMapMutex.Lock();
115 if (outputStreamMap->HasKey(s_addr))
116 {
117 OutputStreamAndDataWriter ^o = outputStreamMap->Lookup(s_addr);
118 outputStreamMapMutex.Unlock();
119 return o;
120 }
121 outputStreamMapMutex.Unlock();
122 uint16_t port = s_addr & 0xFFFF;
123 uint32_t addr = (uint32_t) (s_addr >> 32);
124 //addr = ntohl(addr);
125 char buf[64];
126 unsigned char *ucp = (unsigned char *)&addr;
127 sprintf_s(buf, "%d.%d.%d.%d",
128 ucp[0] & 0xff,
129 ucp[1] & 0xff,
130 ucp[2] & 0xff,
131 ucp[3] & 0xff);
132 char portStr[32];
133 _itoa(port, portStr, 10);
134
135 SLNet::RakString rs1(buf);
136 WCHAR *w_char1 = rs1.ToWideChar();
137 HostName ^hostName = ref new HostName(ref new Platform::String(w_char1));
138 SLNet::RakString rs2(portStr);
139 WCHAR *w_char2 = rs2.ToWideChar();
140 task< IOutputStream^ > op(listener->GetOutputStreamAsync(hostName, ref new Platform::String(w_char2)));
141 op.wait();
142 OutputStreamAndDataWriter ^outputStreamAndDataWriter = ref new OutputStreamAndDataWriter;
143 outputStreamAndDataWriter->outputStream = op.get();
144 outputStreamAndDataWriter->dataWriter = ref new DataWriter(outputStreamAndDataWriter->outputStream);
145
146 rs1.DeallocWideChar(w_char1);
147 rs2.DeallocWideChar(w_char2);
148
149 outputStreamMapMutex.Lock();
150 if (outputStreamMap->HasKey(s_addr)==false)
151 {
152 outputStreamMap->Insert(s_addr, outputStreamAndDataWriter);
153 outputStreamMapMutex.Unlock();
154 return outputStreamAndDataWriter;
155 }
156 else
157 {
158 // Just use the one that was inserted from another thread
159 OutputStreamAndDataWriter ^o = outputStreamMap->Lookup(s_addr);
160 outputStreamMapMutex.Unlock();
161 return o;
162 }
163 }
164
165 void ListenerContext::OnMessage(Windows::Networking::Sockets::DatagramSocket^ socket, Windows::Networking::Sockets::DatagramSocketMessageReceivedEventArgs^ eventArguments)
166 {
167 HostName ^remoteHost=eventArguments->RemoteAddress;
168 eventArguments->RemoteAddress->DisplayName;
169 eventArguments->RemotePort;
170
171 RNS2_WindowsStore8 *rns2 = RNS2_WindowsStore8::GetRNS2FromDatagramSocket(socket);
172 if (rns2==0)
173 return;
174
175 //auto platformBuffer = ref new Platform::Array<BYTE>((unsigned char*) sendParameters->data, (UINT)sendParameters->length);
176 RNS2EventHandler *eventHandler = rns2->GetEventHandler();
177 RNS2RecvStruct *recvFromStruct = eventHandler->AllocRNS2RecvStruct(_FILE_AND_LINE_);
178
179 // http://stackoverflow.com/questions/11853838/getting-an-array-of-bytes-out-of-windowsstoragestreamsibuffer
180 IBuffer ^uselessBuffer = eventArguments->GetDataReader()->DetachBuffer();
181 Windows::Storage::Streams::DataReader^ uselessReader = Windows::Storage::Streams::DataReader::FromBuffer(uselessBuffer);
182 Platform::Array<unsigned char>^ managedBytes = ref new Platform::Array<unsigned char>(uselessBuffer->Length);
183 uselessReader->ReadBytes( managedBytes );
184 for(unsigned int i = 0; i < uselessBuffer->Length; i++)
185 recvFromStruct->data[i] = managedBytes[i];
186 recvFromStruct->bytesRead = uselessBuffer->Length;
187 char ip[64];
188 RakString rs2;
189 rs2.FromWideChar(eventArguments->RemoteAddress->DisplayName->Data());
190 strcpy_s(ip, rs2.C_String());
191 recvFromStruct->systemAddress.address.addr4.sin_addr.s_addr = RNS2_WindowsStore8::WinRTInet_Addr(ip);
192 char portStr[64];
193 rs2.FromWideChar(eventArguments->RemotePort->Data());
194 strcpy_s(portStr, rs2.C_String());
195 recvFromStruct->systemAddress.SetPortHostOrder(atoi(portStr));
196 recvFromStruct->timeRead= SLNet::GetTimeUS();
197 recvFromStruct->socket = rns2;
198 eventHandler->OnRNS2Recv(recvFromStruct);
199
200 /*
201 if (outputStream != nullptr)
202 {
203 EchoMessage(eventArguments);
204 return;
205 }
206
207
208 // We do not have an output stream yet so create one.
209 task<IOutputStream^>(socket->GetOutputStreamAsync(eventArguments->RemoteAddress, eventArguments->RemotePort)).then([this, socket, eventArguments] (IOutputStream^ stream)
210 {
211 // It might happen that the OnMessage was invoked more than once before the GetOutputStreamAsync completed.
212 // In this case we will end up with multiple streams - make sure we have just one of it.
213 EnterCriticalSection(&lock);
214
215 if (outputStream == nullptr)
216 {
217 outputStream = stream;
218 hostName = eventArguments->RemoteAddress;
219 port = eventArguments->RemotePort;
220 }
221
222 LeaveCriticalSection(&lock);
223
224 EchoMessage(eventArguments);
225 }).then([this, socket, eventArguments] (task<void> previousTask)
226 {
227 try
228 {
229 // Try getting all exceptions from the continuation chain above this point.
230 previousTask.get();
231 }
232 catch (Exception^ exception)
233 {
234 // NotifyUserFromAsyncThread("Getting an output stream failed with error: " + exception->Message, NotifyType::ErrorMessage);
235 }
236 });
237 */
238 }
239 void ListenerContext::EchoMessage(DatagramSocketMessageReceivedEventArgs^ eventArguments)
240 {
241 }
242 SLNet::DataStructures::List<RNS2_WindowsStore8*> RNS2_WindowsStore8::rns2List;
243 SimpleMutex RNS2_WindowsStore8::rns2ListMutex;
244 RNS2_WindowsStore8::RNS2_WindowsStore8()
245 {
246 rns2ListMutex.Lock();
247 rns2List.Insert(this, _FILE_AND_LINE_);
248 rns2ListMutex.Unlock();
249 }
250 RNS2_WindowsStore8::~RNS2_WindowsStore8()
251 {
252 unsigned int i;
253 rns2ListMutex.Lock();
254 for (i=0; i < rns2List.Size(); i++)
255 {
256 if (rns2List[i]==this)
257 {
258 rns2List.RemoveAtIndexFast(i);
259 break;
260 }
261 }
262 rns2ListMutex.Unlock();
263 }
264 RNS2_WindowsStore8 *RNS2_WindowsStore8::GetRNS2FromDatagramSocket(Windows::Networking::Sockets::DatagramSocket^ s)
265 {
266 RNS2_WindowsStore8 *out=0;
267 unsigned int i;
268 rns2ListMutex.Lock();
269 for (i=0; i < rns2List.Size(); i++)
270 {
271 if (rns2List[i]->listener==s)
272 {
273 out=rns2List[i];
274 break;
275 }
276 }
277 rns2ListMutex.Unlock();
278 return out;
279 }
280 RNS2BindResult RNS2_WindowsStore8::Bind( Platform::String ^localServiceName ) {
281
282 listener = ref new DatagramSocket();
283 listenerContext = ref new ListenerContext(listener);
284 listener->MessageReceived += ref new TypedEventHandler<DatagramSocket^, DatagramSocketMessageReceivedEventArgs^>(listenerContext, &ListenerContext::OnMessage);
285 // http://msdn.microsoft.com/en-us/library/dd492427.aspx
286 task<void> bindOp(listener->BindServiceNameAsync(localServiceName));
287 try
288 {
289 bindOp.wait();
290 }
291 catch (Exception^ exception)
292 {
293 return BR_FAILED_TO_BIND_SOCKET;
294 }
295
296 return BR_SUCCESS;
297 }
298 void RNS2_WindowsStore8::GetMyIP( SystemAddress addresses[MAXIMUM_NUMBER_OF_INTERNAL_IDS] ) {RakAssert("GetMyIP Unsupported" && 0);}
299 RNS2SendResult RNS2_WindowsStore8::Send( RNS2_SendParameters *sendParameters, const char *file, unsigned int line ) {
300 uint64_t s_addr = sendParameters->systemAddress.address.addr4.sin_addr.s_addr;
301 s_addr <<=32;
302 s_addr |= sendParameters->systemAddress.debugPort;
303 OutputStreamAndDataWriter ^outputStreamAndDataWriter = listenerContext->GetOutputStreamAndDataWriter(s_addr);
304 // DataWriter ^dataWriter = ref new DataWriter(outputStream);
305
306 auto platformBuffer = ref new Platform::Array<BYTE>((unsigned char*) sendParameters->data, (UINT)sendParameters->length);
307 outputStreamAndDataWriter->dataWriter->WriteBytes(platformBuffer);
308
309
310 // Write the locally buffered data to the network. Please note that write operation will succeed
311 // even if the server is not listening.
312 task<unsigned int>(outputStreamAndDataWriter->dataWriter->StoreAsync()).then([&] (task<unsigned int> writeTask)
313 {
314 try
315 {
316 // Try getting an excpetion.
317 // writeTask.get();
318 // SendOutput->Style = dynamic_cast<Windows::UI::Xaml::Style^>(rootPage->Resources->Lookup("StatusStyle"));
319 // SendOutput->Text = "\"" + stringToSend + "\" sent successfully";
320 }
321 catch (Exception^ exception)
322 {
323 // rootPage->NotifyUser("Send failed with error: " + exception->Message, NotifyType::ErrorMessage);
324 OutputDebugStringW(exception->Message->Data());
325 }
326 });
327
328 return 0;
329 }
330 void RNS2_WindowsStore8::DomainNameToIP( const char *domainName, char ip[65] ) {
331 ip[0]=0;
332
333 // RakAssert("DomainNameToIP Unsupported" && 0);
334
335 // std::string s_str = std::string(domainName);
336 // std::wstring wid_str = std::wstring(s_str.begin(), s_str.end());
337 // const wchar_t* w_char = wid_str.c_str();
338
339 SLNet::RakString rs(domainName);
340 WCHAR *w_char = rs.ToWideChar();
341
342 // DatagramSocket ^listener = ref new DatagramSocket();
343
344
345 // task<void> bindOp(listener->BindServiceNameAsync(ref new Platform::String()));
346 //bindOp.wait();
347
348 HostName ^hostName = ref new HostName(ref new Platform::String(w_char));
349 //HostName ^hostName = ref new HostName(ref new Platform::String(L"microsoft.com"));
350 //HostName ^hostName = ref new HostName(ref new Platform::String(L"127.0.0.1"));
351 //task< Windows::Foundation::Collections::IVectorView<EndpointPair^>^ > op(listener->GetEndpointPairsAsync(hostName, L"42"));
352 //listener->GetEndpointPairsAsync(hostName, L"42");
353 // task< Windows::Foundation::Collections::IVectorView<EndpointPair^>^ > op(DatagramSocket::GetEndpointPairsAsync(hostName, L"42"));
354
355 IAsyncOperation<Windows::Foundation::Collections::IVectorView<Windows::Networking::EndpointPair^>^>^ op = DatagramSocket::GetEndpointPairsAsync(hostName, L"0");
356
357 bool completed=false;
358 op->Completed = ref new AsyncOperationCompletedHandler< Windows::Foundation::Collections::IVectorView<Windows::Networking::EndpointPair^>^ >(
359 [&] (
360 IAsyncOperation< Windows::Foundation::Collections::IVectorView<Windows::Networking::EndpointPair^>^>^ result,
361 AsyncStatus status
362 ) {
363 Windows::Foundation::Collections::IVectorView<Windows::Networking::EndpointPair^>^ result2 = result->GetResults();
364 if (result2->Size>0)
365 {
366 Platform::String ^name = result2->GetAt(0)->RemoteHostName->DisplayName;
367 RakString rs2;
368 rs2.FromWideChar(name->Data());
369 strcpy_s(ip, rs2.C_String());
370 }
371 else
372 {
373 ip[0]=0;
374 }
375
376 result->Close();
377 completed=true;
378 }
379 ) ;
380
381 while (!completed)
382 RakSleep(0);
383 /*
384 op->Completed = ref new AsyncOperationCompletedHandler< Windows::Foundation::Collections::IVectorView<EndpointPair^>^ >(
385 [](IAsyncOperation< Windows::Foundation::Collections::IVectorView<EndpointPair^>^ >^ operation)
386 {
387 operation->GetResults();
388
389 });
390 */
391
392
393 // RakSleep(10000);
394 /*
395 try
396 {
397 op.wait();
398 }
399 catch (Exception^ exception)
400 {
401 int a=5;
402 }
403 Windows::Foundation::Collections::IVectorView<EndpointPair^>^view = op.get();
404 if (view->Size>0)
405 {
406 Platform::String ^name = view->GetAt(0)->RemoteHostName->DisplayName;
407 RakString rs2;
408 rs2.FromWideChar(name->Data());
409 strcpy_s(ip, rs2.C_String());
410 }
411 else
412 {
413 ip[0]=0;
414 }
415 */
416
417 rs.DeallocWideChar(w_char);
418
419 }
420
421
422 int RNS2_WindowsStore8::WinRTInet_Addr(const char *str) {
423 int parts[4];
424 unsigned char curVal;
425
426 const char *strIndex=str;
427 int partsIndex;
428
429 for (partsIndex=0; partsIndex < 4; partsIndex++)
430 parts[partsIndex]=0;
431
432 partsIndex=0;
433 curVal=0;
434 while (partsIndex < 4)
435 {
436 if (*strIndex < '0' || *strIndex > '9')
437 {
438 parts[partsIndex]=curVal;
439 partsIndex++;
440 curVal=0;
441
442 if (*strIndex==0)
443 break;
444 }
445 else
446 {
447 curVal*=10;
448 curVal+=*strIndex-'0';
449 }
450 strIndex++;
451 }
452
453 return htonl((parts[0]<<24) | (parts[1]<<16) | (parts[2]<<8) | (parts[3]<<0) );
454 }
455
456 int RNS2_WindowsStore8::WinRTSetSockOpt(Windows::Networking::Sockets::DatagramSocket ^s,
457 int level,
458 int optname,
459 const char * optval,
460 socklen_t optlen) {RakAssert("WinRTSetSockOpt Unsupported" && 0); return 0;}
461
462 int RNS2_WindowsStore8::WinRTIOCTLSocket(Windows::Networking::Sockets::DatagramSocket ^s,
463 long cmd,
464 unsigned long *argp) {RakAssert("WinRTIOCTLSocket Unsupported" && 0); return 0;}
465
466 int RNS2_WindowsStore8::WinRTGetSockName(Windows::Networking::Sockets::DatagramSocket ^s,
467 struct sockaddr *name,
468 socklen_t* namelen) {RakAssert("WinRTGetSockName Unsupported" && 0); return 0;}
469
470 #endif // WINDOWS_STORE_RT
471
472 #endif // file header
473
474 #endif // #ifdef RAKNET_SOCKET_2_INLINE_FUNCTIONS