btrfs: [] on the end of a struct field is a variable length array.
[haiku.git] / src / add-ons / kernel / file_systems / nfs4 / RPCServer.cpp
blobfc5cb132a15fc48588a3cc68f80dd0ac757f2375
1 /*
2 * Copyright 2012 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Paweł Dziepak, pdziepak@quarnos.org
7 */
10 #include "RPCServer.h"
12 #include <stdlib.h>
14 #include <util/AutoLock.h>
15 #include <util/Random.h>
17 #include "RPCCallbackServer.h"
18 #include "RPCReply.h"
21 using namespace RPC;
24 RequestManager::RequestManager()
26 fQueueHead(NULL),
27 fQueueTail(NULL)
29 mutex_init(&fLock, NULL);
33 RequestManager::~RequestManager()
35 mutex_destroy(&fLock);
39 void
40 RequestManager::AddRequest(Request* request)
42 ASSERT(request != NULL);
44 MutexLocker _(fLock);
45 if (fQueueTail != NULL)
46 fQueueTail->fNext = request;
47 else
48 fQueueHead = request;
49 fQueueTail = request;
50 request->fNext = NULL;
54 Request*
55 RequestManager::FindRequest(uint32 xid)
57 MutexLocker _(fLock);
58 Request* req = fQueueHead;
59 Request* prev = NULL;
60 while (req != NULL) {
61 if (req->fXID == xid) {
62 if (prev != NULL)
63 prev->fNext = req->fNext;
64 if (fQueueTail == req)
65 fQueueTail = prev;
66 if (fQueueHead == req)
67 fQueueHead = req->fNext;
69 return req;
72 prev = req;
73 req = req->fNext;
76 return NULL;
80 Server::Server(Connection* connection, PeerAddress* address)
82 fConnection(connection),
83 fAddress(address),
84 fPrivateData(NULL),
85 fCallback(NULL),
86 fRepairCount(0),
87 fXID(get_random<uint32>())
89 ASSERT(connection != NULL);
90 ASSERT(address != NULL);
92 mutex_init(&fCallbackLock, NULL);
93 mutex_init(&fRepairLock, NULL);
95 _StartListening();
99 Server::~Server()
101 if (fCallback != NULL)
102 fCallback->CBServer()->UnregisterCallback(fCallback);
103 delete fCallback;
104 mutex_destroy(&fCallbackLock);
105 mutex_destroy(&fRepairLock);
107 delete fPrivateData;
109 fThreadCancel = true;
110 fConnection->Disconnect();
112 status_t result;
113 wait_for_thread(fThread, &result);
115 delete fConnection;
119 status_t
120 Server::_StartListening()
122 fThreadCancel = false;
123 fThreadError = B_OK;
124 fThread = spawn_kernel_thread(&Server::_ListenerThreadStart,
125 "NFSv4 Listener", B_NORMAL_PRIORITY, this);
126 if (fThread < B_OK)
127 return fThread;
129 status_t result = resume_thread(fThread);
130 if (result != B_OK) {
131 kill_thread(fThread);
132 return result;
135 return B_OK;
139 status_t
140 Server::SendCallAsync(Call* call, Reply** reply, Request** request)
142 ASSERT(call != NULL);
143 ASSERT(reply != NULL);
144 ASSERT(request != NULL);
146 if (fThreadError != B_OK && Repair() != B_OK)
147 return fThreadError;
149 Request* req = new(std::nothrow) Request;
150 if (req == NULL)
151 return B_NO_MEMORY;
153 uint32 xid = _GetXID();
154 call->SetXID(xid);
155 req->fXID = xid;
156 req->fReply = reply;
157 req->fEvent.Init(&req->fEvent, NULL);
158 req->fDone = false;
159 req->fError = B_OK;
160 req->fNext = NULL;
162 fRequests.AddRequest(req);
164 *request = req;
165 status_t error = ResendCallAsync(call, req);
166 if (error != B_OK)
167 delete req;
168 return error;
172 status_t
173 Server::ResendCallAsync(Call* call, Request* request)
175 ASSERT(call != NULL);
176 ASSERT(request != NULL);
178 if (fThreadError != B_OK && Repair() != B_OK) {
179 fRequests.FindRequest(request->fXID);
180 return fThreadError;
183 XDR::WriteStream& stream = call->Stream();
184 status_t result = fConnection->Send(stream.Buffer(), stream.Size());
185 if (result != B_OK) {
186 fRequests.FindRequest(request->fXID);
187 return result;
190 return B_OK;
194 status_t
195 Server::WakeCall(Request* request)
197 ASSERT(request != NULL);
199 Request* req = fRequests.FindRequest(request->fXID);
200 if (req == NULL)
201 return B_OK;
203 request->fError = B_FILE_ERROR;
204 *request->fReply = NULL;
205 request->fDone = true;
206 request->fEvent.NotifyAll();
208 return B_OK;
212 status_t
213 Server::Repair()
215 uint32 thisRepair = fRepairCount;
217 MutexLocker _(fRepairLock);
218 if (fRepairCount != thisRepair)
219 return B_OK;
221 fThreadCancel = true;
223 status_t result = fConnection->Reconnect();
224 if (result != B_OK)
225 return result;
227 wait_for_thread(fThread, &result);
228 result = _StartListening();
230 if (result == B_OK)
231 fRepairCount++;
233 return result;
237 Callback*
238 Server::GetCallback()
240 MutexLocker _(fCallbackLock);
242 if (fCallback == NULL) {
243 fCallback = new(std::nothrow) Callback(this);
244 if (fCallback == NULL)
245 return NULL;
247 CallbackServer* server = CallbackServer::Get(this);
248 if (server == NULL) {
249 delete fCallback;
250 return NULL;
253 if (server->RegisterCallback(fCallback) != B_OK) {
254 delete fCallback;
255 return NULL;
259 return fCallback;
263 uint32
264 Server::_GetXID()
266 return static_cast<uint32>(atomic_add(&fXID, 1));
270 status_t
271 Server::_Listener()
273 status_t result;
274 uint32 size;
275 void* buffer = NULL;
277 while (!fThreadCancel) {
278 result = fConnection->Receive(&buffer, &size);
279 if (result == B_NO_MEMORY)
280 continue;
281 else if (result != B_OK) {
282 fThreadError = result;
283 return result;
286 ASSERT(buffer != NULL && size > 0);
287 Reply* reply = new(std::nothrow) Reply(buffer, size);
288 if (reply == NULL) {
289 free(buffer);
290 continue;
293 Request* req = fRequests.FindRequest(reply->GetXID());
294 if (req != NULL) {
295 *req->fReply = reply;
296 req->fDone = true;
297 req->fEvent.NotifyAll();
298 } else
299 delete reply;
302 return B_OK;
306 status_t
307 Server::_ListenerThreadStart(void* object)
309 ASSERT(object != NULL);
311 Server* server = reinterpret_cast<Server*>(object);
312 return server->_Listener();
316 ServerManager::ServerManager()
318 fRoot(NULL)
320 mutex_init(&fLock, NULL);
324 ServerManager::~ServerManager()
326 mutex_destroy(&fLock);
330 status_t
331 ServerManager::Acquire(Server** _server, AddressResolver* resolver,
332 ProgramData* (*createPrivateData)(Server*))
334 PeerAddress address;
335 status_t result;
337 while ((result = resolver->GetNextAddress(&address)) == B_OK) {
338 result = _Acquire(_server, address, createPrivateData);
339 if (result == B_OK)
340 break;
343 return result;
347 status_t
348 ServerManager::_Acquire(Server** _server, const PeerAddress& address,
349 ProgramData* (*createPrivateData)(Server*))
351 ASSERT(_server != NULL);
352 ASSERT(createPrivateData != NULL);
354 status_t result;
356 MutexLocker locker(fLock);
357 ServerNode* node = _Find(address);
358 if (node != NULL) {
359 node->fRefCount++;
360 *_server = node->fServer;
362 return B_OK;
365 node = new(std::nothrow) ServerNode;
366 if (node == NULL)
367 return B_NO_MEMORY;
369 node->fID = address;
371 Connection* conn;
372 result = Connection::Connect(&conn, address);
373 if (result != B_OK) {
374 delete node;
375 return result;
378 node->fServer = new Server(conn, &node->fID);
379 if (node->fServer == NULL) {
380 delete node;
381 delete conn;
382 return B_NO_MEMORY;
384 node->fServer->SetPrivateData(createPrivateData(node->fServer));
386 node->fRefCount = 1;
387 node->fLeft = node->fRight = NULL;
389 ServerNode* nd = _Insert(node);
390 if (nd != node) {
391 nd->fRefCount++;
393 delete node->fServer;
394 delete node;
395 *_server = nd->fServer;
396 return B_OK;
399 *_server = node->fServer;
400 return B_OK;
404 void
405 ServerManager::Release(Server* server)
407 ASSERT(server != NULL);
409 MutexLocker _(fLock);
410 ServerNode* node = _Find(server->ID());
411 if (node != NULL) {
412 node->fRefCount--;
414 if (node->fRefCount == 0) {
415 _Delete(node);
416 delete node->fServer;
417 delete node;
423 ServerNode*
424 ServerManager::_Find(const PeerAddress& address)
426 ServerNode* node = fRoot;
427 while (node != NULL) {
428 if (node->fID == address)
429 return node;
430 if (node->fID < address)
431 node = node->fRight;
432 else
433 node = node->fLeft;
436 return node;
440 void
441 ServerManager::_Delete(ServerNode* node)
443 ASSERT(node != NULL);
445 bool found = false;
446 ServerNode* previous = NULL;
447 ServerNode* current = fRoot;
448 while (current != NULL) {
449 if (current->fID == node->fID) {
450 found = true;
451 break;
454 if (current->fID < node->fID) {
455 previous = current;
456 current = current->fRight;
457 } else {
458 previous = current;
459 current = current->fLeft;
463 if (!found)
464 return;
466 if (previous == NULL)
467 fRoot = NULL;
468 else if (current->fLeft == NULL && current->fRight == NULL) {
469 if (previous->fID < node->fID)
470 previous->fRight = NULL;
471 else
472 previous->fLeft = NULL;
473 } else if (current->fLeft != NULL && current->fRight == NULL) {
474 if (previous->fID < node->fID)
475 previous->fRight = current->fLeft;
476 else
477 previous->fLeft = current->fLeft;
478 } else if (current->fLeft == NULL && current->fRight != NULL) {
479 if (previous->fID < node->fID)
480 previous->fRight = current->fRight;
481 else
482 previous->fLeft = current->fRight;
483 } else {
484 ServerNode* left_prev = current;
485 ServerNode* left = current->fLeft;
487 while (left->fLeft != NULL) {
488 left_prev = left;
489 left = left->fLeft;
492 if (previous->fID < node->fID)
493 previous->fRight = left;
494 else
495 previous->fLeft = left;
498 left_prev->fLeft = NULL;
503 ServerNode*
504 ServerManager::_Insert(ServerNode* node)
506 ASSERT(node != NULL);
508 ServerNode* previous = NULL;
509 ServerNode* current = fRoot;
510 while (current != NULL) {
511 if (current->fID == node->fID)
512 return current;
513 if (current->fID < node->fID) {
514 previous = current;
515 current = current->fRight;
516 } else {
517 previous = current;
518 current = current->fLeft;
522 if (previous == NULL)
523 fRoot = node;
524 else if (previous->fID < node->fID)
525 previous->fRight = node;
526 else
527 previous->fLeft = node;
529 return node;