summaryrefslogtreecommitdiff
path: root/ijs_client.c
diff options
context:
space:
mode:
Diffstat (limited to 'ijs_client.c')
-rw-r--r--ijs_client.c311
1 files changed, 311 insertions, 0 deletions
diff --git a/ijs_client.c b/ijs_client.c
new file mode 100644
index 0000000..c3ed3d3
--- /dev/null
+++ b/ijs_client.c
@@ -0,0 +1,311 @@
+/**
+ * Copyright (c) 2001-2002 artofcode LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+**/
+
+#include "unistd_.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ijs.h"
+#include "ijs_client.h"
+
+struct _IjsClientCtx {
+ int fd_from;
+ int child_pid;
+ IjsSendChan send_chan;
+ IjsRecvChan recv_chan;
+ int version;
+};
+
+IjsClientCtx *
+ijs_invoke_server (const char *server_cmd)
+{
+ IjsClientCtx *ctx;
+ int fds_to[2], fds_from[2];
+ int child_pid;
+ char helo_buf[8] = IJS_HELO_STR;
+ char resp_buf[8];
+ const char exp_resp_buf[8] = IJS_RESP_STR;
+ ijs_bool ok = TRUE;
+ int nbytes;
+ int version;
+
+ if (ijs_exec_server(server_cmd, &fds_to[1], &fds_from[0], &child_pid) < 0)
+ return NULL;
+
+ ctx = (IjsClientCtx *)malloc (sizeof(IjsClientCtx));
+ ctx->fd_from = fds_from[0];
+ ctx->child_pid = child_pid;
+ ijs_send_init (&ctx->send_chan, fds_to[1]);
+ ijs_recv_init (&ctx->recv_chan, fds_from[0]);
+
+ nbytes = write (ctx->send_chan.fd, helo_buf, sizeof(helo_buf));
+ if (nbytes != sizeof(helo_buf))
+ ok = FALSE;
+
+ if (ok)
+ {
+ nbytes = read (ctx->recv_chan.fd, resp_buf, sizeof(resp_buf));
+ if (nbytes != sizeof(resp_buf) ||
+ memcmp (resp_buf, exp_resp_buf, sizeof(resp_buf)))
+ ok = FALSE;
+ }
+
+ /* exchange version information with server */
+ if (ok)
+ ok = ijs_client_begin_cmd (ctx, IJS_CMD_PING) >= 0;
+ if (ok)
+ ok = ijs_send_int (&ctx->send_chan, IJS_VERSION) >= 0;
+ if (ok)
+ ok = ijs_client_send_cmd_wait (ctx) >= 0;
+ if (ok)
+ ok = ijs_recv_int (&ctx->recv_chan, &version) >= 0;
+ if (ok)
+ {
+ if (version > IJS_VERSION)
+ version = IJS_VERSION;
+ ctx->version = version;
+ }
+
+ if (!ok)
+ {
+ close (ctx->send_chan.fd);
+ close (ctx->recv_chan.fd);
+ free (ctx);
+ ctx = NULL;
+ }
+
+ return ctx;
+}
+
+int
+ijs_client_begin_cmd (IjsClientCtx *ctx, IjsCommand cmd)
+{
+ return ijs_send_begin (&ctx->send_chan, cmd);
+}
+
+int
+ijs_client_send_int (IjsClientCtx *ctx, int val)
+{
+ return ijs_send_int (&ctx->send_chan, val);
+}
+
+int
+ijs_client_send_cmd (IjsClientCtx *ctx)
+{
+ return ijs_send_buf (&ctx->send_chan);
+}
+
+/**
+ * ijs_client_send_cmd_wait: Send command and wait for ack.
+ * @ctx: IJS client context.
+ *
+ * Sends the command in the client context's buffer, and waits for ack.
+ *
+ * Return value: 0 on successful ack, otherwise negative.
+ **/
+int
+ijs_client_send_cmd_wait (IjsClientCtx *ctx)
+{
+ int status;
+
+ status = ijs_client_send_cmd (ctx);
+ if (status >= 0)
+ {
+ status = ijs_recv_ack (&ctx->recv_chan);
+ }
+ return status;
+}
+
+/* This is the blocking version; it's not likely to be efficient */
+int
+ijs_client_send_data_wait (IjsClientCtx *ctx, IjsJobId job_id,
+ const char *buf, int size)
+{
+ int status;
+
+ ijs_client_begin_cmd (ctx, IJS_CMD_SEND_DATA_BLOCK);
+ ijs_send_int (&ctx->send_chan, job_id);
+ ijs_send_int (&ctx->send_chan, size);
+ status = ijs_client_send_cmd (ctx);
+ if (status)
+ return status;
+ status = write (ctx->send_chan.fd, buf, size);
+ if (status != size)
+ return IJS_EIO;
+ status = ijs_recv_ack (&ctx->recv_chan);
+ return status;
+}
+
+int
+ijs_client_open (IjsClientCtx *ctx)
+{
+ ijs_client_begin_cmd (ctx, IJS_CMD_OPEN);
+ return ijs_client_send_cmd_wait (ctx);
+}
+
+int
+ijs_client_close (IjsClientCtx *ctx)
+{
+ ijs_client_begin_cmd (ctx, IJS_CMD_CLOSE);
+ return ijs_client_send_cmd_wait (ctx);
+}
+
+int
+ijs_client_begin_job (IjsClientCtx *ctx, IjsJobId job_id)
+{
+ ijs_client_begin_cmd (ctx, IJS_CMD_BEGIN_JOB);
+ ijs_send_int (&ctx->send_chan, job_id);
+ return ijs_client_send_cmd_wait (ctx);
+}
+
+int
+ijs_client_end_job (IjsClientCtx *ctx, IjsJobId job_id)
+{
+ ijs_client_begin_cmd (ctx, IJS_CMD_END_JOB);
+ ijs_send_int (&ctx->send_chan, job_id);
+ return ijs_client_send_cmd_wait (ctx);
+}
+
+/**
+ * Return value: data block size if nonnegative, or error code if
+ * negative.
+ **/
+int
+ijs_client_list_params (IjsClientCtx *ctx, IjsJobId job_id,
+ char *value, int value_size)
+{
+ int status;
+
+ ijs_client_begin_cmd (ctx, IJS_CMD_LIST_PARAMS);
+ ijs_send_int (&ctx->send_chan, job_id);
+ status = ijs_client_send_cmd (ctx);
+ if (status)
+ return status;
+ status = ijs_recv_ack (&ctx->recv_chan);
+ if (status)
+ return status;
+ status = ijs_recv_block (&ctx->recv_chan, value, value_size);
+ return status;
+}
+
+/**
+ * Return value: data block size if nonnegative, or error code if
+ * negative.
+ **/
+int
+ijs_client_enum_param (IjsClientCtx *ctx, IjsJobId job_id,
+ const char *key,
+ char *value, int value_size)
+{
+ int key_size = strlen (key);
+ int status;
+
+ ijs_client_begin_cmd (ctx, IJS_CMD_ENUM_PARAM);
+ ijs_send_int (&ctx->send_chan, job_id);
+ status = ijs_send_block (&ctx->send_chan, key, key_size + 1);
+ if (status < 0)
+ return IJS_EIO;
+ status = ijs_client_send_cmd (ctx);
+ if (status)
+ return status;
+ status = ijs_recv_ack (&ctx->recv_chan);
+ if (status)
+ return status;
+ status = ijs_recv_block (&ctx->recv_chan, value, value_size);
+ return status;
+}
+
+int
+ijs_client_set_param (IjsClientCtx *ctx, IjsJobId job_id,
+ const char *key,
+ const char *value, int value_size)
+{
+ int key_size = strlen (key);
+ int status;
+
+ ijs_client_begin_cmd (ctx, IJS_CMD_SET_PARAM);
+ ijs_send_int (&ctx->send_chan, job_id);
+ ijs_send_int (&ctx->send_chan, key_size + 1 + value_size);
+ status = ijs_send_block (&ctx->send_chan, key, key_size+1);
+ if (status)
+ return status;
+ status = ijs_send_block (&ctx->send_chan, value, value_size);
+ if (status)
+ return status;
+ status = ijs_client_send_cmd (ctx);
+ if (status)
+ return status;
+ status = ijs_recv_ack (&ctx->recv_chan);
+ return status;
+}
+
+/**
+ * Return value: data block size if nonnegative, or error code if
+ * negative.
+ **/
+int
+ijs_client_get_param (IjsClientCtx *ctx, IjsJobId job_id,
+ const char *key,
+ char *value, int value_size)
+{
+ int key_size = strlen (key);
+ int status;
+
+ ijs_client_begin_cmd (ctx, IJS_CMD_GET_PARAM);
+ ijs_send_int (&ctx->send_chan, job_id);
+ status = ijs_send_block (&ctx->send_chan, key, key_size + 1);
+ if (status < 0)
+ return IJS_EIO;
+ status = ijs_client_send_cmd (ctx);
+ if (status)
+ return status;
+ status = ijs_recv_ack (&ctx->recv_chan);
+ if (status)
+ return status;
+ status = ijs_recv_block (&ctx->recv_chan, value, value_size);
+ return status;
+}
+
+int
+ijs_client_begin_page (IjsClientCtx *ctx, IjsJobId job_id)
+{
+ ijs_client_begin_cmd (ctx, IJS_CMD_BEGIN_PAGE);
+ ijs_send_int (&ctx->send_chan, job_id);
+ return ijs_client_send_cmd_wait (ctx);
+}
+
+int
+ijs_client_end_page (IjsClientCtx *ctx, IjsJobId job_id)
+{
+ ijs_client_begin_cmd (ctx, IJS_CMD_END_PAGE);
+ ijs_send_int (&ctx->send_chan, job_id);
+ return ijs_client_send_cmd_wait (ctx);
+}
+
+int
+ijs_client_get_version (IjsClientCtx *ctx)
+{
+ return ctx->version;
+}