Пример #1
0
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
}
Пример #2
0
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");
    }
}
Пример #3
0
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;
}
Пример #4
0
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;
}
Пример #5
0
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;
    }
}
Пример #6
0
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;
}
Пример #7
0
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;
		}
	}
}
Пример #8
0
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;
	}
}