]> andersk Git - moira.git/blob - lib/mr_call.c
oops. don't rely on stack garbage to initialize our pointers
[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 <netinet/in.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
19
20 RCSID("$Header$");
21
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
38 int mr_do_call(struct mr_params *params, struct mr_params *reply)
39 {
40   int status;
41
42   CHECK_CONNECTED;
43
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
54 int 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);
92
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);
106
107   if (written != length)
108     return MR_ABORTED;
109   else
110     return MR_SUCCESS;
111 }
112
113 int mr_receive(int fd, struct mr_params *reply)
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   
125 int mr_cont_receive(int fd, struct mr_params *reply)
126 {
127   u_long length, data;
128   ssize_t size, more;
129   char *p;
130   int i;
131
132   if (!reply->mr_flattened)
133     {
134       char lbuf[4];
135
136       size = read(fd, lbuf, 4);
137       if (size != 4)
138         return size ? MR_ABORTED : MR_NOT_CONNECTED;
139       getlong(lbuf, length);
140       reply->mr_flattened = malloc(length);
141       if (!reply->mr_flattened)
142         return ENOMEM;
143       memcpy(reply->mr_flattened, lbuf, 4);
144       reply->mr_filled = 4;
145
146       return -1;
147     }
148   else
149     getlong(reply->mr_flattened, length);
150
151   more = read(fd, reply->mr_flattened + reply->mr_filled,
152               length - reply->mr_filled);
153   if (more == -1)
154     {
155       mr_destroy_reply(*reply);
156       return MR_ABORTED;
157     }
158
159   reply->mr_filled += more;
160   
161   if (reply->mr_filled != length)
162     return -1;
163
164   getlong(reply->mr_flattened + 4, data);
165   if (data != MR_VERSION_2)
166     {
167       mr_destroy_reply(*reply);
168       return MR_VERSION_MISMATCH;
169     }
170
171   getlong(reply->mr_flattened + 8, reply->u.mr_status);
172   getlong(reply->mr_flattened + 12, reply->mr_argc);
173   reply->mr_argv = malloc(reply->mr_argc * sizeof(char *));
174   reply->mr_argl = malloc(reply->mr_argc * sizeof(int));
175   if (reply->mr_argc && (!reply->mr_argv || !reply->mr_argl))
176     {
177       mr_destroy_reply(*reply);
178       return ENOMEM;
179     }
180
181   for (i = 0, p = reply->mr_flattened + 16; i < reply->mr_argc; i++)
182     {
183       getlong(p, reply->mr_argl[i]);
184       reply->mr_argv[i] = p + 4;
185       p += 4 + reply->mr_argl[i] + (4 - reply->mr_argl[i] % 4) % 4;
186     }
187
188   return MR_SUCCESS;
189 }
190
191 void mr_destroy_reply(mr_params reply)
192 {
193   free(reply.mr_argl);
194   free(reply.mr_argv);
195   free(reply.mr_flattened);
196 }
This page took 0.050578 seconds and 5 git commands to generate.