LINX_SPID create_test_slave(LINX * linx, LINX_SPID server, int use_linx_api,
			    int use_pthreads)
{
	LINX_SPID test_slave_spid;
	union LINX_SIGNAL *sig;
	LINX_SIGSELECT any_sig[] = { 0 };

	sig = linx_alloc(linx, sizeof(struct connEst), CONN_EST);
	sig->connEst.use_linx_api = htonl(use_linx_api);
	sig->connEst.use_pthreads = htonl(use_pthreads);

	linx_send(linx, &sig, server);

	linx_receive(linx, &sig, any_sig);

	if (sig->sigNo != CONN_EST) {
		ERR("Unknown signal %ud", sig->sigNo);
	}

	test_slave_spid = linx_sender(linx, &sig);

	linx_free_buf(linx, &sig);

	return test_slave_spid;
}
void destroy_test_slave(LINX * linx, LINX_SPID ts)
{
	union LINX_SIGNAL *sig;
	LINX_SIGSELECT any_sig[] = { 0 };

	sig = linx_alloc(linx, sizeof(LINX_SIGSELECT), ATTACH_SLAVE_SIG);
	linx_attach(linx, &sig, ts);

	sig = linx_alloc(linx, sizeof(LINX_SIGSELECT), TERMINATE_REQ);
	TRACE(1, "Terminate request");
	linx_send(linx, &sig, ts);

	linx_receive(linx, &sig, any_sig);

	if (sig->sigNo != ATTACH_SLAVE_SIG) {
		ERR("Wrong signal received while waiting for attach signal"
		    " from test slave. %d", sig->sigNo);
	}
	linx_free_buf(linx, &sig);
}
void server_main()
{
	LINX_SIGSELECT sigsel_any[] = { 0 };
	LINX *linx;
	LINX_SPID client;
	union LINX_SIGNAL *sig;

	printf("Server started.\n");

	/* Open LINX socket */
	linx = linx_open(SERVER_NAME, 0, NULL);
	if (linx == NULL) {
		ERR("linx_open() failed");
	}

	for (;;) {
		/* Wait until a signal arrives */
		if (linx_receive_w_tmo(linx, &sig, IDLE_TIMEOUT,
				       sigsel_any) == -1) {
			ERR("linx_receive() failed");
		}
		if (sig == LINX_NIL) {
			printf("Server: Idle too long, terminating.\n");
			if (linx_close(linx) == -1) {
				ERR("linx_close() failed");
			}
			break;
		}

		switch (sig->sig_no) {
		case REQUEST_SIG:
			{
				printf("Server: REQUEST_SIG received.\n");
				client = linx_sender(linx, &sig);
				if (client == LINX_ILLEGAL_SPID) {
					ERR("linx_sender() failed");
				}

				/* Use same signal for REPLY, just change the 
				 * signal number */
				printf("Server: Sending REPLY_SIG.\n");
				sig->sig_no = REPLY_SIG;
				if (linx_send(linx, &sig, client) == -1) {
					ERR("linx_send() failed.");
					exit(1);
				}
				break;
			}

		default:
			{
				printf("Server: Unexpected signal received "
				       "(sig_no = %d) - ignored\n",
				       sig->sig_no);
				if (linx_free_buf(linx, &sig) == -1) {
					ERR("linx_free_buf() failed");
				}
				break;
			}
		}
	}
}
int OseGW_PLT_HuntReply_cbk(int skt, int len, char *payload,
                            struct ClientInfo *cinfo)
{
	OseGW_UL payload_len = sizeof(struct OseGW_HuntReply);
	struct OseGW_TransportData *reply = NULL;
	struct OseGW_HuntRequest *hunt_request =
		(struct OseGW_HuntRequest *) payload;
	union LINX_SIGNAL *hunt_sig = NULL;
	const LINX_SIGSELECT hunt_sigsel[] = { 1, LINX_OS_HUNT_SIG };
	LINX *gws_hunter;
	PROCESS pid = 0;
	int status = 0;
	int size = 0;

