#ifndef MIDLTESTS_C_CODE

/*
 * For midltests_tcp.exe you may want to
 * redirect the traffic via rinetd
 * with a /etc/rinetd.conf like this:
 *
 * 172.31.9.1 5032 172.31.9.8 5032
 * 172.31.9.1 5064 172.31.9.8 5064
 *
 * This is useful to watch the traffic with
 * a network sniffer.
 */
/*
cpp_quote("#define LISTEN_IP \"0.0.0.0\"")
cpp_quote("#define FORWARD_IP \"127.0.0.1\"")
cpp_quote("#define CONNECT_IP \"172.31.9.1\"")
*/

/*
 * With midltests_tcp.exe NDR64 is enforced by default.
 * For testing it might be needed to allow downgrades
 * to NDR32. This is needed when you use 'pipe'.
 */
cpp_quote("#define DONOT_FORCE_NDR64 1")

[
  uuid("225b9fcb-eb3d-497b-8b0b-591f049a2507"),
  pointer_default(unique)
]
interface midltests
{
	typedef pipe char pipe_char;
	typedef pipe hyper pipe_hyper;
	typedef struct {
		long l;
		short s;
	} structtype;
	typedef pipe structtype pipe_structtype;

	struct msg {
		long l;
		[size_is(l)] char *m;
	};

	long midltests_fn(
		[out,ref] struct msg *out1,
		[out] pipe_structtype outp,
		[in] pipe_structtype inp,
		[in] struct msg in1
	);

	long midltests_ping( [in] struct msg in1);

}

#elif MIDLTESTS_C_CODE

struct pipe_char_state {
	const char *name;
	unsigned long count;
	unsigned long sleep;
};

void pipe_char_pull(
            char * _state,
            unsigned char * buf,
            unsigned long esize,
            unsigned long * ecount)
{
	struct pipe_char_state *state = (struct pipe_char_state *)_state;

	printf("pull1:%s: esize[%u] ecount[%u]\n",
		state->name, esize, *ecount);
	*ecount = state->count--;
	if (*ecount > esize) {
		*ecount = esize;
	}
	memset(buf, 0xDD, *ecount * sizeof(*buf));
	printf("pull2:%s: esize[%u] ecount[%u]\n",
		state->name, esize, *ecount);
}

void pipe_char_push(
            char * _state,
            unsigned char * buf,
            unsigned long ecount)
{
	struct pipe_char_state *state = (struct pipe_char_state *)_state;

	printf("push:%s: ecount[%u]\n",
		state->name, ecount);
}

void pipe_char_alloc(
            char * _state,
            unsigned long bsize,
            unsigned char * * buf,
            unsigned long * bcount)
{
	struct pipe_char_state *state = (struct pipe_char_state *)_state;

	printf("alloc1:%s: bsize[%u], bcount[%u]\n",
		state->name, bsize, *bcount);
	*bcount = bsize / sizeof(**buf);
	*buf = malloc(*bcount * sizeof(**buf));
	printf("alloc2:%s: bsize[%u], bcount[%u]\n",
		state->name, bsize, *bcount);
}

struct pipe_hyper_state {
	const char *name;
	unsigned long count;
	unsigned long sleep;
};

void pipe_hyper_pull(
            char * _state,
            hyper * buf,
            unsigned long esize,
            unsigned long * ecount)
{
	struct pipe_hyper_state *state = (struct pipe_hyper_state *)_state;

	printf("pull1:%s: esize[%u] ecount[%u]\n",
		state->name, esize, *ecount);
	*ecount = state->count--;
	if (*ecount > esize) {
		*ecount = esize;
	}
	memset(buf, 0xDD, *ecount * sizeof(*buf));
	printf("pull2:%s: esize[%u] ecount[%u]\n",
		state->name, esize, *ecount);
}

void pipe_hyper_push(
            char * _state,
            hyper * buf,
            unsigned long ecount)
{
	struct pipe_hyper_state *state = (struct pipe_hyper_state *)_state;

	printf("push:%s: ecount[%u]\n",
		state->name, ecount);
}

void pipe_hyper_alloc(
            char * _state,
            unsigned long bsize,
            hyper * * buf,
            unsigned long * bcount)
{
	struct pipe_hyper_state *state = (struct pipe_hyper_state *)_state;

	printf("alloc1:%s: bsize[%u], bcount[%u]\n",
		state->name, bsize, *bcount);
	*bcount = bsize / sizeof(**buf);
	*buf = malloc(*bcount * sizeof(**buf));
	printf("alloc2:%s: bsize[%u], bcount[%u]\n",
		state->name, bsize, *bcount);
}
struct pipe_structtype_state {
	const char *name;
	unsigned long count;
	unsigned long sleep;
};

