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