patch-1.3.38 linux/net/unix/af_unix.c
Next file: linux/scripts/Configure
Previous file: linux/net/socket.c
Back to the patch index
Back to the overall index
- Lines: 428
- Date:
Mon Nov 6 13:46:28 1995
- Orig file:
v1.3.37/linux/net/unix/af_unix.c
- Orig date:
Sun Oct 29 11:38:50 1995
diff -u --recursive --new-file v1.3.37/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
@@ -19,9 +19,25 @@
* Carsten Paeth : PF_UNIX check, address fixes.
* Alan Cox : Limit size of allocated blocks.
* Alan Cox : Fixed the stupid socketpair bug.
+ * Alan Cox : BSD compatibility fine tuning.
+ *
+ *
+ * Known differences from reference BSD that was tested:
+ *
+ * [TO FIX]
+ * No fd passing yet.
+ * ECONNREFUSED is not returned from one end of a connected() socket to the
+ * other the moment one end closes.
+ * fstat() doesn't return st_dev=NODEV, and give the blksize as high water mark
+ * and a fake inode identifier (nor the BSD first socket fstat twice bug).
+ * [NOT TO FIX]
+ * accept() returns a path name even if the connecting socket has closed
+ * in the meantime (BSD loses the path and gives up).
+ * accept() returns 0 length path for an unbound connector. BSD returns 16
+ * and a null first byte in the path (but not for gethost/peername - BSD bug ??)
+ * socketpair(...SOCK_RAW..) doesnt panic the kernel.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/signal.h>
@@ -47,18 +63,18 @@
#include <net/af_unix.h>
#include <linux/proc_fs.h>
-static unix_socket * unix_socket_list=NULL;
+static unix_socket *unix_socket_list=NULL;
#define min(a,b) (((a)<(b))?(a):(b))
/*
* Make sure the unix name is null-terminated.
*/
-static inline void unix_mkname(struct sockaddr_un * sun, unsigned long len)
+static inline void unix_mkname(struct sockaddr_un * sunaddr, unsigned long len)
{
- if (len >= sizeof(*sun))
- len = sizeof(*sun)-1;
- ((char *)sun)[len]=0;
+ if (len >= sizeof(*sunaddr))
+ len = sizeof(*sunaddr)-1;
+ ((char *)sunaddr)[len]=0;
}
/*
@@ -72,14 +88,15 @@
unix_socket **s;
cli();
- s = &unix_socket_list;
+ s=&unix_socket_list;
while(*s!=NULL)
{
if(*s==sk)
{
*s=sk->next;
- break;
+ sti();
+ return;
}
s=&((*s)->next);
}
@@ -219,6 +236,8 @@
unix_socket *sk=sock->data;
if(sk->type!=SOCK_STREAM)
return -EOPNOTSUPP; /* Only stream sockets accept */
+ if(sk->protinfo.af_unix.name==NULL)
+ return -EINVAL; /* No listens on an unbound socket */
sk->max_ack_backlog=backlog;
sk->state=TCP_LISTEN;
return 0;
@@ -257,17 +276,23 @@
sk=(unix_socket *)kmalloc(sizeof(*sk),GFP_KERNEL);
if(sk==NULL)
return -ENOMEM;
- sk->type=sock->type;
switch(sock->type)
{
case SOCK_STREAM:
break;
+ /*
+ * Believe it or not BSD has AF_UNIX, SOCK_RAW though
+ * nothing uses it.
+ */
+ case SOCK_RAW:
+ sock->type=SOCK_DGRAM;
case SOCK_DGRAM:
break;
default:
kfree_s(sk,sizeof(*sk));
return -ESOCKTNOSUPPORT;
}
+ sk->type=sock->type;
init_timer(&sk->timer);
skb_queue_head_init(&sk->write_queue);
skb_queue_head_init(&sk->receive_queue);
@@ -334,9 +359,15 @@
skpair->state_change(skpair); /* Wake any blocked writes */
}
if(skpair!=NULL)
- skpair->protinfo.af_unix.locks--; /* It may now die */
- sk->protinfo.af_unix.other=NULL; /* No pair */
+ skpair->protinfo.af_unix.locks--; /* It may now die */
+ sk->protinfo.af_unix.other=NULL; /* No pair */
unix_destroy_socket(sk); /* Try and flush out this socket. Throw our buffers at least */
+
+ /*
+ * FIXME: BSD difference: In BSD all sockets connected to use get ECONNRESET and we die on the spot. In
+ * Linux we behave like files and pipes do and wait for the last dereference.
+ */
+
return 0;
}
@@ -370,14 +401,17 @@
static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
{
- struct sockaddr_un *sun=(struct sockaddr_un *)uaddr;
+ struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr;
unix_socket *sk=sock->data;
int old_fs;
int err;
- if(addr_len>sizeof(struct sockaddr_un) || addr_len<3 || sun->sun_family!=AF_UNIX)
+ if(sk->protinfo.af_unix.name)
+ return -EINVAL; /* Already bound */
+
+ if(addr_len>sizeof(struct sockaddr_un) || addr_len<3 || sunaddr->sun_family!=AF_UNIX)
return -EINVAL;
- unix_mkname(sun, addr_len);
+ unix_mkname(sunaddr, addr_len);
/*
* Put ourselves in the filesystem
*/
@@ -387,7 +421,7 @@
sk->protinfo.af_unix.name=kmalloc(addr_len+1, GFP_KERNEL);
if(sk->protinfo.af_unix.name==NULL)
return -ENOMEM;
- memcpy(sk->protinfo.af_unix.name, sun->sun_path, addr_len+1);
+ memcpy(sk->protinfo.af_unix.name, sunaddr->sun_path, addr_len+1);
old_fs=get_fs();
set_fs(get_ds());
@@ -415,7 +449,7 @@
static int unix_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags)
{
unix_socket *sk=sock->data;
- struct sockaddr_un *sun=(struct sockaddr_un *)uaddr;
+ struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr;
unix_socket *other;
struct sk_buff *skb;
int err;
@@ -437,10 +471,10 @@
return -EISCONN;
}
- if(addr_len < sizeof(sun->sun_family)+1 || sun->sun_family!=AF_UNIX)
+ if(addr_len < sizeof(sunaddr->sun_family)+1 || sunaddr->sun_family!=AF_UNIX)
return -EINVAL;
- unix_mkname(sun, addr_len);
+ unix_mkname(sunaddr, addr_len);
if(sk->type==SOCK_DGRAM && sk->protinfo.af_unix.other)
{
@@ -451,9 +485,11 @@
if(sock->type==SOCK_DGRAM)
{
- other=unix_find_other(sun->sun_path, &err);
+ other=unix_find_other(sunaddr->sun_path, &err);
if(other==NULL)
return err;
+ if(other->type!=sk->type)
+ return -EPROTOTYPE;
other->protinfo.af_unix.locks++;
sk->protinfo.af_unix.other=other;
sock->state=SS_CONNECTED;
@@ -474,13 +510,18 @@
skb->sk=sk; /* So they know it is us */
skb->free=1;
sk->state=TCP_CLOSE;
- unix_mkname(sun, addr_len);
- other=unix_find_other(sun->sun_path, &err);
+ unix_mkname(sunaddr, addr_len);
+ other=unix_find_other(sunaddr->sun_path, &err);
if(other==NULL)
{
kfree_skb(skb, FREE_WRITE);
return err;
}
+ if(other->type!=sk->type)
+ {
+ kfree_skb(skb, FREE_WRITE);
+ return -EPROTOTYPE;
+ }
other->protinfo.af_unix.locks++; /* Lock the other socket so it doesn't run off for a moment */
other->ack_backlog++;
sk->protinfo.af_unix.other=other;
@@ -614,7 +655,7 @@
static int unix_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer)
{
unix_socket *sk=sock->data;
- struct sockaddr_un *sun=(struct sockaddr_un *)uaddr;
+ struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr;
if(peer)
{
@@ -622,15 +663,15 @@
return -ENOTCONN;
sk=sk->protinfo.af_unix.other;
}
- sun->sun_family=AF_UNIX;
+ sunaddr->sun_family=AF_UNIX;
if(sk->protinfo.af_unix.name==NULL)
{
- *sun->sun_path=0;
- *uaddr_len=sizeof(sun->sun_family)+1;
+ *sunaddr->sun_path=0;
+ *uaddr_len=sizeof(sunaddr->sun_family)+1;
return 0; /* Not bound */
}
- *uaddr_len=sizeof(sun->sun_family)+strlen(sk->protinfo.af_unix.name)+1;
- strcpy(sun->sun_path,sk->protinfo.af_unix.name); /* 108 byte limited */
+ *uaddr_len=sizeof(sunaddr->sun_family)+strlen(sk->protinfo.af_unix.name)+1;
+ strcpy(sunaddr->sun_path,sk->protinfo.af_unix.name); /* 108 byte limited */
return 0;
}
@@ -638,25 +679,22 @@
{
unix_socket *sk=sock->data;
unix_socket *other;
- struct sockaddr_un *sun=msg->msg_name;
+ struct sockaddr_un *sunaddr=msg->msg_name;
int err,size;
struct sk_buff *skb;
int limit=0;
int sent=0;
if(sk->err)
- {
- cli();
- err=sk->err;
- sk->err=0;
- sti();
- return -err;
- }
-
+ return sock_error(sk);
+
+ if(flags&MSG_OOB)
+ return -EOPNOTSUPP;
+
if(flags || msg->msg_accrights) /* For now */
return -EINVAL;
- if(sun!=NULL)
+ if(sunaddr!=NULL)
{
if(sock->type==SOCK_STREAM)
{
@@ -666,7 +704,7 @@
return -EOPNOTSUPP;
}
}
- if(sun==NULL)
+ if(sunaddr==NULL)
{
if(sk->protinfo.af_unix.other==NULL)
return -ENOTCONN;
@@ -722,7 +760,7 @@
memcpy_fromiovec(skb_put(skb,size),msg->msg_iov, size);
cli();
- if(sun==NULL)
+ if(sunaddr==NULL)
{
other=sk->protinfo.af_unix.other;
if(sock->type==SOCK_DGRAM && other->dead)
@@ -739,8 +777,8 @@
}
else
{
- unix_mkname(sun, msg->msg_namelen);
- other=unix_find_other(sun->sun_path, &err);
+ unix_mkname(sunaddr, msg->msg_namelen);
+ other=unix_find_other(sunaddr->sun_path, &err);
if(other==NULL)
{
kfree_skb(skb, FREE_WRITE);
@@ -762,8 +800,7 @@
static int unix_recvmsg(struct socket *sock, struct msghdr *msg, int size, int noblock, int flags, int *addr_len)
{
unix_socket *sk=sock->data;
- struct sockaddr_un *sun=msg->msg_name;
- int err;
+ struct sockaddr_un *sunaddr=msg->msg_name;
struct sk_buff *skb;
int copied=0;
unsigned char *sp;
@@ -772,17 +809,14 @@
struct iovec *iov=msg->msg_iov;
int ct=msg->msg_iovlen;
+ if(flags&MSG_OOB)
+ return -EOPNOTSUPP;
+
if(addr_len)
*addr_len=0;
if(sk->err)
- {
- cli();
- err=sk->err;
- sk->err=0;
- sti();
- return -err;
- }
+ return sock_error(sk);
/* printk("get rcv sem\n");*/
down(&sk->protinfo.af_unix.readsem); /* Lock the socket */
@@ -838,12 +872,12 @@
}
if(msg->msg_name!=NULL)
{
- sun->sun_family=AF_UNIX;
+ sunaddr->sun_family=AF_UNIX;
if(skb->sk->protinfo.af_unix.name)
{
- memcpy(sun->sun_path, skb->sk->protinfo.af_unix.name, 108);
+ memcpy(sunaddr->sun_path, skb->sk->protinfo.af_unix.name, 108);
if(addr_len)
- *addr_len=strlen(sun->sun_path)+sizeof(short);
+ *addr_len=strlen(sunaddr->sun_path)+sizeof(short);
}
else
if(addr_len)
@@ -989,64 +1023,6 @@
return len;
}
-/*
- * For AF_UNIX we flip everything into an iovec. If this doesnt do any speed harm then it will
- * be easier for all the low levels to be totally iovec based.
- */
-
-static int unix_recvfrom(struct socket *sock, void *ubuf, int size, int noblock, unsigned flags,
- struct sockaddr *sa, int *addr_len)
-{
- struct iovec iov;
- struct msghdr msg;
- iov.iov_base=ubuf;
- iov.iov_len=size;
- msg.msg_name=(void *)sa;
- msg.msg_namelen=0;
- if (addr_len)
- msg.msg_namelen = *addr_len;
- msg.msg_accrights=NULL;
- msg.msg_iov=&iov;
- msg.msg_iovlen=1;
- return unix_recvmsg(sock,&msg,size,noblock,flags,addr_len);
-}
-
-static int unix_read(struct socket *sock, char *ubuf, int size, int noblock)
-{
- return unix_recvfrom(sock,ubuf,size,noblock,0,NULL,NULL);
-}
-
-static int unix_recv(struct socket *sock, void *ubuf, int size, int noblock, unsigned int flags)
-{
- return unix_recvfrom(sock,ubuf,size,noblock,flags,NULL,NULL);
-}
-
-static int unix_sendto(struct socket *sock, const void *ubuf, int size, int noblock, unsigned flags,
- struct sockaddr *sa, int addr_len)
-{
- struct iovec iov;
- struct msghdr msg;
- iov.iov_base=(void *)ubuf;
- iov.iov_len=size;
- msg.msg_name=(void *)sa;
- msg.msg_namelen=addr_len;
- msg.msg_accrights=NULL;
- msg.msg_iov=&iov;
- msg.msg_iovlen=1;
- return unix_sendmsg(sock,&msg,size,noblock,flags);
-}
-
-static int unix_write(struct socket *sock, const char *ubuf, int size, int noblock)
-{
- return unix_sendto(sock,ubuf,size,noblock, 0, NULL, 0);
-}
-
-static int unix_send(struct socket *sock, const void *ubuf, int size, int noblock, unsigned int flags)
-{
- return unix_sendto(sock,ubuf,size,noblock, flags, NULL, 0);
-}
-
-
static struct proto_ops unix_proto_ops = {
AF_UNIX,
@@ -1058,15 +1034,9 @@
unix_socketpair,
unix_accept,
unix_getname,
- unix_read,
- unix_write,
unix_select,
unix_ioctl,
unix_listen,
- unix_send,
- unix_recv,
- unix_sendto,
- unix_recvfrom,
unix_shutdown,
unix_setsockopt,
unix_getsockopt,
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this