+ if (!icmd) {
+ log_err("fio: client: unable to find matching tag\n");
+ return;
+ }
+
+ flist_del(&icmd->list);
+ cmd->tag = icmd->saved_tag;
+ free(icmd);
+}
+
+static void handle_eta(struct fio_client *client, struct fio_net_cmd *cmd)
+{
+ struct jobs_eta *je = (struct jobs_eta *) cmd->payload;
+ struct client_eta *eta = (struct client_eta *) (uintptr_t) cmd->tag;
+
+ dprint(FD_NET, "client: got eta tag %p, %d\n", eta, eta->pending);
+
+ assert(client->eta_in_flight == eta);
+
+ client->eta_in_flight = NULL;
+ flist_del_init(&client->eta_list);
+
+ convert_jobs_eta(je);
+ sum_jobs_eta(&eta->eta, je);
+ dec_jobs_eta(eta);
+}
+
+static void handle_probe(struct fio_client *client, struct fio_net_cmd *cmd)
+{
+ struct cmd_probe_pdu *probe = (struct cmd_probe_pdu *) cmd->payload;
+ const char *os, *arch;
+ char bit[16];
+
+ os = fio_get_os_string(probe->os);
+ if (!os)
+ os = "unknown";
+
+ arch = fio_get_arch_string(probe->arch);
+ if (!arch)
+ os = "unknown";
+
+ sprintf(bit, "%d-bit", probe->bpp * 8);
+
+ log_info("hostname=%s, be=%u, %s, os=%s, arch=%s, fio=%u.%u.%u\n",
+ probe->hostname, probe->bigendian, bit, os, arch,
+ probe->fio_major, probe->fio_minor, probe->fio_patch);
+
+ if (!client->name)
+ client->name = strdup((char *) probe->hostname);
+}
+
+static void handle_start(struct fio_client *client, struct fio_net_cmd *cmd)
+{
+ struct cmd_start_pdu *pdu = (struct cmd_start_pdu *) cmd->payload;
+
+ client->state = Client_started;
+ client->jobs = le32_to_cpu(pdu->jobs);
+}
+
+static void handle_stop(struct fio_client *client, struct fio_net_cmd *cmd)
+{
+ struct cmd_end_pdu *pdu = (struct cmd_end_pdu *) cmd->payload;
+
+ client->state = Client_stopped;
+ client->error = le32_to_cpu(pdu->error);
+
+ if (client->error)
+ log_info("client <%s>: exited with error %d\n", client->hostname, client->error);
+}
+
+static int handle_client(struct fio_client *client, struct client_ops *ops)
+{
+ struct fio_net_cmd *cmd;
+
+ dprint(FD_NET, "client: handle %s\n", client->hostname);
+
+ cmd = fio_net_recv_cmd(client->fd);
+ if (!cmd)
+ return 0;
+
+ dprint(FD_NET, "client: got cmd op %s from %s\n",
+ fio_server_op(cmd->opcode), client->hostname);
+
+ switch (cmd->opcode) {
+ case FIO_NET_CMD_QUIT:
+ remove_client(client);
+ free(cmd);
+ break;
+ case FIO_NET_CMD_TEXT: {
+ const char *buf = (const char *) cmd->payload;
+ ops->text_op(client, f_out, cmd->pdu_len, buf);
+ free(cmd);
+ break;
+ }
+ case FIO_NET_CMD_DU:
+ ops->disk_util(client, cmd);
+ free(cmd);
+ break;
+ case FIO_NET_CMD_TS:
+ ops->thread_status(cmd);
+ free(cmd);
+ break;
+ case FIO_NET_CMD_GS:
+ ops->group_stats(cmd);
+ free(cmd);
+ break;
+ case FIO_NET_CMD_ETA:
+ remove_reply_cmd(client, cmd);
+ ops->eta(client, cmd);
+ free(cmd);
+ break;
+ case FIO_NET_CMD_PROBE:
+ remove_reply_cmd(client, cmd);
+ ops->probe(client, cmd);
+ free(cmd);
+ break;
+ case FIO_NET_CMD_RUN:
+ client->state = Client_running;
+ free(cmd);
+ break;
+ case FIO_NET_CMD_START:
+ handle_start(client, cmd);
+ free(cmd);
+ break;
+ case FIO_NET_CMD_STOP:
+ handle_stop(client, cmd);
+ free(cmd);
+ break;
+ default:
+ log_err("fio: unknown client op: %s\n", fio_server_op(cmd->opcode));
+ free(cmd);
+ break;
+ }
+
+ return 1;