Exemple #1
0
/*!
 * \brief Send the current program version to the client.
 *
 * \param[in] scp  Instance to act on
 * \param[in] sock Client socket
 *
 * \retval true the requested information was sent successfully
 * \retval false failed to respond to the request
 */
static bool __command_send_version(simplecmd_t scp, int sock)
{
	// Unused parameters
	(void) scp;

	__sock_send(sock, NULL, SP_MAIN_VERSION);
	return 1;
}
Exemple #2
0
/*!
 * \brief Add a file to the specified server.
 *
 * \param[in] server_pid Process identifier of the server to act on
 * \param[in] file       Name and path of the file to serve
 * \param[in] uri        URI of the file to serve
 * \param[in] count      Number of times the file should be served
 *
 * \return true if the file was successfully added to the server, false if
 * something went wrong (and the file was not added to the server)
 */
bool simplecmd_set_file(
	pid_t server_pid,
	const char* file,
	const char* uri,
	unsigned int count)
{
	int sock;         // Socket descriptor
	char buffer[512]; // Count as a string

	sock = __open_sock_by_pid(server_pid);
	if(sock < 0) return false;

	__sock_send(sock, __command_handlers[SP_COMMAND_SET_FILE].request, NULL);

	if(file)
	{
		impact(3, "%s: %s: Sending %s %s\n",
			SP_COMMAND_HEADER_NAMESPACE, __func__,
			SP_COMMAND_FILE_FILE, file);
		__sock_send(sock, SP_COMMAND_FILE_FILE, file);
	}

	if(count)
	{
		sprintf(buffer, "%u", count);

		impact(3, "%s: %s: Sending %s %s\n",
			SP_COMMAND_HEADER_NAMESPACE, __func__,
			SP_COMMAND_FILE_COUNT, buffer);
		__sock_send(sock, SP_COMMAND_FILE_COUNT, buffer);
	}

	if(uri)
	{
		impact(3, "%s: %s: Sending %s %s\n",
			SP_COMMAND_HEADER_NAMESPACE, __func__,
			SP_COMMAND_FILE_URI, uri);
		__sock_send(sock, SP_COMMAND_FILE_URI, uri);
	}

	close(sock);

	return true;
}
Exemple #3
0
/*!
 * \brief Send the port our web server is listening on to the client.
 *
 * \note If the web server is not running, zero will be sent as the port
 * number.
 *
 * \param[in] scp  Instance to act on
 * \param[in] sock Client socket
 *
 * \retval true the requested information was sent successfully
 * \retval false failed to respond to the request
 */
static bool __command_send_port(simplecmd_t scp, int sock)
{
	char buffer[30];     // Port as a string
	unsigned short port; // Port the web server is listening on

	port = simplepost_get_port(scp->spp);
	if(port == 0) return false;

	if(sprintf(buffer, "%hu", port) <= 0) return false;
	__sock_send(sock, NULL, buffer);

	return true;
}
Exemple #4
0
/*!
 * \brief Send the primary address our web server is bound to to the client.
 *
 * \note If the web server is not running, a zero-length string will be sent.
 * See the related comments in __sock_send() and __sock_recv() to get a better
 * understanding of how this contingency is handled.
 *
 * \param[in] scp  Instance to act on
 * \param[in] sock Client socket
 *
 * \retval true the requested information was sent successfully
 * \retval false failed to respond to the request
 */
static bool __command_send_address(simplecmd_t scp, int sock)
{
	char* address; // Address of the web server
	size_t length; // Length of the address string

	length = simplepost_get_address(scp->spp, &address);
	if(address == NULL || length == 0) return false;

	__sock_send(sock, NULL, address ? address : "");
	free(address);

	return true;
}
Exemple #5
0
ssize_t
__sock_send_r(int fd, const void *buf, size_t len, int flags)
{
	ssize_t ret = -1;

	pthread_cleanup_push_defer_np(__sock_putuser, &fd);
	if (__sock_getuser(fd)) {
		if ((ret = __sock_send(fd, buf, len, flags)) == -1)
			pthread_testcancel();
		__sock_putuser(&fd);
	} else {
		if ((ret = __libc_send(fd, buf, len, flags)) == -1)
			pthread_testcancel();
	}
	pthread_cleanup_pop_restore_np(0);
	return (ret);
}
Exemple #6
0
/*!
 * \brief Send the list of files that we are serving to the client.
 *
 * \param[in] scp  Instance to act on
 * \param[in] sock Client socket
 *
 * \retval true the requested information was sent successfully
 * \retval false failed to respond to the request
 */
