Пример #1
0
/*
 * Receive data from a TCP socket.
 */
static int
svc_tcp_recvfrom(struct svc_rqst *rqstp)
{
	struct svc_sock	*svsk = rqstp->rq_sock;
	struct svc_serv	*serv = svsk->sk_server;
	struct svc_buf	*bufp = &rqstp->rq_argbuf;
	int		len, ready, used;

	dprintk("svc: tcp_recv %p data %d conn %d close %d\n",
			svsk, svsk->sk_data, svsk->sk_conn, svsk->sk_close);

	if (svsk->sk_close) {
		svc_delete_socket(svsk);
		return 0;
	}

	if (svsk->sk_conn) {
		svc_tcp_accept(svsk);
		svc_sock_accepted(svsk);
		return 0;
	}

	ready = svsk->sk_data;

	/* Receive data. If we haven't got the record length yet, get
	 * the next four bytes. Otherwise try to gobble up as much as
	 * possible up to the complete record length.
	 */
	if (svsk->sk_tcplen < 4) {
		unsigned long	want = 4 - svsk->sk_tcplen;
		struct iovec	iov;

		iov.iov_base = ((char *) &svsk->sk_reclen) + svsk->sk_tcplen;
		iov.iov_len  = want;
		if ((len = svc_recvfrom(rqstp, &iov, 1, want)) < 0)
			goto error;
		svsk->sk_tcplen += len;

		svsk->sk_reclen = ntohl(svsk->sk_reclen);
		if (!(svsk->sk_reclen & 0x80000000)) {
			/* FIXME: technically, a record can be fragmented,
			 *  and non-terminal fragments will not have the top
			 *  bit set in the fragment length header.
			 *  But apparently no known nfs clients send fragmented
			 *  records. */
			/* FIXME: shutdown socket */
			printk(KERN_NOTICE "RPC: bad TCP reclen %08lx",
			       (unsigned long) svsk->sk_reclen);
			return -EIO;
		}
		svsk->sk_reclen &= 0x7fffffff;
		dprintk("svc: TCP record, %d bytes\n", svsk->sk_reclen);
	}

	/* Check whether enough data is available */
	len = svc_recv_available(svsk);
	if (len < 0)
		goto error;

	if (len < svsk->sk_reclen) {
		/* FIXME: if sk_reclen > window-size, then we will
		 * never be able to receive the record, so should
		 * shutdown the connection
		 */
		dprintk("svc: incomplete TCP record (%d of %d)\n",
			len, svsk->sk_reclen);
		svc_sock_received(svsk, ready);
		return -EAGAIN;	/* record not complete */
	}
	/* if we think there is only one more record to read, but
	 * it is bigger than we expect, then two records must have arrived
	 * together, so pretend we aren't using the record.. */
	if (len > svsk->sk_reclen && ready == 1)
		used = 0;
	else	used = 1;

	/* Frob argbuf */
	bufp->iov[0].iov_base += 4;
	bufp->iov[0].iov_len  -= 4;

	/* Now receive data */
	len = svc_recvfrom(rqstp, bufp->iov, bufp->nriov, svsk->sk_reclen);
	if (len < 0)
		goto error;

	dprintk("svc: TCP complete record (%d bytes)\n", len);

	/* Position reply write pointer immediately after
	 * record length */
	rqstp->rq_resbuf.buf += 1;
	rqstp->rq_resbuf.len  = 1;

	rqstp->rq_skbuff      = 0;
	rqstp->rq_argbuf.buf += 1;
	rqstp->rq_argbuf.len  = (len >> 2);
	rqstp->rq_prot	      = IPPROTO_TCP;

	/* Reset TCP read info */
	svsk->sk_reclen = 0;
	svsk->sk_tcplen = 0;

	svc_sock_received(svsk, used);
	if (serv->sv_stats)
		serv->sv_stats->nettcpcnt++;

	return len;

error:
	if (len == -EAGAIN) {
		dprintk("RPC: TCP recvfrom got EAGAIN\n");
		svc_sock_received(svsk, ready); /* Clear data ready */
	} else {
		printk(KERN_NOTICE "%s: recvfrom returned errno %d\n",
					svsk->sk_server->sv_name, -len);
		svc_sock_received(svsk, 0);
	}

	return len;
}
Пример #2
0
/*
 * Receive data from a TCP socket.
 */
