//*****************************************************************************
//
//	gk_rpc.m  
//
//		Mach RPC server for IPC between PPPD and GateKeeper
//
//			by	Felipe A. Rodriguez		
//
//	This code is supplied "as is" the author makes no warranty as to its 
//	suitability for any purpose.  This code is free and may be distributed 
//	in accordance with the terms of the:
//		
//			GNU GENERAL PUBLIC LICENSE
//			Version 2, June 1991
//			copyright (C) 1989, 1991 Free Software Foundation, Inc.
// 			675 Mass Ave, Cambridge, MA 02139, USA
//
//*****************************************************************************

#import <appkit/appkit.h>
#import <mach/mach.h>
#import	<mach/message.h>
#import <mach/mach_error.h>
#import <servers/netname.h>
#import <mach/cthreads.h>
#import <objc/objc-runtime.h>
#include <syslog.h>

#import "Coordinator.h"
#import "CommandScroll.h"
#import "./MiG/Library/gk_rpc_types.h"


					// size of RPC messages 
#define	gk_rpcMaxRequestSize	1024
#define	gk_rpcMaxReplySize		1024

					// server procedures
void server_loop(port_t port); 
kern_return_t set_gk(port_t server, int a);
kern_return_t send_string(port_t server, gk_cstring a);
kern_return_t send_dce_speed(port_t server, gk_cstring a);

					// defined by MiG: 
boolean_t gk_rpc_server(msg_header_t *in, msg_header_t *out);

					// from Request types in nsRPCUser.c 
struct message 
		{                
		msg_header_t    head;        /* standard header field */
		msg_type_t      arg1_type;   /* first arg type */
		int             arg1;        /* first arg */
		msg_type_t      arg2_type;   /* second arg type */
		int             arg2;        /* second arg */
		};

port_t	server_port;
kern_return_t	r;
id GKAppDelegateProxy;




//*****************************************************************************
//
// 		listen for RPC from GateKeeper
//
//*****************************************************************************

void gk_listen(void) 
{
							// allocate a port for this task, ret in arg 2
	if ((r = port_allocate(task_self(), &server_port)) != KERN_SUCCESS) 
		{
		mach_error("port_allocate failed", r);
		exit(1);
		}
				// Register with the Network Name Server.
	r = netname_check_in(NameServerPort,GK_SERVER_NAME, PORT_NULL,server_port);
	if (r != KERN_SUCCESS) 
		{
		mach_error("netname_check_in failed", r);
		exit(1);
		}

	objc_setMultithreaded(YES);			// make objC run time thread safe

										// create server thread and detach it
	cthread_detach(cthread_fork((cthread_fn_t)server_loop,(any_t)server_port));
}
//*****************************************************************************
//
// 		remove our name from net name server
//
//*****************************************************************************

void gk_check_out(void) 
{
									// remove name from Network Name Server.
	r = netname_check_out(name_server_port, GK_SERVER_NAME, PORT_NULL);
	if (r != KERN_SUCCESS) 
		{
		mach_error("netname_check_out failed", r);
		exit(1);
		}
}
//*****************************************************************************
//
// 		c thread loop which listens for RPC  
//
//*****************************************************************************

void server_loop(port_t port)
{
kern_return_t ret;
msg_header_t *msg = (msg_header_t *)malloc(gk_rpcMaxRequestSize);
msg_header_t *reply = (msg_header_t *)malloc(gk_rpcMaxReplySize);

									// connect to DO thread in app delegate
	GKAppDelegateProxy = [NXConnection connectToName:"GKAppDelegate"];

    while (TRUE)
		{        					 /* Receive a request from a client. */
        msg->msg_local_port = port;
        msg->msg_size = gk_rpcMaxRequestSize;
        ret = msg_receive(msg, MSG_OPTION_NONE, 0);
        if (ret != RCV_SUCCESS) /* ignore errors */; 

									/* Feed the request into the server. */
		(void)gk_rpc_server(msg, reply);

       								/* Send a reply to the client. */
        reply->msg_local_port = port;
        ret = msg_send(reply, MSG_OPTION_NONE, 0);
        if (ret != SEND_SUCCESS) 	/* ignore errors */; 
			continue; 
		}
}
//*****************************************************************************
//
//		called by pppd to inform us of its state
//
// 		This function is called by RPC server which was created by MiG.
// 		It is NOT directly called by any client process.
//
//*****************************************************************************

kern_return_t set_gk(port_t server, int a)
{
	[GKAppDelegateProxy setPhase:a];

    return KERN_SUCCESS;
}
//*****************************************************************************
//
//		called by pppd to inform us of its state (no return)
//
// 		This function is called by RPC server which was created by MiG.
// 		It is NOT directly called by any client process.
//
//*****************************************************************************

kern_return_t set_gk_oneway(port_t server, int a)
{
	[GKAppDelegateProxy setPhase:a];

    return KERN_SUCCESS;
}
//*****************************************************************************
//
//		called by chat/pppd to inform us of its state
//
// 		This function is called by RPC server which was created by MiG.
// 		It is NOT directly called by any client process.
//
//*****************************************************************************

kern_return_t send_string(port_t server, gk_cstring a)
{
	[GKAppDelegateProxy displayStatus:a]; 
 
    return KERN_SUCCESS;
}
//*****************************************************************************
//
//		called by chat/pppd to inform us of its state
//
// 		This function is called by RPC server which was created by MiG.
// 		It is NOT directly called by any client process.
//
//*****************************************************************************

kern_return_t send_dce_speed(port_t server, gk_cstring a)
{
	[GKAppDelegateProxy connectedAt:a]; 
 
    return KERN_SUCCESS;
}

