Beispiel #1
0
char *
cmyth_conn_get_backend_hostname(cmyth_conn_t conn)
{
	int count, err;
	char* result = NULL;

  pthread_mutex_lock(&mutex);
	if(conn->conn_version < 17) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: protocol version doesn't support QUERY_HOSTNAME\n",
			  __FUNCTION__);
		return NULL;
	}

	if (!conn) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no connection\n",
			  __FUNCTION__);
		return NULL;
	}

	if ((err = cmyth_send_message(conn,  "QUERY_HOSTNAME")) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message() failed (%d)\n",
			  __FUNCTION__, err);
		goto err;
	}

	if ((count=cmyth_rcv_length(conn)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, count);
		goto err;
	}

	result = ref_alloc(count+1);
	count -= cmyth_rcv_string(conn, &err,
				    result, count, count);
	if (err < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_string() failed (%d)\n",
			  __FUNCTION__, err);
		goto err;
	}

	while(count > 0 && !err) {
		char buffer[100];
		count -= cmyth_rcv_string(conn, &err, buffer, sizeof(buffer)-1, count);
		buffer[sizeof(buffer)-1] = 0;
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: odd left over data %s\n", __FUNCTION__, buffer);
	}
	pthread_mutex_unlock(&mutex);

	if(!strcmp("-1",result))  {
		cmyth_dbg(CMYTH_DBG_PROTO, "%s: Failed to retrieve backend hostname.\n",
			  __FUNCTION__);
	return NULL;
	}
	return result;

err:
	pthread_mutex_unlock(&mutex);
	if(result)
		ref_release(result);

	return NULL;
}
Beispiel #2
0
static char *
cmyth_conn_get_setting_unlocked(cmyth_conn_t conn, const char* hostname, const char* setting)
{
	char msg[256];
	int count, err;
	char* result = NULL;

	if(conn->conn_version < 17) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: protocol version doesn't support QUERY_SETTING\n",
			  __FUNCTION__);
		return NULL;
	}

	if (!conn) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no connection\n",
			  __FUNCTION__);
		return NULL;
	}

	snprintf(msg, sizeof(msg), "QUERY_SETTING %s %s", hostname, setting);
	if ((err = cmyth_send_message(conn, msg)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message() failed (%d)\n",
			  __FUNCTION__, err);
		goto err;
	}

	if ((count=cmyth_rcv_length(conn)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, count);
		goto err;
	}

	result = ref_alloc(count+1);
	count -= cmyth_rcv_string(conn, &err,
				    result, count, count);
	if (err < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_string() failed (%d)\n",
			  __FUNCTION__, err);
		goto err;
	}

	while(count > 0 && !err) {
		char buffer[100];
		count -= cmyth_rcv_string(conn, &err, buffer, sizeof(buffer)-1, count);
		buffer[sizeof(buffer)-1] = 0;
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: odd left over data %s\n", __FUNCTION__, buffer);
	}

	if(!strcmp("-1",result))  {
		cmyth_dbg(CMYTH_DBG_PROTO, "%s: Setting: %s or hostname: %s not found.\n",
			  __FUNCTION__, setting,hostname);
		return NULL;
	}
	return result;

err:
	if(result)
		ref_release(result);

	return NULL;
}
Beispiel #3
0
/*
 * cmyth_recorder_get_duration_map()
 *
 * Scope: PUBLIC
 *
 * Description
 *
 * Request a list of {keynum, duration} pairs starting at keynum
 * 'start' and ending with keynum 'end' from the current recording on
 * recorder 'rec'.
 *
 * Return Value:
 *
 * Success: A non-NULL, held cmyth_posmap_t
 * Failure: A NULL pointer
 */
cmyth_posmap_t
cmyth_recorder_get_duration_map(cmyth_recorder_t rec, uint32_t start, uint32_t end)
{
	int err, count, consumed;
	cmyth_posmap_t ret = NULL;
	char msg[256];
	char tmp[1024];

	if (!rec || !rec->rec_conn) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no recorder connection\n",
			  __FUNCTION__);
		return NULL;
	}

	pthread_mutex_lock(&rec->rec_conn->conn_mutex);

	if (rec->rec_conn->conn_version >= 77)
	{
		snprintf(msg, sizeof(msg), "QUERY_RECORDER %"PRIu32"[]:[]FILL_DURATION_MAP[]:[]%"PRIu32"[]:[]%"PRIu32, rec->rec_id, start, end);

		if ((err = cmyth_send_message(rec->rec_conn, msg)) < 0) {
			cmyth_dbg(CMYTH_DBG_ERROR,
				  "%s: cmyth_send_message() failed (%d)\n",
				  __FUNCTION__, err);
			goto fail;
		}

		count = cmyth_rcv_length(rec->rec_conn);
		if (count < 0) {
			cmyth_dbg(CMYTH_DBG_ERROR,
			"%s: cmyth_rcv_length() failed (%d)\n",
			__FUNCTION__, count);
			goto fail;
		}

		ret = cmyth_posmap_create();
		if (ret == NULL) {
			cmyth_dbg(CMYTH_DBG_ERROR,
				  "%s: cmyth_posmap_create() failed\n",
				  __FUNCTION__);
			goto fail;
		}

		if (count > 2) {
			consumed = cmyth_rcv_posmap(rec->rec_conn, &err, ret, count);
			count -= consumed;
			if (err) {
				cmyth_dbg(CMYTH_DBG_ERROR,
				"%s: cmyth_rcv_posmap() failed (%d)\n",
				__FUNCTION__, err);
				ref_release(ret);
				ret = NULL;
			}
		}
		err = 0;
		while(count > 0 && err == 0) {
			consumed = cmyth_rcv_data(rec->rec_conn, &err, (unsigned char*)tmp, sizeof(tmp) - 1, count);
			cmyth_dbg(CMYTH_DBG_ERROR, "%s: leftover data: count %i, read %i, errno %i\n", __FUNCTION__, count, consumed, err);
			count -= consumed;
		}
	}

fail:
	pthread_mutex_unlock(&rec->rec_conn->conn_mutex);

	return ret;
}
Beispiel #4
0
/*
 * cmyth_conn_connect_path(char* path, cmyth_conn_t control,
 *                         unsigned buflen, int tcp_rcvbuf)
 *
 * Scope: PUBLIC
 *
 * Description:
 *
 * Create a file structure containing a data connection for use
 * transfering a file within the MythTV protocol.  Return a pointer to
 * the newly created file structure.  The connection in the file
 * structure is returned held as is the file structure itself.  The
 * connection will be released when the file structure is released.
 * The file structure can be released using ref_release().
 *
 * Return Value:
 *
 * Success: Non-NULL cmyth_file_t (this is a pointer type)
 *
 * Failure: NULL cmyth_file_t
 */
