示例#1
0
/*!
 * \brief Get the port the specified server is listening on.
 *
 * \param[in] server_pid Process identifier of the server to query
 *
 * \return the server's port number
 */
unsigned short simplecmd_get_port(pid_t server_pid)
{
	int sock;            // Socket descriptor
	unsigned short port; // Port the specified server is listening on
	char* buffer;        // Port as a string (directly from the server)

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

	__sock_recv(sock, __command_handlers[SP_COMMAND_GET_PORT].request, &buffer);
	if(buffer)
	{
		if(sscanf(buffer, "%hu", &port) != 1)
		{
			impact(0, "%s: %s: %s is not a port number\n",
				SP_COMMAND_HEADER_NAMESPACE, SP_COMMAND_HEADER_PROTOCOL_ERROR,
				buffer);
			port = 0;
		}
		free(buffer);
	}
	else
	{
		port = 0;
	}

	close(sock);

	return port;
}
示例#2
0
/*!
 * \brief Process a request accepted by the server.
 *
 * \param[in] p SimplePost command + client socket wrapper
 *
 * \return NULL
 */
static void* __process_request(void* p)
{
	struct simplecmd_request* scrp = (struct simplecmd_request*) p; // Properly cast SimplePost command request handle

	simplecmd_t scp = scrp->scp;  // SimplePost command instance to act on
	int sock = scrp->client_sock; // Socket the client connected on

	free(scrp);
	scrp = p = NULL;

	char* command; // Command to process
	size_t length; // Length of the command string
	bool response; // Command handler return value

	++(scp->client_count);

	length = __sock_recv(sock, NULL, &command);
	if(command == NULL || length == 0) goto error;
	response = -1;

	for(unsigned int i = SP_COMMAND_MIN; i <= SP_COMMAND_MAX; ++i)
	{
		if(strcmp(command, __command_handlers[i].request) == 0)
		{
			impact(2, "%s: Request 0x%lx: Responding to %s command\n",
				SP_COMMAND_HEADER_NAMESPACE, pthread_self(),
				__command_handlers[i].request);
			response = (*__command_handlers[i].handler)(scp, sock);
			break;
		}
	}

	#ifdef DEBUG
	if(response)
	{
		impact(2, "%s: Request 0x%lx: Successfully processed %s command\n",
			SP_COMMAND_HEADER_NAMESPACE, pthread_self(),
			command);
	}
	else
	{
		impact(2, "%s: Request 0x%lx: Failed to process %s command\n",
			SP_COMMAND_HEADER_NAMESPACE, pthread_self(),
			command);
	}
	#endif // DEBUG

error:
	impact(4, "%s: Request 0x%lx: Closing client %d\n",
		SP_COMMAND_HEADER_NAMESPACE, pthread_self(),
		sock);
	close(sock);

	if(command) free(command);
	--(scp->client_count);

	return NULL;
}
示例#3
0
/*!
 * \brief Get the version of the specified server.
 *
 * \param[in]  server_pid Process identifier of the server to query
 * \param[out] version
 * \parblock
 * Version of the server
 *
 * The storage for this string will be dynamically allocated. You are
 * responsible for freeing it (unless it is NULL, in which case an error
 * occurred).
 * \endparblock
 *
 * \return the number of characters written to the version string (excluding
 * the NULL-terminating character)
 */
size_t simplecmd_get_version(pid_t server_pid, char** version)
{
	int sock;          // Socket descriptor
	size_t length = 0; // Length of the version string
	*version = NULL;   // Failsafe

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

	length = __sock_recv(sock, __command_handlers[SP_COMMAND_GET_VERSION].request, version);

	close(sock);

	return length;
}
示例#4
0
/*!
 * \brief Get the address the specified server is bound to.
 *
 * \param[in]  server_pid Process identifier of the server to query
 * \param[out] address
 * \parblock
 * Address of the server
 *
 * The storage for this string will be dynamically allocated. You are
 * responsible for freeing it (unless it is NULL, in which case an error
 * occurred).
 * \endparblock
 *
 * \return the number of characters written to the address (excluding the NULL-
 * terminating character)
 */
