/* * to do a socketpair, we make just connect the two datas, easy! since we * always wait on the socket inode, they're no contention for a wait area, * and deadlock prevention in the case of a process writing to itself is, * ignored, in true unix fashion! */ static int unix_proto_socketpair(struct socket *sock1, struct socket *sock2) { struct unix_proto_data *upd1 = UN_DATA(sock1), *upd2 = UN_DATA(sock2); unix_data_ref(upd1); unix_data_ref(upd2); upd1->peerupd = upd2; upd2->peerupd = upd1; return 0; }
/* * perform a connection. we can only connect to unix sockets (i can't for * the life of me find an application where that wouldn't be the case!) */ static int unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr, int sockaddr_len) { int i; struct unix_proto_data *serv_upd; struct sockaddr_un sockun; PRINTK("unix_proto_connect: socket 0x%x, servlen=%d\n", sock, sockaddr_len); if (sockaddr_len <= UN_PATH_OFFSET || sockaddr_len >= sizeof(struct sockaddr_un)) { PRINTK("unix_proto_connect: bad length %d\n", sockaddr_len); return -EINVAL; } verify_area(uservaddr, sockaddr_len); memcpy_fromfs(&sockun, uservaddr, sockaddr_len); if (sockun.sun_family != AF_UNIX) { PRINTK("unix_proto_connect: family is %d, not AF_UNIX (%d)\n", sockun.sun_family, AF_UNIX); return -EINVAL; } if (!(serv_upd = unix_data_lookup(&sockun, sockaddr_len))) { PRINTK("unix_proto_connect: can't locate peer\n"); return -EINVAL; } if ((i = sock_awaitconn(sock, serv_upd->socket)) < 0) { PRINTK("unix_proto_connect: can't await connection\n"); return i; } unix_data_ref(UN_DATA(sock->conn)); UN_DATA(sock)->peerupd = UN_DATA(sock->conn); /* ref server */ return 0; }
static int unix_connect(struct socket *sock, struct sockaddr *uservaddr, int sockaddr_len, int flags) { char fname[sizeof(((struct sockaddr_un *) 0)->sun_path) + 1]; struct sockaddr_un sockun; struct unix_proto_data *serv_upd; struct inode *inode; unsigned short old_ds; int i; if (sockaddr_len <= 0 || sockaddr_len > sizeof(struct sockaddr_un)) return -EINVAL; if (sock->state == SS_CONNECTING) return -EINPROGRESS; if (sock->state == SS_CONNECTED) return -EISCONN; memcpy(&sockun, uservaddr, sockaddr_len); sockun.sun_path[sockaddr_len] = '\0'; if (sockun.sun_family != AF_UNIX) return -EINVAL; /* * Try to open the name in the filesystem - this is how we identify ourselves * and our server. Note that we don't hold onto the inode much, just enough to * find our server. When we're connected, we mooch off the server. */ memcpy(fname, sockun.sun_path, sockaddr_len); fname[sockaddr_len] = '\0'; old_ds = current->t_regs.ds; current->t_regs.ds = get_ds(); i = open_namei(fname, 2, S_IFSOCK, &inode, NULL); current->t_regs.ds = old_ds; if (i < 0) return i; serv_upd = unix_data_lookup(&sockun, sockaddr_len, inode); iput(inode); if (!serv_upd) return -EINVAL; if ((i = sock_awaitconn(sock, serv_upd->socket, flags)) < 0) return i; if (sock->conn) { unix_data_ref(UN_DATA(sock->conn)); UN_DATA(sock)->peerupd = UN_DATA(sock->conn); /* ref server */ } return 0; }
/* * on accept, we ref the peer's data for safe writes */ static int unix_proto_accept(struct socket *sock, struct socket *newsock) { PRINTK("unix_proto_accept: socket 0x%x accepted via socket 0x%x\n", sock, newsock); unix_data_ref(UN_DATA(newsock->conn)); UN_DATA(newsock)->peerupd = UN_DATA(newsock->conn); return 0; }
static int unix_accept(struct socket *sock, struct socket *newsock, int flags) { struct socket *clientsock; /* * If there aren't any sockets awaiting connection, * then wait for one, unless nonblocking. */ while (!(clientsock = sock->iconn)) { if (flags & O_NONBLOCK) return -EAGAIN; sock->flags |= SO_WAITDATA; interruptible_sleep_on(sock->wait); sock->flags &= ~SO_WAITDATA; if (current->signal /* & ~current->blocked */ ) return -ERESTARTSYS; } /* * Great. Finish the connection relative to server and client, * wake up the client and return the new fd to the server. */ sock->iconn = clientsock->next; clientsock->next = NULL; newsock->conn = clientsock; clientsock->conn = newsock; clientsock->state = SS_CONNECTED; newsock->state = SS_CONNECTED; unix_data_ref(UN_DATA(clientsock)); UN_DATA(newsock)->peerupd = UN_DATA(clientsock); UN_DATA(newsock)->sockaddr_un = UN_DATA(sock)->sockaddr_un; UN_DATA(newsock)->sockaddr_len = UN_DATA(sock)->sockaddr_len; wake_up_interruptible(clientsock->wait); #if 0 sock_wake_async(clientsock, 0); /* Don't need */ #endif return 0; }
/* * on accept, we ref the peer's data for safe writes */ static int unix_proto_accept(struct socket *sock, struct socket *newsock, int flags) { struct socket *clientsock; PRINTK("unix_proto_accept: socket 0x%x accepted via socket 0x%x\n", sock, newsock); /* * if there aren't any sockets awaiting connection, then wait for * one, unless nonblocking */ while (!(clientsock = sock->iconn)) { if (flags & O_NONBLOCK) return -EAGAIN; interruptible_sleep_on(sock->wait); if (current->signal & ~current->blocked) { PRINTK("sys_accept: sleep was interrupted\n"); return -ERESTARTSYS; } } /* * great. finish the connection relative to server and client, * wake up the client and return the new fd to the server */ sock->iconn = clientsock->next; clientsock->next = NULL; newsock->conn = clientsock; clientsock->conn = newsock; clientsock->state = SS_CONNECTED; newsock->state = SS_CONNECTED; wake_up(clientsock->wait); unix_data_ref (UN_DATA(newsock->conn)); UN_DATA(newsock)->peerupd = UN_DATA(newsock->conn); return 0; }