1 /**
2 * Copyright (c) 2001-2002 artofcode LLC.
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 **/
24
25 #include "unistd_.h"
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "ijs.h"
31 #include "ijs_client.h"
32
33 struct _IjsClientCtx {
34 int fd_from;
35 int child_pid;
36 IjsSendChan send_chan;
37 IjsRecvChan recv_chan;
38 int version;
39 };
40
41 IjsClientCtx *
ijs_invoke_server(const char * server_cmd)42 ijs_invoke_server (const char *server_cmd)
43 {
44 IjsClientCtx *ctx;
45 int fds_to[2], fds_from[2];
46 int child_pid;
47 char helo_buf[8] = IJS_HELO_STR;
48 char resp_buf[8];
49 const char exp_resp_buf[8] = IJS_RESP_STR;
50 ijs_bool ok = TRUE;
51 int nbytes;
52 int version;
53
54 if (ijs_exec_server(server_cmd, &fds_to[1], &fds_from[0], &child_pid) < 0)
55 return NULL;
56
57 ctx = (IjsClientCtx *)malloc (sizeof(IjsClientCtx));
58 ctx->fd_from = fds_from[0];
59 ctx->child_pid = child_pid;
60 ijs_send_init (&ctx->send_chan, fds_to[1]);
61 ijs_recv_init (&ctx->recv_chan, fds_from[0]);
62
63 nbytes = write (ctx->send_chan.fd, helo_buf, sizeof(helo_buf));
64 if (nbytes != sizeof(helo_buf))
65 ok = FALSE;
66
67 if (ok)
68 {
69 nbytes = read (ctx->recv_chan.fd, resp_buf, sizeof(resp_buf));
70 if (nbytes != sizeof(resp_buf) ||
71 memcmp (resp_buf, exp_resp_buf, sizeof(resp_buf)))
72 ok = FALSE;
73 }
74
75 /* exchange version information with server */
76 if (ok)
77 ok = ijs_client_begin_cmd (ctx, IJS_CMD_PING) >= 0;
78 if (ok)
79 ok = ijs_send_int (&ctx->send_chan, IJS_VERSION) >= 0;
80 if (ok)
81 ok = ijs_client_send_cmd_wait (ctx) >= 0;
82 if (ok)
83 ok = ijs_recv_int (&ctx->recv_chan, &version) >= 0;
84 if (ok)
85 {
86 if (version > IJS_VERSION)
87 version = IJS_VERSION;
88 ctx->version = version;
89 }
90
91 if (!ok)
92 {
93 close (ctx->send_chan.fd);
94 close (ctx->recv_chan.fd);
95 free (ctx);
96 ctx = NULL;
97 }
98
99 return ctx;
100 }
101
102 int
ijs_client_begin_cmd(IjsClientCtx * ctx,IjsCommand cmd)103 ijs_client_begin_cmd (IjsClientCtx *ctx, IjsCommand cmd)
104 {
105 return ijs_send_begin (&ctx->send_chan, cmd);
106 }
107
108 int
ijs_client_send_int(IjsClientCtx * ctx,int val)109 ijs_client_send_int (IjsClientCtx *ctx, int val)
110 {
111 return ijs_send_int (&ctx->send_chan, val);
112 }
113
114 int
ijs_client_send_cmd(IjsClientCtx * ctx)115 ijs_client_send_cmd (IjsClientCtx *ctx)
116 {
117 return ijs_send_buf (&ctx->send_chan);
118 }
119
120 /**
121 * ijs_client_send_cmd_wait: Send command and wait for ack.
122 * @ctx: IJS client context.
123 *
124 * Sends the command in the client context's buffer, and waits for ack.
125 *
126 * Return value: 0 on successful ack, otherwise negative.
127 **/
128 int
ijs_client_send_cmd_wait(IjsClientCtx * ctx)129 ijs_client_send_cmd_wait (IjsClientCtx *ctx)
130 {
131 int status;
132
133 status = ijs_client_send_cmd (ctx);
134 if (status >= 0)
135 {
136 status = ijs_recv_ack (&ctx->recv_chan);
137 }
138 return status;
139 }
140
141 /* This is the blocking version; it's not likely to be efficient */
142 int
ijs_client_send_data_wait(IjsClientCtx * ctx,IjsJobId job_id,const char * buf,int size)143 ijs_client_send_data_wait (IjsClientCtx *ctx, IjsJobId job_id,
144 const char *buf, int size)
145 {
146 int status;
147
148 ijs_client_begin_cmd (ctx, IJS_CMD_SEND_DATA_BLOCK);
149 ijs_send_int (&ctx->send_chan, job_id);
150 ijs_send_int (&ctx->send_chan, size);
151 status = ijs_client_send_cmd (ctx);
152 if (status)
153 return status;
154 status = write (ctx->send_chan.fd, buf, size);
155 if (status != size)
156 return IJS_EIO;
157 status = ijs_recv_ack (&ctx->recv_chan);
158 return status;
159 }
160
161 int
ijs_client_open(IjsClientCtx * ctx)162 ijs_client_open (IjsClientCtx *ctx)
163 {
164 ijs_client_begin_cmd (ctx, IJS_CMD_OPEN);
165 return ijs_client_send_cmd_wait (ctx);
166 }
167
168 int
ijs_client_close(IjsClientCtx * ctx)169 ijs_client_close (IjsClientCtx *ctx)
170 {
171 ijs_client_begin_cmd (ctx, IJS_CMD_CLOSE);
172 return ijs_client_send_cmd_wait (ctx);
173 }
174
175 int
ijs_client_begin_job(IjsClientCtx * ctx,IjsJobId job_id)176 ijs_client_begin_job (IjsClientCtx *ctx, IjsJobId job_id)
177 {
178 ijs_client_begin_cmd (ctx, IJS_CMD_BEGIN_JOB);
179 ijs_send_int (&ctx->send_chan, job_id);
180 return ijs_client_send_cmd_wait (ctx);
181 }
182
183 int
ijs_client_end_job(IjsClientCtx * ctx,IjsJobId job_id)184 ijs_client_end_job (IjsClientCtx *ctx, IjsJobId job_id)
185 {
186 ijs_client_begin_cmd (ctx, IJS_CMD_END_JOB);
187 ijs_send_int (&ctx->send_chan, job_id);
188 return ijs_client_send_cmd_wait (ctx);
189 }
190
191 /**
192 * Return value: data block size if nonnegative, or error code if
193 * negative.
194 **/
195 int
ijs_client_list_params(IjsClientCtx * ctx,IjsJobId job_id,char * value,int value_size)196 ijs_client_list_params (IjsClientCtx *ctx, IjsJobId job_id,
197 char *value, int value_size)
198 {
199 int status;
200
201 ijs_client_begin_cmd (ctx, IJS_CMD_LIST_PARAMS);
202 ijs_send_int (&ctx->send_chan, job_id);
203 status = ijs_client_send_cmd (ctx);
204 if (status)
205 return status;
206 status = ijs_recv_ack (&ctx->recv_chan);
207 if (status)
208 return status;
209 status = ijs_recv_block (&ctx->recv_chan, value, value_size);
210 return status;
211 }
212
213 /**
214 * Return value: data block size if nonnegative, or error code if
215 * negative.
216 **/
217 int
ijs_client_enum_param(IjsClientCtx * ctx,IjsJobId job_id,const char * key,char * value,int value_size)218 ijs_client_enum_param (IjsClientCtx *ctx, IjsJobId job_id,
219 const char *key,
220 char *value, int value_size)
221 {
222 int key_size = strlen (key);
223 int status;
224
225 ijs_client_begin_cmd (ctx, IJS_CMD_ENUM_PARAM);
226 ijs_send_int (&ctx->send_chan, job_id);
227 status = ijs_send_block (&ctx->send_chan, key, key_size + 1);
228 if (status < 0)
229 return IJS_EIO;
230 status = ijs_client_send_cmd (ctx);
231 if (status)
232 return status;
233 status = ijs_recv_ack (&ctx->recv_chan);
234 if (status)
235 return status;
236 status = ijs_recv_block (&ctx->recv_chan, value, value_size);
237 return status;
238 }
239
240 int
ijs_client_set_param(IjsClientCtx * ctx,IjsJobId job_id,const char * key,const char * value,int value_size)241 ijs_client_set_param (IjsClientCtx *ctx, IjsJobId job_id,
242 const char *key,
243 const char *value, int value_size)
244 {
245 int key_size = strlen (key);
246 int status;
247
248 ijs_client_begin_cmd (ctx, IJS_CMD_SET_PARAM);
249 ijs_send_int (&ctx->send_chan, job_id);
250 ijs_send_int (&ctx->send_chan, key_size + 1 + value_size);
251 status = ijs_send_block (&ctx->send_chan, key, key_size+1);
252 if (status)
253 return status;
254 status = ijs_send_block (&ctx->send_chan, value, value_size);
255 if (status)
256 return status;
257 status = ijs_client_send_cmd (ctx);
258 if (status)
259 return status;
260 status = ijs_recv_ack (&ctx->recv_chan);
261 return status;
262 }
263
264 /**
265 * Return value: data block size if nonnegative, or error code if
266 * negative.
267 **/
268 int
ijs_client_get_param(IjsClientCtx * ctx,IjsJobId job_id,const char * key,char * value,int value_size)269 ijs_client_get_param (IjsClientCtx *ctx, IjsJobId job_id,
270 const char *key,
271 char *value, int value_size)
272 {
273 int key_size = strlen (key);
274 int status;
275
276 ijs_client_begin_cmd (ctx, IJS_CMD_GET_PARAM);
277 ijs_send_int (&ctx->send_chan, job_id);
278 status = ijs_send_block (&ctx->send_chan, key, key_size + 1);
279 if (status < 0)
280 return IJS_EIO;
281 status = ijs_client_send_cmd (ctx);
282 if (status)
283 return status;
284 status = ijs_recv_ack (&ctx->recv_chan);
285 if (status)
286 return status;
287 status = ijs_recv_block (&ctx->recv_chan, value, value_size);
288 return status;
289 }
290
291 int
ijs_client_begin_page(IjsClientCtx * ctx,IjsJobId job_id)292 ijs_client_begin_page (IjsClientCtx *ctx, IjsJobId job_id)
293 {
294 ijs_client_begin_cmd (ctx, IJS_CMD_BEGIN_PAGE);
295 ijs_send_int (&ctx->send_chan, job_id);
296 return ijs_client_send_cmd_wait (ctx);
297 }
298
299 int
ijs_client_end_page(IjsClientCtx * ctx,IjsJobId job_id)300 ijs_client_end_page (IjsClientCtx *ctx, IjsJobId job_id)
301 {
302 ijs_client_begin_cmd (ctx, IJS_CMD_END_PAGE);
303 ijs_send_int (&ctx->send_chan, job_id);
304 return ijs_client_send_cmd_wait (ctx);
305 }
306
307 int
ijs_client_get_version(IjsClientCtx * ctx)308 ijs_client_get_version (IjsClientCtx *ctx)
309 {
310 return ctx->version;
311 }
312