cmyth_file_t
cmyth_conn_connect_path(char* path, cmyth_conn_t control,
			unsigned buflen, int tcp_rcvbuf, char* storage_group)
{
	cmyth_conn_t conn = NULL;
	char *announcement = NULL;
	char reply[16];
	char host[256];
	int err = 0;
	int count = 0;
	int r, port;
	int ann_size = sizeof("ANN FileTransfer  0[]:[][]:[]");
	struct sockaddr_in addr;
        socklen_t addr_size = sizeof(addr);
	cmyth_file_t ret = NULL;

	if (getpeername(control->conn_fd, (struct sockaddr*)&addr, &addr_size)<0) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: getpeername() failed\n",
			  __FUNCTION__);
		goto shut;
	}

	inet_ntop(addr.sin_family, &addr.sin_addr, host, sizeof(host));
	port = ntohs(addr.sin_port);

	ret = cmyth_file_create(control);
	if (!ret) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_file_create() failed\n",
			  __FUNCTION__);
		goto shut;
	}

	cmyth_dbg(CMYTH_DBG_PROTO, "%s: connecting data connection\n",
		  __FUNCTION__);
	conn = cmyth_connect(host, port, buflen, tcp_rcvbuf);
	cmyth_dbg(CMYTH_DBG_PROTO,
		  "%s: done connecting data connection, conn = %p\n",
		  __FUNCTION__, conn);
	if (!conn) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_connect(%s, %d, %d) failed\n",
			  __FUNCTION__, host, port, buflen);
		goto shut;
	}
	/*
	 * Explicitly set the conn version to the control version as cmyth_connect() doesn't and some of
	 * the cmyth_rcv_* functions expect it to be the same as the protocol version used by mythbackend.
	 */
	conn->conn_version = control->conn_version;

	ann_size += strlen(path) + strlen(my_hostname) + strlen(storage_group) + 6;
	announcement = malloc(ann_size);
	if (!announcement) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: malloc(%d) failed for announcement\n",
			  __FUNCTION__, ann_size);
		goto shut;
	}
	if (control->conn_version >= 44) { /*TSP: from version 44 according to the source code*/
		if (strlen(storage_group) > 1) {
			sprintf(announcement, "ANN FileTransfer %s 0 0 0[]:[]%s[]:[]%s",
				  my_hostname, path, storage_group);
		} else {
			sprintf(announcement, "ANN FileTransfer %s 0[]:[]%s[]:[]",  // write = false
				  my_hostname, path);
		}
	} else {
		sprintf(announcement, "ANN FileTransfer %s[]:[]%s",
			  my_hostname, path);
	}
	if (cmyth_send_message(conn, announcement) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message('%s') failed\n",
			  __FUNCTION__, announcement);
		goto shut;
	}
	ret->file_data = ref_hold(conn);
	count = cmyth_rcv_length(conn);
	if (count < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, count);
		goto shut;
	}
	reply[sizeof(reply) - 1] = '\0';
	r = cmyth_rcv_string(conn, &err, reply, sizeof(reply) - 1, count); 
	if (err != 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_string() failed (%d)\n",
			  __FUNCTION__, err);
		goto shut;
	}
	if (strcmp(reply, "OK") != 0) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: reply ('%s') is not 'OK'\n",
			  __FUNCTION__, reply);
		goto shut;
	}
	count -= r;
	r = cmyth_rcv_long(conn, &err, &ret->file_id, count);
	if (err) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: (id) cmyth_rcv_long() failed (%d)\n",
			  __FUNCTION__, err);
		goto shut;
	}
	count -= r;
	r = cmyth_rcv_uint64(conn, &err, &ret->file_length, count);
	if (err) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: (length) cmyth_rcv_uint64() failed (%d)\n",
			  __FUNCTION__, err);
		goto shut;
	}
	count -= r;
	free(announcement);
	ref_release(conn);
	return ret;

    shut:
	if (announcement) {
		free(announcement);
	}
	ref_release(ret);
	ref_release(conn);
	return NULL;
}
Beispiel #5
0
cmyth_event_t
cmyth_event_get(cmyth_conn_t conn, char * data, int len)
{
	int count, err, consumed, i;
	char tmp[1024];
	cmyth_event_t event;
	cmyth_proginfo_t proginfo = NULL;

	if (conn == NULL)
		goto fail;

	if ((count=cmyth_rcv_length(conn)) <= 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, count);
		return CMYTH_EVENT_CLOSE;
	}

	consumed = cmyth_rcv_string(conn, &err, tmp, sizeof(tmp) - 1, count);
	count -= consumed;
	if (strcmp(tmp, "BACKEND_MESSAGE") != 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_string() failed (%d)\n",
			  __FUNCTION__, count);
		goto fail;
	}

	consumed = cmyth_rcv_string(conn, &err, tmp, sizeof(tmp) - 1, count);
	count -= consumed;
	if (strcmp(tmp, "RECORDING_LIST_CHANGE") == 0) {
		event = CMYTH_EVENT_RECORDING_LIST_CHANGE;
	} else if (strncmp(tmp, "RECORDING_LIST_CHANGE ADD", 25) == 0) {
		event = CMYTH_EVENT_RECORDING_LIST_CHANGE_ADD;
		strncpy(data, tmp + 26, len);
	} else if (strcmp(tmp, "RECORDING_LIST_CHANGE UPDATE") == 0) {
		event = CMYTH_EVENT_RECORDING_LIST_CHANGE_UPDATE;
		/* receive a proginfo structure - do nothing with it (yet?)*/
		proginfo = cmyth_proginfo_create();
		if (!proginfo) {
			cmyth_dbg(CMYTH_DBG_ERROR,
				"%s: cmyth_proginfo_create() failed\n",
				__FUNCTION__);
			goto fail;
		}
		consumed = cmyth_rcv_proginfo(conn, &err, proginfo, count);
		ref_release(proginfo);
		proginfo = NULL;
		count -= consumed;
	} else if (strncmp(tmp, "RECORDING_LIST_CHANGE DELETE", 28) == 0) {
		event = CMYTH_EVENT_RECORDING_LIST_CHANGE_DELETE;
		strncpy(data, tmp + 29, len);
	} else if (strcmp(tmp, "SCHEDULE_CHANGE") == 0) {
		event = CMYTH_EVENT_SCHEDULE_CHANGE;
	} else if (strncmp(tmp, "DONE_RECORDING", 14) == 0) {
		event = CMYTH_EVENT_DONE_RECORDING;
	} else if (strncmp(tmp, "QUIT_LIVETV", 11) == 0) {
		event = CMYTH_EVENT_QUIT_LIVETV;
	} else if (strncmp(tmp, "LIVETV_WATCH", 12) == 0) {
		event = CMYTH_EVENT_WATCH_LIVETV;
		strncpy(data, tmp + 13, len);
	/* Sergio: Added to support the new live tv protocol */
	} else if (strncmp(tmp, "LIVETV_CHAIN UPDATE", 19) == 0) {
		event = CMYTH_EVENT_LIVETV_CHAIN_UPDATE;
		strncpy(data, tmp + 20, len);
	} else if (strncmp(tmp, "SIGNAL", 6) == 0) { 
    int dstlen=len;
		event = CMYTH_EVENT_SIGNAL; 
    /*Get Recorder ID */
    strncat(data,"cardid ",7);
    strncat(data,tmp+7,consumed-12);
    strncat(data,";",2);
		/* get slock, signal, seen_pat, matching_pat */ 
    while (count > 0) { 
			
      /* get signalmonitorvalue name */ 
			consumed = cmyth_rcv_string(conn, &err, tmp, sizeof(tmp) - 1, count); 
			count -= consumed; 
      /*strncat(data,tmp,dstlen-2);
      strncat(data,"=",2);
      dstlen -= consumed;*/
			/* get signalmonitorvalue status */ 
			consumed = cmyth_rcv_string(conn, &err, tmp, sizeof(tmp) - 1, count); 
			count -= consumed; 
      strncat(data,tmp,dstlen-2);
      strncat(data,";",2);
      dstlen -= consumed;
		}
	} else if (strncmp(tmp, "ASK_RECORDING", 13) == 0) {
		event = CMYTH_EVENT_ASK_RECORDING;
		if (cmyth_conn_get_protocol_version(conn) < 37) {
			/* receive 4 string - do nothing with them */
			for (i = 0; i < 4; i++) {
				consumed = cmyth_rcv_string(conn, &err, tmp, sizeof(tmp) -1, count);
				count -= consumed;
			}
		} else {
			/* receive a proginfo structure - do nothing with it (yet?)*/
			proginfo = cmyth_proginfo_create();
			if (!proginfo) {
				cmyth_dbg(CMYTH_DBG_ERROR,
					"%s: cmyth_proginfo_create() failed\n",
					__FUNCTION__);
				goto fail;
			}
			consumed = cmyth_rcv_proginfo(conn, &err, proginfo, count);
			ref_release(proginfo);
			proginfo = NULL;
			count -= consumed;
		}
	} else if (strncmp(tmp, "CLEAR_SETTINGS_CACHE", 20) == 0) {
		event = CMYTH_EVENT_CLEAR_SETTINGS_CACHE;
	} else if (strncmp(tmp, "GENERATED_PIXMAP", 16) == 0) {
		/* capture the file which a pixmap has been generated for */
		event = CMYTH_EVENT_GENERATED_PIXMAP;
		consumed = cmyth_rcv_string(conn, &err, tmp, sizeof(tmp) - 1, count);
		if (strncmp(tmp, "OK", 2) == 0) {
			consumed = cmyth_rcv_string(conn, &err, tmp, sizeof(tmp) - 1, count);
			strncpy(data, tmp, len);
		} else {
			data[0] = 0;
		}
	} else if (strncmp(tmp, "SYSTEM_EVENT", 12) == 0) {
		event = CMYTH_EVENT_SYSTEM_EVENT;
		strncpy(data, tmp + 13, len);
	} else if (strncmp(tmp, "UPDATE_FILE_SIZE", 16) == 0) {
		event = CMYTH_EVENT_UPDATE_FILE_SIZE;
		strncpy(data, tmp + 17, len);
	} else {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: unknown mythtv BACKEND_MESSAGE '%s'\n", __FUNCTION__, tmp);
		event = CMYTH_EVENT_UNKNOWN;
	}

	while(count > 0) {
		consumed = cmyth_rcv_string(conn, &err, tmp, sizeof(tmp) - 1, count);
		count -= consumed;
		cmyth_dbg(CMYTH_DBG_DEBUG, "%s: leftover data %s\n", __FUNCTION__, tmp);
	}

	return event;

 fail:
	return CMYTH_EVENT_UNKNOWN;
}
Beispiel #6
0
int
cmyth_conn_get_freespace(cmyth_conn_t control,
			 long long *total, long long *used)
{
	int err, count, ret = 0;
	int r;
	char msg[256];
	char reply[256];
	long long lreply;

	if (control == NULL)
		return -EINVAL;

	if ((total == NULL) || (used == NULL))
		return -EINVAL;

	pthread_mutex_lock(&mutex);

	if (control->conn_version >= 32)
		{ snprintf(msg, sizeof(msg), "QUERY_FREE_SPACE_SUMMARY"); }
	else if (control->conn_version >= 17)	
		{ snprintf(msg, sizeof(msg), "QUERY_FREE_SPACE"); }
	else
		{ snprintf(msg, sizeof(msg), "QUERY_FREESPACE"); }

	if ((err = cmyth_send_message(control, msg)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message() failed (%d)\n",
			  __FUNCTION__, err);
		ret = err;
		goto out;
	}

	if ((count=cmyth_rcv_length(control)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, count);
		ret = count;
		goto out;
	}
	
	if (control->conn_version >= 17) {
		if ((r=cmyth_rcv_long_long(control, &err, &lreply,
					   count)) < 0) {
			cmyth_dbg(CMYTH_DBG_ERROR,
				  "%s: cmyth_rcv_long_long() failed (%d)\n",
				  __FUNCTION__, err);
			ret = err;
			goto out;
		}
		*total = lreply;
		if ((r=cmyth_rcv_long_long(control, &err, &lreply,
					   count-r)) < 0) {
			cmyth_dbg(CMYTH_DBG_ERROR,
				  "%s: cmyth_rcv_long_long() failed (%d)\n",
				  __FUNCTION__, err);
			ret = err;
			goto out;
		}
		*used = lreply;
	}
	else
		{
			if ((r=cmyth_rcv_string(control, &err, reply,
						sizeof(reply)-1, count)) < 0) {
				cmyth_dbg(CMYTH_DBG_ERROR,
					  "%s: cmyth_rcv_string() failed (%d)\n",
					  __FUNCTION__, err);
				ret = err;
				goto out;
			}
			*total = atoi(reply);
			if ((r=cmyth_rcv_string(control, &err, reply,
						sizeof(reply)-1,
						count-r)) < 0) {
				cmyth_dbg(CMYTH_DBG_ERROR,
					  "%s: cmyth_rcv_string() failed (%d)\n",
					  __FUNCTION__, err);
				ret = err;
				goto out;
			}
			*used = atoi(reply);

			*used *= 1024;
			*total *= 1024;
		}

    out:
	pthread_mutex_unlock(&mutex);

	return ret;
}
Beispiel #7
0
/*
 * cmyth_proginfo_fill()
 *
 * Scope: PRIVATE (static)
 *
 * Description
 *
 * Fill out a (possibly incomplete) program info.  Incomplete program
 * info comes from program listings.  Since this modifies the contents of
 * the supplied program info, it must never be called with a program info
 * that has more than one reference).
 *
 * Return Value:
 *
 * Success: 0
 *
 * Failure: a negative error code.
 */
