/* initialise a nbt_dgram_socket. The event_ctx is optional, if provided then operations will use that event context */ struct nbt_dgram_socket *nbt_dgram_socket_init(TALLOC_CTX *mem_ctx, struct tevent_context *event_ctx) { struct nbt_dgram_socket *dgmsock; NTSTATUS status; dgmsock = talloc(mem_ctx, struct nbt_dgram_socket); if (dgmsock == NULL) goto failed; dgmsock->event_ctx = event_ctx; if (dgmsock->event_ctx == NULL) goto failed; status = socket_create("ip", SOCKET_TYPE_DGRAM, &dgmsock->sock, 0); if (!NT_STATUS_IS_OK(status)) goto failed; socket_set_option(dgmsock->sock, "SO_BROADCAST", "1"); talloc_steal(dgmsock, dgmsock->sock); dgmsock->fde = tevent_add_fd(dgmsock->event_ctx, dgmsock, socket_get_fd(dgmsock->sock), 0, dgm_socket_handler, dgmsock); dgmsock->send_queue = NULL; dgmsock->incoming.handler = NULL; dgmsock->mailslot_handlers = NULL; return dgmsock; failed: talloc_free(dgmsock); return NULL; }
static NTSTATUS ipv6_listen(struct socket_context *sock, const struct socket_address *my_address, int queue_size, uint32_t flags) { struct sockaddr_in6 my_addr; struct in6_addr ip_addr; int ret; socket_set_option(sock, "SO_REUSEADDR=1", NULL); if (my_address->sockaddr) { ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen); } else { int one = 1; ip_addr = interpret_addr6(my_address->addr); ZERO_STRUCT(my_addr); my_addr.sin6_addr = ip_addr; my_addr.sin6_port = htons(my_address->port); my_addr.sin6_family = PF_INET6; fix_scope_id(&my_addr, my_address->addr); /* when binding on ipv6 we always want to only bind on v6 */ ret = setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, (const void *)&one, sizeof(one)); if (ret != -1) { ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr)); } } if (ret == -1) { return map_nt_error_from_unix_common(errno); } if (sock->type == SOCKET_TYPE_STREAM) { ret = listen(sock->fd, queue_size); if (ret == -1) { return map_nt_error_from_unix_common(errno); } } if (!(flags & SOCKET_FLAG_BLOCK)) { ret = set_blocking(sock->fd, false); if (ret == -1) { return map_nt_error_from_unix_common(errno); } } sock->state= SOCKET_STATE_SERVER_LISTEN; return NT_STATUS_OK; }
/* note that for simplicity of the API, socket_listen() is also use for DGRAM sockets, but in reality only a bind() is done */ static NTSTATUS ipv4_listen(struct socket_context *sock, const struct socket_address *my_address, int queue_size, uint32_t flags) { struct sockaddr_in my_addr; struct in_addr ip_addr; int ret; socket_set_option(sock, "SO_REUSEADDR=1", NULL); if (my_address->sockaddr) { ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen); } else { ip_addr = interpret_addr2(my_address->addr); ZERO_STRUCT(my_addr); #ifdef HAVE_SOCK_SIN_LEN my_addr.sin_len = sizeof(my_addr); #endif my_addr.sin_addr.s_addr = ip_addr.s_addr; my_addr.sin_port = htons(my_address->port); my_addr.sin_family = PF_INET; ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr)); } if (ret == -1) { return map_nt_error_from_unix_common(errno); } if (sock->type == SOCKET_TYPE_STREAM) { ret = listen(sock->fd, queue_size); if (ret == -1) { return map_nt_error_from_unix_common(errno); } } if (!(flags & SOCKET_FLAG_BLOCK)) { ret = set_blocking(sock->fd, false); if (ret == -1) { return map_nt_error_from_unix_common(errno); } } sock->state= SOCKET_STATE_SERVER_LISTEN; return NT_STATUS_OK; }
/* setup a listen stream socket if you pass *port == 0, then a port > 1024 is used FIXME: This function is TCP/IP specific - uses an int rather than a string for the port. Should leave allocating a port nr to the socket implementation - JRV20070903 */ NTSTATUS stream_setup_socket(TALLOC_CTX *mem_ctx, struct tevent_context *event_context, struct loadparm_context *lp_ctx, const struct model_ops *model_ops, const struct stream_server_ops *stream_ops, const char *family, const char *sock_addr, uint16_t *port, const char *socket_options, void *private_data) { NTSTATUS status; struct stream_socket *stream_socket; struct socket_address *socket_address; struct tevent_fd *fde; int i; struct sockaddr_storage ss; stream_socket = talloc_zero(mem_ctx, struct stream_socket); NT_STATUS_HAVE_NO_MEMORY(stream_socket); if (strcmp(family, "ip") == 0) { /* we will get the real family from the address itself */ if (!interpret_string_addr(&ss, sock_addr, 0)) { talloc_free(stream_socket); return NT_STATUS_INVALID_ADDRESS; } socket_address = socket_address_from_sockaddr_storage(stream_socket, &ss, port?*port:0); NT_STATUS_HAVE_NO_MEMORY_AND_FREE(socket_address, stream_socket); status = socket_create(socket_address->family, SOCKET_TYPE_STREAM, &stream_socket->sock, 0); NT_STATUS_NOT_OK_RETURN(status); } else { status = socket_create(family, SOCKET_TYPE_STREAM, &stream_socket->sock, 0); NT_STATUS_NOT_OK_RETURN(status); /* this is for non-IP sockets, eg. unix domain sockets */ socket_address = socket_address_from_strings(stream_socket, stream_socket->sock->backend_name, sock_addr, port?*port:0); NT_STATUS_HAVE_NO_MEMORY(socket_address); } talloc_steal(stream_socket, stream_socket->sock); stream_socket->lp_ctx = talloc_reference(stream_socket, lp_ctx); /* ready to listen */ status = socket_set_option(stream_socket->sock, "SO_KEEPALIVE", NULL); NT_STATUS_NOT_OK_RETURN(status); if (socket_options != NULL) { status = socket_set_option(stream_socket->sock, socket_options, NULL); NT_STATUS_NOT_OK_RETURN(status); } /* TODO: set socket ACL's (host allow etc) here when they're * implemented */ /* Some sockets don't have a port, or are just described from * the string. We are indicating this by having port == NULL */ if (!port) { status = socket_listen(stream_socket->sock, socket_address, SERVER_LISTEN_BACKLOG, 0); } else if (*port == 0) { for (i=SERVER_TCP_LOW_PORT;i<= SERVER_TCP_HIGH_PORT;i++) { socket_address->port = i; status = socket_listen(stream_socket->sock, socket_address, SERVER_LISTEN_BACKLOG, 0); if (NT_STATUS_IS_OK(status)) { *port = i; break; } } } else { status = socket_listen(stream_socket->sock, socket_address, SERVER_LISTEN_BACKLOG, 0); } if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Failed to listen on %s:%u - %s\n", sock_addr, port ? (unsigned int)(*port) : 0, nt_errstr(status))); talloc_free(stream_socket); return status; } /* Add the FD from the newly created socket into the event * subsystem. it will call the accept handler whenever we get * new connections */ fde = tevent_add_fd(event_context, stream_socket->sock, socket_get_fd(stream_socket->sock), TEVENT_FD_READ, stream_accept_handler, stream_socket); if (!fde) { DEBUG(0,("Failed to setup fd event\n")); talloc_free(stream_socket); return NT_STATUS_NO_MEMORY; } /* we let events system to the close on the socket. This avoids * nasty interactions with waiting for talloc to close the socket. */ tevent_fd_set_close_fn(fde, socket_tevent_fd_close_fn); socket_set_flags(stream_socket->sock, SOCKET_FLAG_NOCLOSE); stream_socket->private_data = talloc_reference(stream_socket, private_data); stream_socket->ops = stream_ops; stream_socket->event_ctx = event_context; stream_socket->model_ops = model_ops; return NT_STATUS_OK; }
void set_option(const OPTION& opt) { static_assert(is_option<OPTION>::VALUE, "you must specify a valid option"); socket_set_option(hdl, OPTION::NAME, reinterpret_cast<const void*>(&opt.value), sizeof(opt.value)); }