aboutsummaryrefslogtreecommitdiff
path: root/lib/cmyth/libcmyth/socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/cmyth/libcmyth/socket.c')
-rw-r--r--lib/cmyth/libcmyth/socket.c291
1 files changed, 183 insertions, 108 deletions
diff --git a/lib/cmyth/libcmyth/socket.c b/lib/cmyth/libcmyth/socket.c
index 552b88d696..4340f2ea78 100644
--- a/lib/cmyth/libcmyth/socket.c
+++ b/lib/cmyth/libcmyth/socket.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2006, Eric Lund
+ * Copyright (C) 2004-2012, Eric Lund
* http://www.mvpmc.org/
*
* This library is free software; you can redistribute it and/or
@@ -21,16 +21,12 @@
* socket.c - functions to handle low level socket interactions with a
* MythTV frontend.
*/
-#include <sys/types.h>
#include <stdlib.h>
-#ifndef _MSC_VER
-#include <unistd.h>
-#include <sys/socket.h>
-#endif
#include <stdio.h>
-#include <string.h>
#include <ctype.h>
+#include <string.h>
#include <errno.h>
+#include <sys/types.h>
#include <cmyth_local.h>
#define __UNSIGNED "0123456789"
@@ -367,7 +363,7 @@ cmyth_rcv_string(cmyth_conn_t conn, int *err, char *buf, int buflen, int count)
}
}
- if (conn->conn_buf[conn->conn_pos] == *state) {
+ if (conn->conn_buf[conn->conn_pos] == (unsigned char)*state) {
/*
* We matched the next (possibly first) step
* of a separator, advance to the next.
@@ -460,7 +456,7 @@ cmyth_rcv_ulong(cmyth_conn_t conn, int *err, unsigned long *buf,
int consumed;
int tmp;
- *buf = 0;
+ *buf = 0;
if (!err) {
err = &tmp;
@@ -836,7 +832,7 @@ cmyth_rcv_short(cmyth_conn_t conn, int *err, short *buf, int count)
}
/*
- * cmyth_rcv_long_long(cmyth_conn_t conn, int *err, long long *buf, int count)
+ * cmyth_rcv_old_int64(cmyth_conn_t conn, int *err, long long *buf, int count)
*
* Scope: PRIVATE (mapped to __cmyth_rcv_long)
*
@@ -867,9 +863,9 @@ cmyth_rcv_short(cmyth_conn_t conn, int *err, short *buf, int count)
* EINVAL The token received is not numeric
*/
int
-cmyth_rcv_long_long(cmyth_conn_t conn, int *err, long long *buf, int count)
+cmyth_rcv_old_int64(cmyth_conn_t conn, int *err, int64_t *buf, int count)
{
- long long val;
+ int64_t val;
int consumed;
int tmp;
unsigned long hi, lo;
@@ -883,45 +879,138 @@ cmyth_rcv_long_long(cmyth_conn_t conn, int *err, long long *buf, int count)
return 0;
}
- if (conn->conn_version >= 66) {
- /*
- * Since protocol 66 mythbackend now sends a single 64 bit integer rather than two hi and lo
- * 32 bit integers for ALL 64 bit values.
- */
- consumed = cmyth_rcv_int64(conn, err, &val, count);
- if (*err) {
- cmyth_dbg(CMYTH_DBG_ERROR,
- "%s: cmyth_rcv_int64() failed (%d)\n",
- __FUNCTION__, consumed);
- return consumed;
- }
+ consumed = cmyth_rcv_u_long(conn, err, &hi, count);
+ if (*err) {
+ cmyth_dbg(CMYTH_DBG_ERROR,
+ "%s: cmyth_rcv_u_long() failed (%d)\n",
+ __FUNCTION__, consumed);
+ return consumed;
}
- else {
- consumed = cmyth_rcv_u_long(conn, err, &hi, count);
- if (*err) {
+ consumed += cmyth_rcv_u_long(conn, err, &lo, count-consumed);
+ if (*err) {
+ cmyth_dbg(CMYTH_DBG_ERROR,
+ "%s: cmyth_rcv_u_long() failed (%d)\n",
+ __FUNCTION__, consumed);
+ return consumed;
+ }
+ val = (((long long)hi) << 32) | ((long long)(lo & 0xFFFFFFFF));
+
+ *err = 0;
+ *buf = val;
+
+ return consumed;
+}
+
+/*
+ * cmyth_rcv_new_int64(cmyth_conn_t conn, int *err, long long *buf, int count)
+ *
+ * Scope: PRIVATE (mapped to __cmyth_rcv_long)
+ *
+ * Description
+ *
+ * Receive a long long (signed 64 bit) integer token from a list of tokens
+ * in a MythTV Protocol message. Tokens in MythTV Protocol messages
+ * are separated by the string: []:[] or terminated by running out of
+ * message. Up to 'count' Bytes will be consumed from the socket
+ * specified by 'conn' (stopping when a separator is seen or 'count'
+ * is exhausted). The long integer value of the token is placed in
+ * the location pointed to by 'buf'. If an error is encountered and
+ * 'err' is not NULL, an indication of the nature of the error will be
+ * recorded by placing an error code in the location pointed to by
+ * 'err'. If all goes well, 'err' wil be set to 0.
+ *
+ * As of protocol version 57, Myth now sends a single 64bit string instead
+ * of 2 32bit strings when sending proginfo data. This does not seem to
+ * apply uniformly though. For instance 'ANN FILETRANSFER' still uses
+ * the old method
+ *
+ * Return Value:
+ *
+ * A value >=0 indicating the number of bytes consumed.
+ *
+ * Error Codes:
+ *
+ * In addition to system call error codes, the following errors may be
+ * placed in 'err':
+ *
+ * ERANGE The token received is too large to fit in a long integer
+ *
+ * EINVAL The token received is not numeric
+ */
+int
+cmyth_rcv_new_int64(cmyth_conn_t conn, int *err, int64_t *buf, int count,
+ int forced)
+{
+ char num[32];
+ char *num_p = num;
+ unsigned long long val = 0;
+ int sign = 1;
+ long long limit = 0x7fffffffffffffffLL;
+ int consumed;
+ int tmp;
+
+ /*
+ * Between protocols 57 and 66, not all messages used the new
+ * format for 64-bit values.
+ */
+ if ((conn->conn_version < 57) ||
+ ((conn->conn_version < 66) && !forced)) {
+ return cmyth_rcv_old_int64(conn, err, buf, count);
+ }
+
+ if (!err) {
+ err = &tmp;
+ }
+ if (count <= 0) {
+ *err = EINVAL;
+ return 0;
+ }
+ *err = 0;
+ consumed = cmyth_rcv_string(conn, err, num, sizeof(num), count);
+ if (*err) {
+ cmyth_dbg(CMYTH_DBG_ERROR,
+ "%s: cmyth_rcv_string() failed (%d)\n",
+ __FUNCTION__, consumed);
+ return consumed;
+ }
+ if (*num_p && (*num_p == '-')) {
+ ++num_p;
+ sign = -1;
+ }
+ while (*num_p) {
+ if (!isdigit(*num_p)) {
cmyth_dbg(CMYTH_DBG_ERROR,
- "%s: cmyth_rcv_u_long_long() failed (%d)\n",
- __FUNCTION__, consumed);
+ "%s: received illegal integer: '%s'\n",
+ __FUNCTION__, num);
+ *err = EINVAL;
return consumed;
}
- consumed += cmyth_rcv_u_long(conn, err, &lo, count-consumed);
- if (*err) {
+ val *= 10;
+ val += ((*num_p) - '0');
+ /*
+ * Check and make sure we are still under the limit (this is
+ * an absolute value limit, sign will be applied later).
+ */
+ if (val > (unsigned long long)limit) {
cmyth_dbg(CMYTH_DBG_ERROR,
- "%s: cmyth_rcv_u_long_long() failed (%d)\n",
- __FUNCTION__, consumed);
+ "%s: long long out of range: '%s'\n",
+ __FUNCTION__, num, limit);
+ *err = ERANGE;
return consumed;
}
- val = (((long long)hi) << 32) | ((long long)(lo & 0xFFFFFFFF));
+ num_p++;
}
- *err = 0;
- *buf = val;
+ /*
+ * Got a result, return it.
+ */
+ *buf = (long long)(sign * val);
return consumed;
}
/*
- * cmyth_rcv_int64(cmyth_conn_t conn, int *err, long long *buf, int count)
+ * cmyth_rcv_new_uint64(cmyth_conn_t conn, int *err, uint64_t *buf, int count)
*
* Scope: PRIVATE (mapped to __cmyth_rcv_long)
*
@@ -957,16 +1046,26 @@ cmyth_rcv_long_long(cmyth_conn_t conn, int *err, long long *buf, int count)
* EINVAL The token received is not numeric
*/
int
-cmyth_rcv_int64(cmyth_conn_t conn, int *err, long long *buf, int count)
+cmyth_rcv_new_uint64(cmyth_conn_t conn, int *err, uint64_t *buf, int count,
+ int forced)
{
char num[32];
char *num_p = num;
- unsigned long long val = 0;
+ uint64_t val = 0;
int sign = 1;
long long limit = 0x7fffffffffffffffLL;
int consumed;
int tmp;
+ /*
+ * Between protocols 57 and 66, not all messages used the new
+ * format for 64-bit values.
+ */
+ if ((conn->conn_version < 57) ||
+ ((conn->conn_version < 66) && !forced)) {
+ return cmyth_rcv_old_uint64(conn, err, buf, count);
+ }
+
if (!err) {
err = &tmp;
}
@@ -1183,16 +1282,14 @@ cmyth_rcv_ushort(cmyth_conn_t conn, int *err, unsigned short *buf, int count)
* EINVAL The token received is not numeric or is signed
*/
int
-cmyth_rcv_ulong_long(cmyth_conn_t conn, int *err,
- unsigned long long *buf, int count)
+cmyth_rcv_old_uint64(cmyth_conn_t conn, int *err, uint64_t *buf, int count)
{
unsigned long long val;
- long long val64;
unsigned long hi, lo;
int consumed;
int tmp;
- *buf = 0;
+ *buf = 0;
if (!err) {
err = &tmp;
@@ -1203,44 +1300,22 @@ cmyth_rcv_ulong_long(cmyth_conn_t conn, int *err,
return 0;
}
- if (conn->conn_version >= 66) {
- /*
- * Since protocol 66 mythbackend now sends a single 64 bit integer rather than two hi and lo
- * 32 bit integers for ALL 64 bit values.
- */
- consumed = cmyth_rcv_int64(conn, err, &val64, count);
- if (*err) {
- cmyth_dbg(CMYTH_DBG_ERROR,
- "%s: cmyth_rcv_int64() failed (%d)\n",
- __FUNCTION__, consumed);
- return consumed;
- }
- if (val64 < 0) {
- cmyth_dbg(CMYTH_DBG_ERROR,
- "%s: cmyth_rcv_int64() failed as signed 64 bit integer received\n",
- __FUNCTION__, consumed);
- *err = EINVAL;
- return consumed;
- }
- val = (unsigned long long)val64;
+ consumed = cmyth_rcv_u_long(conn, err, &hi, count);
+ if (*err) {
+ cmyth_dbg(CMYTH_DBG_ERROR,
+ "%s: cmyth_rcv_u_long() failed (%d)\n",
+ __FUNCTION__, consumed);
+ return consumed;
}
- else {
- consumed = cmyth_rcv_u_long(conn, err, &hi, count);
- if (*err) {
- cmyth_dbg(CMYTH_DBG_ERROR,
- "%s: cmyth_rcv_u_long_long() failed (%d)\n",
- __FUNCTION__, consumed);
- return consumed;
- }
- consumed += cmyth_rcv_u_long(conn, err, &lo, count);
- if (*err) {
- cmyth_dbg(CMYTH_DBG_ERROR,
- "%s: cmyth_rcv_u_long_long() failed (%d)\n",
- __FUNCTION__, consumed);
- return consumed;
- }
- val = (((unsigned long long)hi) << 32) | ((unsigned long long)(lo & 0xFFFFFFFF));
+ consumed += cmyth_rcv_u_long(conn, err, &lo, count - consumed);
+ if (*err) {
+ cmyth_dbg(CMYTH_DBG_ERROR,
+ "%s: cmyth_rcv_u_long() failed (%d)\n",
+ __FUNCTION__, consumed);
+ return consumed;
}
+ val = (((unsigned long long)hi) << 32) | ((unsigned long long)(lo & 0xFFFFFFFF));
+
*err = 0;
*buf = val;
@@ -1446,7 +1521,7 @@ cmyth_proginfo_parse_url(cmyth_proginfo_t p)
}
out:
- if (host && port) {
+ if (host && port && path) {
char tmp = *(port - 1);
*(port - 1) = '\0';
if (p->proginfo_host)
@@ -1508,7 +1583,6 @@ cmyth_rcv_proginfo(cmyth_conn_t conn, int *err, cmyth_proginfo_t buf,
int total = 0;
char *failed = NULL;
char tmp_str[32768];
- int (*rcv_64)(cmyth_conn_t, int *, long long *, int);
if (count <= 0) {
*err = EINVAL;
@@ -1521,15 +1595,6 @@ cmyth_rcv_proginfo(cmyth_conn_t conn, int *err, cmyth_proginfo_t buf,
cmyth_dbg(CMYTH_DBG_DEBUG, "%s: VERSION IS %ld\n",
__FUNCTION__, buf->proginfo_version);
- if (buf->proginfo_version >= 57) {
- /*
- * Since protocol 57 mythbackend now sends a single 64 bit integer rather than two 32 bit
- * hi and lo integers for the proginfo length.
- */
- rcv_64 = &cmyth_rcv_int64;
- } else {
- rcv_64 = &cmyth_rcv_long_long;
- }
/*
* Get proginfo_title (string)
*/
@@ -1707,7 +1772,18 @@ cmyth_rcv_proginfo(cmyth_conn_t conn, int *err, cmyth_proginfo_t buf,
/*
* Get proginfo_Length (long_long)
*/
- consumed = rcv_64(conn, err, &buf->proginfo_Length, count);
+ if (buf->proginfo_version < 57) {
+ consumed = cmyth_rcv_old_int64(conn, err, &buf->proginfo_Length,
+ count);
+ } else {
+ /*
+ * Since protocol 57 mythbackend now sends a single 64 bit
+ * integer rather than two 32 bit hi and lo integers for the
+ * proginfo length.
+ */
+ consumed = cmyth_rcv_new_int64(conn, err, &buf->proginfo_Length,
+ count, 1);
+ }
count -= consumed;
total += consumed;
if (*err) {
@@ -2269,31 +2345,30 @@ cmyth_rcv_proginfo(cmyth_conn_t conn, int *err, cmyth_proginfo_t buf,
failed = "cmyth_rcv_ulong subtitletype";
goto fail;
}
- }
- if (buf->proginfo_version >= 41) {
- /*
- * Get proginfo_prodyear (string)
- */
- consumed = cmyth_rcv_string(conn, err,
- tmp_str, sizeof(tmp_str) - 1, count);
+ }
+
+ /*
+ * Get Year
+ */
+ if (buf->proginfo_version >= 43) {
+ consumed = cmyth_rcv_ushort(conn, err, &buf->proginfo_year,
+ count);
count -= consumed;
total += consumed;
if (*err) {
- failed = "cmyth_rcv_string";
+ failed = "cmyth_rcv_ushort proginfo_year";
goto fail;
}
- if (buf->proginfo_prodyear)
- ref_release(buf->proginfo_prodyear);
- buf->proginfo_prodyear = ref_strdup(tmp_str);
- }
+ }
+
cmyth_dbg(CMYTH_DBG_INFO, "%s: got recording info\n", __FUNCTION__);
cmyth_proginfo_parse_url(buf);
return total;
fail:
- cmyth_dbg(CMYTH_DBG_ERROR, "%s: %s() failed (%d)\n",
- __FUNCTION__, failed, *err);
+ cmyth_dbg(CMYTH_DBG_ERROR, "%s: %s() failed (%d) (count = %d)\n",
+ __FUNCTION__, failed, *err, count);
return total;
}
@@ -2560,8 +2635,8 @@ cmyth_rcv_chaninfo(cmyth_conn_t conn, int *err, cmyth_proginfo_t buf,
return total;
fail:
- cmyth_dbg(CMYTH_DBG_ERROR, "%s: %s() failed (%d)\n",
- __FUNCTION__, failed, *err);
+ cmyth_dbg(CMYTH_DBG_ERROR, "%s: %s() failed (%d) (count = %d)\n",
+ __FUNCTION__, failed, *err, count);
return total;
}
@@ -2890,7 +2965,7 @@ cmyth_rcv_data(cmyth_conn_t conn, int *err, unsigned char *buf, int count)
*err = EINVAL;
return 0;
}
- err = 0;
+ *err = 0;
if (!conn) {
cmyth_dbg(CMYTH_DBG_ERROR, "%s: no connection\n",
__FUNCTION__);