static int
cmyth_proginfo_fill(cmyth_conn_t control, cmyth_proginfo_t prog)
{
	int err = 0;
	int count = 0;
	int ret = 0;
	char *buf;
	char *proginfo;
	int64_t length = 0;

	if (!control) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no connection\n",
			  __FUNCTION__);
		return -EINVAL;
	}
	if (!prog) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no program info\n",
			  __FUNCTION__);
		return -EINVAL;
	}

	proginfo = cmyth_proginfo_string(control, prog);
	if (proginfo == NULL) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: program_info failed.\n",
			  __FUNCTION__);
		return -EINVAL;
	}

	buf = malloc(strlen(proginfo) + 34 + 1);
	if (!buf) {
		free(proginfo);
		return -ENOMEM;
	}
	sprintf(buf, "FILL_PROGRAM_INFO cmyth[]:[]0[]:[]%s", proginfo);
	free(proginfo);

	pthread_mutex_lock(&control->conn_mutex);

	length = prog->proginfo_Length;

	if ((err = cmyth_send_message(control, buf)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message() failed (%d)\n",
			  __FUNCTION__, err);
		ret = err;
		goto out;
	}

	count = cmyth_rcv_length(control);
	if (count < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, count);
		ret = count;
		goto out;
	}
	if (cmyth_rcv_proginfo(control, &err, prog, count) != count) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_proginfo() < count\n", __FUNCTION__);
		ret = err;
		goto out;
	}

	/*
	 * Myth seems to cache the program length, rather than call stat()
	 * every time it needs to know.  Using FILL_PROGRAM_INFO has worked
	 * to force mythbackend to call stat() and return the correct length.
	 *
	 * However, some users are reporting that FILL_PROGRAM_INFO is
	 * returning 0 for the program length.  In that case, the original
	 * number is still probably wrong, but it's better than 0.
	 */
	if (prog->proginfo_Length == 0) {
		prog->proginfo_Length = length;
	}

	out:
	pthread_mutex_unlock(&control->conn_mutex);
	free(buf);

	return ret;
}
Beispiel #8
0
/*
 * cmyth_proginfo_fill(cmyth_conn_t control, cmyth_proginfo_t prog)
 *
 * Scope: PRIVATE (static)
 *
 * Description
 *
 * Fill out a (possibly incomplete) program info.  Incomplete program
 * info comes from program listings.  Since this modifies the contents of
 * the supplied program info, it must never be called with a program info
 * that has more than one reference).
 *
 * Return Value:
 *
 * Success: 0
 *
 * Failure: a negative error code.
 */
static int
cmyth_proginfo_fill(cmyth_conn_t control, cmyth_proginfo_t prog)
{
	int err = 0;
	int count;
	int ret;
	long long length = 0;

	if (!control) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no connection\n",
			  __FUNCTION__);
		return -EINVAL;
	}
	if (!prog) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no program info\n",
			  __FUNCTION__);
		return -EINVAL;
	}

	pthread_mutex_lock(&control->conn_mutex);

	length = prog->proginfo_Length;
	if ((ret=fill_command(control, prog, "FILL_PROGRAM_INFO") != 0))
		goto out;

	count = cmyth_rcv_length(control);
	if (count < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, count);
		ret = count;
		goto out;
	}
	if (cmyth_rcv_proginfo(control, &err, prog, count) != count) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_proginfo() < count\n", __FUNCTION__);
		ret = err;
		goto out;
	}

	/*
	 * Myth seems to cache the program length, rather than call stat()
	 * every time it needs to know.  Using FILL_PROGRAM_INFO has worked
	 * to force mythbackend to call stat() and return the correct length.
	 *
	 * However, some users are reporting that FILL_PROGRAM_INFO is
	 * returning 0 for the program length.  In that case, the original
	 * number is still probably wrong, but it's better than 0.
	 */
	if (prog->proginfo_Length == 0) {
		prog->proginfo_Length = length;
		ret = -1;
		goto out;
	}

	ret = 0;

    out:
	pthread_mutex_unlock(&control->conn_mutex);

	return ret;
}
Beispiel #9
0
/*
 * cmyth_ringbuf_seek(
 *                    cmyth_ringbuf_t file, long long offset, int whence)
 * 
 * Scope: PUBLIC
 *
 * Description
 *
 * Seek to a new position in the file based on the value of whence:
 *	SEEK_SET
 *		The offset is set to offset bytes.
 *	SEEK_CUR
 *		The offset is set to the current position plus offset bytes.
 *	SEEK_END
 *		The offset is set to the size of the file minus offset bytes.
 *
 * Return Value:
 *
 * Sucess: 0
 *
 * Failure: an int containing -errno
 */
long long
cmyth_ringbuf_seek(cmyth_recorder_t rec,
		   long long offset, int whence)
{
	char msg[128];
	int err;
	int count;
	long long c;
	long r;
	long long ret;
	cmyth_ringbuf_t ring;

	if (rec == NULL)
		return -EINVAL;

	ring = rec->rec_ring;

	if ((offset == 0) && (whence == SEEK_CUR))
		return ring->file_pos;

	pthread_mutex_lock(&mutex);

	snprintf(msg, sizeof(msg),
		 "QUERY_RECORDER %u[]:[]SEEK_RINGBUF[]:[]%d[]:[]%d[]:[]%d[]:[]%d[]:[]%d",
		 rec->rec_id,
		 (int32_t)(offset >> 32),
		 (int32_t)(offset & 0xffffffff),
		 whence,
		 (int32_t)(ring->file_pos >> 32),
		 (int32_t)(ring->file_pos & 0xffffffff));

	if ((err = cmyth_send_message(rec->rec_conn, msg)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message() failed (%d)\n",
			  __FUNCTION__, err);
		ret = err;
		goto out;
	}

	count = cmyth_rcv_length(rec->rec_conn);
	if ((r=cmyth_rcv_long_long(rec->rec_conn, &err, &c, count)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, r);
		ret = err;
		goto out;
	}

	switch (whence) {
	case SEEK_SET:
		ring->file_pos = offset;
		break;
	case SEEK_CUR:
		ring->file_pos += offset;
		break;
	case SEEK_END:
		ring->file_pos = ring->file_length - offset;
		break;
	}

	ret = ring->file_pos;

    out:
	pthread_mutex_unlock(&mutex);
	
	return ret;
}
Beispiel #10
0
/*
 * cmyth_recorder_get_next_program_info(cmyth_recorder_t rec,
 *                                      cmyth_proginfo_t proginfo,
 *                                      cmyth_browsedir_t direction)
 *
 * Scope: PRIVATE (static)
 *
 * Description:
 *
 * Request program information from the recorder 'rec' for the next
 * program in the program guide from the current program (i.e. current
 * channel and time slot) in the direction specified by 'direction'
 * which may have any of the following values:
 *
 *     BROWSE_DIRECTION_SAME        - Stay in the same place
 *     BROWSE_DIRECTION_UP          - Move up one slot (down one channel)
 *     BROWSE_DIRECTION_DOWN        - Move down one slot (up one channel)
 *     BROWSE_DIRECTION_LEFT        - Move left one slot (down one time slot)
 *     BROWSE_DIRECTION_RIGHT       - Move right one slot (up one time slot)
 *     BROWSE_DIRECTION_FAVORITE    - Move to the next favorite slot
 *
 * The program information will be used to fill out 'proginfo'.
 *
 * This does not affect the current recording.
 *
 * Return Value:
 *
 * Success: 1 - valid channel, 0 - invalid channel
 *
 * Failure: -(ERRNO)
 */
int
cmyth_recorder_get_next_program_info(cmyth_recorder_t rec,
				     cmyth_proginfo_t cur_prog,
				     cmyth_proginfo_t next_prog,
				     cmyth_browsedir_t direction)
{
        int err, count;
        int ret = -ENOSYS;
        char msg[256];
        char title[256], subtitle[256], desc[256], category[256];
	char callsign[256], iconpath[256];
	char channelname[256], chanid[256], seriesid[256], programid[256];
	char date[256];
	struct tm *tm;
	time_t t;
	cmyth_conn_t control;

        if (!rec) {
                cmyth_dbg(CMYTH_DBG_ERROR, "%s: no recorder connection\n",
                          __FUNCTION__);
                return -ENOSYS;
        }

	control = rec->rec_conn;

        pthread_mutex_lock(&mutex);

	t = time(NULL);
	tm = localtime(&t);
	snprintf(date, sizeof(date), "%.4d%.2d%.2d%.2d%.2d%.2d",
		 tm->tm_year + 1900, tm->tm_mon + 1,
		 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);

        snprintf(msg, sizeof(msg), "QUERY_RECORDER %d[]:[]GET_NEXT_PROGRAM_INFO[]:[]%s[]:[]%ld[]:[]%i[]:[]%s",
                 rec->rec_id, cur_prog->proginfo_channame,
		 cur_prog->proginfo_chanId, direction, date);

        if ((err=cmyth_send_message(control, msg)) < 0) {
                cmyth_dbg(CMYTH_DBG_ERROR,
                          "%s: cmyth_send_message() failed (%d)\n",
                          __FUNCTION__, err);
                ret = err;
                goto out;
        }

        count = cmyth_rcv_length(control);

	count -= cmyth_rcv_string(control, &err,
				  title, sizeof(title), count);
	count -= cmyth_rcv_string(control, &err,
				  subtitle, sizeof(subtitle), count);
	count -= cmyth_rcv_string(control, &err,
				  desc, sizeof(desc), count);
	count -= cmyth_rcv_string(control, &err,
				  category, sizeof(category), count);
	count -= cmyth_rcv_timestamp(control, &err,
				     &next_prog->proginfo_start_ts, count);
	count -= cmyth_rcv_timestamp(control, &err,
				     &next_prog->proginfo_end_ts, count);
	count -= cmyth_rcv_string(control, &err,
				  callsign, sizeof(callsign), count);
	count -= cmyth_rcv_string(control, &err,
				  iconpath, sizeof(iconpath), count);
	count -= cmyth_rcv_string(control, &err,
				  channelname, sizeof(channelname), count);
	count -= cmyth_rcv_string(control, &err,
				  chanid, sizeof(chanid), count);
	if (control->conn_version >= 12) {
		count -= cmyth_rcv_string(control, &err,
					  seriesid, sizeof(seriesid), count);
		count -= cmyth_rcv_string(control, &err,
					  programid, sizeof(programid), count);
	}

	if (count != 0) {
		ret = -1;
		goto out;
	}

	/*
	 * if the program info is blank, return an error
	 */
	if ((strlen(title) == 0) && (strlen(subtitle) == 0) &&
	    (strlen(desc) == 0) && (strlen(channelname) == 0) &&
	    (strlen(chanid) == 0)) {
                cmyth_dbg(CMYTH_DBG_ERROR,
                          "%s: blank channel found\n", __FUNCTION__);
		ret = -1;
		goto out;
	}

	next_prog->proginfo_title = ref_strdup(title);
	next_prog->proginfo_subtitle = ref_strdup(subtitle);
	next_prog->proginfo_description = ref_strdup(desc);
	next_prog->proginfo_channame = ref_strdup(channelname);
	next_prog->proginfo_chansign = ref_strdup(callsign);
	
	next_prog->proginfo_chanId = atoi(chanid);

	ref_hold(next_prog->proginfo_start_ts);
	ref_hold(next_prog->proginfo_end_ts);

	ret = 0;
 
    out:
        pthread_mutex_unlock(&mutex);

        return ret;
}
Beispiel #11
0
/*
 * cmyth_ringbuf_read (cmyth_recorder_t rec, char *buf, unsigned long len)
 * 
 * Scope: PUBLIC
 *
 * Description
 *
 * Request and read a block of data from backend
 *
 * Return Value:
 *
 * Sucess: number of bytes transfered
 *
 * Failure: an int containing -errno
 */
