Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


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