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