static void network_handle_accept(void *opaque) { Socket *server_socket = opaque; Socket *client_socket; struct sockaddr_storage address; socklen_t length = sizeof(address); char hostname[NI_MAXHOST]; char port[NI_MAXSERV]; char buffer[NI_MAXHOST + NI_MAXSERV + 4]; // 4 == strlen("[]:") + 1 char *name = "<unknown>"; Client *client; // accept new client socket client_socket = socket_accept(server_socket, (struct sockaddr *)&address, &length); if (client_socket == NULL) { if (!errno_interrupted()) { log_error("Could not accept new client socket: %s (%d)", get_errno_name(errno), errno); } return; } if (socket_address_to_hostname((struct sockaddr *)&address, length, hostname, sizeof(hostname), port, sizeof(port)) < 0) { log_warn("Could not get hostname and port of client (socket: %d): %s (%d)", client_socket->base.handle, get_errno_name(errno), errno); } else { if (address.ss_family == AF_INET6) { snprintf(buffer, sizeof(buffer), "[%s]:%s", hostname, port); } else { snprintf(buffer, sizeof(buffer), "%s:%s", hostname, port); } name = buffer; } // create new client client = network_create_client(name, &client_socket->base); if (client == NULL) { socket_destroy(client_socket); free(client_socket); return; } #ifdef BRICKD_WITH_RED_BRICK client_send_red_brick_enumerate(client, ENUMERATION_TYPE_CONNECTED); #endif }
void mesh_handle_accept(void *opaque) { char port[NI_MAXSERV]; char *name = "<unknown>"; char hostname[NI_MAXHOST]; Socket *mesh_client_socket; // Socket that is created to the root node of a mesh network. struct sockaddr_storage address; socklen_t length = sizeof(address); Socket *mesh_listen_socket = opaque; char buffer[NI_MAXHOST + NI_MAXSERV + 4]; log_info("New connection on mesh port"); // Accept new mesh client socket. mesh_client_socket = socket_accept(mesh_listen_socket, (struct sockaddr *)&address, &length); if (mesh_client_socket == NULL) { if (!errno_interrupted()) { log_error("Failed to accept new mesh client connection: %s (%d)", get_errno_name(errno), errno); } return; } if (socket_address_to_hostname((struct sockaddr *)&address, length, hostname, sizeof(hostname), port, sizeof(port)) < 0) { log_warn("Could not get hostname and port of mesh client (socket: %d): %s (%d)", mesh_client_socket->base.handle, get_errno_name(errno), errno); } else { snprintf(buffer, sizeof(buffer), "%s:%s", hostname, port); name = buffer; } /* * Allocate and initialise a new mesh stack. Note that in this stage the stack * is not added to brickd's central list of stacks yet. */ if (mesh_stack_create(name, &mesh_client_socket->base) < 0) { log_error("Could not create new mesh stack"); } else { log_info("New mesh stack created"); } }
static void socat_handle_receive(void *opaque) { Socat *socat = opaque; int length; length = socket_receive(socat->socket, (uint8_t *)&socat->notification + socat->notification_used, sizeof(CronNotification) - socat->notification_used); if (length == 0) { log_debug("Socat (handle: %d) disconnected by peer", socat->socket->handle); socat->disconnected = true; return; } if (length < 0) { if (errno_interrupted()) { log_debug("Receiving from socat (handle: %d) was interrupted, retrying", socat->socket->handle); } else if (errno_would_block()) { log_debug("Receiving from socat (handle: %d) Daemon would block, retrying", socat->socket->handle); } else { log_error("Could not receive from socat (handle: %d), disconnecting socat: %s (%d)", socat->socket->handle, get_errno_name(errno), errno); socat->disconnected = true; } return; } socat->notification_used += length; if (socat->notification_used < (int)sizeof(CronNotification)) { // wait for complete request return; } cron_handle_notification(&socat->notification); log_debug("Socat (handle: %d) received complete request, disconnecting socat", socat->socket->handle); socat->disconnected = true; }
static void event_poll_usb_events(void *opaque) { Array *event_sources = opaque; int count; struct usbi_pollfd *pollfd; EventSource *event_source; int i; int k; int ready; uint8_t byte = 0; log_debug("Started USB poll thread"); for (;;) { semaphore_acquire(&_usb_poll_resume); log_event_debug("Resumed USB poll thread"); if (!_usb_poll_running) { goto cleanup; } _usb_poll_pollfds_ready = 0; // update pollfd array count = 0; for (i = 0; i < event_sources->count; ++i) { event_source = array_get(event_sources, i); if (event_source->type == EVENT_SOURCE_TYPE_USB) { ++count; } } if (count == 0) { goto suspend; } ++count; // add the suspend pipe if (array_resize(&_usb_poll_pollfds, count, NULL) < 0) { log_error("Could not resize USB pollfd array: %s (%d)", get_errno_name(errno), errno); goto cleanup; } pollfd = array_get(&_usb_poll_pollfds, 0); pollfd->fd = _usb_poll_suspend_pipe[0]; pollfd->events = USBI_POLLIN; pollfd->revents = 0; for (i = 0, k = 1; i < event_sources->count; ++i) { event_source = array_get(event_sources, i); if (event_source->type != EVENT_SOURCE_TYPE_USB) { continue; } pollfd = array_get(&_usb_poll_pollfds, k); pollfd->fd = event_source->handle; pollfd->events = (short)event_source->events; pollfd->revents = 0; ++k; } // start to poll log_event_debug("Starting to poll on %d %s event source(s)", _usb_poll_pollfds.count - 1, event_get_source_type_name(EVENT_SOURCE_TYPE_USB, false)); retry: ready = usbi_poll((struct usbi_pollfd *)_usb_poll_pollfds.bytes, _usb_poll_pollfds.count, -1); if (ready < 0) { if (errno_interrupted()) { log_debug("Poll got interrupted, retrying"); goto retry; } log_error("Could not poll on %s event source(s): %s (%d)", event_get_source_type_name(EVENT_SOURCE_TYPE_USB, false), get_errno_name(errno), errno); goto suspend; } if (ready == 0) { goto suspend; } // handle poll result pollfd = array_get(&_usb_poll_pollfds, 0); if (pollfd->revents != 0) { log_event_debug("Received suspend signal"); --ready; // remove the suspend pipe } if (ready == 0) { goto suspend; } log_event_debug("Poll returned %d %s event source(s) as ready", ready, event_get_source_type_name(EVENT_SOURCE_TYPE_USB, false)); _usb_poll_pollfds_ready = ready; if (pipe_write(&_usb_poll_ready_pipe, &byte, sizeof(byte)) < 0) { log_error("Could not write to USB ready pipe: %s (%d)", get_errno_name(errno), errno); goto cleanup; } suspend: log_event_debug("Suspending USB poll thread"); semaphore_release(&_usb_poll_suspend); } cleanup: log_debug("Stopped USB poll thread"); semaphore_release(&_usb_poll_suspend); _usb_poll_running = false; }
static void client_handle_read(void *opaque) { Client *client = opaque; int length; const char *message = NULL; char packet_signature[PACKET_MAX_SIGNATURE_LENGTH]; length = io_read(client->io, (uint8_t *)&client->request + client->request_used, sizeof(Packet) - client->request_used); if (length == 0) { log_info("Client ("CLIENT_SIGNATURE_FORMAT") disconnected by peer", client_expand_signature(client)); client->disconnected = true; return; } if (length < 0) { if (length == IO_CONTINUE) { // no actual data received } else if (errno_interrupted()) { log_debug("Receiving from client ("CLIENT_SIGNATURE_FORMAT") was interrupted, retrying", client_expand_signature(client)); } else if (errno_would_block()) { log_debug("Receiving from client ("CLIENT_SIGNATURE_FORMAT") would block, retrying", client_expand_signature(client)); } else { log_error("Could not receive from client ("CLIENT_SIGNATURE_FORMAT"), disconnecting client: %s (%d)", client_expand_signature(client), get_errno_name(errno), errno); client->disconnected = true; } return; } client->request_used += length; while (!client->disconnected && client->request_used > 0) { if (client->request_used < (int)sizeof(PacketHeader)) { // wait for complete header break; } if (!client->request_header_checked) { if (!packet_header_is_valid_request(&client->request.header, &message)) { // FIXME: include packet_get_content_dump output in the error message log_error("Received invalid request (%s) from client ("CLIENT_SIGNATURE_FORMAT"), disconnecting client: %s", packet_get_request_signature(packet_signature, &client->request), client_expand_signature(client), message); client->disconnected = true; return; } client->request_header_checked = true; } length = client->request.header.length; if (client->request_used < length) { // wait for complete packet break; } if (client->request.header.function_id == FUNCTION_DISCONNECT_PROBE) { log_packet_debug("Received disconnect probe from client ("CLIENT_SIGNATURE_FORMAT"), dropping request", client_expand_signature(client)); } else { log_packet_debug("Received request (%s) from client ("CLIENT_SIGNATURE_FORMAT")", packet_get_request_signature(packet_signature, &client->request), client_expand_signature(client)); client_handle_request(client, &client->request); } memmove(&client->request, (uint8_t *)&client->request + length, client->request_used - length); client->request_used -= length; client->request_header_checked = false; } }
int libusb_handle_events_timeout(libusb_context *ctx, struct timeval *tv) { struct pollfd *pollfds; int count = 0; Node *dev_handle_node; libusb_device_handle *dev_handle; int i; int ready; int rc; usbfs_urb *urb; Node *itransfer_node; Node *itransfer_node_next; usbi_transfer *itransfer; struct libusb_transfer *transfer; if (ctx == NULL) { return LIBUSB_ERROR_INVALID_PARAM; // FIXME: no default context support } if (tv->tv_sec != 0 || tv->tv_usec != 0) { return LIBUSB_ERROR_INVALID_PARAM; // FIXME: no timeout support } pollfds = calloc(ctx->dev_handle_count, sizeof(struct pollfd)); if (pollfds == NULL) { return LIBUSB_ERROR_NO_MEM; } usbi_log_debug(ctx, "Handling events"); i = 0; for (dev_handle_node = ctx->dev_handle_sentinel.next; dev_handle_node != &ctx->dev_handle_sentinel; dev_handle_node = dev_handle_node->next) { dev_handle = containerof(dev_handle_node, libusb_device_handle, node); if (dev_handle->disconnected) { continue; } pollfds[i].fd = dev_handle->pollfd.fd; pollfds[i].events = dev_handle->pollfd.events; pollfds[i].revents = 0; ++i; } ready = poll(pollfds, i, 0); if (ready < 0) { if (errno_interrupted()) { rc = LIBUSB_ERROR_INTERRUPTED; } else { rc = LIBUSB_ERROR_IO; } usbi_log_error(ctx, "Count not poll on event source(s): %s (%d)", get_errno_name(errno), errno); free(pollfds); return rc; } usbi_log_debug(ctx, "Poll returned %d of %d USB devices(s) as ready", ready, i); i = 0; for (dev_handle_node = ctx->dev_handle_sentinel.next; dev_handle_node != &ctx->dev_handle_sentinel; dev_handle_node = dev_handle_node->next) { dev_handle = containerof(dev_handle_node, libusb_device_handle, node); if (dev_handle->disconnected) { continue; } if (pollfds[i].revents != 0) { if ((pollfds[i].revents & POLLERR) != 0) { usbi_log_debug(ctx, "Poll for USB device %s returned POLLERR, probably got disconnected", dev_handle->dev->name); dev_handle->disconnected = true; if (ctx->pollfd_removed_callback != NULL) { ctx->pollfd_removed_callback(dev_handle->pollfd.fd, ctx->pollfd_user_data); } for (itransfer_node = dev_handle->itransfer_sentinel.next; itransfer_node != &dev_handle->itransfer_sentinel; itransfer_node = itransfer_node_next) { itransfer_node_next = itransfer_node->next; itransfer = containerof(itransfer_node, usbi_transfer, node); transfer = &itransfer->transfer; node_remove(&itransfer->node); itransfer->submitted = false; transfer->status = LIBUSB_TRANSFER_NO_DEVICE; transfer->actual_length = 0; usbi_log_debug(ctx, "USB device for %s transfer %p probably got disconnected", (LIBUSB_ENDPOINT_IN & transfer->endpoint) != 0 ? "read" : "write"); transfer->callback(transfer); // might free or submit transfer libusb_unref_device(dev_handle->dev); } ++count; continue; } rc = ioctl(pollfds[i].fd, IOCTL_USBFS_REAPURBNDELAY, &urb); if (rc < 0) { if (errno_interrupted()) { rc = LIBUSB_ERROR_INTERRUPTED; } else if (errno == ENODEV) { rc = LIBUSB_ERROR_NO_DEVICE; } else { rc = LIBUSB_ERROR_IO; } usbi_log_error(ctx, "Count not reap URB for device %s: %s (%d)", dev_handle->dev->name, get_errno_name(errno), errno); free(pollfds); return rc; // FIXME: make this non-fatal } itransfer = (usbi_transfer *)urb->user_context; transfer = &itransfer->transfer; node_remove(&itransfer->node); itransfer->submitted = false; if (urb->status == -ENOENT) { transfer->status = LIBUSB_TRANSFER_CANCELLED; } else if (urb->status == -ENODEV || urb->status == -ESHUTDOWN) { transfer->status = LIBUSB_TRANSFER_NO_DEVICE; } else if (urb->status == -EPIPE) { transfer->status = LIBUSB_TRANSFER_STALL; } else if (urb->status == -EOVERFLOW) { transfer->status = LIBUSB_TRANSFER_OVERFLOW; } else if (urb->status != 0) { transfer->status = LIBUSB_TRANSFER_ERROR; } else { transfer->status = LIBUSB_TRANSFER_COMPLETED; } transfer->actual_length = urb->actual_length; usbi_log_debug(ctx, "Triggering callback for %s transfer %p (urb-status: %d)", (LIBUSB_ENDPOINT_IN & transfer->endpoint) != 0 ? "read" : "write", transfer, urb->status); transfer->callback(transfer); // might free or submit transfer libusb_unref_device(dev_handle->dev); ++count; } ++i; } free(pollfds); usbi_log_debug(ctx, "Handled %d event(s)", count); return LIBUSB_SUCCESS; }
static void process_wait(void *opaque) { Process *process = opaque; int status; int rc; ProcessStateChange change; for (;;) { do { rc = waitpid(process->pid, &status, WUNTRACED | WCONTINUED); } while (rc < 0 && errno_interrupted()); if (rc < 0) { log_error("Could not wait for child process (executable: %s, pid: %u) state change: %s (%d)", process->executable->buffer, process->pid, get_errno_name(errno), errno); break; } change.timestamp = time(NULL); if (WIFEXITED(status)) { change.state = PROCESS_STATE_EXITED; change.exit_code = WEXITSTATUS(status); // the child process has limited capabilities to report errors. the // coreutils env executable that executes other programs reserves // three exit codes to report errors (125, 126 and 127). our child // process uses the same mechanism. check for these three exit codes // and change state to error if found. the downside of this approach // is that these three exit codes can be used by the program to be // executed as normal exit codes with a different meaning, leading // to a misinterpretation here. but the coreutils env executable has // the same problem, so we will live with this if (change.exit_code == PROCESS_E_INTERNAL_ERROR || change.exit_code == PROCESS_E_CANNOT_EXECUTE || change.exit_code == PROCESS_E_DOES_NOT_EXIST) { change.state = PROCESS_STATE_ERROR; } } else if (WIFSIGNALED(status)) { change.state = PROCESS_STATE_KILLED; change.exit_code = WTERMSIG(status); } else if (WIFSTOPPED(status)) { change.state = PROCESS_STATE_STOPPED; change.exit_code = WSTOPSIG(status); } else if (WIFCONTINUED(status)) { change.state = PROCESS_STATE_RUNNING; change.exit_code = 0; // invalid } else { change.state = PROCESS_STATE_UNKNOWN; change.exit_code = 0; // invalid } log_debug("State of child process (executable: %s, pid: %u) changed (state: %s, exit_code: %u)", process->executable->buffer, process->pid, process_get_state_name(change.state), change.exit_code); if (pipe_write(&process->state_change_pipe, &change, sizeof(change)) < 0) { log_error("Could not write to state change pipe for child process (executable: %s, pid: %u): %s (%d)", process->executable->buffer, process->pid, get_errno_name(errno), errno); break; } if (!process_state_is_alive(change.state)) { break; } } }
static void client_handle_receive(void *opaque) { Client *client = opaque; const char *message = NULL; int length; PacketHeader *pending_request; length = socket_receive(client->socket, (uint8_t *)&client->packet + client->packet_used, sizeof(Packet) - client->packet_used); if (length < 0) { if (errno_interrupted()) { log_debug("Receiving from client (socket: %d, peer: %s), got interrupted", client->socket, client->peer); } else { log_error("Could not receive from client (socket: %d, peer: %s), disconnecting it: %s (%d)", client->socket, client->peer, get_errno_name(errno), errno); network_client_disconnected(client); } return; } if (length == 0) { log_info("Client (socket: %d, peer: %s) disconnected by peer", client->socket, client->peer); network_client_disconnected(client); return; } client->packet_used += length; while (client->packet_used > 0) { if (client->packet_used < (int)sizeof(PacketHeader)) { // wait for complete header break; } length = client->packet.header.length; if (client->packet_used < length) { // wait for complete packet break; } if (!packet_header_is_valid_request(&client->packet.header, &message)) { log_warn("Got invalid request (U: %u, L: %u, F: %u, S: %u, R: %u) from client (socket: %d, peer: %s): %s", client->packet.header.uid, client->packet.header.length, client->packet.header.function_id, client->packet.header.sequence_number, client->packet.header.response_expected, client->socket, client->peer, message); if (length < (int)sizeof(PacketHeader)) { // skip the complete header if length was too small length = sizeof(PacketHeader); } } else { log_debug("Got request (U: %u, L: %u, F: %u, S: %u, R: %u) from client (socket: %d, peer: %s)", client->packet.header.uid, client->packet.header.length, client->packet.header.function_id, client->packet.header.sequence_number, client->packet.header.response_expected, client->socket, client->peer); if (client->packet.header.response_expected) { if (client->pending_requests.count >= MAX_PENDING_REQUESTS) { log_warn("Dropping %d items from pending request array of client (socket: %d, peer: %s)", client->pending_requests.count - MAX_PENDING_REQUESTS + 1, client->socket, client->peer); while (client->pending_requests.count >= MAX_PENDING_REQUESTS) { array_remove(&client->pending_requests, 0, NULL); } } pending_request = array_append(&client->pending_requests); if (pending_request == NULL) { log_error("Could not append to pending request array: %s (%d)", get_errno_name(errno), errno); return; } memcpy(pending_request, &client->packet.header, sizeof(PacketHeader)); log_debug("Added pending request (U: %u, L: %u, F: %u, S: %u) for client (socket: %d, peer: %s)", pending_request->uid, pending_request->length, pending_request->function_id, pending_request->sequence_number, client->socket, client->peer); } usb_dispatch_packet(&client->packet); } memmove(&client->packet, (uint8_t *)&client->packet + length, client->packet_used - length); client->packet_used -= length; } }