rev |
line source |
nuclear@0
|
1 /************************************************************************************
|
nuclear@0
|
2
|
nuclear@0
|
3 Filename : OVR_RPC1.cpp
|
nuclear@0
|
4 Content : A network plugin that provides remote procedure call functionality.
|
nuclear@0
|
5 Created : June 10, 2014
|
nuclear@0
|
6 Authors : Kevin Jenkins
|
nuclear@0
|
7
|
nuclear@0
|
8 Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
|
nuclear@0
|
9
|
nuclear@0
|
10 Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
|
nuclear@0
|
11 you may not use the Oculus VR Rift SDK except in compliance with the License,
|
nuclear@0
|
12 which is provided at the time of installation or download, or which
|
nuclear@0
|
13 otherwise accompanies this software in either electronic or hard copy form.
|
nuclear@0
|
14
|
nuclear@0
|
15 You may obtain a copy of the License at
|
nuclear@0
|
16
|
nuclear@0
|
17 http://www.oculusvr.com/licenses/LICENSE-3.2
|
nuclear@0
|
18
|
nuclear@0
|
19 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
|
nuclear@0
|
20 distributed under the License is distributed on an "AS IS" BASIS,
|
nuclear@0
|
21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
nuclear@0
|
22 See the License for the specific language governing permissions and
|
nuclear@0
|
23 limitations under the License.
|
nuclear@0
|
24
|
nuclear@0
|
25 ************************************************************************************/
|
nuclear@0
|
26
|
nuclear@0
|
27 #include "OVR_RPC1.h"
|
nuclear@0
|
28 #include "OVR_BitStream.h"
|
nuclear@0
|
29 #include "../Kernel/OVR_Threads.h" // Thread::MSleep
|
nuclear@0
|
30 #include "OVR_MessageIDTypes.h"
|
nuclear@0
|
31
|
nuclear@0
|
32 namespace OVR { namespace Net { namespace Plugins {
|
nuclear@0
|
33
|
nuclear@0
|
34
|
nuclear@0
|
35 //-----------------------------------------------------------------------------
|
nuclear@0
|
36 // Types
|
nuclear@0
|
37
|
nuclear@0
|
38 enum {
|
nuclear@0
|
39 ID_RPC4_SIGNAL,
|
nuclear@0
|
40 CALL_BLOCKING,
|
nuclear@0
|
41 RPC_ERROR_FUNCTION_NOT_REGISTERED,
|
nuclear@0
|
42 ID_RPC4_RETURN,
|
nuclear@0
|
43 };
|
nuclear@0
|
44
|
nuclear@0
|
45
|
nuclear@0
|
46 //-----------------------------------------------------------------------------
|
nuclear@0
|
47 // RPC1
|
nuclear@0
|
48
|
nuclear@0
|
49 RPC1::RPC1()
|
nuclear@0
|
50 {
|
nuclear@0
|
51 blockingOnThisConnection = 0;
|
nuclear@0
|
52 blockingReturnValue = new BitStream();
|
nuclear@0
|
53 }
|
nuclear@0
|
54
|
nuclear@0
|
55 RPC1::~RPC1()
|
nuclear@0
|
56 {
|
nuclear@0
|
57 slotHash.Clear();
|
nuclear@0
|
58 delete blockingReturnValue;
|
nuclear@0
|
59 }
|
nuclear@0
|
60
|
nuclear@0
|
61 void RPC1::RegisterSlot(OVR::String sharedIdentifier, OVR::Observer<RPCSlot>* rpcSlotObserver )
|
nuclear@0
|
62 {
|
nuclear@0
|
63 slotHash.AddObserverToSubject(sharedIdentifier, rpcSlotObserver);
|
nuclear@0
|
64 }
|
nuclear@0
|
65
|
nuclear@0
|
66 bool RPC1::RegisterBlockingFunction(OVR::String uniqueID, RPCDelegate blockingFunction)
|
nuclear@0
|
67 {
|
nuclear@0
|
68 if (registeredBlockingFunctions.Get(uniqueID))
|
nuclear@0
|
69 return false;
|
nuclear@0
|
70
|
nuclear@0
|
71 registeredBlockingFunctions.Set(uniqueID, blockingFunction);
|
nuclear@0
|
72 return true;
|
nuclear@0
|
73 }
|
nuclear@0
|
74
|
nuclear@0
|
75 void RPC1::UnregisterBlockingFunction(OVR::String uniqueID)
|
nuclear@0
|
76 {
|
nuclear@0
|
77 registeredBlockingFunctions.Remove(uniqueID);
|
nuclear@0
|
78 }
|
nuclear@0
|
79
|
nuclear@0
|
80 bool RPC1::CallBlocking( OVR::String uniqueID, OVR::Net::BitStream* bitStream, Ptr<Connection> pConnection, OVR::Net::BitStream* returnData )
|
nuclear@0
|
81 {
|
nuclear@0
|
82 // If invalid parameters,
|
nuclear@0
|
83 if (!pConnection)
|
nuclear@0
|
84 {
|
nuclear@0
|
85 // Note: This may happen if the endpoint disconnects just before the call
|
nuclear@0
|
86 return false;
|
nuclear@0
|
87 }
|
nuclear@0
|
88
|
nuclear@0
|
89 OVR::Net::BitStream out;
|
nuclear@0
|
90 out.Write((MessageID) OVRID_RPC1);
|
nuclear@0
|
91 out.Write((MessageID) CALL_BLOCKING);
|
nuclear@0
|
92 out.Write(uniqueID);
|
nuclear@0
|
93 if (bitStream)
|
nuclear@0
|
94 {
|
nuclear@0
|
95 bitStream->ResetReadPointer();
|
nuclear@0
|
96 out.AlignWriteToByteBoundary();
|
nuclear@0
|
97 out.Write(bitStream);
|
nuclear@0
|
98 }
|
nuclear@0
|
99
|
nuclear@0
|
100 SendParameters sp(pConnection, out.GetData(), out.GetNumberOfBytesUsed());
|
nuclear@0
|
101
|
nuclear@0
|
102 if (returnData)
|
nuclear@0
|
103 {
|
nuclear@0
|
104 returnData->Reset();
|
nuclear@0
|
105 }
|
nuclear@0
|
106
|
nuclear@0
|
107 // Only one thread call at a time
|
nuclear@0
|
108 Lock::Locker singleRPCLocker(&singleRPCLock);
|
nuclear@0
|
109
|
nuclear@0
|
110 // Note this does not prevent multiple calls at a time because .Wait will unlock it below.
|
nuclear@0
|
111 // The purpose of this mutex is to synchronize the polling thread and this one, not prevent
|
nuclear@0
|
112 // multiple threads from invoking RPC.
|
nuclear@0
|
113 Mutex::Locker locker(&callBlockingMutex);
|
nuclear@0
|
114
|
nuclear@0
|
115 blockingReturnValue->Reset();
|
nuclear@0
|
116 blockingOnThisConnection = pConnection;
|
nuclear@0
|
117
|
nuclear@0
|
118 int bytesSent = pSession->Send(&sp);
|
nuclear@0
|
119 if (bytesSent == sp.Bytes)
|
nuclear@0
|
120 {
|
nuclear@0
|
121 while (blockingOnThisConnection == pConnection)
|
nuclear@0
|
122 {
|
nuclear@0
|
123 callBlockingWait.Wait(&callBlockingMutex);
|
nuclear@0
|
124 }
|
nuclear@0
|
125 }
|
nuclear@0
|
126 else
|
nuclear@0
|
127 {
|
nuclear@0
|
128 return false;
|
nuclear@0
|
129 }
|
nuclear@0
|
130
|
nuclear@0
|
131 if (returnData)
|
nuclear@0
|
132 {
|
nuclear@0
|
133 returnData->Write(blockingReturnValue);
|
nuclear@0
|
134 returnData->ResetReadPointer();
|
nuclear@0
|
135 }
|
nuclear@0
|
136
|
nuclear@0
|
137 return true;
|
nuclear@0
|
138 }
|
nuclear@0
|
139
|
nuclear@0
|
140 bool RPC1::Signal(OVR::String sharedIdentifier, OVR::Net::BitStream* bitStream, Ptr<Connection> pConnection)
|
nuclear@0
|
141 {
|
nuclear@0
|
142 OVR::Net::BitStream out;
|
nuclear@0
|
143 out.Write((MessageID) OVRID_RPC1);
|
nuclear@0
|
144 out.Write((MessageID) ID_RPC4_SIGNAL);
|
nuclear@0
|
145 //out.Write(PluginId);
|
nuclear@0
|
146 out.Write(sharedIdentifier);
|
nuclear@0
|
147 if (bitStream)
|
nuclear@0
|
148 {
|
nuclear@0
|
149 bitStream->ResetReadPointer();
|
nuclear@0
|
150 out.AlignWriteToByteBoundary();
|
nuclear@0
|
151 out.Write(bitStream);
|
nuclear@0
|
152 }
|
nuclear@0
|
153 SendParameters sp(pConnection, out.GetData(), out.GetNumberOfBytesUsed());
|
nuclear@0
|
154 int32_t bytesSent = pSession->Send(&sp);
|
nuclear@0
|
155 return bytesSent == sp.Bytes;
|
nuclear@0
|
156 }
|
nuclear@0
|
157 void RPC1::BroadcastSignal(OVR::String sharedIdentifier, OVR::Net::BitStream* bitStream)
|
nuclear@0
|
158 {
|
nuclear@0
|
159 OVR::Net::BitStream out;
|
nuclear@0
|
160 out.Write((MessageID) OVRID_RPC1);
|
nuclear@0
|
161 out.Write((MessageID) ID_RPC4_SIGNAL);
|
nuclear@0
|
162 //out.Write(PluginId);
|
nuclear@0
|
163 out.Write(sharedIdentifier);
|
nuclear@0
|
164 if (bitStream)
|
nuclear@0
|
165 {
|
nuclear@0
|
166 bitStream->ResetReadPointer();
|
nuclear@0
|
167 out.AlignWriteToByteBoundary();
|
nuclear@0
|
168 out.Write(bitStream);
|
nuclear@0
|
169 }
|
nuclear@0
|
170 BroadcastParameters p(out.GetData(), out.GetNumberOfBytesUsed());
|
nuclear@0
|
171 pSession->Broadcast(&p);
|
nuclear@0
|
172 }
|
nuclear@0
|
173 void RPC1::OnReceive(ReceivePayload *pPayload, ListenerReceiveResult *lrrOut)
|
nuclear@0
|
174 {
|
nuclear@0
|
175 OVR_UNUSED(lrrOut);
|
nuclear@0
|
176
|
nuclear@0
|
177 if (pPayload->pData[0] == OVRID_RPC1)
|
nuclear@0
|
178 {
|
nuclear@0
|
179 OVR_ASSERT(pPayload->Bytes >= 2);
|
nuclear@0
|
180
|
nuclear@0
|
181 OVR::Net::BitStream bsIn((char*)pPayload->pData, pPayload->Bytes, false);
|
nuclear@0
|
182 bsIn.IgnoreBytes(2);
|
nuclear@0
|
183
|
nuclear@0
|
184 if (pPayload->pData[1] == RPC_ERROR_FUNCTION_NOT_REGISTERED)
|
nuclear@0
|
185 {
|
nuclear@0
|
186 Mutex::Locker locker(&callBlockingMutex);
|
nuclear@0
|
187
|
nuclear@0
|
188 blockingReturnValue->Reset();
|
nuclear@0
|
189 blockingOnThisConnection = 0;
|
nuclear@0
|
190 callBlockingWait.NotifyAll();
|
nuclear@0
|
191 }
|
nuclear@0
|
192 else if (pPayload->pData[1] == ID_RPC4_RETURN)
|
nuclear@0
|
193 {
|
nuclear@0
|
194 Mutex::Locker locker(&callBlockingMutex);
|
nuclear@0
|
195
|
nuclear@0
|
196 blockingReturnValue->Reset();
|
nuclear@0
|
197 blockingReturnValue->Write(bsIn);
|
nuclear@0
|
198 blockingOnThisConnection = 0;
|
nuclear@0
|
199 callBlockingWait.NotifyAll();
|
nuclear@0
|
200 }
|
nuclear@0
|
201 else if (pPayload->pData[1] == CALL_BLOCKING)
|
nuclear@0
|
202 {
|
nuclear@0
|
203 OVR::String uniqueId;
|
nuclear@0
|
204 bsIn.Read(uniqueId);
|
nuclear@0
|
205
|
nuclear@0
|
206 RPCDelegate *bf = registeredBlockingFunctions.Get(uniqueId);
|
nuclear@0
|
207 if (bf==0)
|
nuclear@0
|
208 {
|
nuclear@0
|
209 OVR::Net::BitStream bsOut;
|
nuclear@0
|
210 bsOut.Write((unsigned char) OVRID_RPC1);
|
nuclear@0
|
211 bsOut.Write((unsigned char) RPC_ERROR_FUNCTION_NOT_REGISTERED);
|
nuclear@0
|
212
|
nuclear@0
|
213 SendParameters sp(pPayload->pConnection, bsOut.GetData(), bsOut.GetNumberOfBytesUsed());
|
nuclear@0
|
214 pSession->Send(&sp);
|
nuclear@0
|
215
|
nuclear@0
|
216 return;
|
nuclear@0
|
217 }
|
nuclear@0
|
218
|
nuclear@0
|
219 OVR::Net::BitStream returnData;
|
nuclear@0
|
220 bsIn.AlignReadToByteBoundary();
|
nuclear@0
|
221 (*bf)(&bsIn, &returnData, pPayload);
|
nuclear@0
|
222
|
nuclear@0
|
223 OVR::Net::BitStream out;
|
nuclear@0
|
224 out.Write((MessageID) OVRID_RPC1);
|
nuclear@0
|
225 out.Write((MessageID) ID_RPC4_RETURN);
|
nuclear@0
|
226 returnData.ResetReadPointer();
|
nuclear@0
|
227 out.AlignWriteToByteBoundary();
|
nuclear@0
|
228 out.Write(returnData);
|
nuclear@0
|
229
|
nuclear@0
|
230 SendParameters sp(pPayload->pConnection, out.GetData(), out.GetNumberOfBytesUsed());
|
nuclear@0
|
231 pSession->Send(&sp);
|
nuclear@0
|
232 }
|
nuclear@0
|
233 else if (pPayload->pData[1]==ID_RPC4_SIGNAL)
|
nuclear@0
|
234 {
|
nuclear@0
|
235 OVR::String sharedIdentifier;
|
nuclear@0
|
236 bsIn.Read(sharedIdentifier);
|
nuclear@0
|
237
|
nuclear@0
|
238 Observer<RPCSlot> *o = slotHash.GetSubject(sharedIdentifier);
|
nuclear@0
|
239
|
nuclear@0
|
240 if (o)
|
nuclear@0
|
241 {
|
nuclear@0
|
242 bsIn.AlignReadToByteBoundary();
|
nuclear@0
|
243
|
nuclear@0
|
244 if (o)
|
nuclear@0
|
245 {
|
nuclear@0
|
246 OVR::Net::BitStream serializedParameters(bsIn.GetData() + bsIn.GetReadOffset()/8, bsIn.GetNumberOfUnreadBits()/8, false);
|
nuclear@0
|
247
|
nuclear@0
|
248 o->Call(&serializedParameters, pPayload);
|
nuclear@0
|
249 }
|
nuclear@0
|
250 }
|
nuclear@0
|
251 }
|
nuclear@0
|
252 }
|
nuclear@0
|
253 }
|
nuclear@0
|
254
|
nuclear@0
|
255 void RPC1::OnDisconnected(Connection* conn)
|
nuclear@0
|
256 {
|
nuclear@0
|
257 if (blockingOnThisConnection == conn)
|
nuclear@0
|
258 {
|
nuclear@0
|
259 blockingOnThisConnection = 0;
|
nuclear@0
|
260 callBlockingWait.NotifyAll();
|
nuclear@0
|
261 }
|
nuclear@0
|
262 }
|
nuclear@0
|
263
|
nuclear@0
|
264 void RPC1::OnConnected(Connection* conn)
|
nuclear@0
|
265 {
|
nuclear@0
|
266 OVR_UNUSED(conn);
|
nuclear@0
|
267 }
|
nuclear@0
|
268
|
nuclear@0
|
269
|
nuclear@0
|
270 }}} // OVR::Net::Plugins
|