int cmyth_ringbuf_read(cmyth_recorder_t rec, char *buf, unsigned long len)
{
	int err, count;
	int ret, req, nfds;
	char *end, *cur;
	char msg[256];
	struct timeval tv;
	fd_set fds;

	if (!rec)
	{
		cmyth_dbg (CMYTH_DBG_ERROR, "%s: no connection\n",
		           __FUNCTION__);
		return -EINVAL;
	}

	pthread_mutex_lock (&mutex);

	snprintf(msg, sizeof(msg),
		 "QUERY_RECORDER %u[]:[]REQUEST_BLOCK_RINGBUF[]:[]%ld",
		 rec->rec_id, len);

	if ( (err = cmyth_send_message (rec->rec_conn, msg) ) < 0)
	{
		cmyth_dbg (CMYTH_DBG_ERROR,
		           "%s: cmyth_send_message() failed (%d)\n",
		           __FUNCTION__, err);
		ret = err;
		goto out;
	}

	nfds = 0;
	req = 1;
	cur = buf;
	end = buf+len;

	while (cur < end || req)
	{
		tv.tv_sec = 20;
		tv.tv_usec = 0;
		FD_ZERO (&fds);
		if(req) {
			if((int)rec->rec_conn->conn_fd > nfds)
				nfds = (int)rec->rec_conn->conn_fd;
			FD_SET (rec->rec_conn->conn_fd, &fds);
		}
		if((int)rec->rec_ring->conn_data->conn_fd > nfds)
			nfds = (int)rec->rec_ring->conn_data->conn_fd;
		FD_SET (rec->rec_ring->conn_data->conn_fd, &fds);

		if ((ret = select (nfds+1, &fds, NULL, NULL,&tv)) < 0)
		{
			cmyth_dbg (CMYTH_DBG_ERROR,
			           "%s: select(() failed (%d)\n",
			           __FUNCTION__, ret);
			goto out;
		}

		if (ret == 0)
		{
			rec->rec_ring->conn_data->conn_hang = 1;
			rec->rec_conn->conn_hang = 1;
			ret = -ETIMEDOUT;
			goto out;
		}

		/* check control connection */
		if (FD_ISSET(rec->rec_conn->conn_fd, &fds) )
		{

			if ((count = cmyth_rcv_length (rec->rec_conn)) < 0)
			{
				cmyth_dbg (CMYTH_DBG_ERROR,
				           "%s: cmyth_rcv_length() failed (%d)\n",
				           __FUNCTION__, count);
				ret = count;
				goto out;
			}

			if ((ret = cmyth_rcv_ulong (rec->rec_conn, &err, &len, count))< 0)
			{
				cmyth_dbg (CMYTH_DBG_ERROR,
				           "%s: cmyth_rcv_long() failed (%d)\n",
				           __FUNCTION__, ret);
				ret = err;
				goto out;
			}

			rec->rec_ring->file_pos += len;
			req = 0;
			end = buf+len;
		}

		/* check data connection */
		if (FD_ISSET(rec->rec_ring->conn_data->conn_fd, &fds))
		{

			if ((ret = recv (rec->rec_ring->conn_data->conn_fd, cur, end-cur, 0)) < 0)
			{
				cmyth_dbg (CMYTH_DBG_ERROR,
				           "%s: recv() failed (%d)\n",
				           __FUNCTION__, ret);
				goto out;
			}
			cur += ret;
		}
	}

	ret = end - buf;
out:
	pthread_mutex_unlock (&mutex);
	return ret;
}
Beispiel #12
0
/*
 * cmyth_ringbuf_setup(cmyth_recorder_t old_rec)
 * 
 * Scope: PUBLIC
 *
 * Description
 *
 * Set up the ring buffer inside a recorder for use in playing live
 * tv.  The recorder is supplied.  This will be duplicated and
 * released, so the caller can re-use the same variable to hold the
 * return.  The new copy of the recorder will have a ringbuffer set up
 * within it.
 *
 * Return Value:
 *
 * Success: A pointer to a new recorder structure with a ringbuffer
 *
 * Faiure: NULL
 */
cmyth_recorder_t
cmyth_ringbuf_setup(cmyth_recorder_t rec)
{
	static const char service[]="rbuf://";
	cmyth_recorder_t new_rec = NULL;
	char *host = NULL;
	char *port = NULL;
	char *path = NULL;
	char tmp;

	int err, count;
	int r;
	long long size, fill;
	char msg[256];
	char url[1024];
	char buf[32];
	cmyth_conn_t control;

	if (!rec) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no recorder connection\n",
			  __FUNCTION__);
		return NULL;
	}

	control = rec->rec_conn;

	pthread_mutex_lock(&mutex);

	snprintf(msg, sizeof(msg),
		 "QUERY_RECORDER %u[]:[]SETUP_RING_BUFFER[]:[]0",
		 rec->rec_id);

	if ((err=cmyth_send_message(control, msg)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message() failed (%d)\n",
			  __FUNCTION__, err);
		goto out;
	}

	count = cmyth_rcv_length(control);

	if (control->conn_version >= 16) {
		r = cmyth_rcv_string(control, &err, buf, sizeof(buf)-1, count);
		count -= r;
	}
	r = cmyth_rcv_string(control, &err, url, sizeof(url)-1, count); 
	count -= r;

	if ((r=cmyth_rcv_long_long(control, &err, &size, count)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, r);
		goto out;
	}
	count -= r;

	if ((r=cmyth_rcv_long_long(control, &err, &fill, count)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, r);
		goto out;
	}

	cmyth_dbg(CMYTH_DBG_DEBUG, "%s: url is: '%s'\n",
		  __FUNCTION__, url);
	path = url;
	if (strncmp(url, service, sizeof(service) - 1) == 0) {
		/*
		 * The URL starts with rbuf://.  The rest looks like
		 * <host>:<port>/<filename>.
		 */
		host = url + strlen(service);
		port = strchr(host, ':');
		if (!port) {
			/*
			 * This does not seem to be a proper URL, so just
			 * assume it is a filename, and get out.
			 */
			cmyth_dbg(CMYTH_DBG_DEBUG,
				  "%s: 1 port %s, host = %s\n",
				  __FUNCTION__, port, host);
			goto out;
		}
		port = port + 1;
		path = strchr(port, '/');
		if (!path) {
			/*
			 * This does not seem to be a proper URL, so just
			 * assume it is a filename, and get out.
			 */
			cmyth_dbg(CMYTH_DBG_DEBUG, "%s: no path\n",
				  __FUNCTION__);
			goto out;
		}
	}

	new_rec = cmyth_recorder_dup(rec);
	if (new_rec == NULL) {
		cmyth_dbg(CMYTH_DBG_DEBUG, "%s: cannot create recorder\n",
			  __FUNCTION__);
		goto out;
	}
	ref_release(rec);
        new_rec->rec_ring = cmyth_ringbuf_create();
        
	tmp = *(port - 1);
	*(port - 1) = '\0';
	new_rec->rec_ring->ringbuf_hostname = ref_strdup(host);
	*(port - 1) = tmp;
	tmp = *(path);
	*(path) = '\0';
	new_rec->rec_ring->ringbuf_port = atoi(port);
	*(path) = tmp;
	new_rec->rec_ring->ringbuf_url = ref_strdup(url);
	new_rec->rec_ring->ringbuf_size = size;
	new_rec->rec_ring->ringbuf_fill = fill;

    out:
	pthread_mutex_unlock(&mutex);

	return new_rec;
}
Beispiel #13
0
static int
delete_command(cmyth_conn_t control, cmyth_proginfo_t prog, char *cmd)
{
    long c = 0;
    char *buf;
    unsigned int len = ((2 * CMYTH_LONGLONG_LEN) +
                        (6 * CMYTH_TIMESTAMP_LEN) +
                        (14 * CMYTH_LONG_LEN));
    char start_ts[CMYTH_TIMESTAMP_LEN + 1];
    char end_ts[CMYTH_TIMESTAMP_LEN + 1];
    char rec_start_ts[CMYTH_TIMESTAMP_LEN + 1];
    char rec_end_ts[CMYTH_TIMESTAMP_LEN + 1];
    char originalairdate[CMYTH_TIMESTAMP_LEN + 1];
    char lastmodified[CMYTH_TIMESTAMP_LEN + 1];
    int err;
    int count;
    long r;
    int ret;

    if (!prog) {
        cmyth_dbg(CMYTH_DBG_ERROR, "%s: no program info\n",
                  __FUNCTION__);
        return -EINVAL;
    }
#define S(a) ((a) == NULL ? "" : (a))

    len += strlen(S(prog->proginfo_title));
    len += strlen(S(prog->proginfo_subtitle));
    len += strlen(S(prog->proginfo_description));
    len += strlen(S(prog->proginfo_category));
    len += strlen(S(prog->proginfo_chanstr));
    len += strlen(S(prog->proginfo_chansign));
    len += strlen(S(prog->proginfo_channame));
    len += strlen(S(prog->proginfo_url));
    len += strlen(S(prog->proginfo_hostname));
    len += strlen(S(prog->proginfo_playgroup));
    len += strlen(S(prog->proginfo_recpriority_2));
    len += strlen(S(prog->proginfo_storagegroup));

    buf = alloca(len + 1+2048);
    if (!buf) {
        return -ENOMEM;
    }

    if(control->conn_version < 14)
    {
        cmyth_timestamp_to_string(start_ts, prog->proginfo_start_ts);
        cmyth_timestamp_to_string(end_ts, prog->proginfo_end_ts);
        cmyth_timestamp_to_string(rec_start_ts,
                                  prog->proginfo_rec_start_ts);
        cmyth_timestamp_to_string(rec_end_ts, prog->proginfo_rec_end_ts);
        cmyth_timestamp_to_string(originalairdate,
                                  prog->proginfo_originalairdate);
        cmyth_timestamp_to_string(lastmodified,
                                  prog->proginfo_lastmodified);
    }
    else
    {
        cmyth_datetime_to_string(start_ts, prog->proginfo_start_ts);
        cmyth_datetime_to_string(end_ts, prog->proginfo_end_ts);
        cmyth_datetime_to_string(rec_start_ts, prog->proginfo_rec_start_ts);
        cmyth_datetime_to_string(rec_end_ts, prog->proginfo_rec_end_ts);
        cmyth_datetime_to_string(originalairdate,
                                 prog->proginfo_originalairdate);
        cmyth_datetime_to_string(lastmodified, prog->proginfo_lastmodified);
    }

    if(control->conn_version > 32) {
        cmyth_timestamp_to_isostring(originalairdate,
                                     prog->proginfo_originalairdate);
    }

    if(control->conn_version < 12)
    {
        cmyth_dbg(CMYTH_DBG_ERROR,
                  "%s: delete not supported with protocol ver %d\n",
                  __FUNCTION__, control->conn_version);
        return -EINVAL;
    } else {
        sprintf(buf,
                "%s 0[]:[]"
                "%s[]:[]%s[]:[]%s[]:[]%s[]:[]%ld[]:[]"
                "%s[]:[]%s[]:[]%s[]:[]%s[]:[]%ld[]:[]"
                "%ld[]:[]%s[]:[]%s[]:[]%s[]:[]%ld[]:[]"
                "%ld[]:[]%s[]:[]%ld[]:[]%ld[]:[]%ld[]:[]"
                "%s[]:[]%ld[]:[]%ld[]:[]%ld[]:[]%ld[]:[]"
                "%ld[]:[]%s[]:[]%s[]:[]%ld[]:[]%ld[]:[]"
                "%s[]:[]%s[]:[]%s[]:[]%s[]:[]"
                "%s[]:[]%s[]:[]%s[]:[]%s[]:[]",
                cmd,
                S(prog->proginfo_title),
                S(prog->proginfo_subtitle),
                S(prog->proginfo_description),
                S(prog->proginfo_category),
                prog->proginfo_chanId,
                S(prog->proginfo_chanstr),
                S(prog->proginfo_chansign),
                S(prog->proginfo_chanicon),
                S(prog->proginfo_url),
                (unsigned long)(prog->proginfo_Length >> 32),
                (unsigned long)(prog->proginfo_Length & 0xffffffff),
                start_ts,
                end_ts,
                S(prog->proginfo_unknown_0),
                prog->proginfo_recording,
                prog->proginfo_override,
                S(prog->proginfo_hostname),
                prog->proginfo_source_id,
                prog->proginfo_card_id,
                prog->proginfo_input_id,
                S(prog->proginfo_rec_priority),
                prog->proginfo_rec_status,
                prog->proginfo_record_id,
                prog->proginfo_rec_type,
                prog->proginfo_rec_dups,
                prog->proginfo_unknown_1,
                rec_start_ts,
                rec_end_ts,
                prog->proginfo_repeat,
                prog->proginfo_program_flags,
                S(prog->proginfo_recgroup),
                S(prog->proginfo_chancommfree),
                S(prog->proginfo_chan_output_filters),
                S(prog->proginfo_seriesid),
                S(prog->proginfo_programid),
                lastmodified,
                S(prog->proginfo_stars),
                originalairdate);
        if (control->conn_version >= 15) {
            sprintf(buf + strlen(buf), "%ld[]:[]",
                    prog->proginfo_hasairdate);
        }
        if (control->conn_version >= 18) {
            sprintf(buf + strlen(buf), "%s[]:[]",
                    S(prog->proginfo_playgroup));
        }
        if (control->conn_version >= 25) {
            sprintf(buf + strlen(buf), "%s[]:[]",
                    S(prog->proginfo_recpriority_2));
        }
        if (control->conn_version >= 31) {
            sprintf(buf + strlen(buf), "%ld[]:[]",
                    prog->proginfo_parentid);
        }
        if (control->conn_version >= 32) {
            sprintf(buf + strlen(buf), "%s[]:[]",
                    S(prog->proginfo_storagegroup));
        }
        if (control->conn_version >= 35) {
            sprintf(buf + strlen(buf), "%ld[]:[]%ld[]:[]%ld[]:[]",
                    prog->proginfo_audioproperties,
                    prog->proginfo_videoproperties,
                    prog->proginfo_subtitletype);
        }
        if (control->conn_version >= 41) {
            sprintf(buf + strlen(buf), "%s[]:[]",
                    S(prog->proginfo_prodyear));
        }
    }
#undef S

    pthread_mutex_lock(&mutex);

    if ((err = cmyth_send_message(control, buf)) < 0) {
        cmyth_dbg(CMYTH_DBG_ERROR,
                  "%s: cmyth_send_message() failed (%d)\n",
                  __FUNCTION__, err);
        ret = err;
        goto out;
    }

    count = cmyth_rcv_length(control);
    if ((r=cmyth_rcv_long(control, &err, &c, count)) < 0) {
        cmyth_dbg(CMYTH_DBG_ERROR,
                  "%s: cmyth_rcv_length() failed (%d)\n",
                  __FUNCTION__, r);
        ret = err;
        goto out;
    }

    /*
     * XXX: for some reason, this seems to return an error, even though
     *      it succeeds...
     */

    ret = 0;

out:
    pthread_mutex_unlock(&mutex);

    return ret;
}
Beispiel #14
0
/*
 * cmyth_file_seek()
 *
 * Scope: PUBLIC
 *
 * Description
 *
 * Seek to a new position in the file based on the value of whence:
 *	WHENCE_SET
 *		The offset is set to offset bytes.
 *	WHENCE_CUR
 *		The offset is set to the current position plus offset bytes.
 *	WHENCE_END
 *		The offset is set to the size of the file minus offset bytes.
 *
 * Return Value:
 *
 * Sucess: 0
 *
 * Failure: an int containing -errno
 */