	/*Fill the header */
	size = sizeof(struct OseGW_TransportHdr) + payload_len;
	reply = (struct OseGW_TransportData *) malloc(size);
	if (reply == NULL) {
		syslog(LOG_ERR, "Malloc failure in Hunt reply");
		return -1;
	}
	reply->hdr.payload_type = htonl(OseGW_PLT_HuntReply);
	reply->hdr.payload_len = htonl(sizeof(struct OseGW_HuntReply));
	/* Fill the payload */
	hunt_request->user = ntohl(hunt_request->user);
	hunt_request->sig_len = ntohl(hunt_request->sig_len);
	hunt_request->name_index = ntohl(hunt_request->name_index);
	if (hunt_request->sig_len != 0) {
		hunt_sig = linx_alloc(cinfo->linx, hunt_request->sig_len,
				      ntohl(hunt_request->sig_no));
		if (hunt_sig == LINX_NIL) {
			syslog(LOG_ERR, "Linx alloc failed in Hunt reply");
			free(reply);
			return -1;
		}
		size = hunt_request->sig_len - sizeof(SIGSELECT);
		memcpy(&((char *) hunt_sig)[sizeof(SIGSELECT)],
		       &hunt_request->
		       data[ntohl(hunt_request->sig_index)], size);
		/*
		 * This hunt sig will be returned to caller or be cleaned
		 * up when caller closes the gateway socket.
		 */
		status = linx_hunt(cinfo->linx,
				   &hunt_request->data
				   [hunt_request->name_index],
				   &hunt_sig);

		if (status == -1) {
			free(reply);
			return status;
		}
	}

	/*
	 * The gateway hunt(...) returns the pid of the hunted process if the
	 * process exist when the hunt is done. The LINX hunt(...) does not so
	 * a hunt/receive_w_tmo/sender is done to get the pid. The gws_hunter
	 * socket is opened to prevent at client from flooding the gw server
	 * with hunt requests that could lead to out-of-memory in the LINX
	 * kernel module. If the hunted process does not exist the hunt is
	 * cleaned up when the gws_hunter socket is closed.
	 */

	gws_hunter = linx_open("gws_hunter", 0, NULL);
	status = linx_hunt(gws_hunter,
			   &hunt_request->data[hunt_request->name_index],
			   NULL);
	if (status == -1) {
	        free(reply);
	        return status;
	}

	status = linx_receive_w_tmo(gws_hunter, &hunt_sig, 0, hunt_sigsel);
	if (status == -1) {
		free(reply);
		return status;
	}

	if (hunt_sig != LINX_NIL) {
		pid = linx_sender(gws_hunter, &hunt_sig);
		if (pid == LINX_ILLEGAL_SPID) {
			free(reply);
			return -1;
		}
		linx_free_buf(gws_hunter, &hunt_sig);
	}
	/* free up the "hunt" */
	linx_close(gws_hunter);

	reply->payload.hunt_reply.status = htonl(cinfo->status);
	reply->payload.hunt_reply.pid = htonl(pid);
	/*Send */
	size = sizeof(struct OseGW_TransportHdr) + payload_len;
	status = send(skt, (void *) reply, size, 0);
	if (status == size) {
		LOG(LOG_INFO, "Gateway Client: replying HuntReply "
                    "on socket %d", skt);
	} else {
		syslog(LOG_INFO, "Gateway Clinet: failed replying "
		       "HuntReply on socket %d", skt);
		status = -1;
	}
	free(reply);
	return status;
}
int OseGW_PLT_ReceiveReply_cbk(int skt, int len, char *payload,
                               struct ClientInfo *cinfo)
{
	OseGW_UL payload_len = sizeof(struct OseGW_ReceiveReply) + len;
	struct OseGW_TransportData *reply;
	union LINX_SIGNAL *signal = (union LINX_SIGNAL *)payload;
	int status = 0;
	int size;

	size = sizeof(struct OseGW_TransportHdr) + payload_len;
	reply = malloc(size);
	if (reply == NULL) {
		syslog(LOG_ERR, "Malloc failure in Receive reply");
		return -1;
	}

	reply->hdr.payload_type = htonl(OseGW_PLT_ReceiveReply);
	reply->hdr.payload_len = htonl(payload_len);

