/* Return a new connection from a socket previously listened. */ error_t S_socket_accept (struct sock_user *user, mach_port_t *port, mach_msg_type_name_t *port_type, mach_port_t *peer_addr_port, mach_msg_type_name_t *peer_addr_port_type) { error_t err; struct sock *sock; if (!user) return EOPNOTSUPP; sock = user->sock; err = ensure_connq (sock); if (!err) { struct timespec noblock = {0, 0}; struct sock *peer_sock; err = connq_listen (sock->listen_queue, (sock->flags & PFLOCAL_SOCK_NONBLOCK) ? &noblock : NULL, &peer_sock); if (!err) { struct addr *peer_addr; *port_type = MACH_MSG_TYPE_MAKE_SEND; err = sock_create_port (peer_sock, port); if (!err) err = sock_get_addr (peer_sock, &peer_addr); if (!err) { *peer_addr_port = ports_get_right (peer_addr); *peer_addr_port_type = MACH_MSG_TYPE_MAKE_SEND; ports_port_deref (peer_addr); } else { /* TEAR DOWN THE CONNECTION XXX */ } } } return err; }
int make_server(const char *host, const char *port) { struct sockaddr addr; int fd; int ret; ret = sock_get_addr(host, port, &addr); if(ret < 0) { return -1; } fd = sock_server_create(&addr); if(fd < 0) { return -1; } return fd; }
/* Find out the name of a socket. */ error_t S_socket_name (struct sock_user *user, mach_port_t *addr_port, mach_msg_type_name_t *addr_port_type) { error_t err; struct addr *addr; if (!user) return EOPNOTSUPP; err = sock_get_addr (user->sock, &addr); if (err) return err; *addr_port = ports_get_right (addr); *addr_port_type = MACH_MSG_TYPE_MAKE_SEND; ports_port_deref (addr); return 0; }
int node_connect(int link, struct node *local_node, struct node *remote_node) { int fd; int ret; struct sockaddr local_addr; struct sockaddr remote_addr; struct sock_packet *sock_pkt; fd_set rset; fd_set wset; struct timeval tv; int error; int len; if(link == NODE_DATA_LINK && remote_node->data_conn_state == NODE_DFD_CONNECTED) { return 0; } if(link == NODE_META_LINK && remote_node->meta_conn_state == NODE_MFD_CONNECTED) { return 0; } fd = sock_create(); if(fd < 0) { return -1; } if(sock_get_addr(local_node->remote_ip, NULL, &local_addr) < 0) { goto err; } if(sock_get_addr(remote_node->remote_ip, remote_node->remote_port, &remote_addr) < 0) { goto err; } if(sock_bind(fd, &local_addr) < 0) { goto err; } sock_set_nonblock(fd); ret = sock_connect(fd, &remote_addr); if(ret < 0 && errno != EINPROGRESS) { goto err; } else if(ret == 0) { goto done; } else { FD_ZERO(&rset); FD_SET(fd, &rset); wset = rset; tv.tv_sec = SOCK_TIMEOUT; tv.tv_usec = 0; ret = select(SELECT_MAX_FDS, &rset, &wset, NULL, &tv); if(ret <= 0) { goto err; } error = 0; len = sizeof(int); if(FD_ISSET(fd, &rset) || FD_ISSET(fd, &wset)) { if(getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { goto err; } } if(error) { goto err; } goto done; } done: if(link == NODE_DATA_LINK) { sock_pkt = create_sock_packet(local_node->id, DATA_HANDSHAKE); } else if(link == NODE_META_LINK) { sock_pkt = create_sock_packet(local_node->id, META_HANDSHAKE); } else { goto err; } if(sock_pkt == NULL) { goto err; } sock_clear_nonblock(fd); sock_packet_send(fd, sock_pkt); free_sock_packet(sock_pkt); if(link == NODE_DATA_LINK) { remote_node->dfd = fd; } else if(link == NODE_META_LINK) { remote_node->mfd = fd; } return 0; err: sock_close(fd); return -1; }
/* Send data over a socket, possibly including Mach ports. */ error_t S_socket_send (struct sock_user *user, struct addr *dest_addr, int flags, char *data, size_t data_len, mach_port_t *ports, size_t num_ports, char *control, size_t control_len, size_t *amount) { error_t err = 0; struct pipe *pipe; struct sock *sock, *dest_sock; struct addr *source_addr; if (!user) return EOPNOTSUPP; sock = user->sock; if (flags & MSG_OOB) /* BSD local sockets don't support OOB data. */ return EOPNOTSUPP; if (dest_addr) { err = addr_get_sock (dest_addr, &dest_sock); if (err == EADDRNOTAVAIL) /* The server went away. */ err = ECONNREFUSED; if (err) return err; if (sock->pipe_class != dest_sock->pipe_class) /* Sending to a different type of socket! */ err = EINVAL; /* ? XXX */ } else dest_sock = 0; /* We could provide a source address for all writes, but we only do so for connectionless sockets because that's the only place it's required, and it's more efficient not to. */ if (!err && sock->pipe_class->flags & PIPE_CLASS_CONNECTIONLESS) err = sock_get_addr (sock, &source_addr); else source_addr = NULL; if (!err) { if (dest_sock) /* Grab the destination socket's read pipe directly, and stuff data into it. This is not quite the usage sock_acquire_read_pipe was intended for, but it will work, as the only inappropriate errors occur on a broken pipe, which shouldn't be possible with the sort of sockets with which we can use socket_send... XXXX */ err = sock_acquire_read_pipe (dest_sock, &pipe); else /* No address, must be a connected socket... */ err = sock_acquire_write_pipe (sock, &pipe); if (!err) { err = pipe_send (pipe, sock->flags & PFLOCAL_SOCK_NONBLOCK, source_addr, data, data_len, control, control_len, ports, num_ports, amount); if (dest_sock) pipe_release_reader (pipe); else pipe_release_writer (pipe); } if (err) /* The send failed, so free any resources it would have consumed (mig gets rid of memory, but we have to do everything else). */ { if (source_addr) ports_port_deref (source_addr); while (num_ports-- > 0) mach_port_deallocate (mach_task_self (), *ports++); } } if (dest_sock) sock_deref (dest_sock); return err; }