int64_t
cmyth_file_seek(cmyth_file_t file, int64_t offset, int8_t whence)
{
	char msg[128];
	int err;
	int count;
	int64_t c;
	int r;
	int64_t ret;

	if (file == NULL)
		return -EINVAL;

	if ((offset == 0) && (whence == WHENCE_CUR))
		return file->file_pos;

	if ((offset == file->file_pos) && (whence == WHENCE_SET))
		return file->file_pos;

	pthread_mutex_lock(&mutex);

	ret = 0;
	while(file->file_pos < file->file_req) {
		c = file->file_req - file->file_pos;
		if(c > sizeof(msg))
			c = sizeof(msg);

		if ((ret = cmyth_file_get_block(file, msg, (size_t)c)) < 0)
			break;
	}
	if (ret < 0)
		goto out;

	if (file->file_control->conn_version >= 66) {
		/*
		 * Since protocol 66 mythbackend expects to receive a single 64 bit integer rather than
		 * two 32 bit hi and lo integers.
		 */
		snprintf(msg, sizeof(msg),
			 "QUERY_FILETRANSFER %"PRIu32"[]:[]SEEK[]:[]%"PRId64"[]:[]%"PRId8"[]:[]%"PRId64,
			 file->file_id,
			 offset,
			 whence,
			 file->file_pos);
	}
	else {
		snprintf(msg, sizeof(msg),
			 "QUERY_FILETRANSFER %"PRIu32"[]:[]SEEK[]:[]%"PRId32"[]:[]%"PRId32"[]:[]%"PRId8"[]:[]%"PRId32"[]:[]%"PRId32,
			 file->file_id,
			 (int32_t)(offset >> 32),
			 (int32_t)(offset & 0xffffffff),
			 whence,
			 (int32_t)(file->file_pos >> 32),
			 (int32_t)(file->file_pos & 0xffffffff));
	}

	if ((err = cmyth_send_message(file->file_control, msg)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message() failed (%d)\n",
			  __FUNCTION__, err);
		ret = err;
		goto out;
	}

	if ((count=cmyth_rcv_length(file->file_control)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, count);
		ret = count;
		goto out;
	}
	if ((r=cmyth_rcv_int64(file->file_control, &err, &c, count)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_int64() failed (%d)\n",
			  __FUNCTION__, r);
		ret = err;
		goto out;
	}

	file->file_pos = c;
	file->file_req = file->file_pos;
	if(file->file_pos > file->file_length)
		file->file_length = file->file_pos;

	ret = file->file_pos;

    out:
	pthread_mutex_unlock(&mutex);

	return ret;
}
Beispiel #15
0
cmyth_proginfo_t
cmyth_proginfo_get_from_basename(cmyth_conn_t control, const char* basename)
{
	int err = 0;
	int count, i;
	char msg[4096];
	char *base;
	cmyth_proginfo_t prog = NULL;
	cmyth_proglist_t list = NULL;

	if (!control) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no connection\n",
			  __FUNCTION__);
		return NULL;
	}

	/*
	 * mythbackend doesn't support spaces in basenames
	 * when doing QUERY_RECORDING.  If there are spaces, fallback
	 * to enumerating all recordings
	 */
	if(control->conn_version >= 32 && strchr(basename, ' ') == NULL) {
		pthread_mutex_lock(&control->conn_mutex);

		snprintf(msg, sizeof(msg), "QUERY_RECORDING BASENAME %s",
			 basename);

		if ((err=cmyth_send_message(control, msg)) < 0) {
			cmyth_dbg(CMYTH_DBG_ERROR,
				  "%s: cmyth_send_message() failed (%d)\n",
			  	__FUNCTION__, err);
			goto out;
		}

		count = cmyth_rcv_length(control);
		if (count < 0) {
			cmyth_dbg(CMYTH_DBG_ERROR,
				  "%s: cmyth_rcv_length() failed (%d)\n",
				  __FUNCTION__, count);
			goto out;
		}

		i = cmyth_rcv_string(control, &err, msg, sizeof(msg), count);
		if (err) {
			cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_string() failed\n",
				  __FUNCTION__);
			goto out;
		}
		count -= i;

		if (strcmp(msg, "OK") != 0) {
			cmyth_dbg(CMYTH_DBG_ERROR, "%s: didn't recieve OK as response\n",
				  __FUNCTION__);
			goto out;
		}

		prog = cmyth_proginfo_create();
		if (cmyth_rcv_proginfo(control, &err, prog, count) != count) {
			cmyth_dbg(CMYTH_DBG_ERROR,
				  "%s: cmyth_rcv_proginfo() < count\n", __FUNCTION__);
			goto out;
		}

		pthread_mutex_unlock(&control->conn_mutex);
		return prog;
		out:
		pthread_mutex_unlock(&control->conn_mutex);
		if(prog)
			ref_release(prog);
		return NULL;

	} else {

		list = cmyth_proglist_get_all_recorded(control);
		if (!list) {
			cmyth_dbg(CMYTH_DBG_ERROR, "%s: no program list\n",
				  __FUNCTION__);
		}

		count = cmyth_proglist_get_count(list);
		for (i = 0;i < count; i++) {
			prog = cmyth_proglist_get_item(list, i);
			if (!prog) {
				cmyth_dbg(CMYTH_DBG_DEBUG, "%s: no program info\n",
					  __FUNCTION__);
				continue;
			}
			base = strrchr(prog->proginfo_pathname, '/');
			if (!base || strcmp(base+1, basename) !=0) {
				ref_release(prog);
				prog = NULL;
				continue;
			}
			break;
		}
		ref_release(list);
		return prog;
	}

}
Beispiel #16
0
/*
 * cmyth_file_read()
 *
 * Scope: PUBLIC
 *
 * Description
 *
 * Request and read a block of data from backend
 *
 * Return Value:
 *
 * Sucess: number of bytes transfered
 *
 * Failure: an int containing -errno
 */
