| 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 | } |