source: trunk/third/moira/lib/mr_call.c @ 24319

Revision 24319, 4.9 KB checked in by broder, 14 years ago (diff)
New Moira snapshot from SVN.
Line 
1/* $Id: mr_call.c 3956 2010-01-05 20:56:56Z zacheiss $
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
25RCSID("$HeadURL: svn+ssh://svn.mit.edu/moira/trunk/moira/lib/mr_call.c $ $Id: mr_call.c 3956 2010-01-05 20:56:56Z zacheiss $");
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
43int 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
59int 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
119int 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
137int 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
220void mr_destroy_reply(mr_params reply)
221{
222  free(reply.mr_argl);
223  free(reply.mr_argv);
224  free(reply.mr_flattened);
225}
Note: See TracBrowser for help on using the repository browser.