	if (signal != LINX_NIL) {
		/*Fill the payload */
		reply->payload.receive_reply.status = htonl(OseGW_StatusOk);
		reply->payload.receive_reply.sender_pid =
			htonl(linx_sender(cinfo->linx, &signal));
		reply->payload.receive_reply.addressee_pid =
			htonl(cinfo->curr_pid);
		reply->payload.receive_reply.sig_len =
			htonl(len + sizeof(SIGSELECT));
		reply->
		  payload
		  .receive_reply
		  .sig_no = htonl(
				  signal->sig_no);
		memcpy(&reply->payload.receive_reply.sig_data[0],
		       &(((SIGSELECT *) signal)[1]), len);
	} else {
		/* Fill the payload */
		syslog(LOG_ERR, " Received timedout (or was canceled)\n");
		size = sizeof(struct OseGW_ReceiveReply);
		memset(&reply->payload.start_of_payload, 0, size);
		reply->payload.receive_reply.status = htonl(OseGW_StatusOk);
	}

	/*Send */
	size = sizeof(struct OseGW_TransportHdr) + payload_len;
	status = send(skt, (void *) reply, size, 0);
	if (status == size) {
		LOG(LOG_INFO, "Gateway Client: replying ReceiveReply "
                    "on socket %d", skt);
	} else {
		syslog(LOG_INFO, "Gateway Client: failed replying "
		       "ReceiveReply on socket %d",  skt);
		status = -1;
	}

