diff options
Diffstat (limited to 'lib/cmyth/libcmyth/socket.c')
-rw-r--r-- | lib/cmyth/libcmyth/socket.c | 291 |
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__); |