~ubuntu-branches/ubuntu/hardy/klibc/hardy-updates

« back to all changes in this revision

Viewing changes to usr/kinit/nfsmount/sunrpc.c

  • Committer: Bazaar Package Importer
  • Author(s): Jeff Bailey
  • Date: 2006-01-04 20:24:52 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20060104202452-ec4v3n829rymukuv
Tags: 1.1.15-0ubuntu1
* New upstream version.

* Patch to fix compilation on parisc64 kernels.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <sys/types.h>
 
2
#include <sys/socket.h>
 
3
#include <netinet/in.h>
 
4
#include <errno.h>
 
5
#include <poll.h>
 
6
#include <stdio.h>
 
7
#include <string.h>
 
8
#include <stdlib.h>
 
9
 
 
10
#include "nfsmount.h"
 
11
#include "sunrpc.h"
 
12
 
 
13
/*
 
14
 * The magic offset is needed here because RPC over TCP includes a
 
15
 * field that RPC over UDP doesn't.  Luvverly.
 
16
 */
 
17
static int rpc_do_reply(struct client *clnt, struct rpc *rpc, size_t off)
 
18
{
 
19
        int ret;
 
20
 
 
21
        if ((ret = read(clnt->sock,
 
22
                        ((char *) rpc->reply) + off,
 
23
                        rpc->reply_len - off)) == -1) {
 
24
                perror("read");
 
25
                goto bail;
 
26
        }
 
27
        else if (ret < sizeof(struct rpc_reply) - off) {
 
28
                fprintf(stderr, "short read: %d < %zu\n", ret,
 
29
                        sizeof(struct rpc_reply) - off);
 
30
                goto bail;
 
31
        }
 
32
        rpc->reply_len = ret + off;
 
33
 
 
34
        if ((!off && !(ntohl(rpc->reply->hdr.frag_hdr) & LAST_FRAG)) ||
 
35
            rpc->reply->hdr.udp.xid != rpc->call->hdr.udp.xid ||
 
36
            rpc->reply->hdr.udp.msg_type != htonl(RPC_REPLY)) {
 
37
                fprintf(stderr, "bad reply\n");
 
38
                goto bail;
 
39
        }
 
40
 
 
41
        if (ntohl(rpc->reply->state) != REPLY_OK) {
 
42
                fprintf(stderr, "rpc failed: %d\n", ntohl(rpc->reply->state));
 
43
                goto bail;
 
44
        }
 
45
 
 
46
        ret = 0;
 
47
        goto done;
 
48
 
 
49
 bail:
 
50
        ret = -1;
 
51
 done:
 
52
        return ret;
 
53
}
 
54
 
 
55
static void rpc_header(struct client *clnt, struct rpc *rpc)
 
56
{
 
57
        (void)clnt;
 
58
 
 
59
        rpc->call->hdr.frag_hdr = htonl(LAST_FRAG | rpc->call_len);
 
60
        rpc->call->hdr.udp.xid = lrand48();
 
61
        rpc->call->hdr.udp.msg_type = htonl(RPC_CALL);
 
62
        rpc->call->rpc_vers = htonl(2);
 
63
}
 
64
 
 
65
static int rpc_call_tcp(struct client *clnt, struct rpc *rpc)
 
66
{
 
67
        int ret;
 
68
 
 
69
        rpc_header(clnt, rpc);
 
70
 
 
71
        if ((ret = write(clnt->sock, rpc->call, rpc->call_len)) == -1) {
 
72
                perror("write");
 
73
                goto bail;
 
74
        }
 
75
        else if (ret < rpc->call_len) {
 
76
                fprintf(stderr, "short write: %d < %zu\n",
 
77
                        ret, rpc->call_len);
 
78
                goto bail;
 
79
        }
 
80
 
 
81
        ret = rpc_do_reply(clnt, rpc, 0);
 
82
        goto done;
 
83
 
 
84
 bail:
 
85
        ret = -1;
 
86
 
 
87
 done:
 
88
        return ret;
 
89
}
 
90
 
 
91
static int rpc_call_udp(struct client *clnt, struct rpc *rpc)
 
