]> andersk Git - moira.git/blame - lib/mr_call.c
Command line printer manipulation client, and build goo.
[moira.git] / lib / mr_call.c
CommitLineData
fa59b86f 1/* $Id$
ca401c43 2 *
7ac48069 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>.
ca401c43 8 */
9
babbc197 10#include <mit-copyright.h>
7ac48069 11#include <moira.h>
8defc06b 12#include "mr_private.h"
ca401c43 13
85330553 14#include <errno.h>
85330553 15#include <stdlib.h>
16#include <string.h>
533bacb3 17#ifndef _WIN32
18#include <netinet/in.h>
19#endif /* _WIN32 */
20
21#ifdef HAVE_UNISTD_H
85330553 22#include <unistd.h>
533bacb3 23#endif
85330553 24
7ac48069 25RCSID("$Header$");
26
85330553 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
43int mr_do_call(struct mr_params *params, struct mr_params *reply)
ca401c43 44{
85330553 45 int status;
46
5eaef520 47 CHECK_CONNECTED;
48
85330553 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
59int mr_send(int fd, struct mr_params *params)
60{
533bacb3 61 u_long length;
62 int written;
85330553 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);
5eaef520 98
85330553 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
533bacb3 108 written = send(fd, buf, length, 0);
85330553 109 free(buf);
110 if (!params->mr_argl)
111 free(argl);
5eaef520 112
533bacb3 113 if (written != (int)length)
85330553 114 return MR_ABORTED;
115 else
116 return MR_SUCCESS;
117}
118
119int mr_receive(int fd, struct mr_params *reply)
12cbd6bd 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
456d95f6 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 */
533bacb3 136
12cbd6bd 137int mr_cont_receive(int fd, struct mr_params *reply)
85330553 138{
139 u_long length, data;
533bacb3 140 int size, more;
456d95f6 141 char *p, *end;
85330553 142 int i;
5eaef520 143
85330553 144 if (!reply->mr_flattened)
85330553 145 {
12cbd6bd 146 char lbuf[4];
147
533bacb3 148 size = recv(fd, lbuf, 4, 0);
12cbd6bd 149 if (size != 4)
150 return size ? MR_ABORTED : MR_NOT_CONNECTED;
151 getlong(lbuf, length);
456d95f6 152 if (length > 8192)
153 return MR_INTERNAL;
12cbd6bd 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;
85330553 161 }
12cbd6bd 162 else
163 getlong(reply->mr_flattened, length);
164
533bacb3 165 more = recv(fd, reply->mr_flattened + reply->mr_filled,
166 length - reply->mr_filled, 0);
12cbd6bd 167 if (more == -1)
5eaef520 168 {
85330553 169 mr_destroy_reply(*reply);
5eaef520 170 return MR_ABORTED;
83e80378 171 }
85330553 172
12cbd6bd 173 reply->mr_filled += more;
456d95f6 174
12cbd6bd 175 if (reply->mr_filled != length)
176 return -1;
177
178 getlong(reply->mr_flattened + 4, data);
85330553 179 if (data != MR_VERSION_2)
180 {
181 mr_destroy_reply(*reply);
182 return MR_VERSION_MISMATCH;
183 }
184
12cbd6bd 185 getlong(reply->mr_flattened + 8, reply->u.mr_status);
186 getlong(reply->mr_flattened + 12, reply->mr_argc);
533bacb3 187 if (reply->mr_argc > ((int)length - 16) / 8)
456d95f6 188 {
189 mr_destroy_reply(*reply);
190 return MR_INTERNAL;
191 }
85330553 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
456d95f6 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++)
85330553 203 {
204 getlong(p, reply->mr_argl[i]);
456d95f6 205 if (p + 4 + reply->mr_argl[i] > end)
206 break;
85330553 207 reply->mr_argv[i] = p + 4;
208 p += 4 + reply->mr_argl[i] + (4 - reply->mr_argl[i] % 4) % 4;
209 }
210
456d95f6 211 if (i != reply->mr_argc)
212 {
213 mr_destroy_reply(*reply);
214 return MR_INTERNAL;
215 }
216
85330553 217 return MR_SUCCESS;
218}
219
220void mr_destroy_reply(mr_params reply)
221{
222 free(reply.mr_argl);
223 free(reply.mr_argv);
224 free(reply.mr_flattened);
ca401c43 225}
This page took 0.354982 seconds and 5 git commands to generate.