patch-1.3.63 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: 144
- Date:
Tue Feb 13 17:16:52 1996
- Orig file:
v1.3.62/linux/net/unix/af_unix.c
- Orig date:
Fri Feb 9 17:53:13 1996
diff -u --recursive --new-file v1.3.62/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
@@ -677,6 +677,9 @@
return 0;
}
+/* if msg->accrights != NULL, we have fds to pass.
+ * Current implementation passes at most one fd.
+ */
static int unix_sendmsg(struct socket *sock, struct msghdr *msg, int len, int nonblock, int flags)
{
unix_socket *sk=sock->data;
@@ -686,6 +689,8 @@
struct sk_buff *skb;
int limit=0;
int sent=0;
+ /* for passing fd, NULL indicates no fd */
+ struct file *filp;
if(sk->err)
return sock_error(sk);
@@ -693,7 +698,7 @@
if(flags&MSG_OOB)
return -EOPNOTSUPP;
- if(flags || msg->msg_accrights) /* For now */
+ if(flags) /* For now */
return -EINVAL;
if(sunaddr!=NULL)
@@ -706,6 +711,7 @@
return -EOPNOTSUPP;
}
}
+
if(sunaddr==NULL)
{
if(sk->protinfo.af_unix.other==NULL)
@@ -713,6 +719,26 @@
}
+ /* see if we want to access rights (fd) -- at the moment,
+ * we can pass none or 1 fd
+ */
+ filp = NULL;
+ if(msg->msg_accrights) {
+ /* then accrightslen is meaningful */
+ if(msg->msg_accrightslen == sizeof(int)) {
+ int fd;
+
+ fd = get_user_long(msg->msg_accrights);
+ filp = file_from_fd(fd);
+ if(!filp)
+ return -EBADF;
+ } else if(msg->msg_accrightslen != 0) {
+ /* if we have accrights, we fail here */
+ return -EINVAL;
+ }
+ }
+
+ /* invariant -- flip points to a file to pass or NULL */
while(sent < len)
{
/*
@@ -792,8 +818,16 @@
return err;
}
}
+ /* at this point, we want to add an fd if we have one */
+ skb->h.filp = filp;
+ if (filp) {
+ filp->f_count++;
+ }
+
skb_queue_tail(&other->receive_queue, skb);
sti();
+ /* if we sent an fd, only do it once */
+ filp = NULL;
other->data_ready(other,size);
sent+=size;
}
@@ -815,6 +849,36 @@
sti();
}
+
+/*
+ * return 0 if we can stick the fd, negative errno if we can't
+ */
+static int stick_fd(struct file *filp, int *uaddr, int size)
+{
+ int slot;
+ int upper_bound;
+
+ if (!uaddr || size < sizeof(int))
+ return -EINVAL;
+
+ upper_bound = current->rlim[RLIMIT_NOFILE].rlim_cur;
+
+ if (upper_bound > NR_OPEN)
+ upper_bound = NR_OPEN;
+
+ for (slot = 0; slot < upper_bound; slot++) {
+ if (current->files->fd[slot])
+ continue;
+ /* have an fd */
+ current->files->fd[slot] = filp;
+ FD_CLR(slot, ¤t->files->close_on_exec);
+ /* need verify area here? */
+ put_user_long(slot, uaddr);
+ return 0;
+ }
+ return -EMFILE;
+}
+
static int unix_recvmsg(struct socket *sock, struct msghdr *msg, int size, int noblock, int flags, int *addr_len)
{
unix_socket *sk=sock->data;
@@ -826,7 +890,8 @@
int num;
struct iovec *iov=msg->msg_iov;
int ct=msg->msg_iovlen;
-
+ struct file *filp;
+
if(flags&MSG_OOB)
return -EOPNOTSUPP;
@@ -879,8 +944,16 @@
if(addr_len)
*addr_len=sizeof(short);
}
+
num=min(skb->len,size-copied);
memcpy_tofs(sp, skb->data, num);
+
+ if ((filp = skb->h.filp) != NULL) {
+ skb->h.filp = NULL;
+ if (stick_fd(filp, msg->msg_accrights, msg->msg_accrightslen) < 0)
+ close_fp(filp);
+ }
+
copied+=num;
done+=num;
sp+=num;
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