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 <stdlib.h>
26 #include <stdio.h>
27 #include "unistd_.h"
28 #include <string.h>
29
30 #include "ijs.h"
31 #include "ijs_server.h"
32
33 #define noVERBOSE
34
35 typedef enum {
36 IJS_N_CHAN_SET = 1,
37 IJS_BPS_SET = 2,
38 IJS_CS_SET = 4,
39 IJS_WIDTH_SET = 8,
40 IJS_HEIGHT_SET = 16,
41 IJS_DPI_SET = 32
42 } IjsFieldsSet;
43
44 #define IJS_FIELDS_REQUIRED (IJS_N_CHAN_SET | IJS_BPS_SET | IJS_CS_SET | \
45 IJS_WIDTH_SET | IJS_HEIGHT_SET | IJS_DPI_SET)
46
47 struct _IjsServerCtx {
48 int fd_from;
49 int child_pid;
50 IjsSendChan send_chan;
51 IjsRecvChan recv_chan;
52 int version;
53
54 /* callbacks */
55 IjsBeginJobCb *begin_cb;
56 void *begin_cb_data;
57 IjsEndJobCb *end_cb;
58 void *end_cb_data;
59 IjsQueryStatusCb *status_cb;
60 void *status_cb_data;
61 IjsListParamsCb *list_cb;
62 void *list_cb_data;
63 IjsEnumParamCb *enum_cb;
64 void *enum_cb_data;
65 IjsSetParamCb *set_cb;
66 void *set_cb_data;
67 IjsGetParamCb *get_cb;
68 void *get_cb_data;
69
70 ijs_bool in_job;
71 IjsJobId job_id;
72
73 IjsPageHeader *ph;
74
75 /* This should be IjsFieldsSet, but David Suffield reports that this
76 causes problems when compiling with g++. */
77 int fields_set;
78 ijs_bool in_page;
79
80 char *buf;
81 int buf_size;
82 int buf_ix;
83 char *overflow_buf;
84 int overflow_buf_size;
85 int overflow_buf_ix;
86 };
87
88 static int
ijs_server_dummy_begin_cb(void * begin_cb_data,IjsServerCtx * ctx,IjsJobId job_id)89 ijs_server_dummy_begin_cb (void *begin_cb_data,
90 IjsServerCtx *ctx,
91 IjsJobId job_id)
92 {
93 return 0;
94 }
95
96 static int
ijs_server_dummy_end_cb(void * end_cb_data,IjsServerCtx * ctx,IjsJobId job_id)97 ijs_server_dummy_end_cb (void *end_cb_data,
98 IjsServerCtx *ctx,
99 IjsJobId job_id)
100 {
101 return 0;
102 }
103
104 IjsServerCtx *
ijs_server_init(void)105 ijs_server_init (void)
106 {
107 ijs_bool ok = TRUE;
108 char helo_buf[8];
109 char resp_buf[8];
110 int nbytes;
111 IjsServerCtx *ctx = (IjsServerCtx *)malloc (sizeof(IjsServerCtx));
112 int fd_from, fd_to;
113
114 memcpy (resp_buf, IJS_RESP_STR, sizeof(resp_buf));
115
116 fd_from = 0;
117 fd_to = 1;
118 #ifdef _MSC_VER
119 _setmode(fd_from, _O_BINARY);
120 _setmode(fd_to, _O_BINARY);
121 #endif
122 #ifdef VERBOSE
123 fprintf (stderr, "fd_from = %d, fd_to = %d\n", fd_from, fd_to);
124 #endif
125 ijs_recv_init (&ctx->recv_chan, fd_from);
126 ijs_send_init (&ctx->send_chan, fd_to);
127 nbytes = read (ctx->recv_chan.fd, helo_buf, sizeof(helo_buf));
128
129 if (nbytes != sizeof(helo_buf))
130 ok = FALSE;
131
132 if (ok)
133 nbytes = write (ctx->send_chan.fd, resp_buf, sizeof(resp_buf));
134 if (nbytes != sizeof(resp_buf))
135 ok = FALSE;
136
137 ctx->in_job = FALSE;
138 ctx->job_id = -1;
139
140 ctx->ph = NULL;
141 ctx->in_page = FALSE;
142 ctx->buf = NULL;
143 ctx->overflow_buf = NULL;
144
145 ctx->begin_cb = ijs_server_dummy_begin_cb;
146 ctx->end_cb = ijs_server_dummy_end_cb;
147
148 if (ok)
149 return ctx;
150 else
151 {
152 ijs_server_done (ctx);
153 return NULL;
154 }
155 }
156
157 int
ijs_server_install_begin_cb(IjsServerCtx * ctx,IjsBeginJobCb * begin_cb,void * begin_cb_data)158 ijs_server_install_begin_cb (IjsServerCtx *ctx,
159 IjsBeginJobCb *begin_cb, void *begin_cb_data)
160 {
161 ctx->begin_cb = begin_cb;
162 ctx->begin_cb_data = begin_cb_data;
163 return 0;
164 }
165
166 int
ijs_server_install_end_cb(IjsServerCtx * ctx,IjsEndJobCb * end_cb,void * end_cb_data)167 ijs_server_install_end_cb (IjsServerCtx *ctx,
168 IjsEndJobCb *end_cb, void *end_cb_data)
169 {
170 ctx->end_cb = end_cb;
171 ctx->end_cb_data = end_cb_data;
172 return 0;
173 }
174
175 int
ijs_server_install_status_cb(IjsServerCtx * ctx,IjsQueryStatusCb * status_cb,void * status_cb_data)176 ijs_server_install_status_cb (IjsServerCtx *ctx,
177 IjsQueryStatusCb *status_cb,
178 void *status_cb_data)
179 {
180 ctx->status_cb = status_cb;
181 ctx->status_cb_data = status_cb_data;
182 return 0;
183 }
184
185 int
ijs_server_install_list_cb(IjsServerCtx * ctx,IjsListParamsCb * list_cb,void * list_cb_data)186 ijs_server_install_list_cb (IjsServerCtx *ctx,
187 IjsListParamsCb *list_cb, void *list_cb_data)
188 {
189 ctx->list_cb = list_cb;
190 ctx->list_cb_data = list_cb_data;
191 return 0;
192 }
193
194 int
ijs_server_install_enum_cb(IjsServerCtx * ctx,IjsEnumParamCb * enum_cb,void * enum_cb_data)195 ijs_server_install_enum_cb (IjsServerCtx *ctx,
196 IjsEnumParamCb *enum_cb, void *enum_cb_data)
197 {
198 ctx->enum_cb = enum_cb;
199 ctx->enum_cb_data = enum_cb_data;
200 return 0;
201 }
202
203 int
ijs_server_install_set_cb(IjsServerCtx * ctx,IjsSetParamCb * set_cb,void * set_cb_data)204 ijs_server_install_set_cb (IjsServerCtx *ctx,
205 IjsSetParamCb *set_cb, void *set_cb_data)
206 {
207 ctx->set_cb = set_cb;
208 ctx->set_cb_data = set_cb_data;
209 return 0;
210 }
211
212 int
ijs_server_install_get_cb(IjsServerCtx * ctx,IjsGetParamCb * get_cb,void * get_cb_data)213 ijs_server_install_get_cb (IjsServerCtx *ctx,
214 IjsGetParamCb *get_cb, void *get_cb_data)
215 {
216 ctx->get_cb = get_cb;
217 ctx->get_cb_data = get_cb_data;
218 return 0;
219 }
220
221 static int
ijs_server_ack(IjsServerCtx * ctx)222 ijs_server_ack (IjsServerCtx *ctx)
223 {
224 int status;
225
226 status = ijs_send_begin (&ctx->send_chan, IJS_CMD_ACK);
227 if (status < 0)
228 return status;
229 return ijs_send_buf (&ctx->send_chan);
230 }
231
232 void
ijs_server_done(IjsServerCtx * ctx)233 ijs_server_done (IjsServerCtx *ctx)
234 {
235 /* todo: close channels */
236 ijs_server_ack (ctx);
237
238 free (ctx);
239 }
240
241 static int
ijs_server_nak(IjsServerCtx * ctx,int errorcode)242 ijs_server_nak (IjsServerCtx *ctx, int errorcode)
243 {
244 int status;
245
246 status = ijs_send_begin (&ctx->send_chan, IJS_CMD_NAK);
247 if (status < 0)
248 return status;
249 status = ijs_send_int (&ctx->send_chan, errorcode);
250 if (status < 0)
251 return status;
252 return ijs_send_buf (&ctx->send_chan);
253 }
254
255 /* The return code is: 0 if ok, positive on normal exit, negative on error */
256 typedef int (*ijs_server_proc) (IjsServerCtx *ctx);
257
258 static int
ijs_server_proc_ack(IjsServerCtx * ctx)259 ijs_server_proc_ack (IjsServerCtx *ctx)
260 {
261 /* servers should not get ack commands */
262 return IJS_EPROTO;
263 }
264
265 static int
ijs_server_proc_nak(IjsServerCtx * ctx)266 ijs_server_proc_nak (IjsServerCtx *ctx)
267 {
268 /* servers should not get nak commands */
269 return IJS_EPROTO;
270 }
271
272 static int
ijs_server_proc_ping(IjsServerCtx * ctx)273 ijs_server_proc_ping (IjsServerCtx *ctx)
274 {
275 int status;
276 int version;
277
278 status = ijs_recv_int (&ctx->recv_chan, &version);
279 if (status < 0)
280 return status;
281 if (version > IJS_VERSION)
282 version = IJS_VERSION;
283 ctx->version = version;
284
285 #ifdef VERBOSE
286 fprintf (stderr, "ping version=%d\n", version);
287 #endif
288 status = ijs_send_begin (&ctx->send_chan, IJS_CMD_PONG);
289 if (status < 0)
290 return status;
291 status = ijs_send_int (&ctx->send_chan, IJS_VERSION);
292 if (status < 0)
293 return status;
294 return ijs_send_buf (&ctx->send_chan);
295 }
296
297 static int
ijs_server_proc_pong(IjsServerCtx * ctx)298 ijs_server_proc_pong (IjsServerCtx *ctx)
299 {
300 /* servers should not get pong commands */
301 return IJS_EPROTO;
302 }
303
304 static int
ijs_server_proc_open(IjsServerCtx * ctx)305 ijs_server_proc_open (IjsServerCtx *ctx)
306 {
307 /* A server might allocate tables here. */
308 return ijs_server_ack (ctx);
309 }
310
311 static int
ijs_server_proc_close(IjsServerCtx * ctx)312 ijs_server_proc_close (IjsServerCtx *ctx)
313 {
314 /* A server might deallocate memory here. */
315 return ijs_server_ack (ctx);
316 }
317
318 static int
ijs_server_proc_begin_job(IjsServerCtx * ctx)319 ijs_server_proc_begin_job (IjsServerCtx *ctx)
320 {
321 int code;
322 IjsJobId job_id;
323
324 code = ijs_recv_int (&ctx->recv_chan, &job_id);
325 if (code < 0) return code;
326
327 if (ctx->in_job)
328 return ijs_server_nak (ctx, IJS_ETOOMANYJOBS);
329 ctx->in_job = TRUE;
330 ctx->job_id = job_id;
331
332 return ijs_server_ack (ctx);
333 }
334
335 static int
ijs_server_proc_end_job(IjsServerCtx * ctx)336 ijs_server_proc_end_job (IjsServerCtx *ctx)
337 {
338 int code;
339 IjsJobId job_id;
340
341 code = ijs_recv_int (&ctx->recv_chan, &job_id);
342 if (code < 0) return code;
343
344 if (!ctx->in_job || job_id != ctx->job_id)
345 return ijs_server_nak (ctx, IJS_EJOBID);
346 ctx->in_job = FALSE;
347
348 return ijs_server_ack (ctx);
349 }
350
351 static int
ijs_server_proc_cancel_job(IjsServerCtx * ctx)352 ijs_server_proc_cancel_job (IjsServerCtx *ctx)
353 {
354 int code;
355 IjsJobId job_id;
356
357 code = ijs_recv_int (&ctx->recv_chan, &job_id);
358 if (code < 0) return code;
359
360 if (!ctx->in_job || job_id != ctx->job_id)
361 return ijs_server_nak (ctx, IJS_EJOBID);
362 /* todo: call cancel callback here */
363 ctx->in_job = FALSE;
364
365 return ijs_server_ack (ctx);
366 }
367
368 static int
ijs_server_proc_query_status(IjsServerCtx * ctx)369 ijs_server_proc_query_status (IjsServerCtx *ctx)
370 {
371 int code;
372 IjsJobId job_id;
373
374 code = ijs_recv_int (&ctx->recv_chan, &job_id);
375 if (code < 0)
376 return code;
377
378 if (!ctx->in_job || ctx->job_id != job_id)
379 return ijs_server_nak (ctx, IJS_EJOBID);
380
381 code = ctx->status_cb (ctx->list_cb_data, ctx, job_id);
382 if (code < 0)
383 return ijs_server_nak (ctx, code);
384 else
385 {
386 int status;
387
388 status = ijs_send_begin (&ctx->send_chan, IJS_CMD_ACK);
389 if (status < 0)
390 return status;
391 status = ijs_send_int (&ctx->send_chan, code);
392 if (status < 0)
393 return status;
394 return ijs_send_buf (&ctx->send_chan);
395 }
396 }
397
398 static int
ijs_server_proc_list_params(IjsServerCtx * ctx)399 ijs_server_proc_list_params (IjsServerCtx *ctx)
400 {
401 int code;
402 char buf[4096];
403 IjsJobId job_id;
404
405 code = ijs_recv_int (&ctx->recv_chan, &job_id);
406 if (code < 0)
407 return code;
408
409 if (!ctx->in_job || ctx->job_id != job_id)
410 return ijs_server_nak (ctx, IJS_EJOBID);
411
412 code = ctx->list_cb (ctx->list_cb_data, ctx, job_id, buf, sizeof(buf));
413 if (code < 0)
414 return ijs_server_nak (ctx, code);
415 else
416 {
417 int status;
418
419 status = ijs_send_begin (&ctx->send_chan, IJS_CMD_ACK);
420 if (status < 0)
421 return status;
422 status = ijs_send_block (&ctx->send_chan, buf, code);
423 if (status < 0)
424 return status;
425 return ijs_send_buf (&ctx->send_chan);
426 }
427 }
428
429 static int
ijs_server_proc_enum_param(IjsServerCtx * ctx)430 ijs_server_proc_enum_param (IjsServerCtx *ctx)
431 {
432 const char *key;
433 int key_size;
434 int code;
435 char buf[4096];
436 IjsJobId job_id;
437
438 code = ijs_recv_int (&ctx->recv_chan, &job_id);
439 if (code < 0)
440 return code;
441
442 if (!ctx->in_job || ctx->job_id != job_id)
443 return ijs_server_nak (ctx, IJS_EJOBID);
444
445 key = ctx->recv_chan.buf + ctx->recv_chan.buf_idx;
446 key_size = ctx->recv_chan.buf_size - ctx->recv_chan.buf_idx;
447 if (key_size == 0 || key[key_size - 1])
448 return IJS_ESYNTAX;
449 #ifdef VERBOSE
450 fprintf (stderr, "ijs_server_proc_enum_param, key_size = %d\n", key_size);
451 #endif
452
453 code = ctx->enum_cb (ctx->enum_cb_data, ctx, job_id, key, buf, sizeof(buf));
454 if (code < 0)
455 return ijs_server_nak (ctx, code);
456 else
457 {
458 int status;
459
460 status = ijs_send_begin (&ctx->send_chan, IJS_CMD_ACK);
461 if (status < 0)
462 return status;
463 status = ijs_send_block (&ctx->send_chan, buf, code);
464 if (status < 0)
465 return status;
466 return ijs_send_buf (&ctx->send_chan);
467 }
468 }
469
470 static int
ijs_strnlen(const char * s,int size)471 ijs_strnlen (const char *s, int size)
472 {
473 int i;
474
475 for (i = 0; i < size; i++)
476 if (s[i] == 0)
477 return i;
478 return size;
479 }
480
481 static int
ijs_server_parse_int(const char * value,int size,int * result)482 ijs_server_parse_int (const char *value, int size, int *result)
483 {
484 int num = 0;
485 int i;
486 int sign = 1;
487
488 i = 0;
489 if (i == size)
490 return IJS_ESYNTAX;
491 if (value[i] == '-')
492 {
493 sign = -1;
494 i++;
495 }
496
497 if (i == size)
498 return IJS_ESYNTAX;
499
500 for (; i < size; i++)
501 {
502 char c = value[i];
503 if (c < '0' || c > '9')
504 return IJS_ESYNTAX;
505 num = (num * 10) + (c - '0');
506 }
507 *result = num;
508 return 0;
509 }
510
511 static int
ijs_server_parse_float(const char * value,int size,double * result)512 ijs_server_parse_float (const char *value, int size, double *result)
513 {
514 char buf[256];
515 char *tail;
516
517 if (size + 1 > sizeof(buf))
518 return IJS_EBUF;
519 memcpy (buf, value, size);
520 buf[size] = 0;
521 *result = strtod (buf, &tail);
522 if (tail == buf)
523 return IJS_ESYNTAX;
524 return 0;
525 }
526
527 static int
ijs_server_set_param(IjsServerCtx * ctx,IjsJobId job_id,const char * key,const char * value,int value_size)528 ijs_server_set_param (IjsServerCtx *ctx, IjsJobId job_id, const char *key,
529 const char *value, int value_size)
530 {
531 int code;
532
533 #ifdef VERBOSE
534 fprintf (stderr, "set_param %s = ", key);
535 fwrite (value, 1, value_size, stderr);
536 fputs ("\n", stderr);
537 #endif
538 if (!strcmp (key, "NumChan"))
539 {
540 code = ijs_server_parse_int (value, value_size, &ctx->ph->n_chan);
541 if (code == 0)
542 ctx->fields_set |= IJS_N_CHAN_SET;
543 return code;
544 }
545 else if (!strcmp (key, "BitsPerSample"))
546 {
547 code = ijs_server_parse_int (value, value_size, &ctx->ph->bps);
548 if (code == 0)
549 ctx->fields_set |= IJS_BPS_SET;
550 return code;
551 }
552 else if (!strcmp (key, "ColorSpace"))
553 {
554 int size = value_size;
555
556 if (size < (int)sizeof(ctx->ph->cs) - 1)
557 size = sizeof(ctx->ph->cs) - 1;
558 memcpy (ctx->ph->cs, value, size);
559 ctx->ph->cs[size] = 0;
560 ctx->fields_set |= IJS_CS_SET;
561 return 0;
562 }
563 else if (!strcmp (key, "Width"))
564 {
565 code = ijs_server_parse_int (value, value_size, &ctx->ph->width);
566 if (code == 0)
567 ctx->fields_set |= IJS_WIDTH_SET;
568 return code;
569 }
570 else if (!strcmp (key, "Height"))
571 {
572 code = ijs_server_parse_int (value, value_size, &ctx->ph->height);
573 if (code == 0)
574 ctx->fields_set |= IJS_HEIGHT_SET;
575 return code;
576 }
577 else if (!strcmp (key, "Dpi"))
578 {
579 int x_ix;
580
581 for (x_ix = 0; x_ix < value_size; x_ix++)
582 if (value[x_ix] == 'x')
583 break;
584 if (x_ix == value_size)
585 return IJS_ESYNTAX;
586 code = ijs_server_parse_float (value, x_ix, &ctx->ph->xres);
587 if (code < 0)
588 return code;
589 code = ijs_server_parse_float (value + x_ix + 1, value_size - (x_ix + 1),
590 &ctx->ph->yres);
591 if (code < 0)
592 return code;
593 ctx->fields_set |= IJS_DPI_SET;
594 return 0;
595 }
596 else
597 {
598 return ctx->set_cb (ctx->set_cb_data, ctx, job_id, key, value, value_size);
599 }
600 }
601
602 static int
ijs_server_proc_set_param(IjsServerCtx * ctx)603 ijs_server_proc_set_param (IjsServerCtx *ctx)
604 {
605 const char *key, *value;
606 int key_size, value_size;
607 IjsJobId job_id;
608 int param_size;
609 int code;
610
611 code = ijs_recv_int (&ctx->recv_chan, &job_id);
612 if (code < 0)
613 return code;
614
615 if (!ctx->in_job || ctx->job_id != job_id)
616 return ijs_server_nak (ctx, IJS_EJOBID);
617
618 code = ijs_recv_int (&ctx->recv_chan, ¶m_size);
619 if (code < 0)
620 return code;
621 if (param_size != ctx->recv_chan.buf_size - ctx->recv_chan.buf_idx)
622 return IJS_EPROTO;
623 key = ctx->recv_chan.buf + ctx->recv_chan.buf_idx;
624 key_size = ijs_strnlen (key, ctx->recv_chan.buf_size);
625 if (key_size == param_size)
626 return IJS_EPROTO;
627 value = key + key_size + 1;
628 value_size = param_size - (key_size + 1);
629 code = ijs_server_set_param (ctx, job_id, key, value, value_size);
630 if (code)
631 return ijs_server_nak (ctx, code);
632 else
633 return ijs_server_ack (ctx);
634 }
635
636 static int
ijs_server_get_param(IjsServerCtx * ctx,IjsJobId job_id,const char * key,char * value,int value_size)637 ijs_server_get_param (IjsServerCtx *ctx, IjsJobId job_id, const char *key,
638 char *value, int value_size)
639 {
640 #ifdef VERBOSE
641 fprintf (stderr, "ijs_server_get_param %s\n", key);
642 #endif
643 return ctx->get_cb (ctx->get_cb_data, ctx, job_id, key,
644 value, value_size);
645 }
646
647 static int
ijs_server_proc_get_param(IjsServerCtx * ctx)648 ijs_server_proc_get_param (IjsServerCtx *ctx)
649 {
650 const char *key;
651 int key_size;
652 int code;
653 char buf[4096];
654 IjsJobId job_id;
655
656 code = ijs_recv_int (&ctx->recv_chan, &job_id);
657 if (code < 0)
658 return code;
659
660 if (!ctx->in_job || ctx->job_id != job_id)
661 return ijs_server_nak (ctx, IJS_EJOBID);
662
663 key = ctx->recv_chan.buf + ctx->recv_chan.buf_idx;
664 key_size = ctx->recv_chan.buf_size - ctx->recv_chan.buf_idx;
665 if (key_size == 0 || key[key_size - 1])
666 return IJS_ESYNTAX;
667 #ifdef VERBOSE
668 fprintf (stderr, "ijs_server_proc_get_param, key_size = %d\n", key_size);
669 #endif
670
671 code = ijs_server_get_param (ctx, job_id, key, buf, sizeof(buf));
672 if (code < 0)
673 return ijs_server_nak (ctx, code);
674 else
675 {
676 int status;
677
678 status = ijs_send_begin (&ctx->send_chan, IJS_CMD_ACK);
679 if (status < 0)
680 return status;
681 status = ijs_send_block (&ctx->send_chan, buf, code);
682 if (status < 0)
683 return status;
684 return ijs_send_buf (&ctx->send_chan);
685 }
686 }
687
688 static int
ijs_server_proc_begin_page(IjsServerCtx * ctx)689 ijs_server_proc_begin_page (IjsServerCtx *ctx)
690 {
691 IjsPageHeader *ph = ctx->ph;
692 int status = 0;
693
694 if (ph == NULL)
695 status = IJS_EPROTO;
696 if ((ctx->fields_set & IJS_FIELDS_REQUIRED) != IJS_FIELDS_REQUIRED)
697 status = IJS_EPROTO;
698 #ifdef VERBOSE
699 fprintf (stderr, "begin page %d %d %d %d %d\n",
700 ph->n_chan, ph->bps, ph->cs, ph->width, ph->height);
701 #endif
702 if (!status)
703 {
704 ctx->in_page = TRUE;
705 return ijs_server_ack (ctx);
706 }
707 else
708 return ijs_server_nak (ctx, status);
709 }
710
711 static int
ijs_server_read_data(IjsServerCtx * ctx,char * buf,int size)712 ijs_server_read_data (IjsServerCtx *ctx, char *buf, int size)
713 {
714 int status;
715
716 status = ijs_recv_read (&ctx->recv_chan, buf, size);
717 return (status == size) ? 0 : IJS_EIO;
718 }
719
720 static int
ijs_server_proc_send_data_block(IjsServerCtx * ctx)721 ijs_server_proc_send_data_block (IjsServerCtx *ctx)
722 {
723 int size;
724 int status = 0;
725 IjsJobId job_id;
726
727 status = ijs_recv_int (&ctx->recv_chan, &job_id);
728 if (status < 0) return status;
729
730 if (!ctx->in_job || job_id != ctx->job_id)
731 status = IJS_EJOBID;
732 else if (ctx->buf == NULL)
733 status = IJS_EPROTO;
734
735 if (!status) status = ijs_recv_int (&ctx->recv_chan, &size);
736
737 #ifdef VERBOSE
738 fprintf (stderr, "status=%d, send data block id=%d, size=%d\n",
739 status, job_id, size);
740 #endif
741 if (status)
742 return ijs_server_nak (ctx, status);
743
744 if (size <= ctx->buf_size - ctx->buf_ix)
745 {
746 status = ijs_server_read_data (ctx, ctx->buf + ctx->buf_ix, size);
747 ctx->buf_ix += size;
748 }
749 else
750 {
751 ctx->overflow_buf_size = size - (ctx->buf_size - ctx->buf_ix);
752 ctx->overflow_buf = (char *)malloc (ctx->overflow_buf_size);
753 ctx->overflow_buf_ix = 0;
754 status = ijs_server_read_data (ctx, ctx->buf + ctx->buf_ix,
755 ctx->buf_size - ctx->buf_ix);
756 ctx->buf_ix = ctx->buf_size;
757 if (!status)
758 {
759 status = ijs_server_read_data (ctx, ctx->overflow_buf,
760 ctx->overflow_buf_size);
761 }
762 }
763 return ijs_server_ack (ctx);
764 }
765
766 static int
ijs_server_proc_end_page(IjsServerCtx * ctx)767 ijs_server_proc_end_page (IjsServerCtx *ctx)
768 {
769 #ifdef VERBOSE
770 fprintf (stderr, "end page\n");
771 #endif
772 return ijs_server_ack (ctx);
773 }
774
775 static int
ijs_server_proc_exit(IjsServerCtx * ctx)776 ijs_server_proc_exit (IjsServerCtx *ctx)
777 {
778 return 1;
779 }
780
781 ijs_server_proc ijs_server_procs[] = {
782 ijs_server_proc_ack,
783 ijs_server_proc_nak,
784 ijs_server_proc_ping,
785 ijs_server_proc_pong,
786 ijs_server_proc_open,
787 ijs_server_proc_close,
788 ijs_server_proc_begin_job,
789 ijs_server_proc_end_job,
790 ijs_server_proc_cancel_job,
791 ijs_server_proc_query_status,
792 ijs_server_proc_list_params,
793 ijs_server_proc_enum_param,
794 ijs_server_proc_set_param,
795 ijs_server_proc_get_param,
796 ijs_server_proc_begin_page,
797 ijs_server_proc_send_data_block,
798 ijs_server_proc_end_page,
799 ijs_server_proc_exit
800 };
801
802 int
ijs_server_iter(IjsServerCtx * ctx)803 ijs_server_iter (IjsServerCtx *ctx)
804 {
805 int cmd_num;
806 int status;
807
808 status = ijs_recv_buf (&ctx->recv_chan);
809
810 if (status < 0)
811 return status;
812
813 cmd_num = ijs_get_int (ctx->recv_chan.buf);
814 #ifdef VERBOSE
815 fprintf (stderr, "command %d, %d bytes\n", cmd_num, ctx->recv_chan.buf_size);
816 #endif
817 if (cmd_num < 0 ||
818 cmd_num >= (int)sizeof(ijs_server_procs) / sizeof(ijs_server_procs[0]))
819 return -1;
820 return ijs_server_procs[cmd_num] (ctx);
821 }
822
823 /**
824 * ijs_server_get_page_header: Get the page header.
825 * @ctx: The server context.
826 * @ph: Where to store the page header.
827 *
828 * Return value: 0 on success, 1 on normal exit, negative on error.
829 **/
830 int
ijs_server_get_page_header(IjsServerCtx * ctx,IjsPageHeader * ph)831 ijs_server_get_page_header (IjsServerCtx *ctx, IjsPageHeader *ph)
832 {
833 int status;
834
835 ctx->ph = ph;
836 ctx->in_page = FALSE;
837
838 do
839 {
840 status = ijs_server_iter (ctx);
841 }
842 while (status == 0 && !ctx->in_page);
843
844 ctx->ph = NULL;
845 return status;
846 }
847
848 /**
849 * ijs_server_get_data: Get data from client.
850 * @ctx: The server context.
851 * @buf: Buffer for data being read.
852 * @size: Size of buf.
853 *
854 * Gets data from client. Data is stored in @buf or the
855 * overflow_buf.
856 *
857 * Return value: Number of bytes read, -1 on end of page, or < 0 on
858 * error.
859 **/
860 int
ijs_server_get_data(IjsServerCtx * ctx,char * buf,int size)861 ijs_server_get_data (IjsServerCtx *ctx, char *buf, int size)
862 {
863 int buf_ix = 0;
864 int status = 0;
865
866 #ifdef VERBOSE
867 fprintf (stderr, "ijs_server_get_data %d\n", size);
868 #endif
869
870 if (ctx->overflow_buf != NULL)
871 {
872 int n_bytes = ctx->overflow_buf_size - ctx->overflow_buf_ix;
873 if (n_bytes > size)
874 n_bytes = size;
875 memcpy (buf, ctx->overflow_buf + ctx->overflow_buf_ix, n_bytes);
876 ctx->overflow_buf_ix += n_bytes;
877 buf_ix = n_bytes;
878 if (ctx->overflow_buf_ix == ctx->overflow_buf_size)
879 {
880 free (ctx->overflow_buf);
881 ctx->overflow_buf = NULL;
882 ctx->overflow_buf_size = 0;
883 ctx->overflow_buf_ix = 0;
884 }
885 }
886 ctx->buf = buf;
887 ctx->buf_size = size;
888 ctx->buf_ix = buf_ix;
889 while (!status && ctx->buf_ix < size)
890 {
891 status = ijs_server_iter (ctx);
892 }
893 ctx->buf = NULL;
894 return status;
895 }
896