static bool __command_send_files(simplecmd_t scp, int sock)
{
	char buffer[30];         // File count or index as a string
	simplepost_file_t files; // List of files being served
	size_t count;            // Number of files being served
	size_t i = 0;            // Index of the current file being sent

	count = simplepost_get_files(scp->spp, &files);

	impact(3, "%s: %s: Sending list of %zu files\n",
		SP_COMMAND_HEADER_NAMESPACE,
		__func__, count);
	if(sprintf(buffer, "%zu", count) <= 0)
	{
		simplepost_file_free(files);
		return false;
	}
	__sock_send(sock, NULL, buffer);

	for(simplepost_file_t p = files; p; p = p->next)
	{
		impact(3, "%s: %s: Sending %s %zu\n",
			SP_COMMAND_HEADER_NAMESPACE, __func__,
			SP_COMMAND_FILE_INDEX, i);
		if(sprintf(buffer, "%zu", i++) <= 0)
		{
			simplepost_file_free(files);
			return false;
		}
		__sock_send(sock, SP_COMMAND_FILE_INDEX, buffer);

		if(p->file)
		{
			impact(3, "%s: %s: Sending %s %s\n",
				SP_COMMAND_HEADER_NAMESPACE, __func__,
				SP_COMMAND_FILE_FILE, p->file);
			__sock_send(sock, SP_COMMAND_FILE_FILE, p->file);
		}

		if(p->count)
		{
			if(sprintf(buffer, "%u", p->count) <= 0)
			{
				impact(0, "%s: %s: Failed to buffer %s %u\n",
					SP_COMMAND_HEADER_NAMESPACE, __func__,
					SP_COMMAND_FILE_COUNT, p->count);
				simplepost_file_free(files);
				return false;
			}

			impact(3, "%s: %s: Sending %s %s\n",
				SP_COMMAND_HEADER_NAMESPACE, __func__,
				SP_COMMAND_FILE_COUNT, buffer);
			__sock_send(sock, SP_COMMAND_FILE_COUNT, buffer);
		}

		/* Always send the URL last. The reason for this is that only the FILE
		 * and URL fields and required per-file. All others are optional.
		 * Therefore to make sure that the optional fields are not skipped on
		 * the client side, always send a required field last.
		 */
		if(p->url)
		{
			impact(3, "%s: %s: Sending %s %s\n",
				SP_COMMAND_HEADER_NAMESPACE, __func__,
				SP_COMMAND_FILE_URL, p->url);
			__sock_send(sock, SP_COMMAND_FILE_URL, p->url);
		}
	}

	simplepost_file_free(files);

	return true;
}
Exemple #7
0
/*!
 * \brief Send a command to the client and read the response.
 *
 * \param[in] sock    Socket descriptor
 * \param[in] command
 * \parblock
 * Command to send to the client
 *
 * If this parameter is NULL, no command will be sent.
 * \endparblock
 * \param[out] data
 * \parblock
 * NULL-terminated string from the client
 *
 * If *data != NULL, you are responsible for freeing it.
 * \endparblock
 *
 * \return the number of bytes written to the read buffer. If an error
 * occurred (or the operation timed out), zero will be returned instead
 */
static size_t __sock_recv(int sock, const char* command, char** data)
{
	char buffer[30]; // Number of characters to be read from the buffer
	size_t length;   // Number of characters received
	char b;          // Last byte read from the client
	*data = NULL;    // Failsafe

	if(command) __sock_send(sock, command, NULL);

	for(size_t i = 0; read(sock, (void*) &b, 1) == 1; ++i)
	{
		if(i == sizeof(buffer))
		{
			impact(0, "%s: %s: String size cannot be longer than %zu bytes\n",
				SP_COMMAND_HEADER_NAMESPACE, SP_COMMAND_HEADER_PROTOCOL_ERROR,
				sizeof(buffer));
			return 0;
		}

		buffer[i] = b;
		if(b == '\0') break;
	}

	if(sscanf(buffer, "%zu", &length) != 1)
	{
		impact(0, "%s: %s: %s is not a valid string size\n",
			SP_COMMAND_HEADER_NAMESPACE, SP_COMMAND_HEADER_PROTOCOL_ERROR,
			buffer);
		return 0;
	}

	*data = (char*) malloc(sizeof(char) * (length + 1));
	if(*data == NULL)
	{
		impact(2, "%s: %s: Failed to allocate memory for command data buffer\n",
			SP_COMMAND_HEADER_NAMESPACE, SP_MAIN_HEADER_MEMORY_ALLOC);

		if(command)
		{
			impact(0, "%s: Data buffer required for command %s\n",
				SP_COMMAND_HEADER_NAMESPACE,
				command);
		}
		else
		{
			impact(0, "%s: Buffer required to receive data\n",
				SP_COMMAND_HEADER_NAMESPACE);
		}

		return 0;
	}

	/* The data received may be a zero-length string. The following loop
	 * handles this condition implicitly, but it is not to be overlooked.
	 * Since no terminating character is sent for data (unlike for its length),
	 * a zero-length data string effectively means that we should not attempt
	 * to read anything from the socket.
	 */
	for(size_t i = 0; i < length; ++i)
	{
		if(read(sock, (void*) &b, 1) == 1)
		{
			(*data)[i] = b;
		}
		else
		{
			impact(0, "%s: Read of %s aborted after receiving only %zu of %zu bytes\n",
				SP_COMMAND_HEADER_NAMESPACE,
				command ? command : "data", i, length);

			free(*data);
			*data = NULL;

			return 0;
		}
	}
	(*data)[length] = '\0';

	return length;
}