pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service) { pa_socket_server *ss; int fd = -1; struct sockaddr_in sa; int on = 1; pa_assert(m); pa_assert(port); if ((fd = pa_socket_cloexec(PF_INET, SOCK_STREAM, 0)) < 0) { pa_log("socket(PF_INET): %s", pa_cstrerror(errno)); goto fail; } #ifdef SO_REUSEADDR if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *) &on, sizeof(on)) < 0) pa_log("setsockopt(): %s", pa_cstrerror(errno)); #endif pa_make_tcp_socket_low_delay(fd); memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_port = htons(port); sa.sin_addr.s_addr = htonl(address); if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { if (errno == EADDRINUSE && fallback) { sa.sin_port = 0; if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) >= 0) goto good; } pa_log("bind(): %s", pa_cstrerror(errno)); goto fail; good: ; } if (listen(fd, 5) < 0) { pa_log("listen(): %s", pa_cstrerror(errno)); goto fail; } if ((ss = pa_socket_server_new(m, fd))) { ss->type = SOCKET_SERVER_IPV4; ss->tcpwrap_service = pa_xstrdup(tcpwrap_service); } return ss; fail: if (fd >= 0) pa_close(fd); return NULL; }
static int do_write(struct userdata *u) { ssize_t r; pa_assert(u); if (!pa_iochannel_is_writable(u->io)) return 0; if (u->write_data) { pa_assert(u->write_index < u->write_length); if ((r = pa_iochannel_write(u->io, (uint8_t*) u->write_data + u->write_index, u->write_length - u->write_index)) <= 0) { pa_log("write() failed: %s", pa_cstrerror(errno)); return -1; } u->write_index += (size_t) r; pa_assert(u->write_index <= u->write_length); if (u->write_index == u->write_length) { pa_xfree(u->write_data); u->write_data = NULL; u->write_index = u->write_length = 0; } } if (!u->write_data && u->state == STATE_PREPARE) { int so_sndbuf = 0; socklen_t sl = sizeof(int); /* OK, we're done with sending all control data we need to, so * let's hand the socket over to the IO thread now */ pa_assert(u->fd < 0); u->fd = pa_iochannel_get_send_fd(u->io); pa_iochannel_set_noclose(u->io, TRUE); pa_iochannel_free(u->io); u->io = NULL; pa_make_tcp_socket_low_delay(u->fd); if (getsockopt(u->fd, SOL_SOCKET, SO_SNDBUF, &so_sndbuf, &sl) < 0) pa_log_warn("getsockopt(SO_SNDBUF) failed: %s", pa_cstrerror(errno)); else { pa_log_debug("SO_SNDBUF is %zu.", (size_t) so_sndbuf); pa_sink_set_max_request(u->sink, PA_MAX((size_t) so_sndbuf, u->block_size)); } pa_log_debug("Connection authenticated, handing fd to IO thread..."); pa_asyncmsgq_post(u->thread_mq.inq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_PASS_SOCKET, NULL, 0, NULL, NULL); u->state = STATE_RUNNING; } return 0; }
static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { pa_socket_server *s = userdata; pa_iochannel *io; int nfd; pa_assert(s); pa_assert(PA_REFCNT_VALUE(s) >= 1); pa_assert(s->mainloop == mainloop); pa_assert(s->io_event == e); pa_assert(e); pa_assert(fd >= 0); pa_assert(fd == s->fd); pa_socket_server_ref(s); if ((nfd = pa_accept_cloexec(fd, NULL, NULL)) < 0) { pa_log("accept(): %s", pa_cstrerror(errno)); goto finish; } if (!s->on_connection) { pa_close(nfd); goto finish; } #ifdef HAVE_LIBWRAP if (s->tcpwrap_service) { struct request_info req; request_init(&req, RQ_DAEMON, s->tcpwrap_service, RQ_FILE, nfd, NULL); fromhost(&req); if (!hosts_access(&req)) { pa_log_warn("TCP connection refused by tcpwrap."); pa_close(nfd); goto finish; } pa_log_info("TCP connection accepted by tcpwrap."); } #endif /* There should be a check for socket type here */ if (s->type == SOCKET_SERVER_IPV4) pa_make_tcp_socket_low_delay(fd); else pa_make_socket_low_delay(fd); pa_assert_se(io = pa_iochannel_new(s->mainloop, nfd, nfd)); s->on_connection(s, io, s->userdata); finish: pa_socket_server_unref(s); }