92
{
 
93
#define NR_FDS 1
 
94
#define TIMEOUT_MS 3000
 
95
#define MAX_TRIES 100
 
96
#define UDP_HDR_OFF (sizeof(struct rpc_header) - sizeof(struct rpc_udp_header))
 
97
        struct pollfd fds[NR_FDS];
 
98
        int ret = -1;
 
99
        int i;
 
100
 
 
101
        rpc_header(clnt, rpc);
 
102
 
 
103
        fds[0].fd = clnt->sock;
 
104
        fds[0].events = POLLRDNORM;
 
105
 
 
106
        rpc->call_len -= UDP_HDR_OFF;
 
107
 
 
108
        for (i = 0; i < MAX_TRIES; i++) {
 
109
                int timeout_ms = TIMEOUT_MS + (lrand48() % (TIMEOUT_MS / 2));
 
110
                if ((ret = write(clnt->sock,
 
111
                                 ((char *) rpc->call) + UDP_HDR_OFF,
 
112
                                 rpc->call_len)) == -1) {
 
113
                        perror("write");
 
114
                        goto bail;
 
115
                }
 
116
                else if (ret < rpc->call_len) {
 
117
                        fprintf(stderr, "short write: %d < %zu\n", ret,
 
118
                                rpc->call_len);
 
119
                        goto bail;
 
120
                }
 
121
                for (; i < MAX_TRIES; i++) {
 
122
                        if ((ret = poll(fds, NR_FDS, timeout_ms)) == -1) {
 
123
                                perror("poll");
 
124
                                goto bail;
 
125
                        }
 
126
                        if (ret == 0) {
 
127
                                DEBUG(("Timeout #%d\n", i + 1));
 
128
                                break;
 
129
                        }
 
130
                        if ((ret = rpc_do_reply(clnt, rpc, UDP_HDR_OFF)) == 0) {
 
131
                                goto done;
 
132
                        } else {
 
133
                                DEBUG(("Failed on try #%d - retrying\n",
 
134
                                       i + 1));
 
135
                        }
 
136
                }
 
137
        }
 
138
 
 
139
 bail:
 
140
        ret = -1;
 
141
 
 
142
 done:
 
143
        return ret;
 
144
}
 
145
 
 
146
struct client *tcp_client(__u32 server, __u16 port, __u32 flags)
 
147
{
 
148
        struct client *clnt = malloc(sizeof(*clnt));
 
149
        struct sockaddr_in addr;
 
150
        int sock;
 
151
 
 
152
        if (clnt == NULL) {
 
153
                perror("malloc");
 
154
                goto bail;
 
155
        }
 
156
 
 
157
        memset(clnt, 0, sizeof(clnt));
 
158
 
 
159
        if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
 
160
                perror("socket");
 
161
                goto bail;
 
162
        }
 
163
 
 
164
        if ((flags & CLI_RESVPORT) && bindresvport(sock, 0) == -1) {
 
165
                perror("bindresvport");
 
166
                goto bail;
 
167
        }
 
168
 
 
169
        clnt->sock = sock;
 
170
        clnt->call_stub = rpc_call_tcp;
 
171
 
 
172
        addr.sin_family = AF_INET;
 
173
        addr.sin_port = htons(port);
 
174
        addr.sin_addr.s_addr = server;
 
175
 
 
176
        if (connect(sock, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
 
177
                perror("connect");
 
178
                goto bail;
 
179
        }
 
180
 
 
181
        goto done;
 
182
 bail:
 
183
        if (clnt) {
 
184
                free(clnt);
 
185
                clnt = NULL;
 
186
        }
 
187
 done:
 
188
        return clnt;
 
189
}
 
190
 
 
191
struct client *udp_client(__u32 server, __u16 port, __u32 flags)
 
192
{
 
193
        struct client *clnt = malloc(sizeof(*clnt));
 
194
        struct sockaddr_in addr;
 
195
        int sock;
 
196
 
 
197
        if (clnt == NULL) {
 
198
                perror("malloc");
 
199
                goto bail;
 
200
        }
 
201
 
 
202
        memset(clnt, 0, sizeof(clnt));
 
203
 
 
204
        if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
 
205
                perror("socket");
 
206
                goto bail;
 
207
        }
 
208
 
 
209
        if ((flags & CLI_RESVPORT) && bindresvport(sock, 0) == -1) {
 
210
                perror("bindresvport");
 
211
                goto bail;
 
212
        } else {
 
213
                struct sockaddr_in me;
 
214
 
 
215
                me.sin_family = AF_INET;
 
216
                me.sin_port = 0;
 
217
                me.sin_addr.s_addr = INADDR_ANY;
 
218
 
 
219
                if (0 && bind(sock, (struct sockaddr *) &me, sizeof(me)) == -1) {
 
220
                        perror("bind");
 
221
                        goto bail;
 
222
                }
 
223
        }
 
224
 
 
225
        clnt->sock = sock;
 
226
        clnt->call_stub = rpc_call_udp;
 
227
 
 
228
        addr.sin_family = AF_INET;
 
229
        addr.sin_port = htons(port);
 
230
        addr.sin_addr.s_addr = server;
 
231
 
 
232
        if (connect(sock, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
 
233
                perror("connect");
 
234
                goto bail;
 
235
        }
 
236
 
 
237
        goto done;
 
238
 bail:
 
239
        if (clnt) {
 
240
                free(clnt);
 
241
                clnt = NULL;
 
242
        }
 
243
 done:
 
244
        return clnt;
 
245
}
 
246
 
 
247
void client_free(struct client *c)
 
248
{
 
249
        if (c->sock != -1)
 
250
                close(c->sock);
 
251
        free(c);
 
252
}
 
253
 
 
254
int rpc_call(struct client *client, struct rpc *rpc)
 
255
{
 
256
        return client->call_stub(client, rpc);
 
257
}