int32_t cmyth_file_read(cmyth_file_t file, char *buf, int32_t len)
{
	int err, count;
	int32_t ret;
	int req, nfds, rec;
	char *end, *cur;
	char msg[256];
	int64_t len64;
	struct timeval tv;
	fd_set fds;

	if (!file || !file->file_data) {
		cmyth_dbg (CMYTH_DBG_ERROR, "%s: no connection\n",
		           __FUNCTION__);
		return -EINVAL;
	}
	if (len == 0)
		return 0;

	if(len > file->file_data->conn_tcp_rcvbuf)
		len = file->file_data->conn_tcp_rcvbuf;

	pthread_mutex_lock (&mutex);

	/* make sure we have outstanding requests that fill the buffer that was called with */
	/* this way we should be able to saturate the network connection better */
	if (file->file_req < file->file_pos + len) {

		snprintf (msg, sizeof (msg),
	            "QUERY_FILETRANSFER %"PRIu32"[]:[]REQUEST_BLOCK[]:[]%"PRId32,
	            file->file_id, (int32_t)(file->file_pos + len - file->file_req));

		if ( (err = cmyth_send_message (file->file_control, msg) ) < 0) {
			cmyth_dbg (CMYTH_DBG_ERROR,
			           "%s: cmyth_send_message() failed (%d)\n",
			           __FUNCTION__, err);
			ret = err;
			goto out;
		}
		req = 1;
	} else {
		req = 0;
	}

	rec = 0;
	cur = buf;
	end = buf+len;

	while (cur == buf || req || rec) {
		if(rec) {
			tv.tv_sec =  0;
			tv.tv_usec = 0;
		} else {
			tv.tv_sec = 20;
			tv.tv_usec = 0;
		}
		nfds = 0;

		FD_ZERO (&fds);
		if (req) {
			if ((int)file->file_control->conn_fd > nfds)
				nfds = (int)file->file_control->conn_fd;
			FD_SET (file->file_control->conn_fd, &fds);
		}
		if ((int)file->file_data->conn_fd > nfds)
			nfds = (int)file->file_data->conn_fd;
		FD_SET (file->file_data->conn_fd, &fds);

		if ((ret = select (nfds+1, &fds, NULL, NULL,&tv)) < 0) {
			cmyth_dbg (CMYTH_DBG_ERROR,
			           "%s: select(() failed (%d)\n",
			           __FUNCTION__, ret);
			goto out;
		}

		if (ret == 0 && !rec) {
			file->file_control->conn_hang = 1;
			file->file_data->conn_hang = 1;
			ret = -ETIMEDOUT;
			goto out;
		}

		/* check control connection */
		if (FD_ISSET(file->file_control->conn_fd, &fds)) {

			if ((count=cmyth_rcv_length (file->file_control)) < 0) {
				cmyth_dbg (CMYTH_DBG_ERROR,
				           "%s: cmyth_rcv_length() failed (%d)\n",
				           __FUNCTION__, count);
				ret = count;
				goto out;
			}

			/*
			 * MythTV originally sent back a signed 32bit value but was changed to a
			 * signed 64bit value in http://svn.mythtv.org/trac/changeset/18011 (1-Aug-2008).
			 *
			 * libcmyth now retrieves the 64-bit signed value, does error-checking,
			 * and then converts to a 32bit signed.
			 *
			 * This rcv_ method needs to be forced to use new_int64 to pull back a
			 * single 64bit number otherwise the handling in rcv_int64 will revert to
			 * the old two 32bit hi and lo long values.
			 */
			if ((ret = cmyth_rcv_new_int64(file->file_control, &err, &len64, count, 1))< 0) {
				cmyth_dbg (CMYTH_DBG_ERROR,
				           "%s: cmyth_rcv_new_int64() failed (%d)\n",
				           __FUNCTION__, ret);
				ret = err;
				goto out;
			}
			if (len64 > 0x7fffffff || len64 < 0) {
				/* -1 seems to be a common result, but isn't valid so use 0 instead. */
				cmyth_dbg (CMYTH_DBG_WARN,
				           "%s: cmyth_rcv_new_int64() returned out of bound value (%"PRId64"). Using 0 instead.\n",
				           __FUNCTION__, len64);
				len64 = 0;
			}
			len = (int32_t)len64;
			req = 0;
			file->file_req += len;

			if (file->file_req < file->file_pos) {
				cmyth_dbg (CMYTH_DBG_ERROR,
				           "%s: received invalid invalid length, read position is ahead of request (req: %"PRId64", pos: %"PRId64", len: %"PRId64")\n",
				           __FUNCTION__, file->file_req, file->file_pos, len64);
				ret = -1;
				goto out;
			}


			/* check if we are already done */
			if (file->file_pos == file->file_req)
				break;
		}

		/* restore direct request fleg */
		rec = 0;

		/* check data connection */
		if (FD_ISSET(file->file_data->conn_fd, &fds)) {
			if (end < cur) {
				cmyth_dbg (CMYTH_DBG_ERROR,
				           "%s: positions invalid on read, bailing out (cur: %x, end: %x)\n",
				           __FUNCTION__, cur, end);
				ret = -1;
				goto out;
			}
			if ((ret = recv (file->file_data->conn_fd, cur, (int32_t)(end - cur), 0)) < 0) {
				cmyth_dbg (CMYTH_DBG_ERROR,
				           "%s: recv() failed (%d)\n",
				           __FUNCTION__, ret);
				goto out;
			}
			cur += ret;
			file->file_pos += ret;
			if(ret)
				rec = 1; /* attempt to read directly again to get all queued packets */
		}
	}

	/* make sure file grows, as we move past length */
	if (file->file_pos > file->file_length)
		file->file_length = file->file_pos;

	ret = (int32_t)(cur - buf);
out:
	pthread_mutex_unlock (&mutex);
	return ret;
}
Beispiel #17
0
cmyth_proginfo_t
cmyth_proginfo_get_from_timeslot(cmyth_conn_t control, uint32_t chanid, const cmyth_timestamp_t recstartts)
{
	int err = 0;
	int count, i;
	char msg[4096];
	cmyth_proginfo_t prog = NULL;
	cmyth_proglist_t list = NULL;
	char time[15];

	if (!control) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no connection\n",
			  __FUNCTION__);
		return NULL;
	}

	if ((err = cmyth_timestamp_to_numstring(time, recstartts)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_timestamp_to_numstring() failed (%d)\n",
			  __FUNCTION__, err);
		return NULL;
	}

	if(control->conn_version >= 32) {
		pthread_mutex_lock(&control->conn_mutex);

		snprintf(msg, sizeof(msg), "QUERY_RECORDING TIMESLOT %"PRIu32" %s",
			chanid, time);

		if ((err=cmyth_send_message(control, msg)) < 0) {
			cmyth_dbg(CMYTH_DBG_ERROR,
				  "%s: cmyth_send_message() failed (%d)\n",
				  __FUNCTION__, err);
			goto out;
		}

		count = cmyth_rcv_length(control);
		if (count < 0) {
			cmyth_dbg(CMYTH_DBG_ERROR,
				  "%s: cmyth_rcv_length() failed (%d)\n",
				  __FUNCTION__, count);
			goto out;
		}

		i = cmyth_rcv_string(control, &err, msg, sizeof(msg), count);
		if (err) {
			cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_string() failed\n",
				  __FUNCTION__);
			goto out;
		}
		count -= i;

		if (strcmp(msg, "OK") != 0) {
			cmyth_dbg(CMYTH_DBG_ERROR, "%s: didn't recieve OK as response\n",
				  __FUNCTION__);
			goto out;
		}

		prog = cmyth_proginfo_create();
		if (cmyth_rcv_proginfo(control, &err, prog, count) != count) {
			cmyth_dbg(CMYTH_DBG_ERROR,
				  "%s: cmyth_rcv_proginfo() < count\n", __FUNCTION__);
			goto out;
		}

		pthread_mutex_unlock(&control->conn_mutex);
		return prog;
		out:
		pthread_mutex_unlock(&control->conn_mutex);
		if(prog)
			ref_release(prog);
		return NULL;

	} else {

		list = cmyth_proglist_get_all_recorded(control);
		if (!list) {
			cmyth_dbg(CMYTH_DBG_ERROR, "%s: no program list\n",
				  __FUNCTION__);
		}

		count = cmyth_proglist_get_count(list);
		for (i = 0;i < count; i++) {
			prog = cmyth_proglist_get_item(list, i);
			if (!prog) {
				cmyth_dbg(CMYTH_DBG_DEBUG, "%s: no program info\n",
					  __FUNCTION__);
				continue;
			}
			if (cmyth_timestamp_compare(prog->proginfo_rec_start_ts, recstartts) != 0 ||
					prog->proginfo_chanId != chanid) {
				ref_release(prog);
				prog = NULL;
				continue;
			}
			break;
		}
		ref_release(list);
		return prog;
	}

}
Beispiel #18
0
static int
proginfo_command(cmyth_conn_t control, cmyth_proginfo_t prog, char *cmd,
		 long *result)
{
	long c = 0;
	char *buf;
	unsigned int len = ((2 * CMYTH_LONGLONG_LEN) + 
			    (6 * CMYTH_TIMESTAMP_LEN) +
			    (16 * CMYTH_LONG_LEN));
	char start_ts[CMYTH_TIMESTAMP_LEN + 1];
	char end_ts[CMYTH_TIMESTAMP_LEN + 1];
	char rec_start_ts[CMYTH_TIMESTAMP_LEN + 1];
	char rec_end_ts[CMYTH_TIMESTAMP_LEN + 1];
	char originalairdate[CMYTH_TIMESTAMP_LEN + 1];
	char lastmodified[CMYTH_TIMESTAMP_LEN + 1];
	int err = 0;
	int count = 0;
	long r = 0;
	int ret = 0;

	if (!prog) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no program info\n",
			  __FUNCTION__);
		return -EINVAL;
	}

	len += strlen(prog->proginfo_title);
	len += strlen(prog->proginfo_subtitle);
	len += strlen(prog->proginfo_description);
	len += strlen(prog->proginfo_category);
	len += strlen(prog->proginfo_chanstr);
	len += strlen(prog->proginfo_chansign);
	len += strlen(prog->proginfo_channame);
	len += strlen(prog->proginfo_url);
	len += strlen(prog->proginfo_hostname);
	len += strlen(prog->proginfo_playgroup);
	len += strlen(prog->proginfo_seriesid);
	len += strlen(prog->proginfo_programid);
	if (prog->proginfo_inetref) {
		len += strlen(prog->proginfo_inetref);
	}
	if (prog->proginfo_recpriority_2) {
		len += strlen(prog->proginfo_recpriority_2);
	}
	if (prog->proginfo_storagegroup) {
		len += strlen(prog->proginfo_storagegroup);
	}

	buf = alloca(len + 1+2048);
	if (!buf) {
		return -ENOMEM;
	}

	if(control->conn_version < 14)
	{
	    cmyth_timestamp_to_string(start_ts, prog->proginfo_start_ts);
	    cmyth_timestamp_to_string(end_ts, prog->proginfo_end_ts);
	    cmyth_timestamp_to_string(rec_start_ts,
	    			      prog->proginfo_rec_start_ts);
	    cmyth_timestamp_to_string(rec_end_ts, prog->proginfo_rec_end_ts);
	    cmyth_timestamp_to_string(originalairdate,
				      prog->proginfo_originalairdate);
	    cmyth_timestamp_to_string(lastmodified,
				      prog->proginfo_lastmodified);
	}
	else
	{
	    cmyth_datetime_to_string(start_ts, prog->proginfo_start_ts);
	    cmyth_datetime_to_string(end_ts, prog->proginfo_end_ts);
	    cmyth_datetime_to_string(rec_start_ts, prog->proginfo_rec_start_ts);
	    cmyth_datetime_to_string(rec_end_ts, prog->proginfo_rec_end_ts);
	    cmyth_datetime_to_string(originalairdate,
				     prog->proginfo_originalairdate);
	    cmyth_datetime_to_string(lastmodified, prog->proginfo_lastmodified);
	}

	if(control->conn_version > 32) {
	    cmyth_timestamp_to_isostring(originalairdate,
				 prog->proginfo_originalairdate);
	}

	if(control->conn_version < 12)
	{
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: delete not supported with protocol ver %d\n",
			  __FUNCTION__, control->conn_version);
		return -EINVAL;
	}
	sprintf(buf, "%s 0[]:[]", cmd);
	sprintf(buf + strlen(buf), "%s[]:[]",  prog->proginfo_title);
	sprintf(buf + strlen(buf), "%s[]:[]",  prog->proginfo_subtitle);
	sprintf(buf + strlen(buf), "%s[]:[]",  prog->proginfo_description);
	if (control->conn_version >= 67) {
		sprintf(buf + strlen(buf), "%u[]:[]", prog->proginfo_season);
		sprintf(buf + strlen(buf), "%u[]:[]", prog->proginfo_episode);
	}
	sprintf(buf + strlen(buf), "%s[]:[]",  prog->proginfo_category);
	sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_chanId);
	sprintf(buf + strlen(buf), "%s[]:[]",  prog->proginfo_chanstr);
	sprintf(buf + strlen(buf), "%s[]:[]",  prog->proginfo_chansign);
	sprintf(buf + strlen(buf), "%s[]:[]",  prog->proginfo_channame);
	sprintf(buf + strlen(buf), "%s[]:[]",  prog->proginfo_url);
	if (control->conn_version >= 57) {
		sprintf(buf + strlen(buf), "%"PRId64"[]:[]", prog->proginfo_Length);
	} else {
		sprintf(buf + strlen(buf), "%d[]:[]", (int32_t)(prog->proginfo_Length >> 32));
		sprintf(buf + strlen(buf), "%d[]:[]", (int32_t)(prog->proginfo_Length & 0xffffffff));
	}
	sprintf(buf + strlen(buf), "%s[]:[]",  start_ts);
	sprintf(buf + strlen(buf), "%s[]:[]",  end_ts);
	if (control->conn_version < 57) {
		sprintf(buf + strlen(buf), "%s[]:[]", prog->proginfo_unknown_0); // "duplicate"
		sprintf(buf + strlen(buf), "%ld[]:[]", 0L); // "shareable"
	}
	sprintf(buf + strlen(buf), "%ld[]:[]", 0L); // "findid"
	sprintf(buf + strlen(buf), "%s[]:[]",  prog->proginfo_hostname);
	sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_source_id);
	sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_card_id);
	sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_input_id);
	sprintf(buf + strlen(buf), "%s[]:[]",  prog->proginfo_rec_priority);
	sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_rec_status);
	sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_record_id);
	sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_rec_type);
	sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_rec_dups);
	sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_unknown_1); // "dupmethod"
	sprintf(buf + strlen(buf), "%s[]:[]",  rec_start_ts);
	sprintf(buf + strlen(buf), "%s[]:[]",  rec_end_ts);
	if (control->conn_version < 57) {
		sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_repeat);
	}
	sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_program_flags);
	sprintf(buf + strlen(buf), "%s[]:[]",  prog->proginfo_recgroup);
	if (control->conn_version < 57) {
		sprintf(buf + strlen(buf), "%s[]:[]", prog->proginfo_chancommfree);
	}
	sprintf(buf + strlen(buf), "%s[]:[]",  prog->proginfo_chan_output_filters);
	sprintf(buf + strlen(buf), "%s[]:[]",  prog->proginfo_seriesid);
	sprintf(buf + strlen(buf), "%s[]:[]",  prog->proginfo_programid);
	if (control->conn_version >= 67) {
		sprintf(buf + strlen(buf), "%s[]:[]", prog->proginfo_inetref);
	}
	sprintf(buf + strlen(buf), "%s[]:[]",  lastmodified);
	sprintf(buf + strlen(buf), "%s[]:[]",  prog->proginfo_stars);
	sprintf(buf + strlen(buf), "%s[]:[]",  originalairdate);
	if (control->conn_version >= 15 && control->conn_version < 57) {
		sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_hasairdate);
	}
	if (control->conn_version >= 18) {
		sprintf(buf + strlen(buf), "%s[]:[]", prog->proginfo_playgroup);
	}
	if (control->conn_version >= 25) {
		sprintf(buf + strlen(buf), "%s[]:[]", prog->proginfo_recpriority_2);
	}
	if (control->conn_version >= 31) {
		sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_parentid);
	}
	if (control->conn_version >= 32) {
		sprintf(buf + strlen(buf), "%s[]:[]", prog->proginfo_storagegroup);
	}
	if (control->conn_version >= 35) {
		sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_audioproperties);
		sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_videoproperties);
		sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_subtitletype);
	}
	if (control->conn_version >= 43) {
		sprintf(buf + strlen(buf), "%d[]:[]", prog->proginfo_year);
	}

	pthread_mutex_lock(&control->conn_mutex);

	if ((err = cmyth_send_message(control, buf)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message() failed (%d)\n",
			  __FUNCTION__, err);
		ret = err;
		goto out;
	}

	count = cmyth_rcv_length(control);
	if ((r=cmyth_rcv_long(control, &err, &c, count)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, r);
		ret = err;
		goto out;
	}

	if (result) {
		*result = c;
	}

    out:
	pthread_mutex_unlock(&control->conn_mutex);

	return ret;
}
Beispiel #19
0
/*
 * cmyth_proginfo_stop_recording()
 *
 * Scope: PUBLIC
 *
 * Description
 *
 * Make a request on the control connection 'control' to ask the
 * MythTV back end to stop recording the program described in 'prog'.
 *
 * Return Value:
 *
 * Success: 0
 *
 * Failure: -(ERRNO)
 */
