예제 #1
0
파일: common.c 프로젝트: zandeez/hgd
/*
 * frees members of a playlist item, but not the item
 * itself, therefore allowing stack allocation if wished
 */
void
hgd_free_playlist_item(struct hgd_playlist_item *i)
{
	if (i->filename != NULL)
		free(i->filename);
	if (i->user != NULL)
		free(i->user);

	hgd_free_media_tags(&i->tags);
}
예제 #2
0
파일: hgd-netd.c 프로젝트: tristan2468/hgd
/*
 * queue a track
 *
 * args: filename|size
 * reponses
 * ok...			ok and waiting for payload
 * ok				ok and payload accepted
 * err|size			size arg was weird
 * err|user_not_identified	user did not identify
 * err|internal			something else went wrong
 *
 * after 'ok...'
 * client then sends 'size' bytes of the media to queue
 */
int
hgd_cmd_queue(struct hgd_session *sess, char **args)
{
	char			*filename_p = args[0], *payload = NULL;
	size_t			bytes = atoi(args[1]);
	char			*unique_fn = NULL;
	int			f = -1, ret = HGD_OK;
	size_t			bytes_recvd = 0, to_write;
	ssize_t			write_ret;
	char			*filename;
	struct hgd_media_tag	tags;

	if ((flood_limit >= 0) &&
	    (hgd_num_tracks_user(sess->user->name) >= flood_limit)) {

		DPRINTF(HGD_D_WARN,
		    "User '%s' trigger flood protection", sess->user->name);
		hgd_sock_send_line(sess->sock_fd,
		    sess->ssl, "err|floodprotection");

		return (HGD_FAIL);
	}

	/* strip path, we don't care about that */
	filename = basename(filename_p);

	if ((bytes == 0) || ((long int) bytes > max_upload_size)) {
		DPRINTF(HGD_D_WARN, "Incorrect file size");
		hgd_sock_send_line(sess->sock_fd, sess->ssl, "err|size");
		ret = HGD_FAIL;
		goto clean;
	}

	/* prepare to recieve the media file and stash away */
	xasprintf(&unique_fn, "%s/" HGD_UNIQ_FILE_PFX "%s", filestore_path, filename);
	DPRINTF(HGD_D_DEBUG, "Template for filestore is '%s'", unique_fn);

	f = mkstemps(unique_fn, strlen(filename) + 1); /* +1 for hyphen */
	if (f < 0) {
		DPRINTF(HGD_D_ERROR, "mkstemp: %s: %s",
		    filestore_path, SERROR);
		hgd_sock_send_line(sess->sock_fd, sess->ssl, "err|internal");
		ret = HGD_FAIL;
		goto clean;
	}

	hgd_sock_send_line(sess->sock_fd, sess->ssl, "ok|...");

	DPRINTF(HGD_D_INFO, "Recving %d byte payload '%s' from %s into %s",
	    (int) bytes, filename, sess->user->name, unique_fn);

	/* recieve bytes in small chunks so that we dont use moar RAM */
	while (bytes_recvd != bytes) {

		if (bytes - bytes_recvd < HGD_BINARY_RECV_SZ)
			to_write = bytes - bytes_recvd;
		else
			to_write = HGD_BINARY_RECV_SZ;

		payload = NULL;

		DPRINTF(HGD_D_DEBUG, "Waiting for chunk of length %d bytes",
		    (int) to_write);

		payload = hgd_sock_recv_bin(sess->sock_fd,
		    sess->ssl, to_write);

		if (payload == NULL) {
			DPRINTF(HGD_D_ERROR, "failed to recv binary");
			hgd_sock_send_line(sess->sock_fd,
			    sess->ssl, "err|internal");

			/* try to clean up a partial upload */
			if (fsync(f) < 0)
				DPRINTF(HGD_D_WARN,
				    "can't sync partial file: %s", SERROR);

			if (close(f) < 0)
				DPRINTF(HGD_D_WARN,
				    "can't close partial file: %s", SERROR);
			f = -1;

			if (unlink(unique_fn) < 0) {
				DPRINTF(HGD_D_WARN,
				    "can't unlink partial upload: '%s': %s",
				    unique_fn, SERROR);
			}

			ret = HGD_FAIL;
			goto clean;
		}
		write_ret = write(f, payload, to_write);

		/* XXX what if write returns less than the chunk? */
		if (write_ret < 0) {
			DPRINTF(HGD_D_ERROR, "Failed to write %d bytes: %s",
			    (int) to_write, SERROR);
			hgd_sock_send_line(sess->sock_fd,
			    sess->ssl, "err|internal");
			unlink(unique_fn); /* don't much care if this fails */
			ret = HGD_FAIL;
			goto clean;
		}

		bytes_recvd += to_write;
		DPRINTF(HGD_D_DEBUG, "Recvd binary chunk of length %d bytes",
		    (int) to_write);
		DPRINTF(HGD_D_DEBUG, "Expecting a further %d bytes",
		    (int) (bytes - bytes_recvd));

		free(payload);
	}
	payload = NULL;

	/*
	 * get tag metadata
	 * no error that there is no #ifdef HAVE_TAGLIB
	 */
	hgd_get_tag_metadata(unique_fn, &tags);

	/* insert track into db */
	if (hgd_insert_track(basename(unique_fn),
		    &tags, sess->user->name) != HGD_OK) {
		hgd_sock_send_line(sess->sock_fd, sess->ssl, "err|sql");
		goto clean;
	}

	hgd_free_media_tags(&tags);

	hgd_sock_send_line(sess->sock_fd, sess->ssl, "ok");
	DPRINTF(HGD_D_INFO, "Transfer of '%s' complete", filename);
clean:
	if (f != -1)
		close(f);
	if (payload)
		free(payload);
	if (unique_fn)
		free(unique_fn);

	if (bytes_recvd != bytes)
		ret = HGD_FAIL;

	return (ret);
}