Magellan Linux

Annotation of /trunk/mkinitrd-magellan/klibc/usr/kinit/nfsmount/sunrpc.c

Parent Directory Parent Directory | Revision Log Revision Log


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