int osi_NetSend(osi_socket asocket, struct sockaddr_in *addr, struct iovec *dvec, int nvecs, afs_int32 alength, int istack) { register afs_int32 code; int i; struct iovec iov[RX_MAXIOVECS]; struct uio u; int haveGlock = ISAFS_GLOCK(); AFS_STATCNT(osi_NetSend); if (nvecs > RX_MAXIOVECS) osi_Panic("osi_NetSend: %d: Too many iovecs.\n", nvecs); for (i = 0; i < nvecs; i++) iov[i] = dvec[i]; u.uio_iov = &iov[0]; u.uio_iovcnt = nvecs; u.uio_offset = 0; u.uio_resid = alength; u.uio_segflg = UIO_SYSSPACE; u.uio_rw = UIO_WRITE; #ifdef AFS_FBSD50_ENV u.uio_td = NULL; #else u.uio_procp = NULL; #endif addr->sin_len = sizeof(struct sockaddr_in); if (haveGlock) AFS_GUNLOCK(); #if KNET_DEBUG printf("+"); #endif #ifdef AFS_FBSD50_ENV code = sosend(asocket, (struct sockaddr *)addr, &u, NULL, NULL, 0, curthread); #else code = sosend(asocket, (struct sockaddr *)addr, &u, NULL, NULL, 0, curproc); #endif #if KNET_DEBUG if (code) { if (code == EINVAL) Debugger("afs NetSend busted"); else printf("z"); } #endif if (haveGlock) AFS_GLOCK(); return code; }
static void ncp_watchdog(struct ncp_conn *conn) { char *buf; struct mbuf *m; int error, len, flags; struct socket *so; struct sockaddr *sa; struct uio auio; sa = NULL; while (conn->wdg_so) { /* not a loop */ so = conn->wdg_so; auio.uio_resid = len = 1000000; auio.uio_td = curthread; flags = MSG_DONTWAIT; error = soreceive(so, (struct sockaddr**)&sa, &auio, &m, (struct mbuf**)0, &flags); if (error) break; len -= auio.uio_resid; NCPSDEBUG("got watch dog %d\n",len); if (len != 2) break; buf = mtod(m, char*); if (buf[1] != '?') break; buf[1] = 'Y'; error = sosend(so, (struct sockaddr*)sa, 0, m, 0, 0, curthread); NCPSDEBUG("send watch dog %d\n",error); break; } if (sa) free(sa, M_SONAME); return; }
errno_t xi_sock_send(xi_socket_t so, void *buf, size_t *len, int flags) { #ifdef __KPI_SOCKET__ struct iovec aio; struct msghdr msg; size_t sentLen = *len; errno_t error; aio.iov_base = buf; aio.iov_len = sentLen; bzero(&msg, sizeof(msg)); msg.msg_iov = (struct iovec *) &aio; msg.msg_iovlen = 1; error = sock_send(so, &msg, flags, &sentLen); #if 1 if(error) DebugPrint(1, false, "xi_sock_send: so = %p, buf_len = %d error = %d\n", so, (int)*len, error); #endif /* if 0 */ *len = sentLen; return error; #else struct iovec aiov; struct uio auio = { 0 }; register struct proc *p = current_proc(); register int error = 0; aiov.iov_base = buf; aiov.iov_len = *len; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_segflg = UIO_SYSSPACE; auio.uio_rw = UIO_WRITE; auio.uio_procp = p; auio.uio_offset = 0; /* XXX */ auio.uio_resid = *len; // IOLog("Before: so = %p, buf_len = %d, aiov.iov_len = %d, error = %d, auio.uio_resid = %d\n", so, (int)len, (int)aiov.iov_len, error,auio.uio_resid); thread_funnel_set(network_flock, TRUE); error = sosend(so, NULL, &auio, NULL, 0, flags); (void) thread_funnel_set(network_flock, FALSE); #if 0 if(error) IOLog("After: so = %p, buf_len = %d, aiov.iov_len = %d, error = %d, auio.uio_resid = %d\n", so, (int)*len, (int)aiov.iov_len, error, auio.uio_resid); #endif /* if 0 */ *len = *len - auio.uio_resid; return error; #endif }
/* * Receive incoming data on our hook. Send it out the socket. */ static int ng_ksocket_rcvdata(hook_p hook, item_p item) { struct thread *td = curthread; /* XXX broken */ const node_p node = NG_HOOK_NODE(hook); const priv_p priv = NG_NODE_PRIVATE(node); struct socket *const so = priv->so; struct sockaddr *sa = NULL; int error; struct mbuf *m; struct sa_tag *stag; /* Extract data */ NGI_GET_M(item, m); NG_FREE_ITEM(item); /* * Look if socket address is stored in packet tags. * If sockaddr is ours, or provided by a third party (zero id), * then we accept it. */ if (((stag = (struct sa_tag *)m_tag_locate(m, NGM_KSOCKET_COOKIE, NG_KSOCKET_TAG_SOCKADDR, NULL)) != NULL) && (stag->id == NG_NODE_ID(node) || stag->id == 0)) sa = &stag->sa; /* Reset specific mbuf flags to prevent addressing problems. */ m->m_flags &= ~(M_BCAST|M_MCAST); /* Send packet */ error = sosend(so, sa, 0, m, 0, 0, td); return (error); }
/* ARGSUSED */ int soo_write(struct file *fp, off_t *poff, struct uio *uio, struct ucred *cred) { return (sosend((struct socket *)fp->f_data, (struct mbuf *)0, uio, (struct mbuf *)0, (struct mbuf *)0, 0)); }
int ncp_sock_send(struct socket *so, struct mbuf *top, struct ncp_rq *rqp) { struct thread *td = curthread; /* XXX */ struct sockaddr *to = 0; struct ncp_conn *conn = rqp->nr_conn; struct mbuf *m; int error, flags=0; for (;;) { m = m_copym(top, 0, M_COPYALL, M_WAIT); /* NCPDDEBUG(m);*/ error = sosend(so, to, 0, m, 0, flags, td); if (error == 0 || error == EINTR || error == ENETDOWN) break; if (rqp->rexmit == 0) break; rqp->rexmit--; pause("ncprsn", conn->li.timeout * hz); error = ncp_chkintr(conn, td); if (error == EINTR) break; } if (error) { log(LOG_INFO, "ncp_send: error %d for server %s", error, conn->li.server); } return error; }
/* * send data by simply allocating an MBUF packet * header and pointing it to our data region. * * Optionally, the caller may supply 'reference' * and 'free' procs. (The latter may call the * user back once the networking stack has * released the buffer). * * The callbacks are provided with the 'closure' * pointer and the 'buflen' argument. */ ssize_t sendto_nocpy ( int s, const void *buf, size_t buflen, int flags, const struct sockaddr *toaddr, int tolen, void *closure, void (*freeproc)(caddr_t, u_int), void (*refproc)(caddr_t, u_int) ) { int error; struct socket *so; struct mbuf *to, *m; int ret = -1; rtems_bsdnet_semaphore_obtain (); if ((so = rtems_bsdnet_fdToSocket (s)) == NULL) { rtems_bsdnet_semaphore_release (); return -1; } error = sockaddrtombuf (&to, toaddr, tolen); if (error) { errno = error; rtems_bsdnet_semaphore_release (); return -1; } MGETHDR(m, M_WAIT, MT_DATA); m->m_pkthdr.len = 0; m->m_pkthdr.rcvif = (struct ifnet *) 0; m->m_flags |= M_EXT; m->m_ext.ext_buf = closure ? closure : (void*)buf; m->m_ext.ext_size = buflen; /* we _must_ supply non-null procs; otherwise, * the kernel code assumes it's a mbuf cluster */ m->m_ext.ext_free = freeproc ? freeproc : dummyproc; m->m_ext.ext_ref = refproc ? refproc : dummyproc; m->m_pkthdr.len += buflen; m->m_len = buflen; m->m_data = (void*)buf; error = sosend (so, to, NULL, m, NULL, flags); if (error) { if (/*auio.uio_resid != len &&*/ (error == EINTR || error == EWOULDBLOCK)) error = 0; } if (error) errno = error; else ret = buflen; if (to) m_freem(to); rtems_bsdnet_semaphore_release (); return (ret); }
static bool_t svc_vc_backchannel_reply(SVCXPRT *xprt, struct rpc_msg *msg, struct sockaddr *addr, struct mbuf *m, uint32_t *seq) { struct ct_data *ct; XDR xdrs; struct mbuf *mrep; bool_t stat = TRUE; int error; /* * Leave space for record mark. */ mrep = m_gethdr(M_WAITOK, MT_DATA); mrep->m_data += sizeof(uint32_t); xdrmbuf_create(&xdrs, mrep, XDR_ENCODE); if (msg->rm_reply.rp_stat == MSG_ACCEPTED && msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { if (!xdr_replymsg(&xdrs, msg)) stat = FALSE; else xdrmbuf_append(&xdrs, m); } else { stat = xdr_replymsg(&xdrs, msg); } if (stat) { m_fixhdr(mrep); /* * Prepend a record marker containing the reply length. */ M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK); *mtod(mrep, uint32_t *) = htonl(0x80000000 | (mrep->m_pkthdr.len - sizeof(uint32_t))); sx_xlock(&xprt->xp_lock); ct = (struct ct_data *)xprt->xp_p2; if (ct != NULL) error = sosend(ct->ct_socket, NULL, NULL, mrep, NULL, 0, curthread); else error = EPIPE; sx_xunlock(&xprt->xp_lock); if (!error) { stat = TRUE; } } else { m_freem(mrep); } XDR_DESTROY(&xdrs); return (stat); }
static bool_t svc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg, struct sockaddr *addr, struct mbuf *m, uint32_t *seq) { XDR xdrs; struct mbuf *mrep; bool_t stat = TRUE; int error, len; /* * Leave space for record mark. */ mrep = m_gethdr(M_WAITOK, MT_DATA); mrep->m_data += sizeof(uint32_t); xdrmbuf_create(&xdrs, mrep, XDR_ENCODE); if (msg->rm_reply.rp_stat == MSG_ACCEPTED && msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { if (!xdr_replymsg(&xdrs, msg)) stat = FALSE; else xdrmbuf_append(&xdrs, m); } else { stat = xdr_replymsg(&xdrs, msg); } if (stat) { m_fixhdr(mrep); /* * Prepend a record marker containing the reply length. */ M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK); len = mrep->m_pkthdr.len; *mtod(mrep, uint32_t *) = htonl(0x80000000 | (len - sizeof(uint32_t))); atomic_add_32(&xprt->xp_snd_cnt, len); error = sosend(xprt->xp_socket, NULL, NULL, mrep, NULL, 0, curthread); if (!error) { atomic_add_rel_32(&xprt->xp_snt_cnt, len); if (seq) *seq = xprt->xp_snd_cnt; stat = TRUE; } else atomic_subtract_32(&xprt->xp_snd_cnt, len); } else { m_freem(mrep); } XDR_DESTROY(&xdrs); return (stat); }
static int kttcp_send(struct thread *td, struct kttcp_io_args *kio) { struct file *fp; int error; struct timeval t0, t1; unsigned long long len = 0; struct uio auio; struct iovec aiov; bzero(&aiov, sizeof(aiov)); bzero(&auio, sizeof(auio)); auio.uio_iov = &aiov; auio.uio_segflg = UIO_NOCOPY; error = fget(td, kio->kio_socket, &fp); if (error != 0) return error; if ((fp->f_flag & FWRITE) == 0) { fdrop(fp, td); return EBADF; } if (fp->f_type == DTYPE_SOCKET) { len = kio->kio_totalsize; microtime(&t0); do { nbyte = MIN(len, (unsigned long long)nbyte); aiov.iov_len = nbyte; auio.uio_resid = nbyte; auio.uio_offset = 0; error = sosend((struct socket *)fp->f_data, NULL, &auio, NULL, NULL, 0, td); len -= auio.uio_offset; } while (error == 0 && len != 0); microtime(&t1); } else error = EFTYPE; fdrop(fp, td); if (error != 0) return error; timersub(&t1, &t0, &kio->kio_elapsed); kio->kio_bytesdone = kio->kio_totalsize - len; return 0; }
/* * Vnode op for write */ int fifo_write(struct vnop_write_args *ap) { struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock; int error; #if DIAGNOSTIC if (ap->a_uio->uio_rw != UIO_WRITE) panic("fifo_write mode"); #endif error = sosend(wso, (struct sockaddr *)0, ap->a_uio, NULL, (struct mbuf *)0, (ap->a_ioflag & IO_NDELAY) ? MSG_NBIO : 0); if (error == 0) lock_vnode_and_post(ap->a_vp, 0); return (error); }
int osi_NetSend(osi_socket asocket, struct sockaddr_in *addr, struct iovec *dvec, int nvecs, afs_int32 alength, int istack) { int i, code; struct iovec iov[RX_MAXIOVECS]; struct uio u; struct mbuf *nam; int haveGlock = ISAFS_GLOCK(); memset(&u, 0, sizeof(u)); memset(&iov, 0, sizeof(iov)); AFS_STATCNT(osi_NetSend); if (nvecs > RX_MAXIOVECS) osi_Panic("osi_NetSend: %d: Too many iovecs.\n", nvecs); for (i = 0; i < nvecs; i++) iov[i] = dvec[i]; u.uio_iov = &iov[0]; u.uio_iovcnt = nvecs; u.uio_offset = 0; u.uio_resid = alength; u.uio_segflg = UIO_SYSSPACE; u.uio_rw = UIO_WRITE; u.uio_procp = NULL; nam = m_get(M_DONTWAIT, MT_SONAME); if (!nam) return ENOBUFS; nam->m_len = addr->sin_len = sizeof(struct sockaddr_in); memcpy(mtod(nam, caddr_t), addr, addr->sin_len); if (haveGlock) AFS_GUNLOCK(); code = sosend(asocket, nam, &u, NULL, NULL, 0); if (haveGlock) AFS_GLOCK(); m_freem(nam); return code; }
static int soo_write(struct file *fp, struct uio *uio, struct ucred *active_cred, int flags, struct thread *td) { struct socket *so = fp->f_data; int error; #ifdef MAC error = mac_socket_check_send(active_cred, so); if (error) return (error); #endif error = sosend(so, 0, uio, 0, 0, 0, uio->uio_td); if (error == EPIPE && (so->so_options & SO_NOSIGPIPE) == 0) { PROC_LOCK(uio->uio_td->td_proc); tdsignal(uio->uio_td, SIGPIPE); PROC_UNLOCK(uio->uio_td->td_proc); } return (error); }
/* ARGSUSED */ int fifo_write(void *v) { struct vop_write_args *ap = v; struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock; struct proc *p = ap->a_uio->uio_procp; int error; #ifdef DIAGNOSTIC if (ap->a_uio->uio_rw != UIO_WRITE) panic("fifo_write mode"); #endif if (ap->a_ioflag & IO_NDELAY) wso->so_state |= SS_NBIO; VOP_UNLOCK(ap->a_vp, 0, p); error = sosend(wso, NULL, ap->a_uio, NULL, NULL, 0); vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p); if (ap->a_ioflag & IO_NDELAY) wso->so_state &= ~SS_NBIO; return (error); }
static bool_t svc_dg_reply(SVCXPRT *xprt, struct rpc_msg *msg, struct sockaddr *addr, struct mbuf *m) { XDR xdrs; struct mbuf *mrep; bool_t stat = TRUE; int error; MGETHDR(mrep, M_WAIT, MT_DATA); mrep->m_len = 0; xdrmbuf_create(&xdrs, mrep, XDR_ENCODE); if (msg->rm_reply.rp_stat == MSG_ACCEPTED && msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { if (!xdr_replymsg(&xdrs, msg)) stat = FALSE; else xdrmbuf_append(&xdrs, m); } else { stat = xdr_replymsg(&xdrs, msg); } if (stat) { m_fixhdr(mrep); error = sosend(xprt->xp_socket, addr, NULL, mrep, NULL, 0, curthread); if (!error) { stat = TRUE; } } else { m_freem(mrep); } XDR_DESTROY(&xdrs); xprt->xp_p2 = NULL; return (stat); }
int bootpc_call( struct bootp_packet *call, struct bootp_packet *reply, /* output */ struct proc *procp) { struct socket *so; struct sockaddr_in *sin; struct mbuf *m, *nam; struct uio auio; struct iovec aio; int error, rcvflg, timo, secs, len; /* Free at end if not null. */ nam = NULL; /* * Create socket and set its recieve timeout. */ if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0,procp))) goto out; m = m_get(M_WAIT, MT_SOOPTS); if (m == NULL) { error = ENOBUFS; goto out; } else { struct timeval *tv; tv = mtod(m, struct timeval *); m->m_len = sizeof(*tv); tv->tv_sec = 1; tv->tv_usec = 0; if ((error = sosetopt(so, SOL_SOCKET, SO_RCVTIMEO, m))) goto out; } /* * Enable broadcast. */ { int *on; m = m_get(M_WAIT, MT_SOOPTS); if (m == NULL) { error = ENOBUFS; goto out; } on = mtod(m, int *); m->m_len = sizeof(*on); *on = 1; if ((error = sosetopt(so, SOL_SOCKET, SO_BROADCAST, m))) goto out; } /* * Bind the local endpoint to a bootp client port. */ m = m_getclr(M_WAIT, MT_SONAME); sin = mtod(m, struct sockaddr_in *); sin->sin_len = m->m_len = sizeof(*sin); sin->sin_family = AF_INET; sin->sin_addr.s_addr = INADDR_ANY; sin->sin_port = htons(IPPORT_BOOTPC); error = sobind(so, m); m_freem(m); if (error) { printf("bind failed\n"); goto out; } /* * Setup socket address for the server. */ nam = m_get(M_WAIT, MT_SONAME); if (nam == NULL) { error = ENOBUFS; goto out; } sin = mtod(nam, struct sockaddr_in *); sin-> sin_len = sizeof(*sin); sin-> sin_family = AF_INET; sin->sin_addr.s_addr = INADDR_BROADCAST; sin->sin_port = htons(IPPORT_BOOTPS); nam->m_len = sizeof(*sin); /* * Send it, repeatedly, until a reply is received, * but delay each re-send by an increasing amount. * If the delay hits the maximum, start complaining. */ for (timo=1; timo <= MAX_RESEND_DELAY; timo++) { /* Send BOOTP request (or re-send). */ aio.iov_base = (caddr_t) call; aio.iov_len = sizeof(*call); auio.uio_iov = &aio; auio.uio_iovcnt = 1; auio.uio_segflg = UIO_SYSSPACE; auio.uio_rw = UIO_WRITE; auio.uio_offset = 0; auio.uio_resid = sizeof(*call); auio.uio_procp = procp; error = sosend(so, nam, &auio, NULL, NULL, 0); if (error) { printf("bootpc_call: sosend: %d\n", error); switch (error) { case ENOBUFS: /* No buffer space available */ case ENETUNREACH: /* Network is unreachable */ case ENETDOWN: /* Network interface is not configured */ case EHOSTDOWN: /* Host is down */ case EHOSTUNREACH: /* Host is unreachable */ case EMSGSIZE: /* Message too long */ /* This is a possibly transient error. We can still receive replies from previous attempts. */ break; default: goto out; } } /* * Wait for up to timo seconds for a reply. * The socket receive timeout was set to 1 second. */ secs = timo; while (secs > 0) { aio.iov_base = (caddr_t) reply; aio.iov_len = sizeof(*reply); auio.uio_iov = &aio; auio.uio_iovcnt = 1; auio.uio_segflg = UIO_SYSSPACE; auio.uio_rw = UIO_READ; auio.uio_offset = 0; auio.uio_resid = sizeof(*reply); auio.uio_procp = procp; rcvflg = 0; error = soreceive(so, NULL, &auio, NULL, NULL, &rcvflg); if (error == EWOULDBLOCK) { secs--; call->secs=htons(ntohs(call->secs)+1); continue; } if (error) goto out; len = sizeof(*reply) - auio.uio_resid; /* Do we have the required number of bytes ? */ if (len < BOOTP_MIN_LEN) continue; /* Is it the right reply? */ if (reply->op != 2) continue; if (reply->xid != call->xid) continue; if (reply->hlen != call->hlen) continue; if (bcmp(reply->chaddr,call->chaddr,call->hlen)) continue; goto gotreply; /* break two levels */ } /* while secs */ } /* send/receive a number of times then return an error */ { uint32_t addr = ntohl(sin->sin_addr.s_addr); printf("BOOTP timeout for server %"PRIu32".%"PRIu32".%"PRIu32".%"PRIu32"\n", (addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff); } error = ETIMEDOUT; goto out; gotreply: out: if (nam) m_freem(nam); soclose(so); return error; }
static void soaio_process_job(struct socket *so, struct sockbuf *sb, struct kaiocb *job) { struct ucred *td_savedcred; struct thread *td; struct file *fp; struct uio uio; struct iovec iov; size_t cnt; int error, flags; SOCKBUF_UNLOCK(sb); aio_switch_vmspace(job); td = curthread; fp = job->fd_file; retry: td_savedcred = td->td_ucred; td->td_ucred = job->cred; cnt = job->uaiocb.aio_nbytes; iov.iov_base = (void *)(uintptr_t)job->uaiocb.aio_buf; iov.iov_len = cnt; uio.uio_iov = &iov; uio.uio_iovcnt = 1; uio.uio_offset = 0; uio.uio_resid = cnt; uio.uio_segflg = UIO_USERSPACE; uio.uio_td = td; flags = MSG_NBIO; /* TODO: Charge ru_msg* to job. */ if (sb == &so->so_rcv) { uio.uio_rw = UIO_READ; #ifdef MAC error = mac_socket_check_receive(fp->f_cred, so); if (error == 0) #endif error = soreceive(so, NULL, &uio, NULL, NULL, &flags); } else { uio.uio_rw = UIO_WRITE; #ifdef MAC error = mac_socket_check_send(fp->f_cred, so); if (error == 0) #endif error = sosend(so, NULL, &uio, NULL, NULL, flags, td); if (error == EPIPE && (so->so_options & SO_NOSIGPIPE) == 0) { PROC_LOCK(job->userproc); kern_psignal(job->userproc, SIGPIPE); PROC_UNLOCK(job->userproc); } } cnt -= uio.uio_resid; td->td_ucred = td_savedcred; /* XXX: Not sure if this is needed? */ if (cnt != 0 && (error == ERESTART || error == EINTR || error == EWOULDBLOCK)) error = 0; if (error == EWOULDBLOCK) { /* * A read() or write() on the socket raced with this * request. If the socket is now ready, try again. * If it is not, place this request at the head of the * queue to try again when the socket is ready. */ SOCKBUF_LOCK(sb); empty_results++; if (soaio_ready(so, sb)) { empty_retries++; SOCKBUF_UNLOCK(sb); goto retry; } if (!aio_set_cancel_function(job, soo_aio_cancel)) { MPASS(cnt == 0); SOCKBUF_UNLOCK(sb); aio_cancel(job); SOCKBUF_LOCK(sb); } else { TAILQ_INSERT_HEAD(&sb->sb_aiojobq, job, list); } } else { aio_complete(job, cnt, error); SOCKBUF_LOCK(sb); } }
static void soaio_process_job(struct socket *so, struct sockbuf *sb, struct kaiocb *job) { struct ucred *td_savedcred; struct thread *td; struct file *fp; struct uio uio; struct iovec iov; size_t cnt, done; long ru_before; int error, flags; SOCKBUF_UNLOCK(sb); aio_switch_vmspace(job); td = curthread; fp = job->fd_file; retry: td_savedcred = td->td_ucred; td->td_ucred = job->cred; done = job->aio_done; cnt = job->uaiocb.aio_nbytes - done; iov.iov_base = (void *)((uintptr_t)job->uaiocb.aio_buf + done); iov.iov_len = cnt; uio.uio_iov = &iov; uio.uio_iovcnt = 1; uio.uio_offset = 0; uio.uio_resid = cnt; uio.uio_segflg = UIO_USERSPACE; uio.uio_td = td; flags = MSG_NBIO; /* * For resource usage accounting, only count a completed request * as a single message to avoid counting multiple calls to * sosend/soreceive on a blocking socket. */ if (sb == &so->so_rcv) { uio.uio_rw = UIO_READ; ru_before = td->td_ru.ru_msgrcv; #ifdef MAC error = mac_socket_check_receive(fp->f_cred, so); if (error == 0) #endif error = soreceive(so, NULL, &uio, NULL, NULL, &flags); if (td->td_ru.ru_msgrcv != ru_before) job->msgrcv = 1; } else { uio.uio_rw = UIO_WRITE; ru_before = td->td_ru.ru_msgsnd; #ifdef MAC error = mac_socket_check_send(fp->f_cred, so); if (error == 0) #endif error = sosend(so, NULL, &uio, NULL, NULL, flags, td); if (td->td_ru.ru_msgsnd != ru_before) job->msgsnd = 1; if (error == EPIPE && (so->so_options & SO_NOSIGPIPE) == 0) { PROC_LOCK(job->userproc); kern_psignal(job->userproc, SIGPIPE); PROC_UNLOCK(job->userproc); } } done += cnt - uio.uio_resid; job->aio_done = done; td->td_ucred = td_savedcred; if (error == EWOULDBLOCK) { /* * The request was either partially completed or not * completed at all due to racing with a read() or * write() on the socket. If the socket is * non-blocking, return with any partial completion. * If the socket is blocking or if no progress has * been made, requeue this request at the head of the * queue to try again when the socket is ready. */ MPASS(done != job->uaiocb.aio_nbytes); SOCKBUF_LOCK(sb); if (done == 0 || !(so->so_state & SS_NBIO)) { empty_results++; if (soaio_ready(so, sb)) { empty_retries++; SOCKBUF_UNLOCK(sb); goto retry; } if (!aio_set_cancel_function(job, soo_aio_cancel)) { SOCKBUF_UNLOCK(sb); if (done != 0) aio_complete(job, done, 0); else aio_cancel(job); SOCKBUF_LOCK(sb); } else { TAILQ_INSERT_HEAD(&sb->sb_aiojobq, job, list); } return; } SOCKBUF_UNLOCK(sb); } if (done != 0 && (error == ERESTART || error == EINTR || error == EWOULDBLOCK)) error = 0; if (error) aio_complete(job, -1, error); else aio_complete(job, done, 0); SOCKBUF_LOCK(sb); }
int osi_NetSend(osi_socket so, struct sockaddr_in *addr, struct iovec *dvec, int nvecs, afs_int32 alength, int istack) { #ifdef AFS_DARWIN80_ENV socket_t asocket = (socket_t)so; struct msghdr msg; size_t slen; #else struct socket *asocket = (struct socket *)so; struct uio u; #endif afs_int32 code; int i; struct iovec iov[RX_MAXIOVECS]; int haveGlock = ISAFS_GLOCK(); AFS_STATCNT(osi_NetSend); if (nvecs > RX_MAXIOVECS) osi_Panic("osi_NetSend: %d: Too many iovecs.\n", nvecs); for (i = 0; i < nvecs; i++) iov[i] = dvec[i]; addr->sin_len = sizeof(struct sockaddr_in); if ((afs_termState == AFSOP_STOP_RXK_LISTENER) || (afs_termState == AFSOP_STOP_COMPLETE)) return -1; if (haveGlock) AFS_GUNLOCK(); #if defined(KERNEL_FUNNEL) thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); #endif #ifdef AFS_DARWIN80_ENV memset(&msg, 0, sizeof(struct msghdr)); msg.msg_name = addr; msg.msg_namelen = ((struct sockaddr *)addr)->sa_len; msg.msg_iov = &iov[0]; msg.msg_iovlen = nvecs; code = sock_send(asocket, &msg, 0, &slen); #else u.uio_iov = &iov[0]; u.uio_iovcnt = nvecs; u.uio_offset = 0; u.uio_resid = alength; u.uio_segflg = UIO_SYSSPACE; u.uio_rw = UIO_WRITE; u.uio_procp = NULL; code = sosend(asocket, (struct sockaddr *)addr, &u, NULL, NULL, 0); #endif #if defined(KERNEL_FUNNEL) thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); #endif if (haveGlock) AFS_GLOCK(); return code; }
static int bootpc_call(struct bootpc_globalcontext *gctx, struct thread *td) { struct socket *so; struct sockaddr_in *sin, dst; struct uio auio; struct sockopt sopt; struct iovec aio; int error, on, rcvflg, timo, len; time_t atimo; time_t rtimo; struct timeval tv; struct bootpc_ifcontext *ifctx; int outstanding; int gotrootpath; int retry; const char *s; /* * Create socket and set its recieve timeout. */ error = socreate(AF_INET, &so, SOCK_DGRAM, 0, td->td_ucred, td); if (error != 0) goto out0; tv.tv_sec = 1; tv.tv_usec = 0; bzero(&sopt, sizeof(sopt)); sopt.sopt_dir = SOPT_SET; sopt.sopt_level = SOL_SOCKET; sopt.sopt_name = SO_RCVTIMEO; sopt.sopt_val = &tv; sopt.sopt_valsize = sizeof tv; error = sosetopt(so, &sopt); if (error != 0) goto out; /* * Enable broadcast. */ on = 1; sopt.sopt_name = SO_BROADCAST; sopt.sopt_val = &on; sopt.sopt_valsize = sizeof on; error = sosetopt(so, &sopt); if (error != 0) goto out; /* * Disable routing. */ on = 1; sopt.sopt_name = SO_DONTROUTE; sopt.sopt_val = &on; sopt.sopt_valsize = sizeof on; error = sosetopt(so, &sopt); if (error != 0) goto out; /* * Bind the local endpoint to a bootp client port. */ sin = &dst; clear_sinaddr(sin); sin->sin_port = htons(IPPORT_BOOTPC); error = sobind(so, (struct sockaddr *)sin, td); if (error != 0) { printf("bind failed\n"); goto out; } /* * Setup socket address for the server. */ sin = &dst; clear_sinaddr(sin); sin->sin_addr.s_addr = INADDR_BROADCAST; sin->sin_port = htons(IPPORT_BOOTPS); /* * Send it, repeatedly, until a reply is received, * but delay each re-send by an increasing amount. * If the delay hits the maximum, start complaining. */ timo = 0; rtimo = 0; for (;;) { outstanding = 0; gotrootpath = 0; for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) { if (bootpc_ifctx_isresolved(ifctx) != 0 && bootpc_tag(&gctx->tmptag, &ifctx->reply, ifctx->replylen, TAG_ROOT) != NULL) gotrootpath = 1; } for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) { ifctx->outstanding = 0; if (bootpc_ifctx_isresolved(ifctx) != 0 && gotrootpath != 0) { continue; } if (bootpc_ifctx_isfailed(ifctx) != 0) continue; outstanding++; ifctx->outstanding = 1; /* Proceed to next step in DHCP negotiation */ if ((ifctx->state == IF_DHCP_OFFERED && ifctx->dhcpquerytype != DHCP_REQUEST) || (ifctx->state == IF_DHCP_UNRESOLVED && ifctx->dhcpquerytype != DHCP_DISCOVER) || (ifctx->state == IF_BOOTP_UNRESOLVED && ifctx->dhcpquerytype != DHCP_NOMSG)) { ifctx->sentmsg = 0; bootpc_compose_query(ifctx, gctx, td); } /* Send BOOTP request (or re-send). */ if (ifctx->sentmsg == 0) { switch(ifctx->dhcpquerytype) { case DHCP_DISCOVER: s = "DHCP Discover"; break; case DHCP_REQUEST: s = "DHCP Request"; break; case DHCP_NOMSG: default: s = "BOOTP Query"; break; } printf("Sending %s packet from " "interface %s (%*D)\n", s, ifctx->ireq.ifr_name, ifctx->sdl->sdl_alen, (unsigned char *) LLADDR(ifctx->sdl), ":"); ifctx->sentmsg = 1; } aio.iov_base = (caddr_t) &ifctx->call; aio.iov_len = sizeof(ifctx->call); auio.uio_iov = &aio; auio.uio_iovcnt = 1; auio.uio_segflg = UIO_SYSSPACE; auio.uio_rw = UIO_WRITE; auio.uio_offset = 0; auio.uio_resid = sizeof(ifctx->call); auio.uio_td = td; /* Set netmask to 0.0.0.0 */ sin = (struct sockaddr_in *) &ifctx->ireq.ifr_addr; clear_sinaddr(sin); error = ifioctl(ifctx->so, SIOCSIFNETMASK, (caddr_t) &ifctx->ireq, td); if (error != 0) panic("bootpc_call:" "set if netmask, error=%d", error); error = sosend(so, (struct sockaddr *) &dst, &auio, NULL, NULL, 0, td); if (error != 0) { printf("bootpc_call: sosend: %d state %08x\n", error, (int) so->so_state); } /* XXX: Is this needed ? */ pause("bootpw", hz/10); /* Set netmask to 255.0.0.0 */ sin = (struct sockaddr_in *) &ifctx->ireq.ifr_addr; clear_sinaddr(sin); sin->sin_addr.s_addr = htonl(0xff000000u); error = ifioctl(ifctx->so, SIOCSIFNETMASK, (caddr_t) &ifctx->ireq, td); if (error != 0) panic("bootpc_call:" "set if netmask, error=%d", error); } if (outstanding == 0 && (rtimo == 0 || time_second >= rtimo)) { error = 0; goto gotreply; } /* Determine new timeout. */ if (timo < MAX_RESEND_DELAY) timo++; else { printf("DHCP/BOOTP timeout for server "); print_sin_addr(&dst); printf("\n"); } /* * Wait for up to timo seconds for a reply. * The socket receive timeout was set to 1 second. */ atimo = timo + time_second; while (time_second < atimo) { aio.iov_base = (caddr_t) &gctx->reply; aio.iov_len = sizeof(gctx->reply); auio.uio_iov = &aio; auio.uio_iovcnt = 1; auio.uio_segflg = UIO_SYSSPACE; auio.uio_rw = UIO_READ; auio.uio_offset = 0; auio.uio_resid = sizeof(gctx->reply); auio.uio_td = td; rcvflg = 0; error = soreceive(so, NULL, &auio, NULL, NULL, &rcvflg); gctx->secs = time_second - gctx->starttime; for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) { if (bootpc_ifctx_isresolved(ifctx) != 0 || bootpc_ifctx_isfailed(ifctx) != 0) continue; ifctx->call.secs = htons(gctx->secs); } if (error == EWOULDBLOCK) continue; if (error != 0) goto out; len = sizeof(gctx->reply) - auio.uio_resid; /* Do we have the required number of bytes ? */ if (len < BOOTP_MIN_LEN) continue; gctx->replylen = len; /* Is it a reply? */ if (gctx->reply.op != BOOTP_REPLY) continue; /* Is this an answer to our query */ for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) { if (gctx->reply.xid != ifctx->call.xid) continue; /* Same HW address size ? */ if (gctx->reply.hlen != ifctx->call.hlen) continue; /* Correct HW address ? */ if (bcmp(gctx->reply.chaddr, ifctx->call.chaddr, ifctx->call.hlen) != 0) continue; break; } if (ifctx != NULL) { s = bootpc_tag(&gctx->tmptag, &gctx->reply, gctx->replylen, TAG_DHCP_MSGTYPE); if (s != NULL) { switch (*s) { case DHCP_OFFER: s = "DHCP Offer"; break; case DHCP_ACK: s = "DHCP Ack"; break; default: s = "DHCP (unexpected)"; break; } } else s = "BOOTP Reply"; printf("Received %s packet" " on %s from ", s, ifctx->ireq.ifr_name); print_in_addr(gctx->reply.siaddr); if (gctx->reply.giaddr.s_addr != htonl(INADDR_ANY)) { printf(" via "); print_in_addr(gctx->reply.giaddr); } if (bootpc_received(gctx, ifctx) != 0) { printf(" (accepted)"); if (ifctx->outstanding) { ifctx->outstanding = 0; outstanding--; } /* Network settle delay */ if (outstanding == 0) atimo = time_second + BOOTP_SETTLE_DELAY; } else printf(" (ignored)"); if (ifctx->gotrootpath) { gotrootpath = 1; rtimo = time_second + BOOTP_SETTLE_DELAY; printf(" (got root path)"); } else printf(" (no root path)"); printf("\n"); } } /* while secs */ #ifdef BOOTP_TIMEOUT if (gctx->secs > BOOTP_TIMEOUT && BOOTP_TIMEOUT > 0) break; #endif /* Force a retry if halfway in DHCP negotiation */ retry = 0; for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) { if (ifctx->state == IF_DHCP_OFFERED) { if (ifctx->dhcpquerytype == DHCP_DISCOVER) retry = 1; else ifctx->state = IF_DHCP_UNRESOLVED; } } if (retry != 0) continue; if (gotrootpath != 0) { gctx->gotrootpath = gotrootpath; if (rtimo != 0 && time_second >= rtimo) break; } } /* forever send/receive */ /* * XXX: These are errors of varying seriousness being silently * ignored */ for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) { if (bootpc_ifctx_isresolved(ifctx) == 0) { printf("%s timeout for interface %s\n", ifctx->dhcpquerytype != DHCP_NOMSG ? "DHCP" : "BOOTP", ifctx->ireq.ifr_name); } } if (gctx->gotrootpath != 0) { #if 0 printf("Got a root path, ignoring remaining timeout\n"); #endif error = 0; goto out; } #ifndef BOOTP_NFSROOT for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) { if (bootpc_ifctx_isresolved(ifctx) != 0) { error = 0; goto out; } } #endif error = ETIMEDOUT; goto out; gotreply: out: soclose(so); out0: return error; }
static int bsd_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio) { return (sosend((struct socket *)fp->f_data, (struct sockaddr *)0, uio, (struct mbuf *)0, (struct mbuf *)0, 0, 0)); }
int t_send(long s, char * buf, int len, int flags) { struct socket * so; int e; /* error holder */ int total_sent = 0; int maxpkt; int sendlen; int sent; so = LONG2SO(s); #ifdef SOC_CHECK_ALWAYS SOC_CHECK(so); #endif if ((so->so_state & SO_IO_OK) != SS_ISCONNECTED) { so->so_error = EPIPE; return SOCKET_ERROR; } so->so_error = 0; /* If this is not a stream socket, assume it is bound and pass to * t_sendto() with a null sockaddr */ if (so->so_type != SOCK_STREAM) return(t_sendto(s, buf, len, flags, NULL, 0)); maxpkt = TCP_MSS; if(so->so_pcb) { struct tcpcb * tp; tp = intotcpcb(so->so_pcb); /* get tcp structure with mss */ if(tp->t_maxseg) /* Make sure it's set */ maxpkt = tp->t_maxseg; } IN_PROFILER(PF_TCP, PF_ENTRY); /* measure time in TCP */ while (len) { if (len > maxpkt) sendlen = maxpkt; /* take biggest block we can */ else sendlen = len; sent = sendlen; LOCK_NET_RESOURCE(NET_RESID); e = sosend (so, NULL, buf, &sendlen, flags); UNLOCK_NET_RESOURCE(NET_RESID); if (e != 0) /* sock_sendit failed? */ { /* if we simply ran out of bufs, report back to caller. */ if ((e == ENOBUFS) || (e == EWOULDBLOCK)) { /* if we actually sent something before running out * of buffers, report what we sent; * else, report the error and let the application * retry the call later */ if (total_sent != 0) { so->so_error = 0; break; /* break out of while(len) loop */ } } so->so_error = e; return SOCKET_ERROR; } /* if we can't send anymore, return now */ if (sendlen != 0) break; /* break out of while(len) loop */ /* adjust numbers & pointers, and go do next send loop */ sent -= sendlen; /* subtract anything that didn't get sent */ buf += sent; len -= sent; total_sent += sent; } IN_PROFILER(PF_TCP, PF_EXIT); /* measure time in TCP */ return total_sent; }
int t_sendto (long s, char * buf, int len, int flags, struct sockaddr * to, int tolen) { struct socket * so; int sendlen; int err; struct mbuf * name; so = LONG2SO(s); SOC_CHECK(so); so->so_error = 0; switch (so->so_type) { case SOCK_STREAM: /* this is a stream socket, so pass this request through * t_send() for its large-send support. */ return t_send(s, buf, len, flags); /*NOTREACHED*/ case SOCK_DGRAM: /* datagram (UDP) socket -- prepare to check length */ sendlen = udp_maxalloc(); break; #ifdef IP_RAW case SOCK_RAW: /* raw socket -- prepare to check length */ sendlen = ip_raw_maxalloc(so->so_options & SO_HDRINCL); break; #endif /* IP_RAW */ default: /* socket has unknown type */ dtrap(); so->so_error = EFAULT; return SOCKET_ERROR; /*NOTREACHED*/ } /* fall through for non-stream sockets: SOCK_DGRAM (UDP) and * SOCK_RAW (raw IP) */ /* check length against underlying stack's maximum */ if (len > sendlen) { so->so_error = EMSGSIZE; return SOCKET_ERROR; } /* if a sockaddr was passed, wrap it in an mbuf and pas it into the * bowels of the BSD code; else assume this is a bound UDP socket * and this call came from t_send() below. */ if (to) /* sockaddr was passed */ { name = sockargs(to, tolen, MT_SONAME); if(name == NULL) { so->so_error = ENOMEM; return SOCKET_ERROR; } } else /* hope user called bind() first... */ name = NULL; sendlen = len; LOCK_NET_RESOURCE(NET_RESID); err = sosend (so, name, buf, &sendlen, flags); if (name) m_freem(name); UNLOCK_NET_RESOURCE(NET_RESID); if (err != 0) { so->so_error = err; return SOCKET_ERROR; } return (len - sendlen); }
int sendit(struct proc *p, int s, struct msghdr *mp, int flags, register_t *retsize) { struct file *fp; struct uio auio; struct iovec *iov; int i; struct mbuf *to, *control; size_t len; int error; #ifdef KTRACE struct iovec *ktriov = NULL; #endif to = NULL; if ((error = getsock(p->p_fd, s, &fp)) != 0) return (error); auio.uio_iov = mp->msg_iov; auio.uio_iovcnt = mp->msg_iovlen; auio.uio_segflg = UIO_USERSPACE; auio.uio_rw = UIO_WRITE; auio.uio_procp = p; auio.uio_offset = 0; /* XXX */ auio.uio_resid = 0; iov = mp->msg_iov; for (i = 0; i < mp->msg_iovlen; i++, iov++) { /* Don't allow sum > SSIZE_MAX */ if (iov->iov_len > SSIZE_MAX || (auio.uio_resid += iov->iov_len) > SSIZE_MAX) { error = EINVAL; goto bad; } } if (mp->msg_name) { error = sockargs(&to, mp->msg_name, mp->msg_namelen, MT_SONAME); if (error) goto bad; #ifdef KTRACE if (KTRPOINT(p, KTR_STRUCT)) ktrsockaddr(p, mtod(to, caddr_t), mp->msg_namelen); #endif } if (mp->msg_control) { if (mp->msg_controllen < CMSG_ALIGN(sizeof(struct cmsghdr))) { error = EINVAL; goto bad; } error = sockargs(&control, mp->msg_control, mp->msg_controllen, MT_CONTROL); if (error) goto bad; } else control = 0; #ifdef KTRACE if (KTRPOINT(p, KTR_GENIO)) { int iovlen = auio.uio_iovcnt * sizeof (struct iovec); ktriov = malloc(iovlen, M_TEMP, M_WAITOK); bcopy(auio.uio_iov, ktriov, iovlen); } #endif len = auio.uio_resid; error = sosend(fp->f_data, to, &auio, NULL, control, flags); if (error) { if (auio.uio_resid != len && (error == ERESTART || error == EINTR || error == EWOULDBLOCK)) error = 0; if (error == EPIPE && (flags & MSG_NOSIGNAL) == 0) ptsignal(p, SIGPIPE, STHREAD); } if (error == 0) { *retsize = len - auio.uio_resid; fp->f_wxfer++; fp->f_wbytes += *retsize; } #ifdef KTRACE if (ktriov != NULL) { if (error == 0) ktrgenio(p, s, UIO_WRITE, ktriov, *retsize); free(ktriov, M_TEMP); } #endif bad: FRELE(fp, p); if (to) m_freem(to); return (error); }
int isc_sendPDU(isc_session_t *sp, pduq_t *pq) { struct mbuf *mh, **mp; pdu_t *pp = &pq->pdu; int len, error; debug_called(8); /* | mbuf for the iSCSI header */ MGETHDR(mh, MB_TRYWAIT, MT_DATA); mh->m_len = mh->m_pkthdr.len = sizeof(union ipdu_u); mh->m_pkthdr.rcvif = NULL; MH_ALIGN(mh, sizeof(union ipdu_u)); bcopy(&pp->ipdu, mh->m_data, sizeof(union ipdu_u)); mh->m_next = NULL; if(sp->hdrDigest) pq->pdu.hdr_dig = sp->hdrDigest(&pp->ipdu, sizeof(union ipdu_u), 0); if(pp->ahs_len) { /* | Add any AHS to the iSCSI hdr mbuf | XXX Assert: (mh->m_pkthdr.len + pp->ahs_len) < MHLEN */ bcopy(pp->ahs, (mh->m_data + mh->m_len), pp->ahs_len); mh->m_len += pp->ahs_len; mh->m_pkthdr.len += pp->ahs_len; if(sp->hdrDigest) pq->pdu.hdr_dig = sp->hdrDigest(&pp->ahs, pp->ahs_len, pq->pdu.hdr_dig); } if(sp->hdrDigest) { debug(2, "hdr_dig=%x", pq->pdu.hdr_dig); /* | Add header digest to the iSCSI hdr mbuf | XXX Assert: (mh->m_pkthdr.len + 4) < MHLEN */ bcopy(&pp->hdr_dig, (mh->m_data + mh->m_len), sizeof(int)); mh->m_len += sizeof(int); mh->m_pkthdr.len += sizeof(int); } mp = &mh->m_next; if(pq->pdu.ds) { struct mbuf *md; int off = 0; len = pp->ds_len; while(len & 03) // the specs say it must be int alligned len++; while(len > 0) { int l; MGET(md, MB_TRYWAIT, MT_DATA); pq->refcnt++; l = min(MCLBYTES, len); debug(5, "setting ext_free(arg=%p len/l=%d/%d)", pq->buf, len, l); md->m_ext.ext_buf = pq->buf; md->m_ext.ext_free = ext_free; md->m_ext.ext_ref = ext_ref; md->m_ext.ext_arg = pq; md->m_ext.ext_size = l; md->m_flags |= M_EXT; md->m_data = pp->ds + off; md->m_len = l; md->m_next = NULL; mh->m_pkthdr.len += l; *mp = md; mp = &md->m_next; len -= l; off += l; } } if(sp->dataDigest) { struct mbuf *me; pp->ds_dig = sp->dataDigest(pp->ds, pp->ds_len, 0); MGET(me, MB_TRYWAIT, MT_DATA); me->m_len = sizeof(int); MH_ALIGN(mh, sizeof(int)); bcopy(&pp->ds_dig, me->m_data, sizeof(int)); me->m_next = NULL; mh->m_pkthdr.len += sizeof(int); *mp = me; } if((error = sosend(sp->soc, NULL, NULL, mh, 0, 0, curthread)) != 0) { sdebug(3, "error=%d", error); return error; } sp->stats.nsent++; getmicrouptime(&sp->stats.t_sent); return 0; }
/* * XXX Liang: timeout for write is not supported yet. */ int libcfs_sock_write (struct socket *sock, void *buffer, int nob, int timeout) { int rc; CFS_DECL_NET_DATA; while (nob > 0) { struct iovec iov = { .iov_base = buffer, .iov_len = nob }; struct uio suio = { .uio_iov = &iov, .uio_iovcnt = 1, .uio_offset = 0, .uio_resid = nob, .uio_segflg = UIO_SYSSPACE, .uio_rw = UIO_WRITE, .uio_procp = NULL }; CFS_NET_IN; rc = sosend(sock, NULL, &suio, (struct mbuf *)0, (struct mbuf *)0, 0); CFS_NET_EX; if (rc != 0) { if ( suio.uio_resid != nob && ( rc == ERESTART || rc == EINTR ||\ rc == EWOULDBLOCK)) rc = 0; if ( rc != 0 ) return -rc; rc = nob - suio.uio_resid; buffer = ((char *)buffer) + rc; nob = suio.uio_resid; continue; } break; } return (0); } /* * XXX Liang: timeout for read is not supported yet. */ int libcfs_sock_read (struct socket *sock, void *buffer, int nob, int timeout) { int rc; CFS_DECL_NET_DATA; while (nob > 0) { struct iovec iov = { .iov_base = buffer, .iov_len = nob }; struct uio ruio = { .uio_iov = &iov, .uio_iovcnt = 1, .uio_offset = 0, .uio_resid = nob, .uio_segflg = UIO_SYSSPACE, .uio_rw = UIO_READ, .uio_procp = NULL }; CFS_NET_IN; rc = soreceive(sock, (struct sockaddr **)0, &ruio, (struct mbuf **)0, (struct mbuf **)0, (int *)0); CFS_NET_EX; if (rc != 0) { if ( ruio.uio_resid != nob && ( rc == ERESTART || rc == EINTR ||\ rc == EWOULDBLOCK)) rc = 0; if (rc != 0) return -rc; rc = nob - ruio.uio_resid; buffer = ((char *)buffer) + rc; nob = ruio.uio_resid; continue; } break; } return (0); } int libcfs_sock_setbuf (struct socket *sock, int txbufsize, int rxbufsize) { struct sockopt sopt; int rc = 0; int option; CFS_DECL_NET_DATA; bzero(&sopt, sizeof sopt); sopt.sopt_dir = SOPT_SET; sopt.sopt_level = SOL_SOCKET; sopt.sopt_val = &option; sopt.sopt_valsize = sizeof(option); if (txbufsize != 0) { option = txbufsize; if (option > KSOCK_MAX_BUF) option = KSOCK_MAX_BUF; sopt.sopt_name = SO_SNDBUF; CFS_NET_IN; rc = sosetopt(sock, &sopt); CFS_NET_EX; if (rc != 0) { CERROR ("Can't set send buffer %d: %d\n", option, rc); return -rc; } } if (rxbufsize != 0) { option = rxbufsize; sopt.sopt_name = SO_RCVBUF; CFS_NET_IN; rc = sosetopt(sock, &sopt); CFS_NET_EX; if (rc != 0) { CERROR ("Can't set receive buffer %d: %d\n", option, rc); return -rc; } } return 0; } int libcfs_sock_getaddr (struct socket *sock, int remote, __u32 *ip, int *port) { struct sockaddr_in *sin; struct sockaddr *sa = NULL; int rc; CFS_DECL_NET_DATA; if (remote != 0) { CFS_NET_IN; rc = sock->so_proto->pr_usrreqs->pru_peeraddr(sock, &sa); CFS_NET_EX; if (rc != 0) { if (sa) FREE(sa, M_SONAME); CERROR ("Error %d getting sock peer IP\n", rc); return -rc; } } else { CFS_NET_IN; rc = sock->so_proto->pr_usrreqs->pru_sockaddr(sock, &sa); CFS_NET_EX; if (rc != 0) { if (sa) FREE(sa, M_SONAME); CERROR ("Error %d getting sock local IP\n", rc); return -rc; } } if (sa != NULL) { sin = (struct sockaddr_in *)sa; if (ip != NULL) *ip = ntohl (sin->sin_addr.s_addr); if (port != NULL) *port = ntohs (sin->sin_port); if (sa) FREE(sa, M_SONAME); } return 0; } int libcfs_sock_getbuf (struct socket *sock, int *txbufsize, int *rxbufsize) { struct sockopt sopt; int rc; CFS_DECL_NET_DATA; bzero(&sopt, sizeof sopt); sopt.sopt_dir = SOPT_GET; sopt.sopt_level = SOL_SOCKET; if (txbufsize != NULL) { sopt.sopt_val = txbufsize; sopt.sopt_valsize = sizeof(*txbufsize); sopt.sopt_name = SO_SNDBUF; CFS_NET_IN; rc = sogetopt(sock, &sopt); CFS_NET_EX; if (rc != 0) { CERROR ("Can't get send buffer size: %d\n", rc); return -rc; } } if (rxbufsize != NULL) { sopt.sopt_val = rxbufsize; sopt.sopt_valsize = sizeof(*rxbufsize); sopt.sopt_name = SO_RCVBUF; CFS_NET_IN; rc = sogetopt(sock, &sopt); CFS_NET_EX; if (rc != 0) { CERROR ("Can't get receive buffer size: %d\n", rc); return -rc; } } return 0; } int libcfs_sock_connect (struct socket **sockp, int *fatal, __u32 local_ip, int local_port, __u32 peer_ip, int peer_port) { struct sockaddr_in srvaddr; struct socket *so; int s; int rc; CFS_DECL_FUNNEL_DATA; rc = libcfs_sock_create(sockp, fatal, local_ip, local_port); if (rc != 0) return rc; so = *sockp; bzero(&srvaddr, sizeof(srvaddr)); srvaddr.sin_len = sizeof(struct sockaddr_in); srvaddr.sin_family = AF_INET; srvaddr.sin_port = htons (peer_port); srvaddr.sin_addr.s_addr = htonl (peer_ip); CFS_NET_IN; rc = soconnect(so, (struct sockaddr *)&srvaddr); if (rc != 0) { CFS_NET_EX; if (rc != EADDRNOTAVAIL && rc != EADDRINUSE) CDEBUG(D_NETERROR, "Error %d connecting %u.%u.%u.%u/%d -> %u.%u.%u.%u/%d\n", rc, HIPQUAD(local_ip), local_port, HIPQUAD(peer_ip), peer_port); goto out; } s = splnet(); while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { CDEBUG(D_NET, "ksocknal sleep for waiting auto_connect.\n"); (void) tsleep((caddr_t)&so->so_timeo, PSOCK, "ksocknal_conn", hz); } if ((rc = so->so_error) != 0) { so->so_error = 0; splx(s); CFS_NET_EX; CDEBUG(D_NETERROR, "Error %d connecting %u.%u.%u.%u/%d -> %u.%u.%u.%u/%d\n", rc, HIPQUAD(local_ip), local_port, HIPQUAD(peer_ip), peer_port); goto out; } LASSERT(so->so_state & SS_ISCONNECTED); splx(s); CFS_NET_EX; if (sockp) *sockp = so; return (0); out: CFS_NET_IN; soshutdown(so, 2); soclose(so); CFS_NET_EX; return (-rc); } void libcfs_sock_release (struct socket *sock) { CFS_DECL_FUNNEL_DATA; CFS_NET_IN; soshutdown(sock, 0); CFS_NET_EX; }
/* * portal_open(struct vnode *a_vp, int a_mode, struct ucred *a_cred, * struct file *a_fp) */ static int portal_open(struct vop_open_args *ap) { struct socket *so = 0; struct portalnode *pt; struct thread *td = curthread; struct vnode *vp = ap->a_vp; struct uio auio; struct iovec aiov[2]; struct sockbuf sio; int res; struct mbuf *cm = 0; struct cmsghdr *cmsg; int newfds; int *ip; int fd; int error; int len; struct portalmount *fmp; struct file *fp; struct portal_cred pcred; /* * Nothing to do when opening the root node. */ if (vp->v_flag & VROOT) return (vop_stdopen(ap)); /* * Can't be opened unless the caller is set up * to deal with the side effects. Check for this * by testing whether the p_dupfd has been set. */ KKASSERT(td->td_proc); if (td->td_lwp->lwp_dupfd >= 0) return (ENODEV); pt = VTOPORTAL(vp); fmp = VFSTOPORTAL(vp->v_mount); /* * Create a new socket. */ error = socreate(AF_UNIX, &so, SOCK_STREAM, 0, td); if (error) goto bad; /* * Reserve some buffer space */ res = pt->pt_size + sizeof(pcred) + 512; /* XXX */ error = soreserve(so, res, res, &td->td_proc->p_rlimit[RLIMIT_SBSIZE]); if (error) goto bad; /* * Kick off connection */ error = portal_connect(so, (struct socket *)fmp->pm_server->f_data); if (error) goto bad; /* * Wait for connection to complete */ /* * XXX: Since the mount point is holding a reference on the * underlying server socket, it is not easy to find out whether * the server process is still running. To handle this problem * we loop waiting for the new socket to be connected (something * which will only happen if the server is still running) or for * the reference count on the server socket to drop to 1, which * will happen if the server dies. Sleep for 5 second intervals * and keep polling the reference count. XXX. */ crit_enter(); while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { if (fmp->pm_server->f_count == 1) { error = ECONNREFUSED; crit_exit(); goto bad; } (void) tsleep((caddr_t) &so->so_timeo, 0, "portalcon", 5 * hz); } crit_exit(); if (so->so_error) { error = so->so_error; goto bad; } /* * Set miscellaneous flags */ so->so_rcv.ssb_timeo = 0; so->so_snd.ssb_timeo = 0; atomic_set_int(&so->so_rcv.ssb_flags, SSB_NOINTR); atomic_set_int(&so->so_snd.ssb_flags, SSB_NOINTR); pcred.pcr_flag = ap->a_mode; pcred.pcr_uid = ap->a_cred->cr_uid; pcred.pcr_ngroups = ap->a_cred->cr_ngroups; bcopy(ap->a_cred->cr_groups, pcred.pcr_groups, NGROUPS * sizeof(gid_t)); aiov[0].iov_base = (caddr_t) &pcred; aiov[0].iov_len = sizeof(pcred); aiov[1].iov_base = pt->pt_arg; aiov[1].iov_len = pt->pt_size; auio.uio_iov = aiov; auio.uio_iovcnt = 2; auio.uio_rw = UIO_WRITE; auio.uio_segflg = UIO_SYSSPACE; auio.uio_td = td; auio.uio_offset = 0; auio.uio_resid = aiov[0].iov_len + aiov[1].iov_len; error = sosend(so, NULL, &auio, NULL, NULL, 0, td); if (error) goto bad; len = sizeof(int); sbinit(&sio, len); do { struct mbuf *m; int flags; flags = MSG_WAITALL; error = soreceive(so, NULL, NULL, &sio, &cm, &flags); if (error) goto bad; /* * Grab an error code from the mbuf. */ if ((m = sio.sb_mb) != NULL) { m = m_pullup(m, sizeof(int)); /* Needed? */ if (m) { error = *(mtod(m, int *)); m_freem(m); } else { error = EINVAL; } } else {
/* * Do a remote procedure call (RPC) and wait for its reply. * If from_p is non-null, then we are doing broadcast, and * the address from whence the response came is saved there. * data: input/output * from_p: output */ int krpc_call(struct sockaddr_in *sa, u_int prog, u_int vers, u_int func, struct mbuf **data, struct mbuf **from_p, int retries) { struct socket *so; struct sockaddr_in *sin; struct mbuf *m, *nam, *mhead, *from, *mopt; struct rpc_call *call; struct rpc_reply *reply; struct uio auio; int error, rcvflg, timo, secs, len; static u_int32_t xid = 0; char addr[INET_ADDRSTRLEN]; int *ip; struct timeval tv; /* * Validate address family. * Sorry, this is INET specific... */ if (sa->sin_family != AF_INET) return (EAFNOSUPPORT); /* Free at end if not null. */ nam = mhead = NULL; from = NULL; /* * Create socket and set its receive timeout. */ if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0))) goto out; m = m_get(M_WAIT, MT_SOOPTS); tv.tv_sec = 1; tv.tv_usec = 0; memcpy(mtod(m, struct timeval *), &tv, sizeof tv); m->m_len = sizeof(tv); if ((error = sosetopt(so, SOL_SOCKET, SO_RCVTIMEO, m))) goto out; /* * Enable broadcast if necessary. */ if (from_p) { int32_t *on; m = m_get(M_WAIT, MT_SOOPTS); on = mtod(m, int32_t *); m->m_len = sizeof(*on); *on = 1; if ((error = sosetopt(so, SOL_SOCKET, SO_BROADCAST, m))) goto out; } /* * Bind the local endpoint to a reserved port, * because some NFS servers refuse requests from * non-reserved (non-privileged) ports. */ MGET(mopt, M_WAIT, MT_SOOPTS); mopt->m_len = sizeof(int); ip = mtod(mopt, int *); *ip = IP_PORTRANGE_LOW; error = sosetopt(so, IPPROTO_IP, IP_PORTRANGE, mopt); if (error) goto out; MGET(m, M_WAIT, MT_SONAME); sin = mtod(m, struct sockaddr_in *); sin->sin_len = m->m_len = sizeof (struct sockaddr_in); sin->sin_family = AF_INET; sin->sin_addr.s_addr = INADDR_ANY; sin->sin_port = htons(0); error = sobind(so, m, &proc0); m_freem(m); if (error) { printf("bind failed\n"); goto out; } MGET(mopt, M_WAIT, MT_SOOPTS); mopt->m_len = sizeof(int); ip = mtod(mopt, int *); *ip = IP_PORTRANGE_DEFAULT; error = sosetopt(so, IPPROTO_IP, IP_PORTRANGE, mopt); if (error) goto out; /* * Setup socket address for the server. */ nam = m_get(M_WAIT, MT_SONAME); sin = mtod(nam, struct sockaddr_in *); bcopy((caddr_t)sa, (caddr_t)sin, (nam->m_len = sa->sin_len)); /* * Prepend RPC message header. */ mhead = m_gethdr(M_WAIT, MT_DATA); mhead->m_next = *data; call = mtod(mhead, struct rpc_call *); mhead->m_len = sizeof(*call); bzero((caddr_t)call, sizeof(*call)); /* rpc_call part */ xid = krpc_get_xid(); call->rp_xid = txdr_unsigned(xid); /* call->rp_direction = 0; */ call->rp_rpcvers = txdr_unsigned(2); call->rp_prog = txdr_unsigned(prog); call->rp_vers = txdr_unsigned(vers); call->rp_proc = txdr_unsigned(func); /* rpc_auth part (auth_unix as root) */ call->rpc_auth.authtype = txdr_unsigned(RPCAUTH_UNIX); call->rpc_auth.authlen = txdr_unsigned(sizeof(struct auth_unix)); /* rpc_verf part (auth_null) */ call->rpc_verf.authtype = 0; call->rpc_verf.authlen = 0; /* * Setup packet header */ len = 0; m = mhead; while (m) { len += m->m_len; m = m->m_next; } mhead->m_pkthdr.len = len; mhead->m_pkthdr.rcvif = NULL; /* * Send it, repeatedly, until a reply is received, * but delay each re-send by an increasing amount. * If the delay hits the maximum, start complaining. */ for (timo = 0; retries; retries--) { /* Send RPC request (or re-send). */ m = m_copym(mhead, 0, M_COPYALL, M_WAIT); if (m == NULL) { error = ENOBUFS; goto out; } error = sosend(so, nam, NULL, m, NULL, 0); if (error) { printf("krpc_call: sosend: %d\n", error); goto out; } m = NULL; /* Determine new timeout. */ if (timo < MAX_RESEND_DELAY) timo++; else printf("RPC timeout for server %s (0x%x) prog %u\n", inet_ntop(AF_INET, &sin->sin_addr, addr, sizeof(addr)), ntohl(sin->sin_addr.s_addr), prog); /* * Wait for up to timo seconds for a reply. * The socket receive timeout was set to 1 second. */ secs = timo; while (secs > 0) { if (from) { m_freem(from); from = NULL; } if (m) { m_freem(m); m = NULL; } auio.uio_resid = len = 1<<16; auio.uio_procp = NULL; rcvflg = 0; error = soreceive(so, &from, &auio, &m, NULL, &rcvflg, 0); if (error == EWOULDBLOCK) { secs--; continue; } if (error) goto out; len -= auio.uio_resid; /* Does the reply contain at least a header? */ if (len < MIN_REPLY_HDR) continue; if (m->m_len < MIN_REPLY_HDR) continue; reply = mtod(m, struct rpc_reply *); /* Is it the right reply? */ if (reply->rp_direction != txdr_unsigned(RPC_REPLY)) continue; if (reply->rp_xid != txdr_unsigned(xid)) continue; /* Was RPC accepted? (authorization OK) */ if (reply->rp_astatus != 0) { error = fxdr_unsigned(u_int32_t, reply->rp_errno); printf("rpc denied, error=%d\n", error); continue; } /* Did the call succeed? */ if (reply->rp_status != 0) { error = fxdr_unsigned(u_int32_t, reply->rp_status); printf("rpc denied, status=%d\n", error); continue; } goto gotreply; /* break two levels */ } /* while secs */ } /* forever send/receive */ error = ETIMEDOUT; goto out; gotreply: /* * Get RPC reply header into first mbuf, * get its length, then strip it off. */ len = sizeof(*reply); if (m->m_len < len) { m = m_pullup(m, len); if (m == NULL) { error = ENOBUFS; goto out; } } reply = mtod(m, struct rpc_reply *); if (reply->rp_auth.authtype != 0) { len += fxdr_unsigned(u_int32_t, reply->rp_auth.authlen); len = (len + 3) & ~3; /* XXX? */ } m_adj(m, len); /* result */ *data = m; if (from_p && error == 0) { *from_p = from; from = NULL; } out: if (nam) m_freem(nam); if (mhead) m_freem(mhead); if (from) m_freem(from); soclose(so); return error; }
/* | Add header digest to the iSCSI hdr mbuf | XXX Assert: (mh->m_pkthdr.len + 4) < MHLEN */ bcopy(&pp->hdr_dig, (mh->m_data + mh->m_len), sizeof(int)); mh->m_len += sizeof(int); mh->m_pkthdr.len += sizeof(int); } mp = &mh->m_next; if(pq->pdu.ds) { struct mbuf *md; int off = 0; len = pp->ds_len; while(len & 03) // the specs say it must be int alligned len++; while(len > 0) { int l; MGET(md, MB_TRYWAIT, MT_DATA); pq->refcnt++; l = min(MCLBYTES, len); debug(5, "setting ext_free(arg=%p len/l=%d/%d)", pq->buf, len, l); md->m_ext.ext_buf = pq->buf; md->m_ext.ext_free = ext_free; md->m_ext.ext_ref = ext_ref; md->m_ext.ext_arg = pq; md->m_ext.ext_size = l; md->m_flags |= M_EXT; md->m_data = pp->ds + off; md->m_len = l; md->m_next = NULL; mh->m_pkthdr.len += l; *mp = md; mp = &md->m_next; len -= l; off += l; } } if(sp->dataDigest) { struct mbuf *me; pp->ds_dig = sp->dataDigest(pp->ds, pp->ds_len, 0); MGET(me, MB_TRYWAIT, MT_DATA); me->m_len = sizeof(int); MH_ALIGN(mh, sizeof(int)); bcopy(&pp->ds_dig, me->m_data, sizeof(int)); me->m_next = NULL; mh->m_pkthdr.len += sizeof(int); *mp = me; } if((error = sosend(sp->soc, NULL, NULL, mh, 0, 0, curthread)) != 0) { sdebug(3, "error=%d", error); return error; } sp->stats.nsent++; getmicrouptime(&sp->stats.t_sent); return 0; } #else /* NO_USE_MBUF */ int isc_sendPDU(isc_session_t *sp, pduq_t *pq) { struct uio *uio = &pq->uio; struct iovec *iv; pdu_t *pp = &pq->pdu; int len, error; debug_called(8); bzero(uio, sizeof(struct uio)); uio->uio_rw = UIO_WRITE; uio->uio_segflg = UIO_SYSSPACE; uio->uio_td = curthread; uio->uio_iov = iv = pq->iov; iv->iov_base = &pp->ipdu; iv->iov_len = sizeof(union ipdu_u); uio->uio_resid = pq->len; iv++; if(sp->hdrDigest) pq->pdu.hdr_dig = sp->hdrDigest(&pp->ipdu, sizeof(union ipdu_u), 0); if(pp->ahs_len) { iv->iov_base = pp->ahs; iv->iov_len = pp->ahs_len; iv++; if(sp->hdrDigest) pq->pdu.hdr_dig = sp->hdrDigest(&pp->ahs, pp->ahs_len, pq->pdu.hdr_dig); } if(sp->hdrDigest) { debug(2, "hdr_dig=%x", pq->pdu.hdr_dig); iv->iov_base = &pp->hdr_dig; iv->iov_len = sizeof(int); iv++; } if(pq->pdu.ds) { iv->iov_base = pp->ds; iv->iov_len = pp->ds_len; while(iv->iov_len & 03) // the specs say it must be int alligned iv->iov_len++; iv++; } if(sp->dataDigest) { pp->ds_dig = sp->dataDigest(pp->ds, pp->ds_len, 0); iv->iov_base = &pp->ds_dig; iv->iov_len = sizeof(int); iv++; } uio->uio_iovcnt = iv - pq->iov; sdebug(5, "opcode=%x iovcnt=%d uio_resid=%d itt=%x", pp->ipdu.bhs.opcode, uio->uio_iovcnt, uio->uio_resid, ntohl(pp->ipdu.bhs.itt)); sdebug(5, "sp=%p sp->soc=%p uio=%p sp->td=%p", sp, sp->soc, uio, sp->td); do { len = uio->uio_resid; error = sosend(sp->soc, NULL, uio, 0, 0, 0, curthread); if(uio->uio_resid == 0 || error || len == uio->uio_resid) { if(uio->uio_resid) { sdebug(2, "uio->uio_resid=%d uio->uio_iovcnt=%d error=%d len=%d", uio->uio_resid, uio->uio_iovcnt, error, len); if(error == 0) error = EAGAIN; // 35 } break; } /* | XXX: untested code */ sdebug(1, "uio->uio_resid=%d uio->uio_iovcnt=%d", uio->uio_resid, uio->uio_iovcnt); iv = uio->uio_iov; len -= uio->uio_resid; while(uio->uio_iovcnt > 0) { if(iv->iov_len > len) { caddr_t bp = (caddr_t)iv->iov_base; iv->iov_len -= len; iv->iov_base = (void *)&bp[len]; break; } len -= iv->iov_len; uio->uio_iovcnt--; uio->uio_iov++; iv++; } } while(uio->uio_resid); if(error == 0) { sp->stats.nsent++; getmicrouptime(&sp->stats.t_sent); } return error; }
int ksocknal_lib_send_iov (ksock_conn_t *conn, ksock_tx_t *tx) { #if SOCKNAL_SINGLE_FRAG_TX struct iovec scratch; struct iovec *scratchiov = &scratch; unsigned int niov = 1; #else struct iovec *scratchiov = conn->ksnc_scheduler->kss_scratch_iov; unsigned int niov = tx->tx_niov; #endif struct socket *sock = conn->ksnc_sock; int nob; int rc; int i; struct uio suio = { .uio_iov = scratchiov, .uio_iovcnt = niov, .uio_offset = 0, .uio_resid = 0, /* This will be valued after a while */ .uio_segflg = UIO_SYSSPACE, .uio_rw = UIO_WRITE, .uio_procp = NULL }; int flags = MSG_DONTWAIT; CFS_DECL_NET_DATA; for (nob = i = 0; i < niov; i++) { scratchiov[i] = tx->tx_iov[i]; nob += scratchiov[i].iov_len; } suio.uio_resid = nob; CFS_NET_IN; rc = sosend(sock, NULL, &suio, (struct mbuf *)0, (struct mbuf *)0, flags); CFS_NET_EX; /* NB there is no return value can indicate how many * have been sent and how many resid, we have to get * sent bytes from suio. */ if (rc != 0) { if (suio.uio_resid != nob &&\ (rc == ERESTART || rc == EINTR || rc == EWOULDBLOCK)) /* We have sent something */ rc = nob - suio.uio_resid; else if ( rc == EWOULDBLOCK ) /* Actually, EAGAIN and EWOULDBLOCK have same value in OSX */ rc = -EAGAIN; else rc = -rc; } else /* rc == 0 */ rc = nob - suio.uio_resid; return rc; } int ksocknal_lib_send_kiov (ksock_conn_t *conn, ksock_tx_t *tx) { #if SOCKNAL_SINGLE_FRAG_TX || !SOCKNAL_RISK_KMAP_DEADLOCK struct iovec scratch; struct iovec *scratchiov = &scratch; unsigned int niov = 1; #else struct iovec *scratchiov = conn->ksnc_scheduler->kss_scratch_iov; unsigned int niov = tx->tx_nkiov; #endif struct socket *sock = conn->ksnc_sock; lnet_kiov_t *kiov = tx->tx_kiov; int nob; int rc; int i; struct uio suio = { .uio_iov = scratchiov, .uio_iovcnt = niov, .uio_offset = 0, .uio_resid = 0, /* It should be valued after a while */ .uio_segflg = UIO_SYSSPACE, .uio_rw = UIO_WRITE, .uio_procp = NULL }; int flags = MSG_DONTWAIT; CFS_DECL_NET_DATA; for (nob = i = 0; i < niov; i++) { scratchiov[i].iov_base = cfs_kmap(kiov[i].kiov_page) + kiov[i].kiov_offset; nob += scratchiov[i].iov_len = kiov[i].kiov_len; } suio.uio_resid = nob; CFS_NET_IN; rc = sosend(sock, NULL, &suio, (struct mbuf *)0, (struct mbuf *)0, flags); CFS_NET_EX; for (i = 0; i < niov; i++) cfs_kunmap(kiov[i].kiov_page); if (rc != 0) { if (suio.uio_resid != nob &&\ (rc == ERESTART || rc == EINTR || rc == EWOULDBLOCK)) /* We have sent something */ rc = nob - suio.uio_resid; else if ( rc == EWOULDBLOCK ) /* EAGAIN and EWOULD BLOCK have same value in OSX */ rc = -EAGAIN; else rc = -rc; } else /* rc == 0 */ rc = nob - suio.uio_resid; return rc; } /* * liang: Hack of inpcb and tcpcb. * To get tcpcb of a socket, and call tcp_output * to send quick ack. */ struct ks_tseg_qent{ int foo; }; struct ks_tcptemp{ int foo; }; LIST_HEAD(ks_tsegqe_head, ks_tseg_qent); struct ks_tcpcb { struct ks_tsegqe_head t_segq; int t_dupacks; struct ks_tcptemp *unused; int t_timer[4]; struct inpcb *t_inpcb; int t_state; u_int t_flags; /* * There are more fields but we dont need * ...... */ }; #define TF_ACKNOW 0x00001 #define TF_DELACK 0x00002 struct ks_inpcb { LIST_ENTRY(ks_inpcb) inp_hash; struct in_addr reserved1; struct in_addr reserved2; u_short inp_fport; u_short inp_lport; LIST_ENTRY(inpcb) inp_list; caddr_t inp_ppcb; /* * There are more fields but we dont need * ...... */ }; #define ks_sotoinpcb(so) ((struct ks_inpcb *)(so)->so_pcb) #define ks_intotcpcb(ip) ((struct ks_tcpcb *)(ip)->inp_ppcb) #define ks_sototcpcb(so) (intotcpcb(sotoinpcb(so))) void ksocknal_lib_eager_ack (ksock_conn_t *conn) { struct socket *sock = conn->ksnc_sock; struct ks_inpcb *inp = ks_sotoinpcb(sock); struct ks_tcpcb *tp = ks_intotcpcb(inp); int s; CFS_DECL_NET_DATA; extern int tcp_output(register struct ks_tcpcb *tp); CFS_NET_IN; s = splnet(); /* * No TCP_QUICKACK supported in BSD, so I have to call tcp_fasttimo * to send immediate ACK. */ if (tp && tp->t_flags & TF_DELACK){ tp->t_flags &= ~TF_DELACK; tp->t_flags |= TF_ACKNOW; (void) tcp_output(tp); } splx(s); CFS_NET_EX; return; } int ksocknal_lib_recv_iov (ksock_conn_t *conn) { #if SOCKNAL_SINGLE_FRAG_RX struct iovec scratch; struct iovec *scratchiov = &scratch; unsigned int niov = 1; #else struct iovec *scratchiov = conn->ksnc_scheduler->kss_scratch_iov; unsigned int niov = conn->ksnc_rx_niov; #endif struct iovec *iov = conn->ksnc_rx_iov; int nob; int rc; int i; struct uio ruio = { .uio_iov = scratchiov, .uio_iovcnt = niov, .uio_offset = 0, .uio_resid = 0, /* It should be valued after a while */ .uio_segflg = UIO_SYSSPACE, .uio_rw = UIO_READ, .uio_procp = NULL }; int flags = MSG_DONTWAIT; CFS_DECL_NET_DATA; for (nob = i = 0; i < niov; i++) { scratchiov[i] = iov[i]; nob += scratchiov[i].iov_len; } LASSERT (nob <= conn->ksnc_rx_nob_wanted); ruio.uio_resid = nob; CFS_NET_IN; rc = soreceive(conn->ksnc_sock, (struct sockaddr **)0, &ruio, (struct mbuf **)0, (struct mbuf **)0, &flags); CFS_NET_EX; if (rc){ if (ruio.uio_resid != nob && \ (rc == ERESTART || rc == EINTR || rc == EWOULDBLOCK || rc == EAGAIN)) /* data particially received */ rc = nob - ruio.uio_resid; else if (rc == EWOULDBLOCK) /* EAGAIN and EWOULD BLOCK have same value in OSX */ rc = -EAGAIN; else rc = -rc; } else rc = nob - ruio.uio_resid; return (rc); } int ksocknal_lib_recv_kiov (ksock_conn_t *conn) { #if SOCKNAL_SINGLE_FRAG_RX || !SOCKNAL_RISK_KMAP_DEADLOCK struct iovec scratch; struct iovec *scratchiov = &scratch; unsigned int niov = 1; #else struct iovec *scratchiov = conn->ksnc_scheduler->kss_scratch_iov; unsigned int niov = conn->ksnc_rx_nkiov; #endif lnet_kiov_t *kiov = conn->ksnc_rx_kiov; int nob; int rc; int i; struct uio ruio = { .uio_iov = scratchiov, .uio_iovcnt = niov, .uio_offset = 0, .uio_resid = 0, .uio_segflg = UIO_SYSSPACE, .uio_rw = UIO_READ, .uio_procp = NULL }; int flags = MSG_DONTWAIT; CFS_DECL_NET_DATA; for (nob = i = 0; i < niov; i++) { scratchiov[i].iov_base = cfs_kmap(kiov[i].kiov_page) + kiov[i].kiov_offset; nob += scratchiov[i].iov_len = kiov[i].kiov_len; } LASSERT (nob <= conn->ksnc_rx_nob_wanted); ruio.uio_resid = nob; CFS_NET_IN; rc = soreceive(conn->ksnc_sock, (struct sockaddr **)0, &ruio, (struct mbuf **)0, NULL, &flags); CFS_NET_EX; for (i = 0; i < niov; i++) cfs_kunmap(kiov[i].kiov_page); if (rc){ if (ruio.uio_resid != nob && \ (rc == ERESTART || rc == EINTR || rc == EWOULDBLOCK)) /* data particially received */ rc = nob - ruio.uio_resid; else if (rc == EWOULDBLOCK) /* receive blocked, EWOULDBLOCK == EAGAIN */ rc = -EAGAIN; else rc = -rc; } else rc = nob - ruio.uio_resid; return (rc); } int ksocknal_lib_get_conn_tunables (ksock_conn_t *conn, int *txmem, int *rxmem, int *nagle) { struct socket *sock = conn->ksnc_sock; int rc; rc = ksocknal_connsock_addref(conn); if (rc != 0) { LASSERT (conn->ksnc_closing); *txmem = *rxmem = *nagle = 0; return -ESHUTDOWN; } rc = libcfs_sock_getbuf(sock, txmem, rxmem); if (rc == 0) { struct sockopt sopt; int len; CFS_DECL_NET_DATA; len = sizeof(*nagle); bzero(&sopt, sizeof sopt); sopt.sopt_dir = SOPT_GET; sopt.sopt_level = IPPROTO_TCP; sopt.sopt_name = TCP_NODELAY; sopt.sopt_val = nagle; sopt.sopt_valsize = len; CFS_NET_IN; rc = -sogetopt(sock, &sopt); CFS_NET_EX; } ksocknal_connsock_decref(conn); if (rc == 0) *nagle = !*nagle; else *txmem = *rxmem = *nagle = 0; return (rc); } int ksocknal_lib_setup_sock (struct socket *so) { struct sockopt sopt; int rc; int option; int keep_idle; int keep_intvl; int keep_count; int do_keepalive; struct linger linger; CFS_DECL_NET_DATA; rc = libcfs_sock_setbuf(so, *ksocknal_tunables.ksnd_tx_buffer_size, *ksocknal_tunables.ksnd_rx_buffer_size); if (rc != 0) { CERROR ("Can't set buffer tx %d, rx %d buffers: %d\n", *ksocknal_tunables.ksnd_tx_buffer_size, *ksocknal_tunables.ksnd_rx_buffer_size, rc); return (rc); } /* Ensure this socket aborts active sends immediately when we close * it. */ bzero(&sopt, sizeof sopt); linger.l_onoff = 0; linger.l_linger = 0; sopt.sopt_dir = SOPT_SET; sopt.sopt_level = SOL_SOCKET; sopt.sopt_name = SO_LINGER; sopt.sopt_val = &linger; sopt.sopt_valsize = sizeof(linger); CFS_NET_IN; rc = -sosetopt(so, &sopt); if (rc != 0) { CERROR ("Can't set SO_LINGER: %d\n", rc); goto out; } if (!*ksocknal_tunables.ksnd_nagle) { option = 1; bzero(&sopt, sizeof sopt); sopt.sopt_dir = SOPT_SET; sopt.sopt_level = IPPROTO_TCP; sopt.sopt_name = TCP_NODELAY; sopt.sopt_val = &option; sopt.sopt_valsize = sizeof(option); rc = -sosetopt(so, &sopt); if (rc != 0) { CERROR ("Can't disable nagle: %d\n", rc); goto out; } } /* snapshot tunables */ keep_idle = *ksocknal_tunables.ksnd_keepalive_idle; keep_count = *ksocknal_tunables.ksnd_keepalive_count; keep_intvl = *ksocknal_tunables.ksnd_keepalive_intvl; do_keepalive = (keep_idle > 0 && keep_count > 0 && keep_intvl > 0); option = (do_keepalive ? 1 : 0); bzero(&sopt, sizeof sopt); sopt.sopt_dir = SOPT_SET; sopt.sopt_level = SOL_SOCKET; sopt.sopt_name = SO_KEEPALIVE; sopt.sopt_val = &option; sopt.sopt_valsize = sizeof(option); rc = -sosetopt(so, &sopt); if (rc != 0) { CERROR ("Can't set SO_KEEPALIVE: %d\n", rc); goto out; } if (!do_keepalive) { /* no more setting, just return */ rc = 0; goto out; } bzero(&sopt, sizeof sopt); sopt.sopt_dir = SOPT_SET; sopt.sopt_level = IPPROTO_TCP; sopt.sopt_name = TCP_KEEPALIVE; sopt.sopt_val = &keep_idle; sopt.sopt_valsize = sizeof(keep_idle); rc = -sosetopt(so, &sopt); if (rc != 0) { CERROR ("Can't set TCP_KEEPALIVE : %d\n", rc); goto out; } out: CFS_NET_EX; return (rc); } void ksocknal_lib_push_conn(ksock_conn_t *conn) { struct socket *sock; struct sockopt sopt; int val = 1; int rc; CFS_DECL_NET_DATA; rc = ksocknal_connsock_addref(conn); if (rc != 0) /* being shut down */ return; sock = conn->ksnc_sock; bzero(&sopt, sizeof sopt); sopt.sopt_dir = SOPT_SET; sopt.sopt_level = IPPROTO_TCP; sopt.sopt_name = TCP_NODELAY; sopt.sopt_val = &val; sopt.sopt_valsize = sizeof val; CFS_NET_IN; sosetopt(sock, &sopt); CFS_NET_EX; ksocknal_connsock_decref(conn); return; } extern void ksocknal_read_callback (ksock_conn_t *conn); extern void ksocknal_write_callback (ksock_conn_t *conn); static void ksocknal_upcall(struct socket *so, caddr_t arg, int waitf) { ksock_conn_t *conn = (ksock_conn_t *)arg; ENTRY; read_lock (&ksocknal_data.ksnd_global_lock); if (conn == NULL) goto out; if (so->so_rcv.sb_flags & SB_UPCALL) { extern int soreadable(struct socket *so); if (conn->ksnc_rx_nob_wanted && soreadable(so)) /* To verify whether the upcall is for receive */ ksocknal_read_callback (conn); } /* go foward? */ if (so->so_snd.sb_flags & SB_UPCALL){ extern int sowriteable(struct socket *so); if (sowriteable(so)) /* socket is writable */ ksocknal_write_callback(conn); } out: read_unlock (&ksocknal_data.ksnd_global_lock); EXIT; } void ksocknal_lib_save_callback(struct socket *sock, ksock_conn_t *conn) { /* No callback need to save in osx */ return; } void ksocknal_lib_set_callback(struct socket *sock, ksock_conn_t *conn) { CFS_DECL_NET_DATA; CFS_NET_IN; sock->so_upcallarg = (void *)conn; sock->so_upcall = ksocknal_upcall; sock->so_snd.sb_timeo = 0; sock->so_rcv.sb_timeo = cfs_time_seconds(2); sock->so_rcv.sb_flags |= SB_UPCALL; sock->so_snd.sb_flags |= SB_UPCALL; CFS_NET_EX; return; } void ksocknal_lib_act_callback(struct socket *sock, ksock_conn_t *conn) { CFS_DECL_NET_DATA; CFS_NET_IN; ksocknal_upcall (sock, (void *)conn, 0); CFS_NET_EX; }