ncafs.c revision 2caf0dcd2abc26b477e317999994020212790d38
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/sysmacros.h>
#include <sys/pathname.h>
#include <sys/kmem_impl.h>
#include <sys/socketvar.h>
#include <sys/sendfile.h>
#define _SUN_TPI_VERSION 2
/* NCAfs vnode operations */
struct caller_context *);
struct caller_context *);
struct pollhead **);
/* NCAfs sonode operations */
static int sonca_listen(struct sonode *, int);
socklen_t, int, int);
struct uio *);
static int sonca_shutdown(struct sonode *, int);
static struct kmem_cache *ncafs_cache;
#ifdef DEBUG
int nca_sendfilev_debug = 0;
#endif
typedef struct ncafs_priv {
int req_size;
int iop_more;
} ncafs_priv_t;
typedef struct so_ncafs {
} so_ncafs_t;
static sonodeops_t ncafs_sonodeops = {
sonca_accept, /* sop_accept */
sonca_bind, /* sop_bind */
sonca_listen, /* sop_listen */
sonca_connect, /* sop_connect */
sotpi_recvmsg, /* sop_recvmsg */
sonca_sendmsg, /* sop_sendmsg */
sotpi_getpeername, /* sop_getpeername */
sonca_getsockname, /* sop_getsockname */
sonca_shutdown, /* sop_shutdown */
sotpi_getsockopt, /* sop_getsockopt */
sotpi_setsockopt /* sop_setsockopt */
};
/*ARGSUSED*/
static int
{
return (0);
}
/*ARGSUSED1*/
static void
{
}
void
sonca_init(void)
{
}
/* ARGSUSED */
void
{
/*
* If no one has reclaimed the vnode, remove from the
* cache now.
*/
/*
* Drop the temporary hold by vn_rele now
*/
return;
}
/* We are the sole owner of so now */
vn_invalid(vp);
}
}
}
}
static int
{
int error;
/* Check if NCA is enabled */
&error);
return (error);
}
/*
* Open stream and send down ioctl to make sure nca is supported.
* Ensure that vnode is unchanged if check succeeds.
*/
static int
{
int error;
return (error);
}
/* release hold in clone_open() */
}
return (EPROTONOSUPPORT);
}
}
return (0);
}
/* ARGSUSED */
struct sonode *
{
int error;
/*
* We rely on the "struct sonode" being the first element in the
* "so_ncfas_t" in sonca_inactive().
*/
now = gethrestime_sec();
/*
* record in so_flag that it is a clone.
*/
so->so_pushcnt = 0;
so->so_options = 0;
so->so_delayed_error = 0;
so->so_oobsigcnt = 0;
/*
* We need to check if NCA is plumbed before letting this
* call succeed. If we are being called from nca_accept,
* don't bother.
*/
return (NULL);
}
/* Set up the Stream now */
return (NULL);
}
return (so);
}
int
int flags)
{
int error;
return (EOPNOTSUPP);
if (namelen != sizeof (struct sockaddr_in))
return (EINVAL);
return (EAFNOSUPPORT);
if (!(flags & _SOBIND_LOCK_HELD)) {
} else {
}
&error);
if (error == 0) {
}
if (!(flags & _SOBIND_LOCK_HELD)) {
} else {
}
return (error);
}
int
{
if (backlog <= 0)
return (EOPNOTSUPP);
return (EINVAL);
int error;
/* Let NCA know that web server is ready */
if (error != 0)
return (error);
}
return (0);
}
/*
* Issue a downcall to NCA by sending a "downcallinfo_t" structure in an M_CTL
* mblk downwards. We cannot use M_DATA mblks because they could carry
* write to it. The M_CTL mblk is marked with a magic number to allow some
* basic sanity tests inside NCA.
*/
static int
{
int error;
return (ENOMEM);
/*
* We must use kstrwritemp() here because we want to send down
* a M_CTL mblk which strwrite() doesn't support. kstrwritemp()
* has more lax checks which is allright in this case because
* NCA sockets always grant write permissions, we don't want
* the mblk_t to be split anyway and there will never be a
* M_HANGUP mblk on a NCA socket's stream.
*/
if (error != 0)
return (error);
}
/* ARGSUSED */
int
{
return (EINVAL);
}
int
{
}
int
{
struct T_conn_ind *conn_ind;
int error = 0;
void *src;
void *opt;
#ifdef NCAFS_DEBUG2
char *nca_request_ptr;
char buf[1024];
int len;
#endif
#ifdef NCAFS_DEBUG3
#endif
/*
* Check that the socket is a listener.
*/
return (error);
}
if (error != 0) {
return (error);
}
goto disconnect_unlocked;
}
if (optlen != 0) {
goto disconnect_unlocked;
}
}
return (EINVAL);
}
return (EINVAL);
}
/*
* Create the new socket.
*/
#ifdef NCAFS_DEBUG3
#endif
#ifdef NCAFS_DEBUG3
#endif
/*
* Accept can not fail with ENOBUFS. sonca_create sleeps
* waiting for memory until a signal is caught so return
* EINTR.
*/
goto disconnect_unlocked;
}
/* Do the automatic bind for the new socket */
/*
* Copy local address from nca_io2_t.
*/
#ifdef NCAFS_DEBUG2
#endif
#ifdef NCAFS_DEBUG2
#endif
nso_priv->iop_dataleft = 0;
if (error != 0) {
goto disconnect_vp_unlocked;
}
}
/*
* Pass out new socket.
*/
return (0);
return (error);
}
/* ARGSUSED */
int
int ioflag,
struct caller_context *ct)
{
} else {
}
} else {
if (so_priv->iop_dataleft > 0) {
lmsg.msg_namelen = 0;
lmsg.msg_controllen = 0;
so_priv->iop_dataleft = 0;
}
} else {
}
return (error);
}
return (0);
}
/*
* NCA will send more data along with nca_io2_t. We need to
* do a sorecvmsg with uiop sizeof (nca_io2_t). Based on that
* we should set so_priv->iop_more, and then do a sorecvmsg on
* user supplied uiop.
*/
xuiop.uio_loffset = 0;
lmsg.msg_namelen = 0;
lmsg.msg_controllen = 0;
if (error != 0)
return (error);
/* Couldn't read entire nca_io2_t. Something is wrong */
"nca_io2_t. Needed %d, read %d",
(int)sizeof (nca_io2_t),
return (EBADMSG);
}
if (error != 0) {
return (error);
}
} else {
}
lmsg.msg_namelen = 0;
lmsg.msg_controllen = 0;
if (error != 0) {
"data. error = %d", error);
return (error);
}
so_priv->iop_dataleft = 0;
}
} else {
if (error != 0) {
"data. error = %d", error);
return (error);
}
}
}
return (error);
}
/* ARGSUSED2 */
int
int ioflag,
struct caller_context *ct)
{
int error;
return (EPIPE);
}
if (error != 0) {
return (error);
}
}
(SS_ISCONNECTED|SS_ISBOUND)) {
return (ENOTCONN);
}
iop->trailer_len = 0;
iop->direct_len = 0;
#ifdef NCAFS_DEBUG
if (error != 0)
#endif
return (error);
}
int
{
switch (cmd) {
case NCA_BIND:
case NCA_LISTEN:
case NCA_READY:
/* Filter out internal ioctl()s used between NCA and NCAfs. */
return (EINVAL);
case I_PUSH:
case I_POP:
/*
* Prohibit popping "sockmod" or pushing a module above
* "sockfmod" for NCA sockets because NCAfs and NCA use
* a private M_CTL interface for data and no application
* using NCA (web servers) needs this feature.
*/
return (ENOTSUP);
}
}
static int
{
/*
* NCA doesn't support socket features like OOB data or bypassing
* the routing table. Reject anything except simple cases like
* "send(fd, msg, len, 0);".
*/
}
/*
* Return EINVAL instead of the more appropriate ENOTSUP because the
* later is not allowed as an error code returned by send(3SOCKET).
*/
return (EINVAL);
}
int
short events,
int anyyet,
short *reventsp,
{
short origevents = events;
short inevents;
int error;
#ifdef NCAFS_DEBUG
#endif
if (!(so_state & SS_ISCONNECTED)) {
/* Not connected yet - turn off write side events */
}
/*
* Check for errors without calling strpoll if the caller wants them.
* and there is no need to ask the stream head for this information.
*/
return (0);
}
/*
* Check if NCA has HTTP request data available or is expecting
* more HTTP request data.
*/
inevents = 0;
if (events == 0) {
return (0);
}
}
/*
* Caller only asked for inputs events and
* no more data is coming.
*/
return (0);
}
}
/*
* Ignore M_PROTO only messages such as the T_EXDATA_IND messages.
* will not trigger a POLLIN event with POLLRDDATA set.
* After shutdown(output) a stream head write error is set.
* However, we should not return output events.
*/
if (error != 0)
return (error);
return (0);
}
int
{
int error = 0;
goto done;
}
switch (how) {
case 0:
break;
case 2:
/* FALLTHRU */
case 1:
(void) nca_emptywrite(so, 0);
}
}
}
break;
default:
goto done;
}
done:
return (error);
}
/* ARGSUSED */
int
int flag,
int count,
{
int error = 0;
(void) nca_emptywrite(so, 0);
}
}
}
if (count > 1)
return (0);
/*
* Only call the close routine when the last open reference through
* any [s, v]node goes away.
*/
}
/*
* Decrement the device driver's reference count for streams
* opened via the clone dip. The driver was held in clone_open().
* The absence of clone_close() forces this asymmetry.
*/
return (error);
}
#define SEND_MAX_CHUNK 16
int
{
int error;
int sfd = -1;
int size;
return (EPROTONOSUPPORT);
return (EPIPE);
}
(SS_ISCONNECTED|SS_ISBOUND)) {
return (ENOTCONN);
}
iop->trailer_len = 0;
iop->direct_len = 0;
sizeof (uio_t) + /* uio */
sizeof (iovec_t); /* iov */
/*
* There are 2 possibilities -
*
* i) A request has a single file fd and multiple optional headers
* SFV_FD_SELF vector if no file fd is present or a single SFV_FD_SELF
* after a file fd. Request of this forms are processed as
* direct_type = NCA_IO_DIRECT_FILE_FD. nca_ncafs_srv() will
* make a single call to nca_httpd_data() to process this
* request.
*
* ii) All other requests containing more than 1 file fd are
* processed using direct_type of NCA_IO_SENDVEC. A special
* case here is 2 SFV_FD_SELF after a file fd.
*/
{
int i;
i < sfvcnt;
/* Header Chunks */
#ifdef DEBUG
if (nca_sendfilev_debug) {
char *ptr;
KM_SLEEP);
"error header "
"debug copyin");
goto fault;
}
"Header (%ld) is: %s",
}
#endif
/* There can only be one trailer */
} else {
direct_type = (sfd < 0) ?
"nca_sendfilev: "
"fd is %d, len = %d, off = %d\n",
goto badf;
goto acces;
}
}
}
uiop->uio_loffset = 0;
if (error != 0)
goto out;
}
/* NCA consumes all uio data unless an error occur */
}
out:
return (error);
goto out;
badf:
goto out;
goto out;
}
/* ARGSUSED */
static int
{
/*
* For AF_NCA type socket, the local address has already been updated
* in so_laddr_sa as part of accept.
*/
return (0);
}