////////////////////////////////////////////////////////////
//
//     	Declaration of a class
//	DceServer
//
//      Copyright 2001 
//
////////////////////////////////////////////////////////////


#ifndef __DCESERVER_H__
#define __DCESERVER_H__

#include <dce/keymgmt.h>
#include <dce/sec_login.h>
#include "DceInterface.h"
#include "AFifo.C"
#include "AThread.h"


	// DceKeyManager - a custom key retrieval
	// a base class
	
struct DceKeyManager
{
virtual int get_key(void ** key,
	char *server_princ_name, unsigned  key_type,  unsigned  key_version)=0;
};


	// DceServerAttributes
	
class DceServer;
class KeyManagerThread;

class DceServerAttributes
{
friend class DceServer;
friend class KeyManagerThread;
public:
	DceServerAttributes();
	DceServerAttributes(const DceServerAttributes&);
	~DceServerAttributes();
	
	DceServerAttributes& operator=(const DceServerAttributes&);
	
	// default rpc_c_listen_max_calls_default
	int set_max_exec_threads(unsigned z)
	{ max_exec_threads=z; return 0;}
	
	// queue size, default rpc_c_protseq_max_reqs_default
	int set_max_call_requests(unsigned z)
	{ max_call_requests=z; return 0;}
	
	// default ncacn_ip_tcp
	// an alternative protocol sequence is "ncadg_ip_udp"
	int set_protocol_sequence(char* z)
	{ protocol_sequence=(unsigned_char_t *)z; return 0;}
	
	// read syntax code from an environment variable
	// or use DCE syntax, if the variable is not set	
	int set_entry_name(const char *name);
	
	// a random server id will be created, if it is not set
	// string length is UUID_STRING_LEN
	int set_id(const char *string_id) 
	{return id.set(string_id);}
	
	// for example a site id, that a client can select a site
	// cannot have interface types, when this is set
	int associate_id(const char *string_id) 
	{return associated_id.set(string_id);}
	
	int own_identity()
	{ own_identity_flag=true; return 0;}
	
	int set_principal_name(const char *name);
	
	// default sec_login_no_flags
	int set_login_flags(sec_login_flags_t z)
	{login_flags=z; return 0;}
	
	// if key file is not set
	// DceKeyManager provides an access to a key
	int use_key_file(const char *path);
	
	// /krb/v5srvtab
	int use_default_key_file()
	{ key_file_flag = true; return 0;}
		
	int set_annotation(const char *name);
	
	int unexport_names()
	{ unexport_names_flag=true; return 0; }
	
	int no_names_export()
	{ no_names_export_flag=true; return 0;}
	
	int no_endpoint_replace()
	{ no_endpoint_replace_flag=true; return 0;}

private:
	unsigned32 max_exec_threads, max_call_requests; 
	unsigned_char_t *protocol_sequence;
	unsigned32 entry_name_syntax;
	unsigned_char_t *entry_name;
	unsigned_char_t *principal_name;
	sec_login_flags_t login_flags;
	sec_key_mgmt_authn_service key_service;
	char *key_file;
	bool key_file_flag;
	unsigned32 key_version_number;
	bool own_identity_flag;
	DceUuid id,associated_id;
	unsigned_char_t * annotation;
	bool unexport_names_flag;
	bool no_endpoint_replace_flag;
	bool no_names_export_flag;
};

	// KeyManagerThread
	// used internally

class KeyManagerThread: public AThread
{
KeyManagerThread(const KeyManagerThread&);
KeyManagerThread& operator=(const KeyManagerThread&);
public:
	KeyManagerThread(DceServerAttributes& att, DceKeyManager * km);
	~KeyManagerThread(){}
		
	int loop(bool& continue_loop);
private:
	DceServerAttributes *attributes;
	void *arg;
};


	// DceServer
	
class DceServer
{
DceServer(const DceServer&);
DceServer& operator=(const DceServer&);
public:

	int status;
	
	struct node
	{ 
		DceCalleeInterface interface;
		rpc_binding_vector_t * binding_vector;
		node():binding_vector(0){}
		node(const DceCalleeInterface& z):interface(z),binding_vector(0){}
	};


	DceServer(DceServerAttributes& att, DceKeyManager * km=0);	
	~DceServer();
	
	// sec_login_auth_src_network,
	// sec_login_auth_src_local, sec_login_auth_src_overridden
	int get_login_service(sec_login_auth_src_t& z)
	{ z=login_service; return 0;}

				
	// register interface with type id, or server id if there is no type id
	int add_interface(const DceCalleeInterface& z);
	
	int add_authentication_service(unsigned authentication_service_code);
	
	// listen loop, blocking
	int launch();
	
	// called from a thread different from one,
	// which drives a listen loop,
	// for example, from an interface implementation
	int stop();
	
	// for a DceCall in a nested call
	const sec_login_handle_t *login_context_pointer()
	{ return &login_context;}
	

protected:


	// a random id unique for each invocation 
	// of the server process
	DceUuid linked_id;
	DceServerAttributes & attributes;
	AFifo<node> interfaces;
	DceKeyManager *key_manager;
	sec_login_handle_t login_context;
	KeyManagerThread key_manager_thread;
	AThreadControl thread_control;
	sec_login_auth_src_t login_service; // output
	
	int add_typeless(rpc_binding_vector_t *& binding_vector,const DceCalleeInterface& z);
	int add_typed(rpc_binding_vector_t *& binding_vector,const DceCalleeInterface& z);
	
	virtual int get_secret_key(){return 0;}
	
	// default - write to stdout
	// provide a custom logging function, if needed
	virtual int log(const char *message, error_status_t status);
	
};


#endif

/* in main:

	DceServerAttributes attr;
	
	//set attributes here
	
	DceServer server(attr);
	
	DceCalleeInterface interface;
	
	//set interface here
	
	server.add_authentication_service(rpc_c_authn_dce_secret);
	
	server.add_interface(interface);
	
	while(1)
	{
		server.launch();
	
		// handle listen loop interruptions here
		// break the loop, if needed
	}


*/