p11_rpc_server_handle (CK_X_FUNCTION_LIST *self,
                       p11_buffer *request,
                       p11_buffer *response)
{
	p11_rpc_message msg;
	CK_RV ret;
	int req_id;

	return_val_if_fail (self != NULL, false);
	return_val_if_fail (request != NULL, false);
	return_val_if_fail (response != NULL, false);

	p11_message_clear ();

	p11_rpc_message_init (&msg, request, response);

	if (!p11_rpc_message_parse (&msg, P11_RPC_REQUEST)) {
		p11_rpc_message_clear (&msg);
		p11_message ("couldn't parse pkcs11 rpc message");
		return false;
	}

	/* This should have been checked by the parsing code */
	assert (msg.call_id > P11_RPC_CALL_ERROR);
	assert (msg.call_id < P11_RPC_CALL_MAX);
	req_id = msg.call_id;

	switch(req_id) {
	#define CASE_CALL(name) \
	case P11_RPC_CALL_##name: \
		ret = rpc_##name (self, &msg); \
		break;
	CASE_CALL (C_Initialize)
	CASE_CALL (C_Finalize)
	CASE_CALL (C_GetInfo)
	CASE_CALL (C_GetSlotList)
	CASE_CALL (C_GetSlotInfo)
	CASE_CALL (C_GetTokenInfo)
	CASE_CALL (C_GetMechanismList)
	CASE_CALL (C_GetMechanismInfo)
	CASE_CALL (C_InitToken)
	CASE_CALL (C_OpenSession)
	CASE_CALL (C_CloseSession)
	CASE_CALL (C_CloseAllSessions)
	CASE_CALL (C_GetSessionInfo)
	CASE_CALL (C_InitPIN)
	CASE_CALL (C_SetPIN)
	CASE_CALL (C_GetOperationState)
	CASE_CALL (C_SetOperationState)
	CASE_CALL (C_Login)
	CASE_CALL (C_Logout)
	CASE_CALL (C_CreateObject)
	CASE_CALL (C_CopyObject)
	CASE_CALL (C_DestroyObject)
	CASE_CALL (C_GetObjectSize)
	CASE_CALL (C_GetAttributeValue)
	CASE_CALL (C_SetAttributeValue)
	CASE_CALL (C_FindObjectsInit)
	CASE_CALL (C_FindObjects)
	CASE_CALL (C_FindObjectsFinal)
	CASE_CALL (C_EncryptInit)
	CASE_CALL (C_Encrypt)
	CASE_CALL (C_EncryptUpdate)
	CASE_CALL (C_EncryptFinal)
	CASE_CALL (C_DecryptInit)
	CASE_CALL (C_Decrypt)
	CASE_CALL (C_DecryptUpdate)
	CASE_CALL (C_DecryptFinal)
	CASE_CALL (C_DigestInit)
	CASE_CALL (C_Digest)
	CASE_CALL (C_DigestUpdate)
	CASE_CALL (C_DigestKey)
	CASE_CALL (C_DigestFinal)
	CASE_CALL (C_SignInit)
	CASE_CALL (C_Sign)
	CASE_CALL (C_SignUpdate)
	CASE_CALL (C_SignFinal)
	CASE_CALL (C_SignRecoverInit)
	CASE_CALL (C_SignRecover)
	CASE_CALL (C_VerifyInit)
	CASE_CALL (C_Verify)
	CASE_CALL (C_VerifyUpdate)
	CASE_CALL (C_VerifyFinal)
	CASE_CALL (C_VerifyRecoverInit)
	CASE_CALL (C_VerifyRecover)
	CASE_CALL (C_DigestEncryptUpdate)
	CASE_CALL (C_DecryptDigestUpdate)
	CASE_CALL (C_SignEncryptUpdate)
	CASE_CALL (C_DecryptVerifyUpdate)
	CASE_CALL (C_GenerateKey)
	CASE_CALL (C_GenerateKeyPair)
	CASE_CALL (C_WrapKey)
	CASE_CALL (C_UnwrapKey)
	CASE_CALL (C_DeriveKey)
	CASE_CALL (C_SeedRandom)
	CASE_CALL (C_GenerateRandom)
	CASE_CALL (C_WaitForSlotEvent)
	#undef CASE_CALL
	default:
		/* This should have been caught by the parse code */
		assert (0 && "Unchecked call");
		break;
	};

	if (p11_buffer_failed (msg.output)) {
		p11_message ("out of memory error putting together message");
		p11_rpc_message_clear (&msg);
		return false;
	}

	/* A filled in response */
	if (ret == CKR_OK) {

		/*
		 * Since we're dealing with many many functions above generating
		 * these messages we want to make sure each of them actually
		 * does what it's supposed to.
		 */
		assert (p11_rpc_message_is_verified (&msg));
		assert (msg.call_type == P11_RPC_RESPONSE);
		assert (msg.call_id == req_id);
		assert (p11_rpc_calls[msg.call_id].response);
		assert (strcmp (p11_rpc_calls[msg.call_id].response, msg.signature) == 0);

	/* Fill in an error respnose */
	} else {
		if (!p11_rpc_message_prep (&msg, P11_RPC_CALL_ERROR, P11_RPC_RESPONSE) ||
		    !p11_rpc_message_write_ulong (&msg, (uint32_t)ret) ||
		    p11_buffer_failed (msg.output)) {
			p11_message ("out of memory responding with error");
			p11_rpc_message_clear (&msg);
			return false;
		}
	}

	p11_rpc_message_clear (&msg);
	return true;
}