AROS: getting closer to link. only a handful of missing symbols now
[deb_libnfs.git] / lib / pdu.c
CommitLineData
84004dbf
RS
1/*
2 Copyright (C) 2010 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 2.1 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program; if not, see <http://www.gnu.org/licenses/>.
16*/
a8a1b858
M
17#ifdef WIN32
18#include "win32_compat.h"
19#ifndef MSG_DONTWAIT
6874f61e 20#define MSG_DONTWAIT 0
a8a1b858 21#endif
6874f61e 22#else
84004dbf 23#include <strings.h>
a8a1b858 24#endif/*WIN32*/
6874f61e
RS
25
26#include <stdio.h>
98f5fee8 27#include <stdlib.h>
763cd6e3
RS
28#include <string.h>
29#include <sys/socket.h>
30#include <netinet/in.h>
f3a75078 31#include <assert.h>
a669857d 32#include <errno.h>
84004dbf 33#include "slist.h"
763cd6e3 34#include "libnfs-zdr.h"
84004dbf
RS
35#include "libnfs.h"
36#include "libnfs-raw.h"
37#include "libnfs-private.h"
38
e77d093c
RS
39#ifdef AROS
40#include "aros_compat.h"
41#endif
42
763cd6e3 43struct rpc_pdu *rpc_allocate_pdu(struct rpc_context *rpc, int program, int version, int procedure, rpc_cb cb, void *private_data, zdrproc_t zdr_decode_fn, int zdr_decode_bufsize)
84004dbf
RS
44{
45 struct rpc_pdu *pdu;
46 struct rpc_msg msg;
47
f3a75078 48 assert(rpc->magic == RPC_CONTEXT_MAGIC);
84004dbf
RS
49
50 pdu = malloc(sizeof(struct rpc_pdu));
51 if (pdu == NULL) {
1896d37b 52 rpc_set_error(rpc, "Out of memory: Failed to allocate pdu structure");
84004dbf
RS
53 return NULL;
54 }
ea98629a 55 memset(pdu, 0, sizeof(struct rpc_pdu));
84004dbf
RS
56 pdu->xid = rpc->xid++;
57 pdu->cb = cb;
58 pdu->private_data = private_data;
763cd6e3
RS
59 pdu->zdr_decode_fn = zdr_decode_fn;
60 pdu->zdr_decode_bufsize = zdr_decode_bufsize;
84004dbf 61
763cd6e3 62 zdrmem_create(&pdu->zdr, rpc->encodebuf, rpc->encodebuflen, ZDR_ENCODE);
a1992412 63 if (rpc->is_udp == 0) {
763cd6e3 64 zdr_setpos(&pdu->zdr, 4); /* skip past the record marker */
a1992412 65 }
84004dbf 66
ea98629a 67 memset(&msg, 0, sizeof(struct rpc_msg));
aab6538b
RS
68 msg.xid = pdu->xid;
69 msg.direction = CALL;
70 msg.body.cbody.rpcvers = RPC_MSG_VERSION;
71 msg.body.cbody.prog = program;
72 msg.body.cbody.vers = version;
73 msg.body.cbody.proc = procedure;
74 msg.body.cbody.cred = rpc->auth->ah_cred;
75 msg.body.cbody.verf = rpc->auth->ah_verf;
84004dbf 76
763cd6e3
RS
77 if (zdr_callmsg(&pdu->zdr, &msg) == 0) {
78 rpc_set_error(rpc, "zdr_callmsg failed");
79 zdr_destroy(&pdu->zdr);
84004dbf
RS
80 free(pdu);
81 return NULL;
82 }
83
84 return pdu;
85}
86
f3a75078 87void rpc_free_pdu(struct rpc_context *rpc, struct rpc_pdu *pdu)
84004dbf 88{
f3a75078
RS
89 assert(rpc->magic == RPC_CONTEXT_MAGIC);
90
84004dbf
RS
91 if (pdu->outdata.data != NULL) {
92 free(pdu->outdata.data);
93 pdu->outdata.data = NULL;
94 }
95
763cd6e3
RS
96 if (pdu->zdr_decode_buf != NULL) {
97 zdr_free(pdu->zdr_decode_fn, pdu->zdr_decode_buf);
98 free(pdu->zdr_decode_buf);
99 pdu->zdr_decode_buf = NULL;
84004dbf
RS
100 }
101
763cd6e3 102 zdr_destroy(&pdu->zdr);
df5af25f 103
84004dbf
RS
104 free(pdu);
105}
106
107
108int rpc_queue_pdu(struct rpc_context *rpc, struct rpc_pdu *pdu)
109{
110 int size, recordmarker;
111
f3a75078
RS
112 assert(rpc->magic == RPC_CONTEXT_MAGIC);
113
763cd6e3 114 size = zdr_getpos(&pdu->zdr);
84004dbf 115
a669857d
RS
116 /* for udp we dont queue, we just send it straight away */
117 if (rpc->is_udp != 0) {
763cd6e3 118// XXX add a rpc->udp_dest_sock_size and get rid of sys/socket.h and netinet/in.h
a669857d
RS
119 if (sendto(rpc->fd, rpc->encodebuf, size, MSG_DONTWAIT, rpc->udp_dest, sizeof(struct sockaddr_in)) < 0) {
120 rpc_set_error(rpc, "Sendto failed with errno %s", strerror(errno));
121 rpc_free_pdu(rpc, pdu);
122 return -1;
123 }
124 SLIST_ADD_END(&rpc->waitpdu, pdu);
125 return 0;
126 }
127
84004dbf 128 /* write recordmarker */
763cd6e3 129 zdr_setpos(&pdu->zdr, 0);
84004dbf 130 recordmarker = (size - 4) | 0x80000000;
763cd6e3 131 zdr_int(&pdu->zdr, &recordmarker);
84004dbf
RS
132
133 pdu->outdata.size = size;
134 pdu->outdata.data = malloc(pdu->outdata.size);
135 if (pdu->outdata.data == NULL) {
136 rpc_set_error(rpc, "Out of memory. Failed to allocate buffer for pdu\n");
137 rpc_free_pdu(rpc, pdu);
138 return -1;
139 }
140
141 memcpy(pdu->outdata.data, rpc->encodebuf, pdu->outdata.size);
142 SLIST_ADD_END(&rpc->outqueue, pdu);
143
144 return 0;
145}
146
147int rpc_get_pdu_size(char *buf)
148{
149 uint32_t size;
150
151 size = ntohl(*(uint32_t *)buf);
152
84004dbf
RS
153 return (size & 0x7fffffff) + 4;
154}
155
763cd6e3 156static int rpc_process_reply(struct rpc_context *rpc, struct rpc_pdu *pdu, ZDR *zdr)
84004dbf
RS
157{
158 struct rpc_msg msg;
159
f3a75078
RS
160 assert(rpc->magic == RPC_CONTEXT_MAGIC);
161
ea98629a 162 memset(&msg, 0, sizeof(struct rpc_msg));
aab6538b 163 msg.body.rbody.reply.areply.verf = _null_auth;
763cd6e3
RS
164 if (pdu->zdr_decode_bufsize > 0) {
165 if (pdu->zdr_decode_buf != NULL) {
166 free(pdu->zdr_decode_buf);
1b9917b8 167 }
763cd6e3
RS
168 pdu->zdr_decode_buf = malloc(pdu->zdr_decode_bufsize);
169 if (pdu->zdr_decode_buf == NULL) {
170 rpc_set_error(rpc, "zdr_replymsg failed in portmap_getport_reply");
171 pdu->cb(rpc, RPC_STATUS_ERROR, "Failed to allocate buffer for decoding of ZDR reply", pdu->private_data);
84004dbf
RS
172 return 0;
173 }
763cd6e3 174 memset(pdu->zdr_decode_buf, 0, pdu->zdr_decode_bufsize);
84004dbf 175 }
aab6538b
RS
176 msg.body.rbody.reply.areply.reply_data.results.where = pdu->zdr_decode_buf;
177 msg.body.rbody.reply.areply.reply_data.results.proc = pdu->zdr_decode_fn;
84004dbf 178
763cd6e3
RS
179 if (zdr_replymsg(zdr, &msg) == 0) {
180 rpc_set_error(rpc, "zdr_replymsg failed in portmap_getport_reply");
84004dbf 181 pdu->cb(rpc, RPC_STATUS_ERROR, "Message rejected by server", pdu->private_data);
763cd6e3
RS
182 if (pdu->zdr_decode_buf != NULL) {
183 free(pdu->zdr_decode_buf);
184 pdu->zdr_decode_buf = NULL;
84004dbf
RS
185 }
186 return 0;
187 }
aab6538b 188 if (msg.body.rbody.stat != MSG_ACCEPTED) {
84004dbf
RS
189 pdu->cb(rpc, RPC_STATUS_ERROR, "RPC Packet not accepted by the server", pdu->private_data);
190 return 0;
191 }
aab6538b 192 switch (msg.body.rbody.reply.areply.stat) {
84004dbf 193 case SUCCESS:
763cd6e3 194 pdu->cb(rpc, RPC_STATUS_SUCCESS, pdu->zdr_decode_buf, pdu->private_data);
84004dbf
RS
195 break;
196 case PROG_UNAVAIL:
197 pdu->cb(rpc, RPC_STATUS_ERROR, "Server responded: Program not available", pdu->private_data);
198 break;
199 case PROG_MISMATCH:
200 pdu->cb(rpc, RPC_STATUS_ERROR, "Server responded: Program version mismatch", pdu->private_data);
201 break;
202 case PROC_UNAVAIL:
203 pdu->cb(rpc, RPC_STATUS_ERROR, "Server responded: Procedure not available", pdu->private_data);
204 break;
205 case GARBAGE_ARGS:
206 pdu->cb(rpc, RPC_STATUS_ERROR, "Server responded: Garbage arguments", pdu->private_data);
207 break;
208 case SYSTEM_ERR:
209 pdu->cb(rpc, RPC_STATUS_ERROR, "Server responded: System Error", pdu->private_data);
210 break;
211 default:
212 pdu->cb(rpc, RPC_STATUS_ERROR, "Unknown rpc response from server", pdu->private_data);
213 break;
214 }
215
216 return 0;
217}
218
219int rpc_process_pdu(struct rpc_context *rpc, char *buf, int size)
220{
221 struct rpc_pdu *pdu;
763cd6e3 222 ZDR zdr;
d678b73e 223 int pos, recordmarker = 0;
84004dbf 224 unsigned int xid;
d678b73e 225 char *reasbuf = NULL;
84004dbf 226
f3a75078
RS
227 assert(rpc->magic == RPC_CONTEXT_MAGIC);
228
763cd6e3 229 memset(&zdr, 0, sizeof(ZDR));
84004dbf 230
763cd6e3 231 zdrmem_create(&zdr, buf, size, ZDR_DECODE);
a669857d 232 if (rpc->is_udp == 0) {
763cd6e3
RS
233 if (zdr_int(&zdr, &recordmarker) == 0) {
234 rpc_set_error(rpc, "zdr_int reading recordmarker failed");
235 zdr_destroy(&zdr);
a669857d
RS
236 return -1;
237 }
d678b73e 238 if (!(recordmarker&0x80000000)) {
763cd6e3 239 zdr_destroy(&zdr);
d678b73e
RS
240 if (rpc_add_fragment(rpc, buf+4, size-4) != 0) {
241 rpc_set_error(rpc, "Failed to queue fragment for reassembly.");
242 return -1;
243 }
244 return 0;
245 }
84004dbf 246 }
d678b73e
RS
247
248 /* reassembly */
249 if (recordmarker != 0 && rpc->fragments != NULL) {
250 struct rpc_fragment *fragment;
574095b9 251 uint32_t total = size - 4;
d678b73e
RS
252 char *ptr;
253
763cd6e3 254 zdr_destroy(&zdr);
d678b73e
RS
255 for (fragment = rpc->fragments; fragment; fragment = fragment->next) {
256 total += fragment->size;
257 }
258
259 reasbuf = malloc(total);
260 if (reasbuf == NULL) {
261 rpc_set_error(rpc, "Failed to reassemble PDU");
262 rpc_free_all_fragments(rpc);
263 return -1;
264 }
265 ptr = reasbuf;
266 for (fragment = rpc->fragments; fragment; fragment = fragment->next) {
267 memcpy(ptr, fragment->data, fragment->size);
268 ptr += fragment->size;
269 }
270 memcpy(ptr, buf + 4, size - 4);
763cd6e3 271 zdrmem_create(&zdr, reasbuf, total, ZDR_DECODE);
d678b73e
RS
272 rpc_free_all_fragments(rpc);
273 }
274
763cd6e3
RS
275 pos = zdr_getpos(&zdr);
276 if (zdr_int(&zdr, (int *)&xid) == 0) {
277 rpc_set_error(rpc, "zdr_int reading xid failed");
278 zdr_destroy(&zdr);
d678b73e
RS
279 if (reasbuf != NULL) {
280 free(reasbuf);
281 }
84004dbf
RS
282 return -1;
283 }
763cd6e3 284 zdr_setpos(&zdr, pos);
84004dbf
RS
285
286 for (pdu=rpc->waitpdu; pdu; pdu=pdu->next) {
287 if (pdu->xid != xid) {
288 continue;
289 }
a669857d
RS
290 if (rpc->is_udp == 0 || rpc->is_broadcast == 0) {
291 SLIST_REMOVE(&rpc->waitpdu, pdu);
292 }
763cd6e3 293 if (rpc_process_reply(rpc, pdu, &zdr) != 0) {
1896d37b 294 rpc_set_error(rpc, "rpc_procdess_reply failed");
84004dbf 295 }
763cd6e3 296 zdr_destroy(&zdr);
a669857d
RS
297 if (rpc->is_udp == 0 || rpc->is_broadcast == 0) {
298 rpc_free_pdu(rpc, pdu);
299 }
d678b73e
RS
300 if (reasbuf != NULL) {
301 free(reasbuf);
302 }
84004dbf
RS
303 return 0;
304 }
1896d37b 305 rpc_set_error(rpc, "No matching pdu found for xid:%d", xid);
763cd6e3 306 zdr_destroy(&zdr);
d678b73e
RS
307 if (reasbuf != NULL) {
308 free(reasbuf);
309 }
84004dbf
RS
310 return -1;
311}
312