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