size_t simplecmd_get_address(pid_t server_pid, char** address)
{
	int sock;          // Socket descriptor
	size_t length = 0; // Length of the address
	*address = NULL;   // Failsafe

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

	length = __sock_recv(sock, __command_handlers[SP_COMMAND_GET_ADDRESS].request, address);

	close(sock);

	return length;
}
示例#5
0
/**
 * @brief Recursive receive data from a socket.
 * @param fd the socket from which to receive data.
 * @param buf a pointer to a buffer into which to receive the data.
 * @param len the length of the buffer.
 * @param flags receive flags (e.g. MSG_WAITALL).
 */
ssize_t
__sock_recv_r(int fd, 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_recv(fd, buf, len, flags)) == -1)
			pthread_testcancel();
		__sock_putuser(&fd);
	} else {
		if ((ret = __libc_recv(fd, buf, len, flags)) == -1)
			pthread_testcancel();
	}
	pthread_cleanup_pop_restore_np(0);
	return (ret);
}
示例#6
0
/*!
 * \brief Receive a file and count from the client and add it our web server.
 *
 * \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_recv_file(simplecmd_t scp, int sock)
{
	char* url = NULL;    // URL of the file being served
	char* file = NULL;   // Name and path of the file to serve
	char* uri = NULL;    // URI of the file to serve
	char* buffer = NULL; // Count or identifier string from the client
	unsigned int count;  // Number of times the file should be served

	while(__sock_recv(sock, NULL, &buffer))
	{
		if(buffer == NULL) goto error;

		impact(3, "%s: %s: Receiving %s\n",
			SP_COMMAND_HEADER_NAMESPACE, __func__,
			buffer);

		if(strcmp(buffer, SP_COMMAND_FILE_FILE) == 0)
		{
			free(buffer);
			buffer = NULL;

			if(file)
			{
				impact(0, "%s: %s: Received a second FILE\n",
					SP_COMMAND_HEADER_NAMESPACE, SP_COMMAND_HEADER_PROTOCOL_ERROR);
				goto error;
			}
			else if(__sock_recv(sock, NULL, &file) == 0)
			{
				impact(0, "%s: %s: Did not receive a FILE as expected\n",
					SP_COMMAND_HEADER_NAMESPACE, SP_COMMAND_HEADER_PROTOCOL_ERROR);
				goto error;
			}
		}
		else if(strcmp(buffer, SP_COMMAND_FILE_URI) == 0)
		{
			free(buffer);
			buffer = NULL;

			if(uri)
			{
				impact(0, "%s: %s: Received a second URI\n",
					SP_COMMAND_HEADER_NAMESPACE, SP_COMMAND_HEADER_PROTOCOL_ERROR);
				goto error;
			}
			else if(__sock_recv(sock, NULL, &uri) == 0)
			{
				impact(0, "%s: %s: Did not receive a URI as expected\n",
					SP_COMMAND_HEADER_NAMESPACE, SP_COMMAND_HEADER_PROTOCOL_ERROR);
				goto error;
			}
		}
		else if(strcmp(buffer, SP_COMMAND_FILE_COUNT) == 0)
		{
			free(buffer);
			buffer = NULL;

			if(__sock_recv(sock, NULL, &buffer) == 0)
			{
				impact(0, "%s: %s: Did not receive the COUNT as expected\n",
					SP_COMMAND_HEADER_NAMESPACE, SP_COMMAND_HEADER_PROTOCOL_ERROR);
				goto error;
			}

			if(sscanf(buffer, "%u", &count) == EOF)
			{
				impact(0, "%s: %s: %s is not a valid COUNT\n",
					SP_COMMAND_HEADER_NAMESPACE, SP_MAIN_HEADER_MEMORY_ALLOC,
					buffer);
				goto error;
			}

			free(buffer);
			buffer = NULL;
		}
		else
		{
			impact(3, "%s: %s: Invalid file identifier \"%s\"\n",
				SP_COMMAND_HEADER_NAMESPACE, SP_COMMAND_HEADER_PROTOCOL_ERROR,
				buffer);
			goto error;
		}
	}

	if(file == NULL)
	{
		impact(0, "%s: %s: Did not receive a FILE to serve\n",
			SP_COMMAND_HEADER_NAMESPACE, SP_COMMAND_HEADER_PROTOCOL_ERROR);
		goto error;
	}

	if(simplepost_serve_file(scp->spp, &url, file, uri, count) == 0) return false;

	free(buffer);
	free(uri);
	free(file);
	free(url);
	return true;

error:
	free(buffer);
	free(uri);
	free(file);
	free(url);
	return false;
}
示例#7
0
/*!
 * \brief Get the list of files being served by the specified server.
 *
 * \param[in] server_pid Process identifier of the server to act on
 * \param[out] files     List of files currently being served
 *
 * \return the number of files hosted by the server, or -1 if the list could
 * not be retrieved
 */
