⛏️ index : haiku.git

/*
 * Copyright 2012 Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Paweł Dziepak, pdziepak@quarnos.org
 */


#include "Request.h"

#include "FileSystem.h"
#include "Inode.h"


status_t
Request::Send(Cookie* cookie)
{
	switch (fServer->ID().fProtocol) {
		case IPPROTO_UDP:	return _SendUDP(cookie);
		case IPPROTO_TCP:	return _SendTCP(cookie);
	}

	return B_BAD_VALUE;
}


status_t
Request::_SendUDP(Cookie* cookie)
{
	RPC::Reply* rpl = NULL;
	RPC::Request* rpc;

	status_t result = fServer->SendCallAsync(fBuilder.Request(), &rpl, &rpc);
	if (result != B_OK)
		return result;

	if (cookie != NULL)
		cookie->RegisterRequest(rpc);

	int requestTimeout = sSecToBigTime(60);
	int retryLimit = 0;
	bool hard = true;

	if (fFileSystem != NULL) {
		requestTimeout = fFileSystem->GetConfiguration().fRequestTimeout;
		retryLimit = fFileSystem->GetConfiguration().fRetryLimit;
		hard = fFileSystem->GetConfiguration().fHard;
	}

	if (fSingleAttempt) {
		requestTimeout /= 10;
		retryLimit = 0;
	}

	result = fServer->WaitCall(rpc, requestTimeout);
	if (result != B_OK) {
		int attempts = 1;
		while (result != B_OK && (hard || attempts++ < retryLimit)) {
			result = fServer->ResendCallAsync(fBuilder.Request(), rpc);
			if (result != B_OK) {
				if (cookie != NULL)
					cookie->UnregisterRequest(rpc);
				delete rpc;
				return result;
			}

			result = fServer->WaitCall(rpc, requestTimeout);
		}

		if (result != B_OK) {
			if (cookie != NULL)
				cookie->UnregisterRequest(rpc);
			fServer->CancelCall(rpc);
			delete rpc;
			return result;
		}
	}

	if (cookie != NULL)
		cookie->UnregisterRequest(rpc);

	if (rpc->fError != B_OK) {
		delete rpl;
		result = rpc->fError;
		delete rpc;
		return result;
	} else {
		fReply.SetTo(rpl);
		delete rpc;
		return B_OK;
	}
}


status_t
Request::_SendTCP(Cookie* cookie)
{
	RPC::Reply* rpl = NULL;
	RPC::Request* rpc;

	status_t result;
	int attempts = 0;

	int requestTimeout = sSecToBigTime(60);
	int retryLimit = 0;
	bool hard = true;

	if (fFileSystem != NULL) {
		requestTimeout = fFileSystem->GetConfiguration().fRequestTimeout;
		retryLimit = fFileSystem->GetConfiguration().fRetryLimit;
		hard = fFileSystem->GetConfiguration().fHard;
	}

	if (fSingleAttempt) {
		requestTimeout /= 10;
		retryLimit = 0;
	}

	do {
		result = fServer->SendCallAsync(fBuilder.Request(), &rpl, &rpc);
		if (result == B_NO_MEMORY)
			return result;
		else if (result != B_OK) {
			fServer->Repair();
			continue;
		}

		if (cookie != NULL)
			cookie->RegisterRequest(rpc);

		result = fServer->WaitCall(rpc, requestTimeout);
		if (result != B_OK) {
			if (cookie != NULL)
				cookie->UnregisterRequest(rpc);

			fServer->CancelCall(rpc);
			delete rpc;

			fServer->Repair();	
		}
	} while (result != B_OK && (hard || attempts++ < retryLimit));

	if (result != B_OK)
		return result;

	if (cookie != NULL)
		cookie->UnregisterRequest(rpc);

	if (rpc->fError != B_OK) {
		delete rpl;
		result = rpc->fError;
		delete rpc;
		return result;
	} 

	fReply.SetTo(rpl);
	delete rpc;
	return B_OK;
}


void
Request::Reset(uid_t uid, gid_t gid)
{
	fBuilder.Reset(uid, gid);
	fReply.Reset();
}