int
cmyth_proginfo_stop_recording(cmyth_conn_t control, cmyth_proginfo_t prog)
{
	int32_t c = 0;
	int err = 0;
	int count = 0;
	int r = 0;
	int ret = 0;
	char *buf;
	char *proginfo;

	if (!control) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no connection\n",
			  __FUNCTION__);
		return -EINVAL;
	}
	if (control->conn_version < 12)
	{
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: stop not supported with protocol ver %d\n",
			  __FUNCTION__, control->conn_version);
		return -EINVAL;
	}

	proginfo = cmyth_proginfo_string(control, prog);
	if (proginfo == NULL) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: program_info failed.\n",
			  __FUNCTION__);
		return -EINVAL;
	}

	buf = malloc(strlen(proginfo) + 21 + 1);
	if (!buf) {
		free(proginfo);
		return -ENOMEM;
	}
	sprintf(buf, "STOP_RECORDING 0[]:[]%s", proginfo);
	free(proginfo);

	pthread_mutex_lock(&control->conn_mutex);

	if ((err = cmyth_send_message(control, buf)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message() failed (%d)\n",
			  __FUNCTION__, err);
		ret = err;
		goto out;
	}

	count = cmyth_rcv_length(control);
	if ((r = cmyth_rcv_int32(control, &err, &c, count)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, r);
		ret = err;
		goto out;
	}

	out:
	pthread_mutex_unlock(&control->conn_mutex);
	free(buf);

	return ret;
}
Beispiel #20
0
/*
 * cmyth_conn_get_free_recorder(cmyth_conn_t control, cmyth_recorder_t rec)
 *                             
 * 
 * Scope: PUBLIC
 *
 * Description
 *
 * Obtain the next available free recorder the connection specified by
 * 'control'.  This fills out the recorder structure specified by 'rec'.
 *
 * Return Value:
 *
 * Success: 0 for not complete, 1 for complete
 *
 * Failure: -(errno)
 */
cmyth_recorder_t
cmyth_conn_get_free_recorder(cmyth_conn_t conn)
{
	int err, count;
	int r;
	long port, id;
	char msg[256];
	char reply[256];
	cmyth_recorder_t rec = NULL;

	if (!conn) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no connection\n",
			  __FUNCTION__);
		return NULL;
	}

	pthread_mutex_lock(&mutex);

	if ((rec=cmyth_recorder_create()) == NULL)
		goto fail;

	snprintf(msg, sizeof(msg), "GET_FREE_RECORDER");

	if ((err = cmyth_send_message(conn, msg)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message() failed (%d)\n",
			  __FUNCTION__, err);
		goto fail;
	}

	count = cmyth_rcv_length(conn);
	if (count < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, count);
		goto fail;
	}
	if ((r=cmyth_rcv_long(conn, &err, &id, count)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_long() failed (%d)\n",
			  __FUNCTION__, r);
		goto fail;
	}
	count -= r;
	if ((r=cmyth_rcv_string(conn, &err,
				reply, sizeof(reply)-1, count)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_string() failed (%d)\n",
			  __FUNCTION__, r);
		goto fail;
	}
	count -= r;
	if ((r=cmyth_rcv_long(conn, &err, &port, count)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_long() failed (%d)\n",
			  __FUNCTION__, r);
		goto fail;
	}

	if (port == -1)
		goto fail;

	rec->rec_id = id;
	rec->rec_server = ref_strdup(reply);
	rec->rec_port = port;

	if (cmyth_conn_connect_recorder(rec, conn->conn_buflen,
					conn->conn_tcp_rcvbuf) < 0)
		goto fail;

	pthread_mutex_unlock(&mutex);

	return rec;

    fail:
	if (rec)
		ref_release(rec);

	pthread_mutex_unlock(&mutex);

	return NULL;
}
Beispiel #21
0
Datei: file.c Projekt: tsp/cmyth
/*
 * cmyth_file_seek(cmyth_file_t file, long long offset, int whence)
 * 
 * Scope: PUBLIC
 *
 * Description
 *
 * Seek to a new position in the file based on the value of whence:
 *	SEEK_SET
 *		The offset is set to offset bytes.
 *	SEEK_CUR
 *		The offset is set to the current position plus offset bytes.
 *	SEEK_END
 *		The offset is set to the size of the file minus offset bytes.
 *
 * Return Value:
 *
 * Sucess: 0
 *
 * Failure: an int containing -errno
 */
