Tizen 2.1 base
[platform/upstream/hplip.git] / prnt / hpijs / ijs.c
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 <string.h>
26 #include "unistd_.h"
27 #include "ijs.h"
28
29 static void
30 ijs_put_int (char *p, int val)
31 {
32   p[0] = (val >> 24) & 0xff;
33   p[1] = (val >> 16) & 0xff;
34   p[2] = (val >> 8) & 0xff;
35   p[3] = val & 0xff;
36 }
37
38 void
39 ijs_send_init (IjsSendChan *ch, int fd)
40 {
41   ch->fd = fd;
42   ch->buf_size = 0;
43 }
44
45 int
46 ijs_send_int (IjsSendChan *ch, int val)
47 {
48   if ((ch->buf_size + 4) > (int)sizeof(ch->buf))
49     return IJS_ERANGE;
50   ijs_put_int (ch->buf + ch->buf_size, val);
51   ch->buf_size += 4;
52   return 0;
53 }
54
55 int
56 ijs_send_begin (IjsSendChan *ch, IjsCommand cmd)
57 {
58   if (ch->buf_size != 0)
59     return IJS_EINTERNAL;
60   ijs_send_int (ch, cmd);
61   ch->buf_size += 4; /* leave room for size field */
62   return 0;
63 }
64
65 int
66 ijs_send_block (IjsSendChan *ch, const char *buf, int len)
67 {
68   if ((ch->buf_size + len) > (int)sizeof(ch->buf))
69     return IJS_ERANGE;
70   memcpy (ch->buf + ch->buf_size, buf, len);
71   ch->buf_size += len;
72   return 0;
73 }
74
75 int
76 ijs_send_buf (IjsSendChan *ch)
77 {
78   int status;
79
80   ijs_put_int (ch->buf + 4, ch->buf_size);
81   status = write (ch->fd, ch->buf, ch->buf_size);
82   status = (status == ch->buf_size) ? 0 : IJS_EIO;
83   ch->buf_size = 0;
84   return status;
85 }
86
87 void
88 ijs_recv_init (IjsRecvChan *ch, int fd)
89 {
90   ch->fd = fd;
91   ch->buf_size = 0;
92 }
93
94 int
95 ijs_get_int (const char *p)
96 {
97   const unsigned char *up = (const unsigned char *)p;
98   return (up[0] << 24) | (up[1] << 16) | (up[2] << 8) | up[3];
99 }
100
101 /* This is a drop-in replacement for read(), but handles partial reads. */
102 int
103 ijs_recv_read (IjsRecvChan *ch, char *buf, int size)
104 {
105   int ix = 0;
106   int nbytes;
107
108   do
109     {
110       nbytes = read (ch->fd, buf + ix, size - ix);
111       if (nbytes < 0)
112         return nbytes;
113       else if (nbytes == 0)
114         return ix;
115       else
116         ix += nbytes;
117     }
118   while (ix < size);
119   return ix;
120 }
121
122 int
123 ijs_recv_buf (IjsRecvChan *ch)
124 {
125   int nbytes;
126   int data_size;
127
128   nbytes = ijs_recv_read (ch, ch->buf, 8);
129   if (nbytes != 8)
130     return IJS_EIO;
131   ch->buf_size = ijs_get_int (ch->buf + 4);
132   if (ch->buf_size < 8 || ch->buf_size > (int)sizeof(ch->buf))
133     return IJS_ERANGE;
134   data_size = ch->buf_size - 8;
135   if (data_size > 0)
136     {
137       nbytes = ijs_recv_read (ch, ch->buf + 8, data_size);
138       if (nbytes != data_size)
139         return IJS_EIO;
140     }
141   ch->buf_idx = 8;
142   return 0;
143 }
144
145 /**
146  * ijs_recv_ack: Receive an acknowledgement.
147  * @ch: Channel.
148  *
149  * Receives an acknowledgement code (generally from server to client).
150  * Note that the distinction between local error and error generated
151  * by the remote peer is lost in this routine. If it is important to
152  * preserve this distinction, use ijs_recv_buf directly instead.
153  *
154  * Return value: 0 on success, negative on error.
155  **/
156 int
157 ijs_recv_ack (IjsRecvChan *ch)
158 {
159   int status;
160
161   status = ijs_recv_buf (ch);
162   if (status == 0)
163     {
164       int cmd = ijs_get_int (ch->buf);
165
166       if (cmd == IJS_CMD_NAK)
167         {
168           if (ch->buf_size != 12)
169             status = IJS_EPROTO;
170           else
171             status = ijs_get_int (ch->buf + 8);
172         }
173     }
174   return status;
175 }
176
177 int
178 ijs_recv_int (IjsRecvChan *ch, int *val)
179 {
180   if (ch->buf_idx + 4 > ch->buf_size)
181     return IJS_EPROTO;
182   *val = ijs_get_int (ch->buf + ch->buf_idx);
183   ch->buf_idx += 4;
184   return 0;
185 }
186
187 /**
188  * Return value: data block size if nonnegative, or error code if
189  * negative.
190  **/
191 int
192 ijs_recv_block (IjsRecvChan *ch, char *buf, int buf_size)
193 {
194   int size = ch->buf_size - ch->buf_idx;
195
196   if (size > buf_size)
197     return IJS_ERANGE;
198   memcpy (buf, ch->buf + ch->buf_idx, size);
199   ch->buf_idx = ch->buf_size;
200   return size;
201 }