ssize_t simplecmd_get_files(pid_t server_pid, simplepost_file_t* files)
{
	int sock;               // Socket descriptor
	char* buffer = NULL;    // Count, index, or identifier string from the server
	size_t count;           // Number of files being served
	size_t i = 0;           // Index of the current file being received
	size_t t = 0;           // Temporary file index converted from the buffer
	simplepost_file_t tail; // Last file in the *files list
	tail = *files = NULL;   // Failsafe

	sock = __open_sock_by_pid(server_pid);
	if(sock < 0) return -1;

	__sock_recv(sock, __command_handlers[SP_COMMAND_GET_FILES].request, &buffer);
	if(buffer == NULL) goto error;

	if(sscanf(buffer, "%zu", &count) != 1)
	{
		impact(0, "%s: %s: %s is not a number\n",
			SP_COMMAND_HEADER_NAMESPACE, SP_COMMAND_HEADER_PROTOCOL_ERROR,
			buffer);
		goto error;
	}
	free(buffer);
	buffer = NULL;

	impact(3, "%s: %s: Receiving list of %zu files\n",
		SP_COMMAND_HEADER_NAMESPACE, __func__,
		count);
	if(count == 0) goto no_error;

	while((i + 1) < count || tail == NULL || tail->file == NULL || tail->url == NULL)
	{
		__sock_recv(sock, NULL, &buffer);
		if(buffer == NULL) goto error;

		impact(3, "%s: %s: Receiving %s\n",
			SP_COMMAND_HEADER_NAMESPACE, __func__,
			buffer);

		if(strcmp(buffer, SP_COMMAND_FILE_INDEX) == 0)
		{
			free(buffer);
			buffer = NULL;

			__sock_recv(sock, NULL, &buffer);
			if(buffer == NULL)
			{
				impact(0, "%s: %s: Did not receive the next file index as expected\n",
					SP_COMMAND_HEADER_NAMESPACE, SP_COMMAND_HEADER_PROTOCOL_ERROR);
				goto error;
			}

			if(sscanf(buffer, "%zu", &t) != 1)
			{
				impact(0, "%s: %s: %s is not a number\n",
					SP_COMMAND_HEADER_NAMESPACE, SP_COMMAND_HEADER_PROTOCOL_ERROR,
					buffer);
				goto error;
			}
			free(buffer);
			buffer = NULL;

			if(tail == NULL)
			{
				if(t != i)
				{
					impact(0, "%s: %s: Expected the next file index to be %zu, not %zu\n",
						SP_COMMAND_HEADER_NAMESPACE, SP_COMMAND_HEADER_PROTOCOL_ERROR,
						i, t);
					goto error;
				}

				tail = *files = simplepost_file_init();
				if(tail == NULL) goto error;
			}
			else
			{
				if(t != ++i)
				{
					impact(0, "%s: %s: Expected the next file index to be %zu, not %zu\n",
						SP_COMMAND_HEADER_NAMESPACE, SP_COMMAND_HEADER_PROTOCOL_ERROR,
						i, t);
					goto error;
				}

				simplepost_file_t prev = tail;

				tail = simplepost_file_init();
				if(tail == NULL) goto error;

				tail->prev = prev;
				prev->next = tail;
			}
		}
		else if(tail == NULL)
		{
			impact(0, "%s: %s: Received \"%s\" before the first file index\n",
				SP_COMMAND_HEADER_NAMESPACE, SP_COMMAND_HEADER_PROTOCOL_ERROR,
				buffer);
			goto error;
		}
		else if(strcmp(buffer, SP_COMMAND_FILE_FILE) == 0)
		{
			free(buffer);
			buffer = NULL;

			__sock_recv(sock, NULL, &buffer);
			if(buffer == NULL)
			{
				impact(0, "%s: %s: Did not receive the file[%zu] location as expected\n",
					SP_COMMAND_HEADER_NAMESPACE, SP_COMMAND_HEADER_PROTOCOL_ERROR,
					i);
				goto error;
			}

			if(tail->file)
			{
				impact(0, "%s: %s: Received new file[%zu] location \"%s\", but it is already set to \"%s\"\n",
					SP_COMMAND_HEADER_NAMESPACE, SP_COMMAND_HEADER_PROTOCOL_ERROR,
					i, buffer, tail->file);
				goto error;
			}

			tail->file = buffer;
		}
		else if(strcmp(buffer, SP_COMMAND_FILE_URL) == 0)
		{
			free(buffer);
			buffer = NULL;

			__sock_recv(sock, NULL, &buffer);
			if(buffer == NULL)
			{
				impact(0, "%s: %s: Did not receive the file[%zu] URL as expected\n",
					SP_COMMAND_HEADER_NAMESPACE, SP_COMMAND_HEADER_PROTOCOL_ERROR,
					i);
				goto error;
			}

			if(tail->url)
			{
				impact(0, "%s: %s: Received new file[%zu] URL \"%s\", but it is already set to \"%s\"\n",
					SP_COMMAND_HEADER_NAMESPACE, SP_COMMAND_HEADER_PROTOCOL_ERROR,
					i, buffer, tail->url);
				goto error;
			}

			tail->url = buffer;
		}
		else if(strcmp(buffer, SP_COMMAND_FILE_COUNT) == 0)
		{
			free(buffer);
			buffer = NULL;

			__sock_recv(sock, NULL, &buffer);
			if(buffer == NULL)
			{
				impact(0, "%s: %s: Did not receive the file[%zu] count as expected\n",
					SP_COMMAND_HEADER_NAMESPACE, SP_COMMAND_HEADER_PROTOCOL_ERROR,
					i);
				goto error;
			}

			if(sscanf(buffer, "%u", &tail->count) != 1)
			{
				impact(0, "%s: %s: Received new file[%zu] count \"%s\", but it is not a positive integer as expected!\n",
					SP_COMMAND_HEADER_NAMESPACE, SP_COMMAND_HEADER_PROTOCOL_ERROR,
					i, buffer);
				goto error;
			}

			free(buffer);
			buffer = NULL;
		}
		else
		{
			/* We probably should not have run into this condition in the
			 * first place. It most likely means that we are talking to an
			 * older (or newer) version of this program, and the command
			 * protocol has changed. If not, it is probably a bug.
			 */
			impact(3, "%s: %s: Skipping unsupported file identifier \"%s\"\n",
				SP_COMMAND_HEADER_NAMESPACE, SP_COMMAND_HEADER_PROTOCOL_ERROR,
				buffer);
			free(buffer);
			buffer = NULL;

			/* Read and discard the argument that presumably comes after the
			 * unsupported file identifier that we encountered.
			 */
			__sock_recv(sock, NULL, &buffer);
			free(buffer);
			buffer = NULL;
		}
	}

	for(tail = *files, i = 0; tail; tail = tail->next, ++i);
	if(i != count)
	{
		impact(0, "%s: BUG! Only received %zu of %zu files\n",
			__PRETTY_FUNCTION__,
			i, count);
		goto error;
	}

no_error:
	close(sock);

	return count;

error:
	simplepost_file_free(*files);
	*files = NULL;

	free(buffer);
	close(sock);

	return -1;
}