]> andersk Git - moira.git/blob - lib/mr_call.c
Command line printer manipulation client, and build goo.
[moira.git] / lib / mr_call.c
1 /* $Id$
2  *
3  * Pass an mr_params off to the Moira server and get a reply
4  *
5  * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
6  * For copying and distribution information, please see the file
7  * <mit-copyright.h>.
8  */
9
10 #include <mit-copyright.h>
11 #include <moira.h>
12 #include "mr_private.h"
13
14 #include <errno.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #ifndef _WIN32
18 #include <netinet/in.h>
19 #endif /* _WIN32 */
20
21 #ifdef HAVE_UNISTD_H
22 #include <unistd.h>
23 #endif
24
25 RCSID("$Header$");
26
27 /* Moira RPC format:
28
29    4-byte total length (including these 4 bytes)
30    4-byte version number (MR_VERSION_2 == 2)
31    4-byte opcode (from client) or status (from server)
32    4-byte argc
33
34    4-byte len, followed by null-terminated string, padded to 4-byte boundary
35      (the len doesn't include the padding)
36    ...
37
38    (followed by more packets if status was MR_MORE_DATA)
39
40    All numbers are in network byte order.
41 */
42
43 int mr_do_call(struct mr_params *params, struct mr_params *reply)
44 {
45   int status;
46
47   CHECK_CONNECTED;
48
49   status = mr_send(_mr_conn, params);
50   if (status == MR_SUCCESS)
51     status = mr_receive(_mr_conn, reply);
52
53   if (status)
54     mr_disconnect();
55
56   return status;
57 }
58
59 int mr_send(int fd, struct mr_params *params)
60 {
61   u_long length;
62   int written;
63   int i, *argl;
64   char *buf, *p;
65
66   length = 16; /* length + version + opcode/status + argc */
67
68   if (params->mr_argl)
69     {
70       argl = params->mr_argl;
71       for (i = 0; i < params->mr_argc; i++)
72         length += 8 + argl[i];
73     }
74   else
75     {
76       argl = malloc(params->mr_argc * sizeof(int));
77       if (params->mr_argc && !argl)
78         return ENOMEM;
79       for (i = 0; i < params->mr_argc; i++)
80         {
81           argl[i] = strlen(params->mr_argv[i]) + 1;
82           length += 8 + argl[i];
83         }
84     }
85
86   buf = malloc(length);
87   if (!buf)
88     {
89       if (!params->mr_argl)
90         free(argl);
91       return ENOMEM;
92     }
93   memset(buf, 0, length);
94
95   putlong(buf + 4, MR_VERSION_2);
96   putlong(buf + 8, params->u.mr_procno);
97   putlong(buf + 12, params->mr_argc);
98
99   for (i = 0, p = buf + 16; i < params->mr_argc; i++)
100     {
101       putlong(p, argl[i]);
102       memcpy(p += 4, params->mr_argv[i], argl[i]);
103       p += argl[i] + (4 - argl[i] % 4) % 4;
104     }
105   length = p - buf;
106   putlong(buf, length);
107
108   written = send(fd, buf, length, 0);
109   free(buf);
110   if (!params->mr_argl)
111     free(argl);
112
113   if (written != (int)length)
114     return MR_ABORTED;
115   else
116     return MR_SUCCESS;
117 }
118
119 int mr_receive(int fd, struct mr_params *reply)
120 {
121   int status;
122
123   memset(reply, 0, sizeof(struct mr_params));
124   do
125     status = mr_cont_receive(fd, reply);
126   while (status == -1);
127
128   return status;
129 }
130   
131 /* Read some or all of a client response, without losing if it turns
132  * out to be malformed. Returns MR_SUCCESS on success, an error code
133  * on failure, or -1 if the packet hasn't been completely received
134  * yet.
135  */
136
137 int mr_cont_receive(int fd, struct mr_params *reply)
138 {
139   u_long length, data;
140   int size, more;
141   char *p, *end;
142   int i;
143
144   if (!reply->mr_flattened)
145     {
146       char lbuf[4];
147
148       size = recv(fd, lbuf, 4, 0);
149       if (size != 4)
150         return size ? MR_ABORTED : MR_NOT_CONNECTED;
151       getlong(lbuf, length);
152       if (length > 8192)
153         return MR_INTERNAL;
154       reply->mr_flattened = malloc(length);
155       if (!reply->mr_flattened)
156         return ENOMEM;
157       memcpy(reply->mr_flattened, lbuf, 4);
158       reply->mr_filled = 4;
159
160       return -1;
161     }
162   else
163     getlong(reply->mr_flattened, length);
164
165   more = recv(fd, reply->mr_flattened + reply->mr_filled,
166               length - reply->mr_filled, 0);
167   if (more == -1)
168     {
169       mr_destroy_reply(*reply);
170       return MR_ABORTED;
171     }
172
173   reply->mr_filled += more;
174
175   if (reply->mr_filled != length)
176     return -1;
177
178   getlong(reply->mr_flattened + 4, data);
179   if (data != MR_VERSION_2)
180     {
181       mr_destroy_reply(*reply);
182       return MR_VERSION_MISMATCH;
183     }
184
185   getlong(reply->mr_flattened + 8, reply->u.mr_status);
186   getlong(reply->mr_flattened + 12, reply->mr_argc);
187   if (reply->mr_argc > ((int)length - 16) / 8)
188     {
189       mr_destroy_reply(*reply);
190       return MR_INTERNAL;
191     }
192   reply->mr_argv = malloc(reply->mr_argc * sizeof(char *));
193   reply->mr_argl = malloc(reply->mr_argc * sizeof(int));
194   if (reply->mr_argc && (!reply->mr_argv || !reply->mr_argl))
195     {
196       mr_destroy_reply(*reply);
197       return ENOMEM;
198     }
199
200   p = (char *)reply->mr_flattened + 16;
201   end = (char *)reply->mr_flattened + length;
202   for (i = 0; i < reply->mr_argc && p + 4 <= end; i++)
203     {
204       getlong(p, reply->mr_argl[i]);
205       if (p + 4 + reply->mr_argl[i] > end)
206         break;
207       reply->mr_argv[i] = p + 4;
208       p += 4 + reply->mr_argl[i] + (4 - reply->mr_argl[i] % 4) % 4;
209     }
210
211   if (i != reply->mr_argc)
212     {
213       mr_destroy_reply(*reply);
214       return MR_INTERNAL;
215     }
216
217   return MR_SUCCESS;
218 }
219
220 void mr_destroy_reply(mr_params reply)
221 {
222   free(reply.mr_argl);
223   free(reply.mr_argv);
224   free(reply.mr_flattened);
225 }
This page took 0.080821 seconds and 5 git commands to generate.