File: | src/lib/libc/rpc/clnt_tcp.c |
Warning: | line 299, column 16 Called function pointer is null (null dereference) |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: clnt_tcp.c,v 1.36 2022/07/15 17:33:28 deraadt Exp $ */ | |||
2 | ||||
3 | /* | |||
4 | * Copyright (c) 2010, Oracle America, Inc. | |||
5 | * | |||
6 | * Redistribution and use in source and binary forms, with or without | |||
7 | * modification, are permitted provided that the following conditions are | |||
8 | * met: | |||
9 | * | |||
10 | * * Redistributions of source code must retain the above copyright | |||
11 | * notice, this list of conditions and the following disclaimer. | |||
12 | * * Redistributions in binary form must reproduce the above | |||
13 | * copyright notice, this list of conditions and the following | |||
14 | * disclaimer in the documentation and/or other materials | |||
15 | * provided with the distribution. | |||
16 | * * Neither the name of the "Oracle America, Inc." nor the names of its | |||
17 | * contributors may be used to endorse or promote products derived | |||
18 | * from this software without specific prior written permission. | |||
19 | * | |||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |||
23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |||
24 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |||
25 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | |||
27 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||
28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |||
29 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |||
30 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |||
31 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
32 | */ | |||
33 | ||||
34 | /* | |||
35 | * clnt_tcp.c, Implements a TCP/IP based, client side RPC. | |||
36 | * | |||
37 | * TCP based RPC supports 'batched calls'. | |||
38 | * A sequence of calls may be batched-up in a send buffer. The rpc call | |||
39 | * return immediately to the client even though the call was not necessarily | |||
40 | * sent. The batching occurs if the results' xdr routine is NULL (0) AND | |||
41 | * the rpc timeout value is zero (see clnt.h, rpc). | |||
42 | * | |||
43 | * Clients should NOT casually batch calls that in fact return results; that is, | |||
44 | * the server side should be aware that a call is batched and not produce any | |||
45 | * return message. Batched calls that produce many result messages can | |||
46 | * deadlock (netlock) the client and the server.... | |||
47 | * | |||
48 | * Now go hang yourself. | |||
49 | */ | |||
50 | ||||
51 | #include <stdio.h> | |||
52 | #include <stdlib.h> | |||
53 | #include <string.h> | |||
54 | #include <unistd.h> | |||
55 | #include <rpc/rpc.h> | |||
56 | #include <sys/socket.h> | |||
57 | #include <netdb.h> | |||
58 | #include <errno(*__errno()).h> | |||
59 | #include <rpc/pmap_clnt.h> | |||
60 | ||||
61 | #define MCALL_MSG_SIZE24 24 | |||
62 | ||||
63 | static enum clnt_stat clnttcp_call(CLIENT *, u_long, xdrproc_t, caddr_t, | |||
64 | xdrproc_t, caddr_t, struct timeval); | |||
65 | static void clnttcp_abort(CLIENT *); | |||
66 | static void clnttcp_geterr(CLIENT *, struct rpc_err *); | |||
67 | static bool_tint32_t clnttcp_freeres(CLIENT *, xdrproc_t, caddr_t); | |||
68 | static bool_tint32_t clnttcp_control(CLIENT *, u_int, void *); | |||
69 | static void clnttcp_destroy(CLIENT *); | |||
70 | ||||
71 | static const struct clnt_ops tcp_ops = { | |||
72 | clnttcp_call, | |||
73 | clnttcp_abort, | |||
74 | clnttcp_geterr, | |||
75 | clnttcp_freeres, | |||
76 | clnttcp_destroy, | |||
77 | clnttcp_control | |||
78 | }; | |||
79 | ||||
80 | struct ct_data { | |||
81 | int ct_sock; | |||
82 | bool_tint32_t ct_closeit; | |||
83 | int ct_connected; /* pre-connected */ | |||
84 | struct timeval ct_wait; | |||
85 | bool_tint32_t ct_waitset; /* wait set by clnt_control? */ | |||
86 | struct sockaddr_in ct_addr; | |||
87 | struct rpc_err ct_error; | |||
88 | char ct_mcall[MCALL_MSG_SIZE24]; /* marshalled callmsg */ | |||
89 | u_int ct_mpos; /* pos after marshal */ | |||
90 | XDR ct_xdrs; | |||
91 | }; | |||
92 | ||||
93 | static int readtcp(struct ct_data *, caddr_t, int); | |||
94 | static int writetcp(struct ct_data *, caddr_t, int); | |||
95 | ||||
96 | /* | |||
97 | * Create a client handle for a tcp/ip connection. | |||
98 | * If *sockp<0, *sockp is set to a newly created TCP socket and it is | |||
99 | * connected to raddr. If *sockp non-negative then | |||
100 | * raddr is ignored. The rpc/tcp package does buffering | |||
101 | * similar to stdio, so the client must pick send and receive buffer sizes,]; | |||
102 | * 0 => use the default. | |||
103 | * If raddr->sin_port is 0, then a binder on the remote machine is | |||
104 | * consulted for the right port number. | |||
105 | * NB: *sockp is copied into a private area. | |||
106 | * NB: It is the client's responsibility to close *sockp, unless | |||
107 | * clnttcp_create() was called with *sockp = -1 (so it created | |||
108 | * the socket), and CLNT_DESTROY() is used. | |||
109 | * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this | |||
110 | * something more useful. | |||
111 | */ | |||
112 | CLIENT * | |||
113 | clnttcp_create(struct sockaddr_in *raddr, u_long prog, u_long vers, int *sockp, | |||
114 | u_int sendsz, u_int recvsz) | |||
115 | { | |||
116 | CLIENT *h; | |||
117 | struct ct_data *ct = NULL((void *)0); | |||
118 | struct rpc_msg call_msg; | |||
119 | ||||
120 | h = (CLIENT *)mem_alloc(sizeof(*h))malloc(sizeof(*h)); | |||
121 | if (h == NULL((void *)0)) { | |||
122 | rpc_createerr.cf_stat = RPC_SYSTEMERROR; | |||
123 | rpc_createerr.cf_error.re_errnoru.RE_errno = errno(*__errno()); | |||
124 | goto fooy; | |||
125 | } | |||
126 | ct = (struct ct_data *)mem_alloc(sizeof(*ct))malloc(sizeof(*ct)); | |||
127 | if (ct == NULL((void *)0)) { | |||
128 | rpc_createerr.cf_stat = RPC_SYSTEMERROR; | |||
129 | rpc_createerr.cf_error.re_errnoru.RE_errno = errno(*__errno()); | |||
130 | goto fooy; | |||
131 | } | |||
132 | ||||
133 | /* | |||
134 | * If no port number given ask the pmap for one | |||
135 | */ | |||
136 | if (raddr->sin_port == 0) { | |||
137 | u_short port; | |||
138 | if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP6)) == 0) { | |||
139 | mem_free((caddr_t)ct, sizeof(struct ct_data))free((caddr_t)ct); | |||
140 | mem_free((caddr_t)h, sizeof(CLIENT))free((caddr_t)h); | |||
141 | return (NULL((void *)0)); | |||
142 | } | |||
143 | raddr->sin_port = htons(port)(__uint16_t)(__builtin_constant_p(port) ? (__uint16_t)(((__uint16_t )(port) & 0xffU) << 8 | ((__uint16_t)(port) & 0xff00U ) >> 8) : __swap16md(port)); | |||
144 | } | |||
145 | ||||
146 | /* | |||
147 | * If no socket given, open one | |||
148 | */ | |||
149 | if (*sockp < 0) { | |||
150 | *sockp = socket(AF_INET2, SOCK_STREAM1, IPPROTO_TCP6); | |||
151 | (void)bindresvport(*sockp, NULL((void *)0)); | |||
152 | if ((*sockp == -1) | |||
153 | || (connect(*sockp, (struct sockaddr *)raddr, | |||
154 | sizeof(*raddr)) == -1)) { | |||
155 | rpc_createerr.cf_stat = RPC_SYSTEMERROR; | |||
156 | rpc_createerr.cf_error.re_errnoru.RE_errno = errno(*__errno()); | |||
157 | if (*sockp != -1) | |||
158 | (void)close(*sockp); | |||
159 | goto fooy; | |||
160 | } | |||
161 | ct->ct_closeit = TRUE(1); | |||
162 | } else { | |||
163 | ct->ct_closeit = FALSE(0); | |||
164 | } | |||
165 | ||||
166 | /* | |||
167 | * Set up private data struct | |||
168 | */ | |||
169 | ct->ct_sock = *sockp; | |||
170 | ct->ct_wait.tv_usec = 0; | |||
171 | ct->ct_waitset = FALSE(0); | |||
172 | ct->ct_addr = *raddr; | |||
173 | ||||
174 | /* | |||
175 | * Initialize call message | |||
176 | */ | |||
177 | call_msg.rm_xid = arc4random(); | |||
178 | call_msg.rm_direction = CALL; | |||
179 | call_msg.rm_callru.RM_cmb.cb_rpcvers = RPC_MSG_VERSION((unsigned long) 2); | |||
180 | call_msg.rm_callru.RM_cmb.cb_prog = prog; | |||
181 | call_msg.rm_callru.RM_cmb.cb_vers = vers; | |||
182 | ||||
183 | /* | |||
184 | * pre-serialize the static part of the call msg and stash it away | |||
185 | */ | |||
186 | xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE24, | |||
187 | XDR_ENCODE); | |||
188 | if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { | |||
189 | if (ct->ct_closeit) { | |||
190 | (void)close(*sockp); | |||
191 | } | |||
192 | goto fooy; | |||
193 | } | |||
194 | ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs))(*(&(ct->ct_xdrs))->x_ops->x_getpostn)(&(ct-> ct_xdrs)); | |||
195 | XDR_DESTROY(&(ct->ct_xdrs))if ((&(ct->ct_xdrs))->x_ops->x_destroy) (*(& (ct->ct_xdrs))->x_ops->x_destroy)(&(ct->ct_xdrs )); | |||
196 | ||||
197 | /* | |||
198 | * Create a client handle which uses xdrrec for serialization | |||
199 | * and authnone for authentication. | |||
200 | */ | |||
201 | xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, | |||
202 | (caddr_t)ct, (int(*)(caddr_t, caddr_t, int))readtcp, | |||
203 | (int(*)(caddr_t, caddr_t, int))writetcp); | |||
204 | h->cl_ops = &tcp_ops; | |||
205 | h->cl_private = (caddr_t) ct; | |||
206 | h->cl_auth = authnone_create(); | |||
207 | if (h->cl_auth == NULL((void *)0)) { | |||
208 | rpc_createerr.cf_stat = RPC_SYSTEMERROR; | |||
209 | rpc_createerr.cf_error.re_errnoru.RE_errno = errno(*__errno()); | |||
210 | goto fooy; | |||
211 | } | |||
212 | return (h); | |||
213 | ||||
214 | fooy: | |||
215 | /* | |||
216 | * Something goofed, free stuff and barf | |||
217 | */ | |||
218 | if (ct) | |||
219 | mem_free((caddr_t)ct, sizeof(struct ct_data))free((caddr_t)ct); | |||
220 | if (h) | |||
221 | mem_free((caddr_t)h, sizeof(CLIENT))free((caddr_t)h); | |||
222 | return (NULL((void *)0)); | |||
223 | } | |||
224 | DEF_WEAK(clnttcp_create)__asm__(".weak " "clnttcp_create" " ; " "clnttcp_create" " = " "_libc_clnttcp_create"); | |||
225 | ||||
226 | static enum clnt_stat | |||
227 | clnttcp_call(CLIENT *h, u_long proc, xdrproc_t xdr_args, caddr_t args_ptr, | |||
228 | xdrproc_t xdr_results, caddr_t results_ptr, struct timeval timeout) | |||
229 | { | |||
230 | struct ct_data *ct = (struct ct_data *) h->cl_private; | |||
231 | XDR *xdrs = &(ct->ct_xdrs); | |||
232 | struct rpc_msg reply_msg; | |||
233 | u_long x_id; | |||
234 | u_int32_t *msg_x_id = (u_int32_t *)(ct->ct_mcall); /* yuk */ | |||
235 | bool_tint32_t shipnow; | |||
236 | int refreshes = 2; | |||
237 | ||||
238 | if (!ct->ct_waitset) { | |||
| ||||
239 | ct->ct_wait = timeout; | |||
240 | } | |||
241 | ||||
242 | shipnow = | |||
243 | (xdr_results == NULL((void *)0) && timeout.tv_sec == 0 | |||
244 | && timeout.tv_usec == 0) ? FALSE(0) : TRUE(1); | |||
245 | ||||
246 | call_again: | |||
247 | xdrs->x_op = XDR_ENCODE; | |||
248 | ct->ct_error.re_status = RPC_SUCCESS; | |||
249 | x_id = ntohl(--(*msg_x_id))(__uint32_t)(__builtin_constant_p(--(*msg_x_id)) ? (__uint32_t )(((__uint32_t)(--(*msg_x_id)) & 0xff) << 24 | ((__uint32_t )(--(*msg_x_id)) & 0xff00) << 8 | ((__uint32_t)(--( *msg_x_id)) & 0xff0000) >> 8 | ((__uint32_t)(--(*msg_x_id )) & 0xff000000) >> 24) : __swap32md(--(*msg_x_id)) ); | |||
250 | if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)(*(xdrs)->x_ops->x_putbytes)(xdrs, ct->ct_mcall, ct-> ct_mpos)) || | |||
251 | (! XDR_PUTLONG(xdrs, (long *)&proc)(*(xdrs)->x_ops->x_putlong)(xdrs, (long *)&proc)) || | |||
252 | (! AUTH_MARSHALL(h->cl_auth, xdrs)((*((h->cl_auth)->ah_ops->ah_marshal))(h->cl_auth , xdrs))) || | |||
253 | (! (*xdr_args)(xdrs, args_ptr))) { | |||
254 | if (ct->ct_error.re_status == RPC_SUCCESS) | |||
255 | ct->ct_error.re_status = RPC_CANTENCODEARGS; | |||
256 | (void)xdrrec_endofrecord(xdrs, TRUE(1)); | |||
257 | return (ct->ct_error.re_status); | |||
258 | } | |||
259 | if (! xdrrec_endofrecord(xdrs, shipnow)) | |||
260 | return (ct->ct_error.re_status = RPC_CANTSEND); | |||
261 | if (! shipnow
| |||
262 | return (RPC_SUCCESS); | |||
263 | /* | |||
264 | * Hack to provide rpc-based message passing | |||
265 | */ | |||
266 | if (timeout.tv_sec
| |||
267 | return(ct->ct_error.re_status = RPC_TIMEDOUT); | |||
268 | } | |||
269 | ||||
270 | ||||
271 | /* | |||
272 | * Keep receiving until we get a valid transaction id | |||
273 | */ | |||
274 | xdrs->x_op = XDR_DECODE; | |||
275 | while (TRUE(1)) { | |||
276 | reply_msg.acpted_rplyru.RM_rmb.ru.RP_ar.ar_verf = _null_auth; | |||
277 | reply_msg.acpted_rplyru.RM_rmb.ru.RP_ar.ar_resultsru.AR_results.where = NULL((void *)0); | |||
278 | reply_msg.acpted_rplyru.RM_rmb.ru.RP_ar.ar_resultsru.AR_results.proc = xdr_void; | |||
279 | if (! xdrrec_skiprecord(xdrs)) | |||
280 | return (ct->ct_error.re_status); | |||
281 | /* now decode and validate the response header */ | |||
282 | if (! xdr_replymsg(xdrs, &reply_msg)) { | |||
283 | if (ct->ct_error.re_status == RPC_SUCCESS) | |||
284 | continue; | |||
285 | return (ct->ct_error.re_status); | |||
286 | } | |||
287 | if (reply_msg.rm_xid == x_id) | |||
288 | break; | |||
289 | } | |||
290 | ||||
291 | /* | |||
292 | * process header | |||
293 | */ | |||
294 | _seterr_reply(&reply_msg, &(ct->ct_error)); | |||
295 | if (ct->ct_error.re_status == RPC_SUCCESS) { | |||
296 | if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)((*((h->cl_auth)->ah_ops->ah_validate))((h->cl_auth ), &reply_msg.ru.RM_rmb.ru.RP_ar.ar_verf))) { | |||
297 | ct->ct_error.re_status = RPC_AUTHERROR; | |||
298 | ct->ct_error.re_whyru.RE_why = AUTH_INVALIDRESP; | |||
299 | } else if (! (*xdr_results)(xdrs, results_ptr)) { | |||
| ||||
300 | if (ct->ct_error.re_status == RPC_SUCCESS) | |||
301 | ct->ct_error.re_status = RPC_CANTDECODERES; | |||
302 | } | |||
303 | /* free verifier ... */ | |||
304 | if (reply_msg.acpted_rplyru.RM_rmb.ru.RP_ar.ar_verf.oa_base != NULL((void *)0)) { | |||
305 | xdrs->x_op = XDR_FREE; | |||
306 | (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rplyru.RM_rmb.ru.RP_ar.ar_verf)); | |||
307 | } | |||
308 | } /* end successful completion */ | |||
309 | else { | |||
310 | /* maybe our credentials need to be refreshed ... */ | |||
311 | if (refreshes-- && AUTH_REFRESH(h->cl_auth)((*((h->cl_auth)->ah_ops->ah_refresh))(h->cl_auth ))) | |||
312 | goto call_again; | |||
313 | } /* end of unsuccessful completion */ | |||
314 | return (ct->ct_error.re_status); | |||
315 | } | |||
316 | ||||
317 | static void | |||
318 | clnttcp_geterr(CLIENT *h, struct rpc_err *errp) | |||
319 | { | |||
320 | struct ct_data *ct = | |||
321 | (struct ct_data *) h->cl_private; | |||
322 | ||||
323 | *errp = ct->ct_error; | |||
324 | } | |||
325 | ||||
326 | static bool_tint32_t | |||
327 | clnttcp_freeres(CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr) | |||
328 | { | |||
329 | struct ct_data *ct = (struct ct_data *)cl->cl_private; | |||
330 | XDR *xdrs = &(ct->ct_xdrs); | |||
331 | ||||
332 | xdrs->x_op = XDR_FREE; | |||
333 | return ((*xdr_res)(xdrs, res_ptr)); | |||
334 | } | |||
335 | ||||
336 | static void | |||
337 | clnttcp_abort(CLIENT *clnt) | |||
338 | { | |||
339 | } | |||
340 | ||||
341 | static bool_tint32_t | |||
342 | clnttcp_control(CLIENT *cl, u_int request, void *info) | |||
343 | { | |||
344 | struct ct_data *ct = (struct ct_data *)cl->cl_private; | |||
345 | ||||
346 | switch (request) { | |||
347 | case CLSET_TIMEOUT1: | |||
348 | ct->ct_wait = *(struct timeval *)info; | |||
349 | ct->ct_waitset = TRUE(1); | |||
350 | break; | |||
351 | case CLGET_TIMEOUT2: | |||
352 | *(struct timeval *)info = ct->ct_wait; | |||
353 | break; | |||
354 | case CLGET_SERVER_ADDR3: | |||
355 | *(struct sockaddr_in *)info = ct->ct_addr; | |||
356 | break; | |||
357 | case CLSET_CONNECTED6: | |||
358 | ct->ct_connected = *(int *)info; | |||
359 | break; | |||
360 | default: | |||
361 | return (FALSE(0)); | |||
362 | } | |||
363 | return (TRUE(1)); | |||
364 | } | |||
365 | ||||
366 | ||||
367 | static void | |||
368 | clnttcp_destroy(CLIENT *h) | |||
369 | { | |||
370 | struct ct_data *ct = | |||
371 | (struct ct_data *) h->cl_private; | |||
372 | ||||
373 | if (ct->ct_closeit && ct->ct_sock != -1) { | |||
374 | (void)close(ct->ct_sock); | |||
375 | } | |||
376 | XDR_DESTROY(&(ct->ct_xdrs))if ((&(ct->ct_xdrs))->x_ops->x_destroy) (*(& (ct->ct_xdrs))->x_ops->x_destroy)(&(ct->ct_xdrs )); | |||
377 | mem_free((caddr_t)ct, sizeof(struct ct_data))free((caddr_t)ct); | |||
378 | mem_free((caddr_t)h, sizeof(CLIENT))free((caddr_t)h); | |||
379 | } | |||
380 | ||||
381 | /* | |||
382 | * Interface between xdr serializer and tcp connection. | |||
383 | * Behaves like the system calls, read & write, but keeps some error state | |||
384 | * around for the rpc level. | |||
385 | */ | |||
386 | static int | |||
387 | readtcp(struct ct_data *ct, caddr_t buf, int len) | |||
388 | { | |||
389 | struct pollfd pfd[1]; | |||
390 | struct timespec start, after, duration, delta, wait; | |||
391 | int r, save_errno; | |||
392 | ||||
393 | if (len == 0) | |||
394 | return (0); | |||
395 | ||||
396 | pfd[0].fd = ct->ct_sock; | |||
397 | pfd[0].events = POLLIN0x0001; | |||
398 | TIMEVAL_TO_TIMESPEC(&ct->ct_wait, &wait)do { (&wait)->tv_sec = (&ct->ct_wait)->tv_sec ; (&wait)->tv_nsec = (&ct->ct_wait)->tv_usec * 1000; } while (0); | |||
399 | delta = wait; | |||
400 | WRAP(clock_gettime)_libc_clock_gettime_wrap(CLOCK_MONOTONIC3, &start); | |||
401 | for (;;) { | |||
402 | r = ppoll(pfd, 1, &delta, NULL((void *)0)); | |||
403 | save_errno = errno(*__errno()); | |||
404 | ||||
405 | WRAP(clock_gettime)_libc_clock_gettime_wrap(CLOCK_MONOTONIC3, &after); | |||
406 | timespecsub(&start, &after, &duration)do { (&duration)->tv_sec = (&start)->tv_sec - ( &after)->tv_sec; (&duration)->tv_nsec = (&start )->tv_nsec - (&after)->tv_nsec; if ((&duration) ->tv_nsec < 0) { (&duration)->tv_sec--; (&duration )->tv_nsec += 1000000000L; } } while (0); | |||
407 | timespecsub(&wait, &duration, &delta)do { (&delta)->tv_sec = (&wait)->tv_sec - (& duration)->tv_sec; (&delta)->tv_nsec = (&wait)-> tv_nsec - (&duration)->tv_nsec; if ((&delta)->tv_nsec < 0) { (&delta)->tv_sec--; (&delta)->tv_nsec += 1000000000L; } } while (0); | |||
408 | if (delta.tv_sec < 0 || !timespecisset(&delta)((&delta)->tv_sec || (&delta)->tv_nsec)) | |||
409 | r = 0; | |||
410 | ||||
411 | switch (r) { | |||
412 | case 0: | |||
413 | ct->ct_error.re_status = RPC_TIMEDOUT; | |||
414 | return (-1); | |||
415 | case 1: | |||
416 | if (pfd[0].revents & POLLNVAL0x0020) | |||
417 | errno(*__errno()) = EBADF9; | |||
418 | else if (pfd[0].revents & POLLERR0x0008) | |||
419 | errno(*__errno()) = EIO5; | |||
420 | else | |||
421 | break; | |||
422 | /* FALLTHROUGH */ | |||
423 | case -1: | |||
424 | if (errno(*__errno()) == EINTR4) | |||
425 | continue; | |||
426 | ct->ct_error.re_status = RPC_CANTRECV; | |||
427 | ct->ct_error.re_errnoru.RE_errno = save_errno; | |||
428 | return (-1); | |||
429 | } | |||
430 | break; | |||
431 | } | |||
432 | ||||
433 | switch (len = read(ct->ct_sock, buf, len)) { | |||
434 | case 0: | |||
435 | /* premature eof */ | |||
436 | ct->ct_error.re_errnoru.RE_errno = ECONNRESET54; | |||
437 | ct->ct_error.re_status = RPC_CANTRECV; | |||
438 | len = -1; /* it's really an error */ | |||
439 | break; | |||
440 | case -1: | |||
441 | ct->ct_error.re_errnoru.RE_errno = errno(*__errno()); | |||
442 | ct->ct_error.re_status = RPC_CANTRECV; | |||
443 | break; | |||
444 | } | |||
445 | return (len); | |||
446 | } | |||
447 | ||||
448 | static int | |||
449 | writetcp(struct ct_data *ct, caddr_t buf, int len) | |||
450 | { | |||
451 | int i, cnt; | |||
452 | ||||
453 | for (cnt = len; cnt > 0; cnt -= i, buf += i) { | |||
454 | if ((i = write(ct->ct_sock, buf, cnt)) == -1) { | |||
455 | ct->ct_error.re_errnoru.RE_errno = errno(*__errno()); | |||
456 | ct->ct_error.re_status = RPC_CANTSEND; | |||
457 | return (-1); | |||
458 | } | |||
459 | } | |||
460 | return (len); | |||
461 | } |