static int
svc_tcp_recvfrom(struct svc_rqst *rqstp)
{
	struct svc_sock	*svsk = rqstp->rq_sock;
	struct svc_serv	*serv = svsk->sk_server;
	struct svc_buf	*bufp = &rqstp->rq_argbuf;
	int		len, ready;

	dprintk("svc: tcp_recv %p data %d conn %d close %d\n",
			svsk, svsk->sk_data, svsk->sk_conn, svsk->sk_close);

	if (svsk->sk_close) {
		svc_delete_socket(svsk);
		return 0;
	}

	if (svsk->sk_conn) {
		svc_tcp_accept(svsk);
		svc_sock_accepted(svsk);
		return 0;
	}

	ready = svsk->sk_data;

	/* Receive data. If we haven't got the record length yet, get
	 * the next four bytes. Otherwise try to gobble up as much as
	 * possible up to the complete record length.
	 */
	if (svsk->sk_tcplen < 4) {
		unsigned long	want = 4 - svsk->sk_tcplen;
		struct iovec	iov;

		iov.iov_base = ((u32 *) &svsk->sk_reclen) + svsk->sk_tcplen;
		iov.iov_len  = want;
		if ((len = svc_recvfrom(rqstp, &iov, 1, want)) < 0)
			goto error;
		svsk->sk_tcplen += len;

		svsk->sk_reclen = ntohl(svsk->sk_reclen);
		if (!(svsk->sk_reclen & 0x80000000)) {
			/* FIXME: shutdown socket */
			printk(KERN_NOTICE "RPC: bad TCP reclen %08lx",
					(unsigned long) svsk->sk_reclen);
			return -EIO;
		}
		svsk->sk_reclen &= 0x7fffffff;
		dprintk("svc: TCP record, %ld bytes\n", svsk->sk_reclen);
	}

	/* Check whether enough data is available */
	len = svc_recv_available(svsk);
	if (len < 0)
		goto error;

	if (len < svsk->sk_reclen) {
		dprintk("svc: incomplete TCP record (%d of %ld)\n",
				len, svsk->sk_reclen);
		svc_sock_received(svsk, ready);
		len = -EAGAIN;	/* record not complete */
	}

	/* Frob argbuf */
	bufp->iov[0].iov_base += 4;
	bufp->iov[0].iov_len  -= 4;

	/* Now receive data */
	len = svc_recvfrom(rqstp, bufp->iov, bufp->nriov, svsk->sk_reclen);
	if (len < 0)
		goto error;

	dprintk("svc: TCP complete record (%d bytes)\n", len);

	/* Position reply write pointer immediately after
	 * record length */
	rqstp->rq_resbuf.buf += 1;
	rqstp->rq_resbuf.len  = 1;

	rqstp->rq_skbuff      = 0;
	rqstp->rq_argbuf.buf += 1;
	rqstp->rq_argbuf.len  = (len >> 2);
	rqstp->rq_prot	      = IPPROTO_TCP;

	/* Reset TCP read info */
	svsk->sk_reclen = 0;
	svsk->sk_tcplen = 0;

	svc_sock_received(svsk, 1);
	if (serv->sv_stats)
		serv->sv_stats->nettcpcnt++;

	return len;

error:
	if (len == -EAGAIN) {
		dprintk("RPC: TCP recvfrom got EAGAIN\n");
		svc_sock_received(svsk, ready); /* Clear data ready */
	} else {
		printk(KERN_NOTICE "%s: recvfrom returned errno %d\n",
					svsk->sk_server->sv_name, -len);
		svc_sock_received(svsk, 0);
	}

	return len;
}