	/* Clean up */
	if (signal != LINX_NIL) {
		linx_free_buf(cinfo->linx, &signal);
	}
	free(reply);
	return status;
}
int main(int argc, char *argv[])
{
	LINX *linx;
	LINX_SPID server_spid;
	union LINX_SIGNAL *sig;
	pthread_t server_th;
	int c;
	int loop_cnt = LOOP_CNT;
	int use_linx_api = LINX_SOCKET;
	size_t msg_size = BURST_SIZE;
	unsigned long burst_cnt = BURST_CNT;
	size_t start_msg_size = START_MSG_SIZE;
	size_t end_msg_size = END_MSG_SIZE;
	unsigned long throughput_instances = THROUGHPUT_INSTANCES;
	int iterations = ITERATIONS;
	LINX_SIGSELECT any_sig[] = { 0 };

	char *path = NULL;
	char *server_name = NULL;
	int run_attach_test = 0;
	int run_com_test = 0;
	int kill_server = 0;
	int all = 0;
	int use_pthreads = 0;

	if (argc < 2) {
		print_usage(argv[0]);
		return 0;
	}

	while ((c = getopt(argc, argv, "S?p:ac:n:m:b:i:s:e:Alt:qP")) != -1) {
		switch (c) {
		case 'S':
			/* Start server */
			server_name = (optarg == NULL ? SERVER_NAME : optarg);
			break;

		case 'P':
			/* Start server as posix thread */
			server_name = SERVER_NAME;
			use_pthreads = 1;
			break;

		case 'p':
			/* Hunt path */
			path = optarg;
			break;

		case 'a':
			/* Run attach test */
			run_attach_test = 1;
			break;

		case 'c':
			/* Connection test */
			run_com_test = atoi(optarg);
			break;

		case 'n':
			/* Loop count */
			loop_cnt = atoi(optarg);
			break;

		case 'm':
			/* Message size */
			msg_size = atol(optarg);
			break;

		case 'b':
			/* Burst count */
			burst_cnt = atol(optarg);
			break;

		case 'i':
			/* Iterations */
			iterations = atoi(optarg);
			break;

		case 's':
			/* Start message size */
			start_msg_size = atol(optarg);
			break;

		case 'e':
			/* End message size */
			end_msg_size = atol(optarg);
			break;

		case 'A':
			/* Run all tests */
			all = 1;
			break;

		case 'l':
			/* Use linx api in tests */
			use_linx_api = LINX_API;
			break;

		case 't':
			/* Number of instances in throughput */
			throughput_instances = atoi(optarg);
			break;

		case 'q':
			/* Quit the server */
			kill_server = 1;
			break;
		default:
			print_usage(argv[0]);
			return 0;
		}
	}

	if(use_pthreads) {
		kill_server = 1;
		if (pthread_create(&server_th, NULL, server,
				   (void *)server_name)) {
			fprintf(stderr, "pthread_create(): %d\n", errno);
			exit(errno);
		}
	} else if (server_name != NULL) {
		(void)server(server_name);
		return 0;
	}

	/* Path to server */
	path = path && *path ? path : CS_PATH SERVER_NAME;

	/* Hunt for server */
	linx = linx_open(CLIENT_NAME, 0, NULL);
	linx_hunt(linx, path, NULL);
	linx_receive_w_tmo(linx, &sig, 1000, any_sig);
	if (sig == NULL) {
		printf("Hunt failed. No server found at path '%s'.\n"
		       "Is the server started and path ok? "
		       "(Server started with -S option)\n", path);
		linx_close(linx);
		return 1;
	}
	if (sig->sigNo != LINX_OS_HUNT_SIG) {
		ERR("Failed to hunt for '%s'", path);
		linx_free_buf(linx, &sig);
		linx_close(linx);
		return 1;
	}
	server_spid = linx_sender(linx, &sig);
	linx_free_buf(linx, &sig);

	/* Attach to server */
	sig = linx_alloc(linx, sizeof(LINX_SIGSELECT), ATTACH_SERV_SIG);
	linx_attach(linx, &sig, server_spid);

	if (run_attach_test) {
		attach_test(linx, path, loop_cnt, server_spid, use_linx_api,
			    use_pthreads);
	}

	switch (run_com_test) {
	case 1:
		/* Start com test 1 */
		linx_bmark_latency(linx, path, loop_cnt, msg_size, msg_size,
				   ONE_ITERATION, server_spid, use_linx_api,
				   use_pthreads);
		break;
	case 2:
		/* Start com test 2 */
		linx_bmark_burst(linx, path, loop_cnt, msg_size,
				 msg_size, ONE_ITERATION,
				 burst_cnt, server_spid, use_linx_api,
				 use_pthreads);
		break;
	case 3:
		/* Start com test 3 */
		linx_bmark_latency(linx, path, loop_cnt, start_msg_size,
				   end_msg_size, iterations, server_spid,
				   use_linx_api, use_pthreads);
		break;
	case 4:
		/* Start com test 4 */
		linx_bmark_burst(linx, path, loop_cnt, start_msg_size,
				 end_msg_size, iterations, burst_cnt,
				 server_spid, use_linx_api, use_pthreads);
		break;
	case 5:
		/* Start com test 5 */
		linx_bmark_throughput(path, loop_cnt, msg_size,
				      server_spid, use_linx_api,
				      throughput_instances, use_pthreads);
		break;
	default:
		break;
	}

	if (all) {
		/* All tests  */
		attach_test(linx, path, loop_cnt, server_spid, use_linx_api,
			    use_pthreads);
		linx_bmark_latency(linx, path, loop_cnt, msg_size, msg_size,
				   ONE_ITERATION, server_spid, use_linx_api,
				   use_pthreads);
		linx_bmark_burst(linx, path, loop_cnt, msg_size, msg_size,
				 ONE_ITERATION, burst_cnt,
				 server_spid, use_linx_api, use_pthreads);
		linx_bmark_latency(linx, path, loop_cnt, start_msg_size,
				   end_msg_size, iterations,
				   server_spid, use_linx_api, use_pthreads);
		linx_bmark_burst(linx, path, loop_cnt, start_msg_size,
				 end_msg_size, iterations, burst_cnt,
				 server_spid, use_linx_api, use_pthreads);
		linx_bmark_throughput(path, loop_cnt, msg_size,
				      server_spid, use_linx_api,
				      throughput_instances, use_pthreads);
	}

	if (kill_server) {
		/* If no test argument specified, let server close */
		sig = linx_alloc(linx, sizeof(LINX_SIGSELECT), CONN_TERM);
		linx_send(linx, &sig, server_spid);
		printf("Waiting for attach from server.\n");
		linx_receive(linx, &sig, any_sig);
		if (sig == LINX_NIL) {
			ERR("No attach signal was received from the server.");
		}
		if (sig->sigNo != ATTACH_SERV_SIG) {
			ERR("Wrong signal received while waiting for "
			    "attach signal from server.");
		}
		linx_free_buf(linx, &sig);

		/* Close client spid */
		linx_close(linx);
	}

	if(use_pthreads)
		pthread_join(server_th, NULL);
	
	return 0;
}
void *server(void *server_name)
{
	LINX *linx;
	union LINX_SIGNAL *sig;
	LINX_SPID client;
	pid_t pid;
	LINX_SIGSELECT any_sig[] = { 0 };
	unsigned slave_no = 0;
	char *name = (char *)server_name;
	if (!(name && *name))
		name = SERVER_NAME;
	PRINT(INFO, "Server master start. Using service name \"%s\"\n", name);

	linx = linx_open(name, 0, NULL);
	if (linx == NULL) {
		ERR("server linx_open failed. (insmod linx.ko done?)");
	}

	for (;;) {
		linx_receive(linx, &sig, any_sig);

		if (sig->sigNo == CONN_EST) {
			uint32_t use_linx_api =
			    ntohl(sig->connEst.use_linx_api);
			uint32_t use_pthreads = 
				ntohl(sig->connEst.use_pthreads);
			client = linx_sender(linx, &sig);
			linx_free_buf(linx, &sig);
			slave_no++;


			/* Spawn a test slave handling the
			 * requests from the client */
			if (use_pthreads) {
				pthread_t server_slave_th;
				struct slave_args *input =
					malloc(sizeof(*input));
				if(input == NULL) {
					ERR("Failed to allocate memory");
					exit(1);
				}
	input->client = client;
				input->slave_no = slave_no;
				input->use_linx_api = use_linx_api;
				input->use_pthreads = use_pthreads;
				if (pthread_create(&server_slave_th,
						   NULL, test_slave_proc,
						   (void *)input)) {
					fprintf(stderr, "pthread_create(): %d\n", errno);
					exit(errno);
				}
				/* thread frees arguments */
			} else {
				pid = fork();
				if (pid < 0) {
					ERR("server failed to fork. pid %d", pid);
					exit(1);
				}
				if (!pid) {
					pid = fork();
					if (pid < 0) {
						ERR("server failed to perform second "
						    "fork. pid %d", pid);
						exit(1);
					}
					if (!pid) {
						struct slave_args arg_;
						arg_.client = client;
						arg_.slave_no = slave_no;
						arg_.use_linx_api = use_linx_api;
						arg_.use_pthreads = use_pthreads;
						(void)test_slave_proc((void *)&arg_);
						exit(0);
					}
					exit(0);
				}
				wait(NULL);
			}
		} else if (sig->sigNo == CONN_TERM) {
			printf("server_master received conn_term\n");
			linx_free_buf(linx, &sig);
			printf("closing...\n");
			linx_close(linx);
			return NULL;
		} else {
			WARN("Ignoring unknown signal %ud", sig->sigNo);
			linx_free_buf(linx, &sig);
		}
	}
	return NULL;
}
static void test_with_linxlib(LINX_SPID client, LINX * linx)
{
	LINX_SPID sender;
	union LINX_SIGNAL *sig;
	LINX_SIGSELECT any_sig[] = { 0 };

	for (;;) {
		linx_receive(linx, &sig, any_sig);

		sender = linx_sender(linx, &sig);
		if (sender != client) {
			WARN("Ignoring signal from spid %ud", sender);
			linx_free_buf(linx, &sig);
			continue;
		}

		switch (sig->sigNo) {
		case ECHO_SIG:
			TRACE(1, "Sending echo");
			linx_send(linx, &sig, client);
			break;

		case TERMINATE_REQ:
			TRACE(1, "Terminating");
			linx_free_buf(linx, &sig);
			linx_close(linx);
			return;

		case ATTACH_TEST_REQ:
			linx_send(linx, &sig, client);
			linx_close(linx);
			return;

		case BURST_REQ:
			{
				int sigCnt = ntohl(sig->burstReq.n);
				int reply_size =
				    ntohl(sig->burstReq.reply_size);
				LINX_SIGSELECT reply_sigNo =
				    ntohl(sig->burstReq.reply_sigNo);
				union LINX_SIGNAL *list = 0;

				linx_free_buf(linx, &sig);

				/* Allocate all signals before sending then to
				 * make the send loop as tight as possible */
				while (sigCnt--) {
					sig = linx_alloc(linx, reply_size,
							 reply_sigNo);
					sig->burstSig.sigNo = reply_sigNo;
					sig->burstSig.next = list;
					list = sig;
				}

				while (list) {
					sig = list;
					list = list->burstSig.next;
					sig->burstSig.next = NULL;
					linx_send(linx, &sig, client);
				}
				break;
			}

		default:
			WARN("Ignoring unknown signal %ud", sig->sigNo);
			linx_free_buf(linx, &sig);
		}
	}
}