diff options
Diffstat (limited to 'ijs_client.c')
-rw-r--r-- | ijs_client.c | 311 |
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; +} |