static int __netlink_sendreq (struct netlink_handle *h, int type) { struct { struct nlmsghdr nlh; struct rtgenmsg g; } req; struct sockaddr_nl nladdr; if (h->seq == 0) h->seq = time (NULL); req.nlh.nlmsg_len = sizeof (req); req.nlh.nlmsg_type = type; req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; req.nlh.nlmsg_pid = 0; req.nlh.nlmsg_seq = h->seq; req.g.rtgen_family = AF_UNSPEC; memset (&nladdr, '\0', sizeof (nladdr)); nladdr.nl_family = AF_NETLINK; return TEMP_FAILURE_RETRY (__sendto (h->fd, (void *) &req, sizeof (req), 0, (struct sockaddr *) &nladdr, sizeof (nladdr))); }
ssize_t send(int s, const void *msg, size_t len, int flags) { #ifdef VARIANT_CANCELABLE return (__sendto(s, msg, len, flags, NULL, 0)); #else /* !VARIANT_CANCELABLE */ return (__sendto_nocancel(s, msg, len, flags, NULL, 0)); #endif /* VARIANT_CANCELABLE */ }
int rtime (struct sockaddr_in *addrp, struct rpc_timeval *timep, struct rpc_timeval *timeout) { int s; struct pollfd fd; int milliseconds; int res; /* RFC 868 says the time is transmitted as a 32-bit value. */ uint32_t thetime; struct sockaddr_in from; int fromlen; int type; if (timeout == NULL) type = SOCK_STREAM; else type = SOCK_DGRAM; s = __socket (AF_INET, type, 0); if (s < 0) return (-1); addrp->sin_family = AF_INET; addrp->sin_port = htons (IPPORT_TIMESERVER); if (type == SOCK_DGRAM) { res = __sendto (s, (char *) &thetime, sizeof (thetime), 0, (struct sockaddr *) addrp, sizeof (*addrp)); if (res < 0) { do_close (s); return -1; } milliseconds = (timeout->tv_sec * 1000) + (timeout->tv_usec / 1000); fd.fd = s; fd.events = POLLIN; do res = __poll (&fd, 1, milliseconds); while (res < 0 && errno == EINTR); if (res <= 0) { if (res == 0) __set_errno (ETIMEDOUT); do_close (s); return (-1); } fromlen = sizeof (from); res = __recvfrom (s, (char *) &thetime, sizeof (thetime), 0, (struct sockaddr *) &from, &fromlen); do_close (s); if (res < 0) return -1; } else { if (__connect (s, (struct sockaddr *) addrp, sizeof (*addrp)) < 0) { do_close (s); return -1; } res = __read (s, (char *) &thetime, sizeof (thetime)); do_close (s); if (res < 0) return (-1); } if (res != sizeof (thetime)) { __set_errno (EIO); return -1; } thetime = ntohl (thetime); timep->tv_sec = thetime - TOFFSET; timep->tv_usec = 0; return 0; }
int res_send(struct SocketBase * libPtr, const char * buf, int buflen, char * answer, int anslen) { register int n; int try, v_circuit, resplen, nscount; int gotsomewhere = 0, connected = 0; int connreset = 0; u_short id, len; char *cp; fd_set dsmask; struct timeval timeout; struct in_addr *ns; struct sockaddr_in host; HEADER *hp = (HEADER *) buf; HEADER *anhp = (HEADER *) answer; u_char terrno = ETIMEDOUT; #define JUNK_SIZE 512 char junk[JUNK_SIZE]; /* buffer for trash data */ #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send()\n")); D(bug("[AROSTCP](res_send.c) res_send: using socket %d\n", res_sock)); #endif #ifdef RES_DEBUG printf("res_send()\n"); __p_query(buf, libPtr); #endif /* RES_DEBUG */ v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; id = hp->id; /* * Send request, RETRY times, or until successful */ for (try = 0; try < _res.retry; try++) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Attempt %d\n", try)); #endif nscount = 0; DRES(Printf("Retry #%ld\n",try);) for (ns = _res.nsaddr_list; ns->s_addr; ns++) { nscount++; #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Querying server #%ld address = %s\n", nscount, __inet_ntoa(ns->s_addr, libPtr))); #endif #ifdef RES_DEBUG Printf("Querying server #%ld address = %s\n", nscount, __Inet_NtoA(ns->s_addr, libPtr)); #endif /* RES_DEBUG */ host.sin_len = sizeof(host); host.sin_family = AF_INET; host.sin_port = htons(NAMESERVER_PORT); host.sin_addr.s_addr = ns->s_addr; aligned_bzero_const(&host.sin_zero, sizeof(host.sin_zero)); usevc: if (v_circuit) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Using v_circuit\n")); #endif int truncated = 0; /* * Use virtual circuit; * at most one attempt per server. */ try = _res.retry; if (res_sock < 0) { res_sock = __socket(AF_INET, SOCK_STREAM, 0, libPtr); if (res_sock < 0) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Failed to create socket!!\n")); terrno = readErrnoValue(libPtr); #endif #ifdef RES_DEBUG Perror("socket (vc)"); #endif /* RES_DEBUG */ continue; } #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: created socket %d\n", res_sock)); #endif if (__connect(res_sock, (struct sockaddr *)&host, sizeof(struct sockaddr), libPtr) < 0) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Failed to connect\n")); #endif terrno = readErrnoValue(libPtr); #ifdef RES_DEBUG Perror("connect (vc)"); #endif /* RES_DEBUG */ (void) __CloseSocket(res_sock, libPtr); res_sock = -1; continue; } } /* * Send length & message */ len = htons((u_short)buflen); if ((__send(res_sock, (char *)&len, sizeof(len), 0, libPtr) != sizeof(len)) || ((__send(res_sock, (char *)buf, buflen, 0, libPtr) != buflen))) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Failed sending query\n")); #endif terrno = readErrnoValue(libPtr); #ifdef RES_DEBUG Perror("write(vc)"); #endif /* RES_DEBUG */ (void) __CloseSocket(res_sock, libPtr); res_sock = -1; continue; } /* * Receive length & response */ cp = answer; len = sizeof(short); while (len != 0 && (n = __recv(res_sock, (char *)cp, (int)len, 0, libPtr)) > 0) { cp += n; len -= n; } if (n <= 0) { terrno = readErrnoValue(libPtr); #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Failed recieving response\n")); #endif #ifdef RES_DEBUG Perror("read (vc)"); #endif /* RES_DEBUG */ (void) __CloseSocket(res_sock, libPtr); res_sock = -1; /* * A long running process might get its TCP * connection reset if the remote server was * restarted. Requery the server instead of * trying a new one. When there is only one * server, this means that a query might work * instead of failing. We only allow one reset * per query to prevent looping. */ if (terrno == ECONNRESET && !connreset) { connreset = 1; ns--; } continue; } cp = answer; if ((resplen = ntohs(*(u_short *)cp)) > anslen) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Truncated response\n")); #endif #ifdef RES_DEBUG Printf("response truncated\n"); #endif /* RES_DEBUG */ len = anslen; truncated = 1; } else len = resplen; while (len != 0 && (n = __recv(res_sock, (char *)cp, (int)len, 0, libPtr)) > 0) { cp += n; len -= n; } if (n <= 0) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Error recieving response\n")); #endif terrno = readErrnoValue(libPtr); #ifdef RES_DEBUG Perror("read (vc)"); #endif /* RES_DEBUG */ (void) __CloseSocket(res_sock, libPtr); res_sock = -1; continue; } if (truncated) { /* * Flush rest of answer * so connection stays in synch. */ anhp->tc = 1; len = resplen - anslen; while (len != 0) { n = (len > JUNK_SIZE ? JUNK_SIZE : len); if ((n = __recv(res_sock, junk, n, 0, libPtr)) > 0) len -= n; else break; } } } else { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Using datagrams\n")); #endif /* * Use datagrams. */ if (res_sock < 0) { res_sock = __socket(AF_INET, SOCK_DGRAM, 0, libPtr); if (res_sock < 0) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Failed to create socket\n")); #endif terrno = readErrnoValue(libPtr); #ifdef RES_DEBUG Perror("socket (dg)"); #endif /* RES_DEBUG */ continue; } } /* * I'm tired of answering this question, so: * On a 4.3BSD+ machine (client and server, * actually), sending to a nameserver datagram * port with no nameserver will cause an * ICMP port unreachable message to be returned. * If our datagram socket is "connected" to the * server, we get an ECONNREFUSED error on the next * socket operation, and select returns if the * error message is received. We can thus detect * the absence of a nameserver without timing out. * If we have sent queries to at least two servers, * however, we don't want to remain connected, * as we wish to receive answers from the first * server to respond. */ #warning "TODO*: see comment here .." /* This piece of code still behaves slightly wrong in case of ECONNREFUSED error. On next retry socket will be in disconnected state and instead of getting ECONNREFUSED again we'll timeout in WaitSelect() and get ETIMEDOUT. However, this is not critical and is queued for future - Pavel Fedin*/ if (try == 0 && nscount == 1) { /* * Don't use connect if we might * still receive a response * from another server. */ if (connected == 0) { if (__connect(res_sock, (struct sockaddr *)&host, sizeof(struct sockaddr), libPtr) < 0) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Error connecting\n")); #endif #ifdef RES_DEBUG Perror("connect (dg)"); #endif /* RES_DEBUG */ continue; } connected = 1; } if (__send(res_sock, buf, buflen, 0, libPtr) != buflen) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Error sending\n")); #endif #ifdef RES_DEBUG Perror("send (dg)"); #endif /* RES_DEBUG */ continue; } } else { /* * Disconnect if we want to listen * for responses from more than one server. */ if (connected) { (void) __connect(res_sock, &no_addr, sizeof(no_addr), libPtr); connected = 0; } if (__sendto(res_sock, buf, buflen, 0, (struct sockaddr *)&host, sizeof(struct sockaddr), libPtr) != buflen) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: [__sendto] Error\n")); #endif #ifdef RES_DEBUG Perror("sendto (dg)"); #endif /* RES_DEBUG */ continue; } } /* * Wait for reply */ timeout.tv_sec = (_res.retrans << try); if (try > 0) timeout.tv_sec /= nscount; if (timeout.tv_sec <= 0) timeout.tv_sec = 1; timeout.tv_usec = 0; wait: FD_ZERO(&dsmask); FD_SET(res_sock, &dsmask); n = __WaitSelect(res_sock+1, &dsmask, NULL, NULL, &timeout, NULL, libPtr); if (n < 0) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: [__WaitSelect] Error\n")); #endif #ifdef RES_DEBUG Perror("select"); #endif /* RES_DEBUG */ terrno = readErrnoValue(libPtr); if (terrno == EINTR) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: closing socket\n")); #endif __CloseSocket(res_sock, libPtr); res_sock = -1; return (-1); } continue; } if (n == 0) { /* * timeout */ #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Timeout!\n")); #endif #ifdef RES_DEBUG Printf("timeout\n"); #endif /* RES_DEBUG */ #if 1 || BSD >= 43 gotsomewhere = 1; #endif continue; } if ((resplen = __recv(res_sock, answer, anslen, 0, libPtr)) <= 0) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Error recieving\n")); #endif #ifdef RES_DEBUG Perror("recv (dg)"); #endif /* RES_DEBUG */ continue; } gotsomewhere = 1; if (id != anhp->id) { /* * response from old query, ignore it */ #ifdef RES_DEBUG Printf("old answer:\n"); __p_query(answer, libPtr); #endif /* RES_DEBUG */ goto wait; } if (!(_res.options & RES_IGNTC) && anhp->tc) { /* * get rest of answer; * use TCP with same server. */ #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Response is truncated\n")); #endif #ifdef RES_DEBUG Printf("truncated answer\n"); #endif /* RES_DEBUG */ (void)__CloseSocket(res_sock, libPtr); res_sock = -1; v_circuit = 1; goto usevc; } } #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Recieved answer\n")); #endif #ifdef RES_DEBUG Printf("got answer:\n"); __p_query(answer, libPtr); #endif /* RES_DEBUG */ /* * If using virtual circuits, we assume that the first server * is preferred * over the rest (i.e. it is on the local * machine) and only keep that one open. * If we have temporarily opened a virtual circuit, * or if we haven't been asked to keep a socket open, * close the socket. */ if ((v_circuit && ((_res.options & RES_USEVC) == 0 || ns->s_addr != 0)) || (_res.options & RES_STAYOPEN) == 0) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Closing socket\n")); #endif (void) __CloseSocket(res_sock, libPtr); res_sock = -1; } return (resplen); }
static enum clnt_stat clntudp_call (/* client handle */ CLIENT *cl, /* procedure number */ u_long proc, /* xdr routine for args */ xdrproc_t xargs, /* pointer to args */ caddr_t argsp, /* xdr routine for results */ xdrproc_t xresults, /* pointer to results */ caddr_t resultsp, /* seconds to wait before giving up */ struct timeval utimeout) { struct cu_data *cu = (struct cu_data *) cl->cl_private; XDR *xdrs; int outlen = 0; int inlen; socklen_t fromlen; struct pollfd fd; int milliseconds = (cu->cu_wait.tv_sec * 1000) + (cu->cu_wait.tv_usec / 1000); struct sockaddr_in from; struct rpc_msg reply_msg; XDR reply_xdrs; struct timeval time_waited; bool_t ok; int nrefreshes = 2; /* number of times to refresh cred */ struct timeval timeout; int anyup; /* any network interface up */ if (cu->cu_total.tv_usec == -1) { timeout = utimeout; /* use supplied timeout */ } else { timeout = cu->cu_total; /* use default timeout */ } time_waited.tv_sec = 0; time_waited.tv_usec = 0; call_again: xdrs = &(cu->cu_outxdrs); if (xargs == NULL) goto get_reply; xdrs->x_op = XDR_ENCODE; XDR_SETPOS (xdrs, cu->cu_xdrpos); /* * the transaction is the first thing in the out buffer */ (*(uint32_t *) (cu->cu_outbuf))++; if ((!XDR_PUTLONG (xdrs, (long *) &proc)) || (!AUTH_MARSHALL (cl->cl_auth, xdrs)) || (!(*xargs) (xdrs, argsp))) return (cu->cu_error.re_status = RPC_CANTENCODEARGS); outlen = (int) XDR_GETPOS (xdrs); send_again: if (__sendto (cu->cu_sock, cu->cu_outbuf, outlen, 0, (struct sockaddr *) &(cu->cu_raddr), cu->cu_rlen) != outlen) { cu->cu_error.re_errno = errno; return (cu->cu_error.re_status = RPC_CANTSEND); } /* * Hack to provide rpc-based message passing */ if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { return (cu->cu_error.re_status = RPC_TIMEDOUT); } get_reply: /* * sub-optimal code appears here because we have * some clock time to spare while the packets are in flight. * (We assume that this is actually only executed once.) */ reply_msg.acpted_rply.ar_verf = _null_auth; reply_msg.acpted_rply.ar_results.where = resultsp; reply_msg.acpted_rply.ar_results.proc = xresults; fd.fd = cu->cu_sock; fd.events = POLLIN; anyup = 0; for (;;) { switch (__poll (&fd, 1, milliseconds)) { case 0: if (anyup == 0) { anyup = is_network_up (cu->cu_sock); if (!anyup) return (cu->cu_error.re_status = RPC_CANTRECV); } time_waited.tv_sec += cu->cu_wait.tv_sec; time_waited.tv_usec += cu->cu_wait.tv_usec; while (time_waited.tv_usec >= 1000000) { time_waited.tv_sec++; time_waited.tv_usec -= 1000000; } if ((time_waited.tv_sec < timeout.tv_sec) || ((time_waited.tv_sec == timeout.tv_sec) && (time_waited.tv_usec < timeout.tv_usec))) goto send_again; return (cu->cu_error.re_status = RPC_TIMEDOUT); /* * buggy in other cases because time_waited is not being * updated. */ case -1: if (errno == EINTR) continue; cu->cu_error.re_errno = errno; return (cu->cu_error.re_status = RPC_CANTRECV); } #ifdef IP_RECVERR if (fd.revents & POLLERR) { struct msghdr msg; struct cmsghdr *cmsg; struct sock_extended_err *e; struct sockaddr_in err_addr; struct iovec iov; char *cbuf = malloc (outlen + 256); int ret; if (cbuf == NULL) { cu->cu_error.re_errno = errno; return (cu->cu_error.re_status = RPC_CANTRECV); } iov.iov_base = cbuf + 256; iov.iov_len = outlen; msg.msg_name = (void *) &err_addr; msg.msg_namelen = sizeof (err_addr); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_flags = 0; msg.msg_control = cbuf; msg.msg_controllen = 256; ret = __recvmsg (cu->cu_sock, &msg, MSG_ERRQUEUE); if (ret >= 0 && memcmp (cbuf + 256, cu->cu_outbuf, ret) == 0 && (msg.msg_flags & MSG_ERRQUEUE) && ((msg.msg_namelen == 0 && ret >= 12) || (msg.msg_namelen == sizeof (err_addr) && err_addr.sin_family == AF_INET && memcmp (&err_addr.sin_addr, &cu->cu_raddr.sin_addr, sizeof (err_addr.sin_addr)) == 0 && err_addr.sin_port == cu->cu_raddr.sin_port))) for (cmsg = CMSG_FIRSTHDR (&msg); cmsg; cmsg = CMSG_NXTHDR (&msg, cmsg)) if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR) { free (cbuf); e = (struct sock_extended_err *) CMSG_DATA(cmsg); cu->cu_error.re_errno = e->ee_errno; return (cu->cu_error.re_status = RPC_CANTRECV); } free (cbuf); } #endif do { fromlen = sizeof (struct sockaddr); inlen = __recvfrom (cu->cu_sock, cu->cu_inbuf, (int) cu->cu_recvsz, MSG_DONTWAIT, (struct sockaddr *) &from, &fromlen); } while (inlen < 0 && errno == EINTR); if (inlen < 0) { if (errno == EWOULDBLOCK) continue; cu->cu_error.re_errno = errno; return (cu->cu_error.re_status = RPC_CANTRECV); } if (inlen < 4) continue; /* see if reply transaction id matches sent id. Don't do this if we only wait for a replay */ if (xargs != NULL && memcmp (cu->cu_inbuf, cu->cu_outbuf, sizeof (u_int32_t)) != 0) continue; /* we now assume we have the proper reply */ break; } /* * now decode and validate the response */ xdrmem_create (&reply_xdrs, cu->cu_inbuf, (u_int) inlen, XDR_DECODE); ok = xdr_replymsg (&reply_xdrs, &reply_msg); /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ if (ok) { _seterr_reply (&reply_msg, &(cu->cu_error)); if (cu->cu_error.re_status == RPC_SUCCESS) { if (!AUTH_VALIDATE (cl->cl_auth, &reply_msg.acpted_rply.ar_verf)) { cu->cu_error.re_status = RPC_AUTHERROR; cu->cu_error.re_why = AUTH_INVALIDRESP; } if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { xdrs->x_op = XDR_FREE; (void) xdr_opaque_auth (xdrs, &(reply_msg.acpted_rply.ar_verf)); } } /* end successful completion */ else { /* maybe our credentials need to be refreshed ... */ if (nrefreshes > 0 && AUTH_REFRESH (cl->cl_auth)) { nrefreshes--; goto call_again; } } /* end of unsuccessful completion */ } /* end of valid reply message */ else { cu->cu_error.re_status = RPC_CANTDECODERES; } return cu->cu_error.re_status; }