void pipe_structtype_pull(
            char * _state,
            structtype * buf,
            unsigned long esize,
            unsigned long * ecount)
{
	struct pipe_structtype_state *state = (struct pipe_structtype_state *)_state;

	printf("pull1:%s: esize[%u] ecount[%u]\n",
		state->name, esize, *ecount);
	*ecount = state->count--;
	if (*ecount > esize) {
		*ecount = esize;
	}
	memset(buf, 0xDD, *ecount * sizeof(*buf));
	printf("pull2:%s: esize[%u] ecount[%u]\n",
		state->name, esize, *ecount);
}

void pipe_structtype_push(
            char * _state,
            structtype * buf,
            unsigned long ecount)
{
	struct pipe_structtype_state *state = (struct pipe_structtype_state *)_state;

	printf("push:%s: ecount[%u]\n",
		state->name, ecount);
}

void pipe_structtype_alloc(
            char * _state,
            unsigned long bsize,
            structtype * * buf,
            unsigned long * bcount)
{
	struct pipe_structtype_state *state = (struct pipe_structtype_state *)_state;

	printf("alloc1:%s: bsize[%u], bcount[%u]\n",
		state->name, bsize, *bcount);
	*bcount = bsize / sizeof(**buf);
	*buf = malloc(*bcount * sizeof(**buf));
	printf("alloc2:%s: bsize[%u], bcount[%u]\n",
		state->name, bsize, *bcount);
}
static void midltests(void)
{
	struct msg out1;
	unsigned char out1b[3];
	struct pipe_structtype_state outs;
	pipe_structtype outp;
	struct pipe_structtype_state ins;
	pipe_structtype inp;
	struct msg in1;
	unsigned char in1b[3000];

	in1.l = sizeof(in1b);
	memset(&in1b, 0xAA, sizeof(in1b));
	in1.m = in1b;

	memset(&outs, 0, sizeof(outs));
	outs.name = "outp";
	memset(&outp, 0, sizeof(outp));
	outp.pull = pipe_structtype_pull;
	outp.push = pipe_structtype_push;
	outp.alloc = pipe_structtype_alloc;
	outp.state = (char *)&outs;

	memset(&ins, 0, sizeof(ins));
	ins.name = "inp";
	ins.count = 35;
	memset(&inp, 0, sizeof(inp));
	inp.pull = pipe_structtype_pull;
	inp.push = pipe_structtype_push;
	inp.alloc = pipe_structtype_alloc;
	inp.state = (char *)&ins;

	out1.l = sizeof(out1b);
	memset(&out1b, 0xFF, sizeof(out1b));
	out1.m = out1b;

	cli_midltests_ping(in1);
	cli_midltests_fn(&out1, outp, inp, in1);
}

long srv_midltests_fn(
	    /* [ref][out] */ struct msg *out1,
    /* [out] */ pipe_structtype outp,
    /* [in] */ pipe_structtype inp,
    /* [in] */ struct msg in1)
{
	structtype inb[2500];
	unsigned long inb_len = 0;
	structtype *outb = NULL;
	unsigned long outb_size = 0;
	unsigned long outb_len = 0;

	printf("srv_midltests_fn: Start\n");
	fflush(stdout);

	do {
		inp.pull(inp.state, inb, sizeof(inb), &inb_len);
		printf("pull inp_len[%u]\n", inb_len);
		fflush(stdout);
	} while (inb_len > 0);

	outb_size = 50;
	do {
		outp.alloc(outp.state, outb_size, &outb, &outb_len);
		memset(outb, 0xCC, outb_len * sizeof(*outb));
		printf("push outb_len[%u]\n", outb_len);
		fflush(stdout);
		outp.push(outp.state, outb, outb_len);
		//Sleep(1000);
		outb_size--;
	} while (outb_len > 0);

	out1->l = 3;
	out1->m = (unsigned char *)malloc(out1->l);
	memset(out1->m, 0xBB, out1->l);
	printf("srv_midltests_fn: End\n");
	fflush(stdout);
	return 0x65757254;
}

long srv_midltests_ping(
    /* [in] */ struct msg in1)
{
	printf("srv_midltests_fn: Start\n");
	printf("srv_midltests_fn: End\n");
	return 0x65757254;
}
#endif