long long
cmyth_file_seek(cmyth_file_t file, long long offset, int whence)
{
	char msg[128];
	int err;
	int count;
	long long c;
	long r;
	long long ret;

	if (file == NULL)
		return -EINVAL;

	if ((offset == 0) && (whence == SEEK_CUR))
		return file->file_pos;

	pthread_mutex_lock(&mutex);

	snprintf(msg, sizeof(msg),
		 "QUERY_FILETRANSFER %ld[]:[]SEEK[]:[]%d[]:[]%d[]:[]%d[]:[]%d[]:[]%d",
		 file->file_id,
		 (int32_t)(offset >> 32),
		 (int32_t)(offset & 0xffffffff),
		 whence,
		 (int32_t)(file->file_pos >> 32),
		 (int32_t)(file->file_pos & 0xffffffff));

	if ((err = cmyth_send_message(file->file_control, msg)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message() failed (%d)\n",
			  __FUNCTION__, err);
		ret = err;
		goto out;
	}

	if ((count=cmyth_rcv_length(file->file_control)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, count);
		ret = count;
		goto out;
	}
	if ((r=cmyth_rcv_long_long(file->file_control, &err, &c, count)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_long_long() failed (%d)\n",
			  __FUNCTION__, r);
		ret = err;
		goto out;
	}

	switch (whence) {
	case SEEK_SET:
		file->file_pos = offset;
		break;
	case SEEK_CUR:
		file->file_pos += offset;
		break;
	case SEEK_END:
		file->file_pos = file->file_length - offset;
		break;
	}

	ret = file->file_pos;

    out:
	pthread_mutex_unlock(&mutex);
	
	return ret;
}
Beispiel #22
0
/*
 * cmyth_conn_connect_file(char *server, unsigned short port, unsigned buflen
 *                         cmyth_proginfo_t prog)
 *
 * Scope: PUBLIC
 *
 * Description:
 *
 * Create a file structure containing a data connection for use
 * transfering a file within the MythTV protocol.  Return a pointer to
 * the newly created file structure.  The connection in the file
 * structure is returned held as is the file structure itself.  The
 * connection will be released when the file structure is released.
 * The file structure can be released using ref_release().
 *
 * Return Value:
 *
 * Success: Non-NULL cmyth_file_t (this is a pointer type)
 *
 * Failure: NULL cmyth_file_t
 */
cmyth_file_t
cmyth_conn_connect_file(cmyth_proginfo_t prog,  cmyth_conn_t control,
			unsigned buflen, int tcp_rcvbuf)
{
	cmyth_conn_t conn = NULL;
	char *announcement = NULL;
	char *myth_host = NULL;
	char reply[16];
	int err = 0;
	int count = 0;
	int r;
	int ann_size = sizeof("ANN FileTransfer []:[][]:[]");
	cmyth_file_t ret = NULL;

	if (!prog) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: prog is NULL\n", __FUNCTION__);
		goto shut;
	}
	if (!prog->proginfo_host) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: prog host is NULL\n",
			  __FUNCTION__);
		goto shut;
	}
	if (!prog->proginfo_pathname) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: prog has no pathname in it\n",
			  __FUNCTION__);
		goto shut;
	}
	ret = cmyth_file_create(control);
	if (!ret) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_file_create() failed\n",
			  __FUNCTION__);
		goto shut;
	}
	cmyth_dbg(CMYTH_DBG_PROTO, "%s: connecting data connection\n",
		  __FUNCTION__);
	if (control->conn_version >= 17) {
		myth_host = cmyth_conn_get_setting_unlocked(control, prog->proginfo_host,
		                                   "BackendServerIP");
	}
	if (!myth_host) {
		cmyth_dbg(CMYTH_DBG_PROTO,
		          "%s: BackendServerIP setting not found. Using proginfo_host: %s\n",
		          __FUNCTION__, prog->proginfo_host);
		myth_host = ref_alloc(strlen(prog->proginfo_host) + 1);
		strcpy(myth_host, prog->proginfo_host);
	}
	conn = cmyth_connect(myth_host, prog->proginfo_port,
			     buflen, tcp_rcvbuf);
	cmyth_dbg(CMYTH_DBG_PROTO,
		  "%s: done connecting data connection, conn = %d\n",
		  __FUNCTION__, conn);
	if (!conn) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_connect(%s, %d, %d) failed\n",
			  __FUNCTION__,
			  myth_host, prog->proginfo_port, buflen);
		goto shut;
	}
	ann_size += strlen(prog->proginfo_pathname) + strlen(my_hostname);
	announcement = malloc(ann_size);
	if (!announcement) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: malloc(%d) failed for announcement\n",
			  __FUNCTION__, ann_size);
		goto shut;
	}
	if (control->conn_version >= 44) {
		sprintf(announcement, "ANN FileTransfer %s[]:[]%s[]:[]",
			  my_hostname, prog->proginfo_pathname);
	}
	else {
		sprintf(announcement, "ANN FileTransfer %s[]:[]%s",
			  my_hostname, prog->proginfo_pathname);
	}

	if (cmyth_send_message(conn, announcement) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message('%s') failed\n",
			  __FUNCTION__, announcement);
		goto shut;
	}
	ret->file_data = ref_hold(conn);
	count = cmyth_rcv_length(conn);
	if (count < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, count);
		goto shut;
	}
	reply[sizeof(reply) - 1] = '\0';
	r = cmyth_rcv_string(conn, &err, reply, sizeof(reply) - 1, count); 
	if (err != 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_string() failed (%d)\n",
			  __FUNCTION__, err);
		goto shut;
	}
	if (strcmp(reply, "OK") != 0) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: reply ('%s') is not 'OK'\n",
			  __FUNCTION__, reply);
		goto shut;
	}
	count -= r;
	r = cmyth_rcv_long(conn, &err, &ret->file_id, count);
	if (err) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: (id) cmyth_rcv_long() failed (%d)\n",
			  __FUNCTION__, err);
		goto shut;
	}
	count -= r;
	r = cmyth_rcv_u_long_long(conn, &err, &ret->file_length, count);
	if (err) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: (length) cmyth_rcv_longlong() failed (%d)\n",
			  __FUNCTION__, err);
		goto shut;
	}
	count -= r;
	free(announcement);
	ref_release(conn);
	ref_release(myth_host);
	return ret;

    shut:
	if (announcement) {
		free(announcement);
	}
	ref_release(ret);
	ref_release(conn);
	ref_release(myth_host);
	return NULL;
}
Beispiel #23
0
/*
 * cmyth_file_seek(cmyth_file_t file, long long offset, int whence)
 *
 * Scope: PUBLIC
 *
 * Description
 *
 * Seek to a new position in the file based on the value of whence:
 *	SEEK_SET
 *		The offset is set to offset bytes.
 *	SEEK_CUR
 *		The offset is set to the current position plus offset bytes.
 *	SEEK_END
 *		The offset is set to the size of the file minus offset bytes.
 *
 * Return Value:
 *
 * Sucess: 0
 *
 * Failure: an int containing -errno
 */
long long
cmyth_file_seek(cmyth_file_t file, long long offset, int whence)
{
    char msg[128];
    int err;
    int count;
    int64_t c;
    long r;
    long long ret;

    if (file == NULL)
        return -EINVAL;

    if ((offset == 0) && (whence == SEEK_CUR))
        return file->file_pos;

    if ((offset == file->file_pos) && (whence == SEEK_SET))
        return file->file_pos;

    while(file->file_pos < file->file_req) {
        c = file->file_req - file->file_pos;
        if(c > sizeof(msg))
            c = sizeof(msg);

        if (cmyth_file_get_block(file, msg, (unsigned long)c) < 0)
            return -1;
    }

    pthread_mutex_lock(&mutex);

    if (file->file_control->conn_version >= 66) {
        /*
         * Since protocol 66 mythbackend expects to receive a single 64 bit integer rather than
         * two 32 bit hi and lo integers.
         */
        snprintf(msg, sizeof(msg),
                 "QUERY_FILETRANSFER %ld[]:[]SEEK[]:[]%"PRIu64"[]:[]%d[]:[]%"PRIu64,
                 file->file_id,
                 (int64_t)offset,
                 whence,
                 (int64_t)file->file_pos);
    }
    else {
        snprintf(msg, sizeof(msg),
                 "QUERY_FILETRANSFER %ld[]:[]SEEK[]:[]%d[]:[]%d[]:[]%d[]:[]%d[]:[]%d",
                 file->file_id,
                 (int32_t)(offset >> 32),
                 (int32_t)(offset & 0xffffffff),
                 whence,
                 (int32_t)(file->file_pos >> 32),
                 (int32_t)(file->file_pos & 0xffffffff));
    }

    if ((err = cmyth_send_message(file->file_control, msg)) < 0) {
        cmyth_dbg(CMYTH_DBG_ERROR,
                  "%s: cmyth_send_message() failed (%d)\n",
                  __FUNCTION__, err);
        ret = err;
        goto out;
    }

    if ((count=cmyth_rcv_length(file->file_control)) < 0) {
        cmyth_dbg(CMYTH_DBG_ERROR,
                  "%s: cmyth_rcv_length() failed (%d)\n",
                  __FUNCTION__, count);
        ret = count;
        goto out;
    }
    if ((r=cmyth_rcv_int64(file->file_control, &err, &c, count)) < 0) {
        cmyth_dbg(CMYTH_DBG_ERROR,
                  "%s: cmyth_rcv_int64() failed (%d)\n",
                  __FUNCTION__, r);
        ret = err;
        goto out;
    }

    switch (whence) {
    case SEEK_SET:
        file->file_pos = offset;
        break;
    case SEEK_CUR:
        file->file_pos += offset;
        break;
    case SEEK_END:
        file->file_pos = file->file_length - offset;
        break;
    }

    file->file_req = file->file_pos;
    if(file->file_pos > file->file_length)
        file->file_length = file->file_pos;

    ret = file->file_pos;

out:
    pthread_mutex_unlock(&mutex);

    return ret;
}