mach_server.c   [plain text]


#include <stdio.h>
#include <stdlib.h>
#include <launch.h>
#include <dispatch/dispatch.h>
#include <mach/mach.h>
#include <mach/mach_port.h>
#include <asl.h>
#include <mach-o/dyld.h>
#include <limits.h>

void
load(void)
{
	launch_data_t msg, config, dict, array, val;
	
	config = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
	
	val = launch_data_new_string("com.apple.test.mach-server");
	launch_data_dict_insert(config, val, LAUNCH_JOBKEY_LABEL);
	
	val = launch_data_new_bool(1);
	dict = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
	launch_data_dict_insert(dict, val, "com.apple.test.mach-server");
	launch_data_dict_insert(config, dict, LAUNCH_JOBKEY_MACHSERVICES);

	char path[PATH_MAX];
	uint32_t size = sizeof(path);
	_NSGetExecutablePath(path, &size);
	
	array = launch_data_alloc(LAUNCH_DATA_ARRAY);
	val = launch_data_new_string(path);
	launch_data_array_set_index(array, val, 0);
	val = launch_data_new_string("-launchd");
	launch_data_array_set_index(array, val, 1);
	launch_data_dict_insert(config, array, LAUNCH_JOBKEY_PROGRAMARGUMENTS);
	
	
	msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
	launch_data_dict_insert(msg, config, LAUNCH_KEY_SUBMITJOB);
	fprintf(stderr, "loading launchd job com.apple.test.mach-server\n");
	msg = launch_msg(msg);
	if (msg && launch_data_get_type(config) == LAUNCH_DATA_ERRNO) {
		fprintf(stderr, "launch load failed: %s\n", strerror(launch_data_get_errno(msg)));
	} else {
		fprintf(stderr, "successful\n");
	}
}

mach_port_t
checkin(void)
{
	launch_data_t config = NULL, checkin = NULL;
	checkin = launch_data_new_string(LAUNCH_KEY_CHECKIN);
	config = launch_msg(checkin);
	if (!config || launch_data_get_type(config) == LAUNCH_DATA_ERRNO)
		return MACH_PORT_NULL;
	
	launch_data_t svc;
	svc = launch_data_dict_lookup(config, LAUNCH_JOBKEY_MACHSERVICES);
	if (!svc) return MACH_PORT_NULL;

	svc = launch_data_dict_lookup(svc, "com.apple.test.mach-server");
	if (!svc) return MACH_PORT_NULL;

	mach_port_t mp = launch_data_get_machport(svc);
	return mp;
}


#include <CoreFoundation/CoreFoundation.h>

void my_cf_callback(CFMachPortRef mp, void *msg, CFIndex size, void *info)
{
	char *payload = (char *)((uintptr_t)msg + sizeof(mach_msg_header_t));
	asl_log(NULL, NULL, ASL_LEVEL_NOTICE, "message received: %s %s", payload, (char *)info);
}

DISPATCH_CFMACHPORT_CALLBACK_DECL(my_mig_callback, my_cf_callback);

struct strmsg {
	mach_msg_header_t header;
	char payload[32];
	mach_msg_security_trailer_t trailer;
};

int
client(int argc, char* argv[])
{
	mach_port_t mp;
	kern_return_t kr;
	struct strmsg msg;

	char *str = (argc > 1) ? argv[1] : "<unspecified>";

	kr = bootstrap_look_up(bootstrap_port, "com.apple.test.mach-server",
		&mp);
	printf("lookup %s\n", !kr ? "successful" : mach_error_string(kr));

	strlcpy(msg.payload, str, sizeof(msg.payload));
	msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,MACH_MSG_TYPE_MAKE_SEND_ONCE);
	msg.header.msgh_size = round_msg(sizeof(msg.header) + strlen(msg.payload) + 1);
	msg.header.msgh_remote_port = mp;
	msg.header.msgh_local_port = MACH_PORT_NULL;
	msg.header.msgh_id = 0x12345678;
	kr = mach_msg(&msg.header, MACH_SEND_MSG, msg.header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
	printf("client send %s\n", !kr ? "successful" : mach_error_string(kr));
}

int main(int argc, char* argv[])
{
	if (argc > 1 && strcmp(argv[1], "-launchd") == 0) {
		mach_port_t mp = checkin();
		printf("checkin %s\n", mp ? "successful" : "failed");
		if (mp) {
			kern_return_t kr;
			kr = mach_port_set_context(mach_task_self(), mp, (mach_vm_address_t)"phear");
			
			dispatch_source_t mig = dispatch_source_mig_create(mp, 0 /* max msg size */,
															   NULL, dispatch_get_main_queue(), my_mig_callback);
			dispatch_main();
		}
	} else if (argc > 1) {
		client(argc, argv);
	} else {
		// load the job
		load();
	}

	return 0;
}