194c47dc6SPawel Dziepak/*
2266b99b7SPawel Dziepak * Copyright 2012-2013 Haiku, Inc. All rights reserved.
394c47dc6SPawel Dziepak * Distributed under the terms of the MIT License.
494c47dc6SPawel Dziepak *
594c47dc6SPawel Dziepak * Authors:
694c47dc6SPawel Dziepak *		Pawe�� Dziepak, pdziepak@quarnos.org
794c47dc6SPawel Dziepak */
894c47dc6SPawel Dziepak
994c47dc6SPawel Dziepak
1094c47dc6SPawel Dziepak#include "RPCCallbackServer.h"
1194c47dc6SPawel Dziepak
1294c47dc6SPawel Dziepak#include "NFS4Defs.h"
1394c47dc6SPawel Dziepak#include "RPCCallback.h"
14feb15cc6SPawel Dziepak#include "RPCCallbackReply.h"
1594c47dc6SPawel Dziepak#include "RPCCallbackRequest.h"
16266b99b7SPawel Dziepak#include "RPCServer.h"
1794c47dc6SPawel Dziepak
1894c47dc6SPawel Dziepak
1994c47dc6SPawel Dziepakusing namespace RPC;
2094c47dc6SPawel Dziepak
2194c47dc6SPawel Dziepak
2294c47dc6SPawel DziepakCallbackServer* gRPCCallbackServer		= NULL;
23266b99b7SPawel DziepakCallbackServer* gRPCCallbackServer6		= NULL;
2494c47dc6SPawel Dziepak
2594c47dc6SPawel Dziepak
26266b99b7SPawel DziepakCallbackServer::CallbackServer(int networkFamily)
2794c47dc6SPawel Dziepak	:
2894c47dc6SPawel Dziepak	fConnectionList(NULL),
2994c47dc6SPawel Dziepak	fListener(NULL),
3094c47dc6SPawel Dziepak	fThreadRunning(false),
3141217416SPawel Dziepak	fCallbackArray(NULL),
3294c47dc6SPawel Dziepak	fArraySize(0),
33266b99b7SPawel Dziepak	fFreeSlot(-1),
34266b99b7SPawel Dziepak	fNetworkFamily(networkFamily)
3594c47dc6SPawel Dziepak{
3694c47dc6SPawel Dziepak	mutex_init(&fConnectionLock, NULL);
3794c47dc6SPawel Dziepak	mutex_init(&fThreadLock, NULL);
3894c47dc6SPawel Dziepak	rw_lock_init(&fArrayLock, NULL);
3994c47dc6SPawel Dziepak}
4094c47dc6SPawel Dziepak
4194c47dc6SPawel Dziepak
4294c47dc6SPawel DziepakCallbackServer::~CallbackServer()
4394c47dc6SPawel Dziepak{
4494c47dc6SPawel Dziepak	StopServer();
4594c47dc6SPawel Dziepak
4641217416SPawel Dziepak	free(fCallbackArray);
4794c47dc6SPawel Dziepak	rw_lock_destroy(&fArrayLock);
4894c47dc6SPawel Dziepak	mutex_destroy(&fThreadLock);
4994c47dc6SPawel Dziepak	mutex_destroy(&fConnectionLock);
5094c47dc6SPawel Dziepak}
5194c47dc6SPawel Dziepak
5294c47dc6SPawel Dziepak
53266b99b7SPawel DziepakCallbackServer*
54266b99b7SPawel DziepakCallbackServer::Get(Server* server)
55266b99b7SPawel Dziepak{
56266b99b7SPawel Dziepak	ASSERT(server != NULL);
57266b99b7SPawel Dziepak
58266b99b7SPawel Dziepak	int family = server->ID().Family();
59266b99b7SPawel Dziepak	ASSERT(family == AF_INET || family == AF_INET6);
60266b99b7SPawel Dziepak
61266b99b7SPawel Dziepak	int idx;
62266b99b7SPawel Dziepak	switch (family) {
63266b99b7SPawel Dziepak		case AF_INET:
64266b99b7SPawel Dziepak			idx = 0;
65266b99b7SPawel Dziepak			break;
66266b99b7SPawel Dziepak		case AF_INET6:
67266b99b7SPawel Dziepak			idx = 1;
68266b99b7SPawel Dziepak			break;
69266b99b7SPawel Dziepak		default:
70266b99b7SPawel Dziepak			return NULL;
71266b99b7SPawel Dziepak	}
72266b99b7SPawel Dziepak
73266b99b7SPawel Dziepak	MutexLocker _(fServerCreationLock);
74266b99b7SPawel Dziepak	if (fServers[idx] == NULL)
75266b99b7SPawel Dziepak		fServers[idx] = new CallbackServer(family);
76266b99b7SPawel Dziepak	return fServers[idx];
77266b99b7SPawel Dziepak}
78266b99b7SPawel Dziepak
79266b99b7SPawel Dziepak
80266b99b7SPawel Dziepakvoid
81266b99b7SPawel DziepakCallbackServer::ShutdownAll()
82266b99b7SPawel Dziepak{
83266b99b7SPawel Dziepak	MutexLocker _(fServerCreationLock);
84266b99b7SPawel Dziepak	for (unsigned int i = 0; i < sizeof(fServers) / sizeof(fServers[0]); i++)
85266b99b7SPawel Dziepak		delete fServers[i];
86266b99b7SPawel Dziepak	memset(&fServers, 0, sizeof(fServers));
87266b99b7SPawel Dziepak}
88266b99b7SPawel Dziepak
89266b99b7SPawel Dziepak
90266b99b7SPawel Dziepakmutex			CallbackServer::fServerCreationLock = MUTEX_INITIALIZER(NULL);
91266b99b7SPawel DziepakCallbackServer*	CallbackServer::fServers[2] = { NULL, NULL };
92266b99b7SPawel Dziepak
93266b99b7SPawel Dziepak
9494c47dc6SPawel Dziepakstatus_t
9594c47dc6SPawel DziepakCallbackServer::RegisterCallback(Callback* callback)
9694c47dc6SPawel Dziepak{
971e67a2cdSPawel Dziepak	ASSERT(callback != NULL);
981e67a2cdSPawel Dziepak
9994c47dc6SPawel Dziepak	status_t result = StartServer();
10094c47dc6SPawel Dziepak	if (result != B_OK)
10194c47dc6SPawel Dziepak		return result;
10294c47dc6SPawel Dziepak
10394c47dc6SPawel Dziepak	WriteLocker _(fArrayLock);
10494c47dc6SPawel Dziepak	if (fFreeSlot == -1) {
10594c47dc6SPawel Dziepak		uint32 newSize = max_c(fArraySize * 2, 4);
10694c47dc6SPawel Dziepak		uint32 size = newSize * sizeof(CallbackSlot);
10794c47dc6SPawel Dziepak		CallbackSlot* array	= reinterpret_cast<CallbackSlot*>(malloc(size));
10894c47dc6SPawel Dziepak		if (array == NULL)
10994c47dc6SPawel Dziepak			return B_NO_MEMORY;
11094c47dc6SPawel Dziepak
11194c47dc6SPawel Dziepak		if (fCallbackArray != NULL)
11294c47dc6SPawel Dziepak			memcpy(array, fCallbackArray, fArraySize * sizeof(CallbackSlot));
11394c47dc6SPawel Dziepak
11494c47dc6SPawel Dziepak		for (uint32 i = fArraySize; i < newSize; i++)
11594c47dc6SPawel Dziepak			array[i].fNext = i + 1;
11694c47dc6SPawel Dziepak
1174a153753SPawel Dziepak		array[newSize - 1].fNext = -1;
11894c47dc6SPawel Dziepak
11994c47dc6SPawel Dziepak		fCallbackArray = array;
12094c47dc6SPawel Dziepak		fFreeSlot = fArraySize;
12194c47dc6SPawel Dziepak		fArraySize = newSize;
12294c47dc6SPawel Dziepak	}
12394c47dc6SPawel Dziepak
12494c47dc6SPawel Dziepak	int32 id = fFreeSlot;
12594c47dc6SPawel Dziepak	fFreeSlot = fCallbackArray[id].fNext;
12694c47dc6SPawel Dziepak
12794c47dc6SPawel Dziepak	fCallbackArray[id].fCallback = callback;
12894c47dc6SPawel Dziepak	callback->SetID(id);
129266b99b7SPawel Dziepak	callback->SetCBServer(this);
13094c47dc6SPawel Dziepak
13194c47dc6SPawel Dziepak	return B_OK;
13294c47dc6SPawel Dziepak}
13394c47dc6SPawel Dziepak
13494c47dc6SPawel Dziepak
13594c47dc6SPawel Dziepakstatus_t
13694c47dc6SPawel DziepakCallbackServer::UnregisterCallback(Callback* callback)
13794c47dc6SPawel Dziepak{
1381e67a2cdSPawel Dziepak	ASSERT(callback != NULL);
139266b99b7SPawel Dziepak	ASSERT(callback->CBServer() == this);
1401e67a2cdSPawel Dziepak
14194c47dc6SPawel Dziepak	int32 id = callback->ID();
14294c47dc6SPawel Dziepak
14394c47dc6SPawel Dziepak	WriteLocker _(fArrayLock);
14494c47dc6SPawel Dziepak	fCallbackArray[id].fNext = fFreeSlot;
14594c47dc6SPawel Dziepak	fFreeSlot = id;
14694c47dc6SPawel Dziepak
147266b99b7SPawel Dziepak	callback->SetCBServer(NULL);
14894c47dc6SPawel Dziepak	return B_OK;
14994c47dc6SPawel Dziepak}
15094c47dc6SPawel Dziepak
15194c47dc6SPawel Dziepak
15294c47dc6SPawel Dziepakstatus_t
15394c47dc6SPawel DziepakCallbackServer::StartServer()
15494c47dc6SPawel Dziepak{
15594c47dc6SPawel Dziepak	MutexLocker _(fThreadLock);
15694c47dc6SPawel Dziepak	if (fThreadRunning)
15794c47dc6SPawel Dziepak		return B_OK;
15894c47dc6SPawel Dziepak
159266b99b7SPawel Dziepak	status_t result = ConnectionListener::Listen(&fListener, fNetworkFamily);
16094c47dc6SPawel Dziepak	if (result != B_OK)
16194c47dc6SPawel Dziepak		return result;
16294c47dc6SPawel Dziepak
16394c47dc6SPawel Dziepak	fThread = spawn_kernel_thread(&CallbackServer::ListenerThreadLauncher,
16494c47dc6SPawel Dziepak		"NFSv4 Callback Listener", B_NORMAL_PRIORITY, this);
16594c47dc6SPawel Dziepak	if (fThread < B_OK)
16694c47dc6SPawel Dziepak		return fThread;
16794c47dc6SPawel Dziepak
16894c47dc6SPawel Dziepak	fThreadRunning = true;
16994c47dc6SPawel Dziepak
17094c47dc6SPawel Dziepak	result = resume_thread(fThread);
17194c47dc6SPawel Dziepak	if (result != B_OK) {
17294c47dc6SPawel Dziepak		kill_thread(fThread);
17394c47dc6SPawel Dziepak		fThreadRunning = false;
17494c47dc6SPawel Dziepak		return result;
17594c47dc6SPawel Dziepak	}
17694c47dc6SPawel Dziepak
17794c47dc6SPawel Dziepak	return B_OK;
17894c47dc6SPawel Dziepak}
17994c47dc6SPawel Dziepak
18094c47dc6SPawel Dziepak
18194c47dc6SPawel Dziepakstatus_t
18294c47dc6SPawel DziepakCallbackServer::StopServer()
18394c47dc6SPawel Dziepak{
18494c47dc6SPawel Dziepak	MutexLocker _(&fThreadLock);
18594c47dc6SPawel Dziepak	if (!fThreadRunning)
18694c47dc6SPawel Dziepak		return B_OK;
18794c47dc6SPawel Dziepak
18894c47dc6SPawel Dziepak	fListener->Disconnect();
18994c47dc6SPawel Dziepak	status_t result;
19094c47dc6SPawel Dziepak	wait_for_thread(fThread, &result);
19194c47dc6SPawel Dziepak
19294c47dc6SPawel Dziepak	MutexLocker locker(fConnectionLock);
19394c47dc6SPawel Dziepak	while (fConnectionList != NULL) {
19494c47dc6SPawel Dziepak		ConnectionEntry* entry = fConnectionList;
19594c47dc6SPawel Dziepak		fConnectionList = entry->fNext;
19694c47dc6SPawel Dziepak		entry->fConnection->Disconnect();
197d8e2263fSPawel Dziepak
198d8e2263fSPawel Dziepak		status_t result;
199d8e2263fSPawel Dziepak		wait_for_thread(entry->fThread, &result);
200d8e2263fSPawel Dziepak
20194c47dc6SPawel Dziepak		delete entry->fConnection;
20294c47dc6SPawel Dziepak		delete entry;
20394c47dc6SPawel Dziepak	}
20494c47dc6SPawel Dziepak
20594c47dc6SPawel Dziepak	delete fListener;
20694c47dc6SPawel Dziepak
20794c47dc6SPawel Dziepak	fThreadRunning = false;
20894c47dc6SPawel Dziepak	return B_OK;
20994c47dc6SPawel Dziepak}
21094c47dc6SPawel Dziepak
21194c47dc6SPawel Dziepak
21294c47dc6SPawel Dziepakstatus_t
21394c47dc6SPawel DziepakCallbackServer::NewConnection(Connection* connection)
21494c47dc6SPawel Dziepak{
2151e67a2cdSPawel Dziepak	ASSERT(connection != NULL);
2161e67a2cdSPawel Dziepak
21794c47dc6SPawel Dziepak	ConnectionEntry* entry = new ConnectionEntry;
21894c47dc6SPawel Dziepak	entry->fConnection = connection;
21994c47dc6SPawel Dziepak	entry->fPrev = NULL;
22094c47dc6SPawel Dziepak
22194c47dc6SPawel Dziepak	MutexLocker locker(fConnectionLock);
22294c47dc6SPawel Dziepak	entry->fNext = fConnectionList;
223d8e2263fSPawel Dziepak	if (fConnectionList != NULL)
224d8e2263fSPawel Dziepak		fConnectionList->fPrev = entry;
22594c47dc6SPawel Dziepak	fConnectionList = entry;
22694c47dc6SPawel Dziepak	locker.Unlock();
22794c47dc6SPawel Dziepak
22894c47dc6SPawel Dziepak	void** arguments = reinterpret_cast<void**>(malloc(sizeof(void*) * 2));
22994c47dc6SPawel Dziepak	if (arguments == NULL)
23094c47dc6SPawel Dziepak		return B_NO_MEMORY;
23194c47dc6SPawel Dziepak
23294c47dc6SPawel Dziepak	arguments[0] = this;
2338019eaf1SPawel Dziepak	arguments[1] = entry;
23494c47dc6SPawel Dziepak
23594c47dc6SPawel Dziepak	thread_id thread;
23694c47dc6SPawel Dziepak	thread = spawn_kernel_thread(&CallbackServer::ConnectionThreadLauncher,
23794c47dc6SPawel Dziepak		"NFSv4 Callback Connection", B_NORMAL_PRIORITY, arguments);
23894c47dc6SPawel Dziepak	if (thread < B_OK) {
239d8e2263fSPawel Dziepak		ReleaseConnection(entry);
24094c47dc6SPawel Dziepak		free(arguments);
24194c47dc6SPawel Dziepak		return thread;
24294c47dc6SPawel Dziepak	}
24394c47dc6SPawel Dziepak
244d8e2263fSPawel Dziepak	entry->fThread = thread;
245d8e2263fSPawel Dziepak
24694c47dc6SPawel Dziepak	status_t result = resume_thread(thread);
24794c47dc6SPawel Dziepak	if (result != B_OK) {
24894c47dc6SPawel Dziepak		kill_thread(thread);
249d8e2263fSPawel Dziepak		ReleaseConnection(entry);
25094c47dc6SPawel Dziepak		free(arguments);
25194c47dc6SPawel Dziepak		return result;
25294c47dc6SPawel Dziepak	}
25394c47dc6SPawel Dziepak
25494c47dc6SPawel Dziepak	return B_OK;
25594c47dc6SPawel Dziepak}
25694c47dc6SPawel Dziepak
25794c47dc6SPawel Dziepak
25894c47dc6SPawel Dziepakstatus_t
25994c47dc6SPawel DziepakCallbackServer::ReleaseConnection(ConnectionEntry* entry)
26094c47dc6SPawel Dziepak{
2611e67a2cdSPawel Dziepak	ASSERT(entry != NULL);
2621e67a2cdSPawel Dziepak
26394c47dc6SPawel Dziepak	MutexLocker _(fConnectionLock);
26494c47dc6SPawel Dziepak	if (entry->fNext != NULL)
26594c47dc6SPawel Dziepak		entry->fNext->fPrev = entry->fPrev;
26694c47dc6SPawel Dziepak	if (entry->fPrev != NULL)
26794c47dc6SPawel Dziepak		entry->fPrev->fNext = entry->fNext;
26894c47dc6SPawel Dziepak	else
26994c47dc6SPawel Dziepak		fConnectionList = entry->fNext;
27094c47dc6SPawel Dziepak
27194c47dc6SPawel Dziepak	delete entry->fConnection;
27294c47dc6SPawel Dziepak	delete entry;
27394c47dc6SPawel Dziepak	return B_OK;
27494c47dc6SPawel Dziepak}
27594c47dc6SPawel Dziepak
27694c47dc6SPawel Dziepak
27794c47dc6SPawel Dziepakstatus_t
27894c47dc6SPawel DziepakCallbackServer::ConnectionThreadLauncher(void* object)
27994c47dc6SPawel Dziepak{
2801e67a2cdSPawel Dziepak	ASSERT(object != NULL);
2811e67a2cdSPawel Dziepak
28294c47dc6SPawel Dziepak	void** objects = reinterpret_cast<void**>(object);
28394c47dc6SPawel Dziepak	CallbackServer* server = reinterpret_cast<CallbackServer*>(objects[0]);
28494c47dc6SPawel Dziepak	ConnectionEntry* entry = reinterpret_cast<ConnectionEntry*>(objects[1]);
28594c47dc6SPawel Dziepak	free(objects);
28694c47dc6SPawel Dziepak
28794c47dc6SPawel Dziepak	return server->ConnectionThread(entry);
28894c47dc6SPawel Dziepak}
28994c47dc6SPawel Dziepak
29094c47dc6SPawel Dziepak
29194c47dc6SPawel Dziepakstatus_t
29294c47dc6SPawel DziepakCallbackServer::ConnectionThread(ConnectionEntry* entry)
29394c47dc6SPawel Dziepak{
2941e67a2cdSPawel Dziepak	ASSERT(entry != NULL);
2951e67a2cdSPawel Dziepak
29694c47dc6SPawel Dziepak	Connection* connection = entry->fConnection;
297feb15cc6SPawel Dziepak	CallbackReply* reply;
2988019eaf1SPawel Dziepak
29994c47dc6SPawel Dziepak	while (fThreadRunning) {
30094c47dc6SPawel Dziepak		uint32 size;
30194c47dc6SPawel Dziepak		void* buffer;
30294c47dc6SPawel Dziepak		status_t result = connection->Receive(&buffer, &size);
30394c47dc6SPawel Dziepak		if (result != B_OK) {
304d8e2263fSPawel Dziepak			if (result != ECONNABORTED)
305d8e2263fSPawel Dziepak				ReleaseConnection(entry);
30694c47dc6SPawel Dziepak			return result;
30794c47dc6SPawel Dziepak		}
30894c47dc6SPawel Dziepak
3095691cd56SPawel Dziepak		CallbackRequest* request
3105691cd56SPawel Dziepak			= new(std::nothrow) CallbackRequest(buffer, size);
311ce6f81f7SPawel Dziepak		if (request == NULL) {
31294c47dc6SPawel Dziepak			free(buffer);
313ce6f81f7SPawel Dziepak			continue;
314ce6f81f7SPawel Dziepak		} else if (request->Error() != B_OK) {
315feb15cc6SPawel Dziepak			reply = CallbackReply::Create(request->XID(), request->RPCError());
316feb15cc6SPawel Dziepak			if (reply != NULL) {
317feb15cc6SPawel Dziepak				connection->Send(reply->Stream().Buffer(),
318feb15cc6SPawel Dziepak					reply->Stream().Size());
319feb15cc6SPawel Dziepak				delete reply;
320feb15cc6SPawel Dziepak			}
321ce6f81f7SPawel Dziepak			delete request;
322feb15cc6SPawel Dziepak			continue;
32394c47dc6SPawel Dziepak		}
32494c47dc6SPawel Dziepak
32594c47dc6SPawel Dziepak		switch (request->Procedure()) {
32694c47dc6SPawel Dziepak			case CallbackProcCompound:
32794c47dc6SPawel Dziepak				GetCallback(request->ID())->EnqueueRequest(request, connection);
32894c47dc6SPawel Dziepak				break;
32994c47dc6SPawel Dziepak
33094c47dc6SPawel Dziepak			case CallbackProcNull:
331feb15cc6SPawel Dziepak				reply = CallbackReply::Create(request->XID());
332feb15cc6SPawel Dziepak				if (reply != NULL) {
333feb15cc6SPawel Dziepak					connection->Send(reply->Stream().Buffer(),
334feb15cc6SPawel Dziepak						reply->Stream().Size());
335feb15cc6SPawel Dziepak					delete reply;
336feb15cc6SPawel Dziepak				}
33794c47dc6SPawel Dziepak
33894c47dc6SPawel Dziepak			default:
339ce6f81f7SPawel Dziepak				delete request;
34094c47dc6SPawel Dziepak		}
34194c47dc6SPawel Dziepak	}
34294c47dc6SPawel Dziepak
34394c47dc6SPawel Dziepak	return B_OK;
34494c47dc6SPawel Dziepak}
34594c47dc6SPawel Dziepak
34694c47dc6SPawel Dziepak
34794c47dc6SPawel Dziepakstatus_t
34894c47dc6SPawel DziepakCallbackServer::ListenerThreadLauncher(void* object)
34994c47dc6SPawel Dziepak{
3501e67a2cdSPawel Dziepak	ASSERT(object != NULL);
3511e67a2cdSPawel Dziepak
35294c47dc6SPawel Dziepak	CallbackServer* server = reinterpret_cast<CallbackServer*>(object);
35394c47dc6SPawel Dziepak	return server->ListenerThread();
35494c47dc6SPawel Dziepak}
35594c47dc6SPawel Dziepak
35694c47dc6SPawel Dziepak
35794c47dc6SPawel Dziepakstatus_t
35894c47dc6SPawel DziepakCallbackServer::ListenerThread()
35994c47dc6SPawel Dziepak{
36094c47dc6SPawel Dziepak	while (fThreadRunning) {
36194c47dc6SPawel Dziepak		Connection* connection;
36299092223SPawel Dziepak
36394c47dc6SPawel Dziepak		status_t result = fListener->AcceptConnection(&connection);
36494c47dc6SPawel Dziepak		if (result != B_OK) {
36594c47dc6SPawel Dziepak			fThreadRunning = false;
36694c47dc6SPawel Dziepak			return result;
36794c47dc6SPawel Dziepak		}
36894c47dc6SPawel Dziepak		result = NewConnection(connection);
36994c47dc6SPawel Dziepak		if (result != B_OK)
37094c47dc6SPawel Dziepak			delete connection;
37194c47dc6SPawel Dziepak	}
37294c47dc6SPawel Dziepak
37394c47dc6SPawel Dziepak	return B_OK;
37494c47dc6SPawel Dziepak}
37594c47dc6SPawel Dziepak
376