File: | src/lib/libc/rpc/clnt_tcp.c |
Warning: | line 298, column 16 Called function pointer is null (null dereference) |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: clnt_tcp.c,v 1.34 2020/07/06 13:33:06 pirofti 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 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 | struct timeval ct_wait; | |||
84 | bool_tint32_t ct_waitset; /* wait set by clnt_control? */ | |||
85 | struct sockaddr_in ct_addr; | |||
86 | struct rpc_err ct_error; | |||
87 | char ct_mcall[MCALL_MSG_SIZE24]; /* marshalled callmsg */ | |||
88 | u_int ct_mpos; /* pos after marshal */ | |||
89 | XDR ct_xdrs; | |||
90 | }; | |||
91 | ||||
92 | static int readtcp(struct ct_data *, caddr_t, int); | |||
93 | static int writetcp(struct ct_data *, caddr_t, int); | |||
94 | ||||
95 | /* | |||
96 | * Create a client handle for a tcp/ip connection. | |||
97 | * If *sockp<0, *sockp is set to a newly created TCP socket and it is | |||
98 | * connected to raddr. If *sockp non-negative then | |||
99 | * raddr is ignored. The rpc/tcp package does buffering | |||
100 | * similar to stdio, so the client must pick send and receive buffer sizes,]; | |||
101 | * 0 => use the default. | |||
102 | * If raddr->sin_port is 0, then a binder on the remote machine is | |||
103 | * consulted for the right port number. | |||
104 | * NB: *sockp is copied into a private area. | |||
105 | * NB: It is the client's responsibility to close *sockp, unless | |||
106 | * clnttcp_create() was called with *sockp = -1 (so it created | |||
107 | * the socket), and CLNT_DESTROY() is used. | |||
108 | * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this | |||
109 | * something more useful. | |||
110 | */ | |||
111 | CLIENT * | |||
112 | clnttcp_create(struct sockaddr_in *raddr, u_long prog, u_long vers, int *sockp, | |||
113 | u_int sendsz, u_int recvsz) | |||
114 | { | |||
115 | CLIENT *h; | |||
116 | struct ct_data *ct = NULL((void *)0); | |||
117 | struct rpc_msg call_msg; | |||
118 | ||||
119 | h = (CLIENT *)mem_alloc(sizeof(*h))malloc(sizeof(*h)); | |||
120 | if (h == NULL((void *)0)) { | |||
121 | rpc_createerr.cf_stat = RPC_SYSTEMERROR; | |||
122 | rpc_createerr.cf_error.re_errnoru.RE_errno = errno(*__errno()); | |||
123 | goto fooy; | |||
124 | } | |||
125 | ct = (struct ct_data *)mem_alloc(sizeof(*ct))malloc(sizeof(*ct)); | |||
126 | if (ct == NULL((void *)0)) { | |||
127 | rpc_createerr.cf_stat = RPC_SYSTEMERROR; | |||
128 | rpc_createerr.cf_error.re_errnoru.RE_errno = errno(*__errno()); | |||
129 | goto fooy; | |||
130 | } | |||
131 | ||||
132 | /* | |||
133 | * If no port number given ask the pmap for one | |||
134 | */ | |||
135 | if (raddr->sin_port == 0) { | |||
136 | u_short port; | |||
137 | if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP6)) == 0) { | |||
138 | mem_free((caddr_t)ct, sizeof(struct ct_data))free((caddr_t)ct); | |||
139 | mem_free((caddr_t)h, sizeof(CLIENT))free((caddr_t)h); | |||
140 | return (NULL((void *)0)); | |||
141 | } | |||
142 | 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)); | |||
143 | } | |||
144 | ||||
145 | /* | |||
146 | * If no socket given, open one | |||
147 | */ | |||
148 | if (*sockp < 0) { | |||
149 | *sockp = socket(AF_INET2, SOCK_STREAM1, IPPROTO_TCP6); | |||
150 | (void)bindresvport(*sockp, NULL((void *)0)); | |||
151 | if ((*sockp == -1) | |||
152 | || (connect(*sockp, (struct sockaddr *)raddr, | |||
153 | sizeof(*raddr)) == -1)) { | |||
154 | rpc_createerr.cf_stat = RPC_SYSTEMERROR; | |||
155 | rpc_createerr.cf_error.re_errnoru.RE_errno = errno(*__errno()); | |||
156 | if (*sockp != -1) | |||
157 | (void)close(*sockp); | |||
158 | goto fooy; | |||
159 | } | |||
160 | ct->ct_closeit = TRUE(1); | |||
161 | } else { | |||
162 | ct->ct_closeit = FALSE(0); | |||
163 | } | |||
164 | ||||
165 | /* | |||
166 | * Set up private data struct | |||
167 | */ | |||
168 | ct->ct_sock = *sockp; | |||
169 | ct->ct_wait.tv_usec = 0; | |||
170 | ct->ct_waitset = FALSE(0); | |||
171 | ct->ct_addr = *raddr; | |||
172 | ||||
173 | /* | |||
174 | * Initialize call message | |||
175 | */ | |||
176 | call_msg.rm_xid = arc4random(); | |||
177 | call_msg.rm_direction = CALL; | |||
178 | call_msg.rm_callru.RM_cmb.cb_rpcvers = RPC_MSG_VERSION((unsigned long) 2); | |||
179 | call_msg.rm_callru.RM_cmb.cb_prog = prog; | |||
180 | call_msg.rm_callru.RM_cmb.cb_vers = vers; | |||
181 | ||||
182 | /* | |||
183 | * pre-serialize the static part of the call msg and stash it away | |||
184 | */ | |||
185 | xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE24, | |||
186 | XDR_ENCODE); | |||
187 | if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { | |||
188 | if (ct->ct_closeit) { | |||
189 | (void)close(*sockp); | |||
190 | } | |||
191 | goto fooy; | |||
192 | } | |||
193 | ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs))(*(&(ct->ct_xdrs))->x_ops->x_getpostn)(&(ct-> ct_xdrs)); | |||
194 | XDR_DESTROY(&(ct->ct_xdrs))if ((&(ct->ct_xdrs))->x_ops->x_destroy) (*(& (ct->ct_xdrs))->x_ops->x_destroy)(&(ct->ct_xdrs )); | |||
195 | ||||
196 | /* | |||
197 | * Create a client handle which uses xdrrec for serialization | |||
198 | * and authnone for authentication. | |||
199 | */ | |||
200 | xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, | |||
201 | (caddr_t)ct, (int(*)(caddr_t, caddr_t, int))readtcp, | |||
202 | (int(*)(caddr_t, caddr_t, int))writetcp); | |||
203 | h->cl_ops = &tcp_ops; | |||
204 | h->cl_private = (caddr_t) ct; | |||
205 | h->cl_auth = authnone_create(); | |||
206 | if (h->cl_auth == NULL((void *)0)) { | |||
207 | rpc_createerr.cf_stat = RPC_SYSTEMERROR; | |||
208 | rpc_createerr.cf_error.re_errnoru.RE_errno = errno(*__errno()); | |||
209 | goto fooy; | |||
210 | } | |||
211 | return (h); | |||
212 | ||||
213 | fooy: | |||
214 | /* | |||
215 | * Something goofed, free stuff and barf | |||
216 | */ | |||
217 | if (ct) | |||
218 | mem_free((caddr_t)ct, sizeof(struct ct_data))free((caddr_t)ct); | |||
219 | if (h) | |||
220 | mem_free((caddr_t)h, sizeof(CLIENT))free((caddr_t)h); | |||
221 | return (NULL((void *)0)); | |||
222 | } | |||
223 | DEF_WEAK(clnttcp_create)__asm__(".weak " "clnttcp_create" " ; " "clnttcp_create" " = " "_libc_clnttcp_create"); | |||
224 | ||||
225 | static enum clnt_stat | |||
226 | clnttcp_call(CLIENT *h, u_long proc, xdrproc_t xdr_args, caddr_t args_ptr, | |||
227 | xdrproc_t xdr_results, caddr_t results_ptr, struct timeval timeout) | |||
228 | { | |||
229 | struct ct_data *ct = (struct ct_data *) h->cl_private; | |||
230 | XDR *xdrs = &(ct->ct_xdrs); | |||
231 | struct rpc_msg reply_msg; | |||
232 | u_long x_id; | |||
233 | u_int32_t *msg_x_id = (u_int32_t *)(ct->ct_mcall); /* yuk */ | |||
234 | bool_tint32_t shipnow; | |||
235 | int refreshes = 2; | |||
236 | ||||
237 | if (!ct->ct_waitset) { | |||
| ||||
238 | ct->ct_wait = timeout; | |||
239 | } | |||
240 | ||||
241 | shipnow = | |||
242 | (xdr_results == NULL((void *)0) && timeout.tv_sec == 0 | |||
243 | && timeout.tv_usec == 0) ? FALSE(0) : TRUE(1); | |||
244 | ||||
245 | call_again: | |||
246 | xdrs->x_op = XDR_ENCODE; | |||
247 | ct->ct_error.re_status = RPC_SUCCESS; | |||
248 | 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)) ); | |||
249 | if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)(*(xdrs)->x_ops->x_putbytes)(xdrs, ct->ct_mcall, ct-> ct_mpos)) || | |||
250 | (! XDR_PUTLONG(xdrs, (long *)&proc)(*(xdrs)->x_ops->x_putlong)(xdrs, (long *)&proc)) || | |||
251 | (! AUTH_MARSHALL(h->cl_auth, xdrs)((*((h->cl_auth)->ah_ops->ah_marshal))(h->cl_auth , xdrs))) || | |||
252 | (! (*xdr_args)(xdrs, args_ptr))) { | |||
253 | if (ct->ct_error.re_status == RPC_SUCCESS) | |||
254 | ct->ct_error.re_status = RPC_CANTENCODEARGS; | |||
255 | (void)xdrrec_endofrecord(xdrs, TRUE(1)); | |||
256 | return (ct->ct_error.re_status); | |||
257 | } | |||
258 | if (! xdrrec_endofrecord(xdrs, shipnow)) | |||
259 | return (ct->ct_error.re_status = RPC_CANTSEND); | |||
260 | if (! shipnow
| |||
261 | return (RPC_SUCCESS); | |||
262 | /* | |||
263 | * Hack to provide rpc-based message passing | |||
264 | */ | |||
265 | if (timeout.tv_sec
| |||
266 | return(ct->ct_error.re_status = RPC_TIMEDOUT); | |||
267 | } | |||
268 | ||||
269 | ||||
270 | /* | |||
271 | * Keep receiving until we get a valid transaction id | |||
272 | */ | |||
273 | xdrs->x_op = XDR_DECODE; | |||
274 | while (TRUE(1)) { | |||
275 | reply_msg.acpted_rplyru.RM_rmb.ru.RP_ar.ar_verf = _null_auth; | |||
276 | reply_msg.acpted_rplyru.RM_rmb.ru.RP_ar.ar_resultsru.AR_results.where = NULL((void *)0); | |||
277 | reply_msg.acpted_rplyru.RM_rmb.ru.RP_ar.ar_resultsru.AR_results.proc = xdr_void; | |||
278 | if (! xdrrec_skiprecord(xdrs)) | |||
279 | return (ct->ct_error.re_status); | |||
280 | /* now decode and validate the response header */ | |||
281 | if (! xdr_replymsg(xdrs, &reply_msg)) { | |||
282 | if (ct->ct_error.re_status == RPC_SUCCESS) | |||
283 | continue; | |||
284 | return (ct->ct_error.re_status); | |||
285 | } | |||
286 | if (reply_msg.rm_xid == x_id) | |||
287 | break; | |||
288 | } | |||
289 | ||||
290 | /* | |||
291 | * process header | |||
292 | */ | |||
293 | _seterr_reply(&reply_msg, &(ct->ct_error)); | |||
294 | if (ct->ct_error.re_status == RPC_SUCCESS) { | |||
295 | 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))) { | |||
296 | ct->ct_error.re_status = RPC_AUTHERROR; | |||
297 | ct->ct_error.re_whyru.RE_why = AUTH_INVALIDRESP; | |||
298 | } else if (! (*xdr_results)(xdrs, results_ptr)) { | |||
| ||||
299 | if (ct->ct_error.re_status == RPC_SUCCESS) | |||
300 | ct->ct_error.re_status = RPC_CANTDECODERES; | |||
301 | } | |||
302 | /* free verifier ... */ | |||
303 | if (reply_msg.acpted_rplyru.RM_rmb.ru.RP_ar.ar_verf.oa_base != NULL((void *)0)) { | |||
304 | xdrs->x_op = XDR_FREE; | |||
305 | (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rplyru.RM_rmb.ru.RP_ar.ar_verf)); | |||
306 | } | |||
307 | } /* end successful completion */ | |||
308 | else { | |||
309 | /* maybe our credentials need to be refreshed ... */ | |||
310 | if (refreshes-- && AUTH_REFRESH(h->cl_auth)((*((h->cl_auth)->ah_ops->ah_refresh))(h->cl_auth ))) | |||
311 | goto call_again; | |||
312 | } /* end of unsuccessful completion */ | |||
313 | return (ct->ct_error.re_status); | |||
314 | } | |||
315 | ||||
316 | static void | |||
317 | clnttcp_geterr(CLIENT *h, struct rpc_err *errp) | |||
318 | { | |||
319 | struct ct_data *ct = | |||
320 | (struct ct_data *) h->cl_private; | |||
321 | ||||
322 | *errp = ct->ct_error; | |||
323 | } | |||
324 | ||||
325 | static bool_tint32_t | |||
326 | clnttcp_freeres(CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr) | |||
327 | { | |||
328 | struct ct_data *ct = (struct ct_data *)cl->cl_private; | |||
329 | XDR *xdrs = &(ct->ct_xdrs); | |||
330 | ||||
331 | xdrs->x_op = XDR_FREE; | |||
332 | return ((*xdr_res)(xdrs, res_ptr)); | |||
333 | } | |||
334 | ||||
335 | static void | |||
336 | clnttcp_abort(CLIENT *clnt) | |||
337 | { | |||
338 | } | |||
339 | ||||
340 | static bool_tint32_t | |||
341 | clnttcp_control(CLIENT *cl, u_int request, void *info) | |||
342 | { | |||
343 | struct ct_data *ct = (struct ct_data *)cl->cl_private; | |||
344 | ||||
345 | switch (request) { | |||
346 | case CLSET_TIMEOUT1: | |||
347 | ct->ct_wait = *(struct timeval *)info; | |||
348 | ct->ct_waitset = TRUE(1); | |||
349 | break; | |||
350 | case CLGET_TIMEOUT2: | |||
351 | *(struct timeval *)info = ct->ct_wait; | |||
352 | break; | |||
353 | case CLGET_SERVER_ADDR3: | |||
354 | *(struct sockaddr_in *)info = ct->ct_addr; | |||
355 | break; | |||
356 | default: | |||
357 | return (FALSE(0)); | |||
358 | } | |||
359 | return (TRUE(1)); | |||
360 | } | |||
361 | ||||
362 | ||||
363 | static void | |||
364 | clnttcp_destroy(CLIENT *h) | |||
365 | { | |||
366 | struct ct_data *ct = | |||
367 | (struct ct_data *) h->cl_private; | |||
368 | ||||
369 | if (ct->ct_closeit && ct->ct_sock != -1) { | |||
370 | (void)close(ct->ct_sock); | |||
371 | } | |||
372 | XDR_DESTROY(&(ct->ct_xdrs))if ((&(ct->ct_xdrs))->x_ops->x_destroy) (*(& (ct->ct_xdrs))->x_ops->x_destroy)(&(ct->ct_xdrs )); | |||
373 | mem_free((caddr_t)ct, sizeof(struct ct_data))free((caddr_t)ct); | |||
374 | mem_free((caddr_t)h, sizeof(CLIENT))free((caddr_t)h); | |||
375 | } | |||
376 | ||||
377 | /* | |||
378 | * Interface between xdr serializer and tcp connection. | |||
379 | * Behaves like the system calls, read & write, but keeps some error state | |||
380 | * around for the rpc level. | |||
381 | */ | |||
382 | static int | |||
383 | readtcp(struct ct_data *ct, caddr_t buf, int len) | |||
384 | { | |||
385 | struct pollfd pfd[1]; | |||
386 | struct timespec start, after, duration, delta, wait; | |||
387 | int r, save_errno; | |||
388 | ||||
389 | if (len == 0) | |||
390 | return (0); | |||
391 | ||||
392 | pfd[0].fd = ct->ct_sock; | |||
393 | pfd[0].events = POLLIN0x0001; | |||
394 | 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); | |||
395 | delta = wait; | |||
396 | WRAP(clock_gettime)_libc_clock_gettime_wrap(CLOCK_MONOTONIC3, &start); | |||
397 | for (;;) { | |||
398 | r = ppoll(pfd, 1, &delta, NULL((void *)0)); | |||
399 | save_errno = errno(*__errno()); | |||
400 | ||||
401 | WRAP(clock_gettime)_libc_clock_gettime_wrap(CLOCK_MONOTONIC3, &after); | |||
402 | 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); | |||
403 | 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); | |||
404 | if (delta.tv_sec < 0 || !timespecisset(&delta)((&delta)->tv_sec || (&delta)->tv_nsec)) | |||
405 | r = 0; | |||
406 | ||||
407 | switch (r) { | |||
408 | case 0: | |||
409 | ct->ct_error.re_status = RPC_TIMEDOUT; | |||
410 | return (-1); | |||
411 | case 1: | |||
412 | if (pfd[0].revents & POLLNVAL0x0020) | |||
413 | errno(*__errno()) = EBADF9; | |||
414 | else if (pfd[0].revents & POLLERR0x0008) | |||
415 | errno(*__errno()) = EIO5; | |||
416 | else | |||
417 | break; | |||
418 | /* FALLTHROUGH */ | |||
419 | case -1: | |||
420 | if (errno(*__errno()) == EINTR4) | |||
421 | continue; | |||
422 | ct->ct_error.re_status = RPC_CANTRECV; | |||
423 | ct->ct_error.re_errnoru.RE_errno = save_errno; | |||
424 | return (-1); | |||
425 | } | |||
426 | break; | |||
427 | } | |||
428 | ||||
429 | switch (len = read(ct->ct_sock, buf, len)) { | |||
430 | case 0: | |||
431 | /* premature eof */ | |||
432 | ct->ct_error.re_errnoru.RE_errno = ECONNRESET54; | |||
433 | ct->ct_error.re_status = RPC_CANTRECV; | |||
434 | len = -1; /* it's really an error */ | |||
435 | break; | |||
436 | case -1: | |||
437 | ct->ct_error.re_errnoru.RE_errno = errno(*__errno()); | |||
438 | ct->ct_error.re_status = RPC_CANTRECV; | |||
439 | break; | |||
440 | } | |||
441 | return (len); | |||
442 | } | |||
443 | ||||
444 | static int | |||
445 | writetcp(struct ct_data *ct, caddr_t buf, int len) | |||
446 | { | |||
447 | int i, cnt; | |||
448 | ||||
449 | for (cnt = len; cnt > 0; cnt -= i, buf += i) { | |||
450 | if ((i = write(ct->ct_sock, buf, cnt)) == -1) { | |||
451 | ct->ct_error.re_errnoru.RE_errno = errno(*__errno()); | |||
452 | ct->ct_error.re_status = RPC_CANTSEND; | |||
453 | return (-1); | |||
454 | } | |||
455 | } | |||
456 | return (len); | |||
457 | } |