Modifications to add HDHR prime, tuner as multicast source

Change-Id: Id83504747d3928d623546c0ba6e43c25b8813dae
diff --git a/libhdhomerun/hdhomerun_channels.c b/libhdhomerun/hdhomerun_channels.c
index c78ebce..4cfaf4a 100755
--- a/libhdhomerun/hdhomerun_channels.c
+++ b/libhdhomerun/hdhomerun_channels.c
@@ -79,16 +79,6 @@
 	{  0,   0,         0,       0}
 };
 
-/* KR cable channels. */
-static const struct hdhomerun_channelmap_range_t hdhomerun_channelmap_range_kr_cable[] = {
-	{  2,   4,  57000000, 6000000},
-	{  5,   6,  79000000, 6000000},
-	{  7,  13, 177000000, 6000000},
-	{ 14,  22, 123000000, 6000000},
-	{ 23, 153, 219000000, 6000000},
-	{  0,   0,         0,       0}
-};
-
 /* US antenna channels. */
 static const struct hdhomerun_channelmap_range_t hdhomerun_channelmap_range_us_bcast[] = {
 	{  2,   4,  57000000, 6000000},
@@ -145,8 +135,6 @@
 	{"tw-bcast", hdhomerun_channelmap_range_us_bcast, "tw-bcast",               "TW"},
 	{"tw-cable", hdhomerun_channelmap_range_us_cable, "tw-cable",               "TW"},
 
-	{"kr-bcast", hdhomerun_channelmap_range_us_bcast, "kr-bcast",               "KR"},
-	{"kr-cable", hdhomerun_channelmap_range_kr_cable, "kr-cable",               "KR"},
 	{"us-bcast", hdhomerun_channelmap_range_us_bcast, "us-bcast",               "CA US"},
 	{"us-cable", hdhomerun_channelmap_range_us_cable, "us-cable us-hrc us-irc", "CA PA US"},
 	{"us-hrc",   hdhomerun_channelmap_range_us_hrc  , "us-cable us-hrc us-irc", "CA PA US"},
diff --git a/libhdhomerun/hdhomerun_channelscan.c b/libhdhomerun/hdhomerun_channelscan.c
index 8c1f8db..ed1ec43 100755
--- a/libhdhomerun/hdhomerun_channelscan.c
+++ b/libhdhomerun/hdhomerun_channelscan.c
@@ -259,6 +259,29 @@
 	return 1;
 }
 
+int channelscan_at(struct hdhomerun_channelscan_t *scan, int number, struct hdhomerun_channelscan_result_t *result)
+{
+	memset(result, 0, sizeof(struct hdhomerun_channelscan_result_t));
+  struct hdhomerun_channel_entry_t *entry = hdhomerun_channel_list_last( scan->channel_list );
+  while ( entry ) {
+    if ( hdhomerun_channel_entry_channel_number( entry ) == number )
+      break;
+    entry = hdhomerun_channel_list_prev(scan->channel_list, entry);
+  }
+	scan->next_channel = 0;
+  
+
+	/* Combine channels with same frequency. */
+	result->frequency = hdhomerun_channel_entry_frequency(entry);
+	strncpy(result->channel_str, hdhomerun_channel_entry_name(entry), sizeof(result->channel_str) - 1);
+	result->channel_str[sizeof(result->channel_str) - 1] = 0;
+
+	char *ptr = strchr(result->channel_str, 0);
+	sprintf(ptr, ", %s", hdhomerun_channel_entry_name(entry));
+
+	return 1;
+}
+
 int channelscan_detect(struct hdhomerun_channelscan_t *scan, struct hdhomerun_channelscan_result_t *result)
 {
 	scan->scanned_channels++;
diff --git a/libhdhomerun/hdhomerun_channelscan.h b/libhdhomerun/hdhomerun_channelscan.h
index 8a1fac2..69db553 100755
--- a/libhdhomerun/hdhomerun_channelscan.h
+++ b/libhdhomerun/hdhomerun_channelscan.h
@@ -47,6 +47,7 @@
 extern LIBTYPE int channelscan_advance(struct hdhomerun_channelscan_t *scan, struct hdhomerun_channelscan_result_t *result);
 extern LIBTYPE int channelscan_detect(struct hdhomerun_channelscan_t *scan, struct hdhomerun_channelscan_result_t *result);
 extern LIBTYPE uint8_t channelscan_get_progress(struct hdhomerun_channelscan_t *scan);
+extern LIBTYPE int channelscan_at(struct hdhomerun_channelscan_t *scan, int number, struct hdhomerun_channelscan_result_t *result); //ZQ
 
 #ifdef __cplusplus
 }
diff --git a/libhdhomerun/hdhomerun_device.c b/libhdhomerun/hdhomerun_device.c
index 059c043..7bbb75a 100755
--- a/libhdhomerun/hdhomerun_device.c
+++ b/libhdhomerun/hdhomerun_device.c
@@ -1296,6 +1296,22 @@
 	return ret;
 }
 
+int hdhomerun_device_channelscan_at(struct hdhomerun_device_t *hd, int channel_num, struct hdhomerun_channelscan_result_t *result)
+{
+	if (!hd->scan) {
+		hdhomerun_debug_printf(hd->dbg, "hdhomerun_device_channelscan_at: scan not initialized\n");
+		return 0;
+	}
+
+	int ret = channelscan_at(hd->scan, channel_num, result);
+	if (ret <= 0) { /* Free scan if normal finish or fatal error */
+		channelscan_destroy(hd->scan);
+		hd->scan = NULL;
+	}
+
+	return ret;
+}
+
 int hdhomerun_device_channelscan_detect(struct hdhomerun_device_t *hd, struct hdhomerun_channelscan_result_t *result)
 {
 	if (!hd->scan) {
diff --git a/libhdhomerun/hdhomerun_device.h b/libhdhomerun/hdhomerun_device.h
index 51c2b86..0648caa 100755
--- a/libhdhomerun/hdhomerun_device.h
+++ b/libhdhomerun/hdhomerun_device.h
@@ -239,6 +239,7 @@
 extern LIBTYPE int hdhomerun_device_channelscan_advance(struct hdhomerun_device_t *hd, struct hdhomerun_channelscan_result_t *result);
 extern LIBTYPE int hdhomerun_device_channelscan_detect(struct hdhomerun_device_t *hd, struct hdhomerun_channelscan_result_t *result);
 extern LIBTYPE uint8_t hdhomerun_device_channelscan_get_progress(struct hdhomerun_device_t *hd);
+extern LIBTYPE int hdhomerun_device_channelscan_at(struct hdhomerun_device_t *hd, int channel_num, struct hdhomerun_channelscan_result_t *result);
 
 /*
  * Upload new firmware to the device.
diff --git a/libhdhomerun/hdhomerun_sock_posix.c b/libhdhomerun/hdhomerun_sock_posix.c
index 52dccc0..5a8c376 100755
--- a/libhdhomerun/hdhomerun_sock_posix.c
+++ b/libhdhomerun/hdhomerun_sock_posix.c
@@ -50,19 +50,13 @@
 
 #include <net/if.h>
 #include <sys/ioctl.h>
-
 #ifndef SIOCGIFCONF
 #include <sys/sockio.h>
 #endif
-
 #ifndef _SIZEOF_ADDR_IFREQ
 #define _SIZEOF_ADDR_IFREQ(x) sizeof(x)
 #endif
 
-#ifndef MSG_NOSIGNAL
-#define MSG_NOSIGNAL 0
-#endif
-
 int hdhomerun_local_ip_info(struct hdhomerun_local_ip_info_t ip_info_list[], int max_count)
 {
 	int sock = socket(AF_INET, SOCK_DGRAM, 0);
@@ -374,20 +368,30 @@
 	sock_addr.sin_addr.s_addr = htonl(remote_addr);
 	sock_addr.sin_port = htons(remote_port);
 
-	if (connect(sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) {
-		if ((errno != EAGAIN) && (errno != EWOULDBLOCK) && (errno != EINPROGRESS)) {
-			return FALSE;
-		}
+	if (connect(sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) == 0) {
+		return TRUE;
 	}
 
 	uint64_t stop_time = getcurrenttime() + timeout;
 
+	/*
+	 * getpeername() is used to detect if connect succeeded. Bug - cygwin
+	 * will return getpeername success even if the connect process hasn't
+	 * completed. This first call to select is used to work around the
+	 * problem (at least for low numbered sockets where select is used).
+	 */
+	if (!hdhomerun_sock_wait_for_write_event(sock, stop_time)) {
+		return FALSE;
+	}
+
 	while (1) {
-		if (send(sock, NULL, 0, MSG_NOSIGNAL) == 0) {
+		struct sockaddr_in sock_addr;
+		socklen_t sockaddr_size = sizeof(sock_addr);
+		if (getpeername(sock, (struct sockaddr *)&sock_addr, &sockaddr_size) == 0) {
 			return TRUE;
 		}
 
-		if ((errno != EAGAIN) && (errno != EWOULDBLOCK) && (errno != EINPROGRESS) && (errno != ENOTCONN)) {
+		if (errno != ENOTCONN) {
 			return FALSE;
 		}
 
@@ -403,24 +407,26 @@
 	const uint8_t *ptr = (const uint8_t *)data;
 
 	while (1) {
-		int ret = send(sock, ptr, length, MSG_NOSIGNAL);
-		if (ret <= 0) {
-			if ((errno != EAGAIN) && (errno != EWOULDBLOCK) && (errno != EINPROGRESS)) {
-				return FALSE;
-			}
-			if (!hdhomerun_sock_wait_for_write_event(sock, stop_time)) {
-				return FALSE;
-			}
-			continue;
+		int ret = send(sock, ptr, length, 0);
+		if (ret >= (int)length) {
+			return TRUE;
 		}
 
-		if (ret < (int)length) {
+		if (ret > 0) {
 			ptr += ret;
 			length -= ret;
-			continue;
 		}
 
-		return TRUE;
+		if (errno == EINPROGRESS) {
+			errno = EWOULDBLOCK;
+		}
+		if (errno != EWOULDBLOCK) {
+			return FALSE;
+		}
+
+		if (!hdhomerun_sock_wait_for_write_event(sock, stop_time)) {
+			return FALSE;
+		}
 	}
 }
 
@@ -437,23 +443,25 @@
 		sock_addr.sin_port = htons(remote_port);
 
 		int ret = sendto(sock, ptr, length, 0, (struct sockaddr *)&sock_addr, sizeof(sock_addr));
-		if (ret <= 0) {
-			if ((errno != EAGAIN) && (errno != EWOULDBLOCK) && (errno != EINPROGRESS)) {
-				return FALSE;
-			}
-			if (!hdhomerun_sock_wait_for_write_event(sock, stop_time)) {
-				return FALSE;
-			}
-			continue;
+		if (ret >= (int)length) {
+			return TRUE;
 		}
 
-		if (ret < (int)length) {
+		if (ret > 0) {
 			ptr += ret;
 			length -= ret;
-			continue;
 		}
 
-		return TRUE;
+		if (errno == EINPROGRESS) {
+			errno = EWOULDBLOCK;
+		}
+		if (errno != EWOULDBLOCK) {
+			return FALSE;
+		}
+
+		if (!hdhomerun_sock_wait_for_write_event(sock, stop_time)) {
+			return FALSE;
+		}
 	}
 }
 
@@ -463,22 +471,21 @@
 
 	while (1) {
 		int ret = recv(sock, data, *length, 0);
-		if (ret < 0) {
-			if ((errno != EAGAIN) && (errno != EWOULDBLOCK) && (errno != EINPROGRESS)) {
-				return FALSE;
-			}
-			if (!hdhomerun_sock_wait_for_read_event(sock, stop_time)) {
-				return FALSE;
-			}
-			continue;
+		if (ret > 0) {
+			*length = ret;
+			return TRUE;
 		}
 
-		if (ret == 0) {
+		if (errno == EINPROGRESS) {
+			errno = EWOULDBLOCK;
+		}
+		if (errno != EWOULDBLOCK) {
 			return FALSE;
 		}
 
-		*length = ret;
-		return TRUE;
+		if (!hdhomerun_sock_wait_for_read_event(sock, stop_time)) {
+			return FALSE;
+		}
 	}
 }
 
@@ -492,23 +499,22 @@
 		socklen_t sockaddr_size = sizeof(sock_addr);
 
 		int ret = recvfrom(sock, data, *length, 0, (struct sockaddr *)&sock_addr, &sockaddr_size);
-		if (ret < 0) {
-			if ((errno != EAGAIN) && (errno != EWOULDBLOCK) && (errno != EINPROGRESS)) {
-				return FALSE;
-			}
-			if (!hdhomerun_sock_wait_for_read_event(sock, stop_time)) {
-				return FALSE;
-			}
-			continue;
+		if (ret > 0) {
+			*remote_addr = ntohl(sock_addr.sin_addr.s_addr);
+			*remote_port = ntohs(sock_addr.sin_port);
+			*length = ret;
+			return TRUE;
 		}
 
-		if (ret == 0) {
+		if (errno == EINPROGRESS) {
+			errno = EWOULDBLOCK;
+		}
+		if (errno != EWOULDBLOCK) {
 			return FALSE;
 		}
 
-		*remote_addr = ntohl(sock_addr.sin_addr.s_addr);
-		*remote_port = ntohs(sock_addr.sin_port);
-		*length = ret;
-		return TRUE;
+		if (!hdhomerun_sock_wait_for_read_event(sock, stop_time)) {
+			return FALSE;
+		}
 	}
 }
diff --git a/libhdhomerun/hdhomerun_sock_windows.c b/libhdhomerun/hdhomerun_sock_windows.c
index c599694..d03a059 100755
--- a/libhdhomerun/hdhomerun_sock_windows.c
+++ b/libhdhomerun/hdhomerun_sock_windows.c
@@ -269,6 +269,16 @@
 
 bool_t hdhomerun_sock_connect(hdhomerun_sock_t sock, uint32_t remote_addr, uint16_t remote_port, uint64_t timeout)
 {
+	WSAEVENT wsa_event = WSACreateEvent();
+	if (wsa_event == WSA_INVALID_EVENT) {
+		return FALSE;
+	}
+
+	if (WSAEventSelect(sock, wsa_event, FD_CONNECT) == SOCKET_ERROR) {
+		WSACloseEvent(wsa_event);
+		return FALSE;
+	}
+
 	/* Connect (non-blocking). */
 	struct sockaddr_in sock_addr;
 	memset(&sock_addr, 0, sizeof(sock_addr));
@@ -278,41 +288,22 @@
 
 	if (connect(sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) {
 		if (WSAGetLastError() != WSAEWOULDBLOCK) {
+			WSACloseEvent(wsa_event);
 			return FALSE;
 		}
 	}
 
 	/* Wait for connect to complete (both success and failure will signal). */
-	WSAEVENT wsa_event = WSACreateEvent();
-	if (wsa_event == WSA_INVALID_EVENT) {
-		return FALSE;
-	}
-
-	if (WSAEventSelect(sock, wsa_event, FD_WRITE | FD_CLOSE) == SOCKET_ERROR) {
-		WSACloseEvent(wsa_event);
-		return FALSE;
-	}
-
 	DWORD ret = WaitForSingleObjectEx(wsa_event, (DWORD)timeout, FALSE);
 	WSACloseEvent(wsa_event);
+
 	if (ret != WAIT_OBJECT_0) {
 		return FALSE;
 	}
 
 	/* Detect success/failure. */
-	wsa_event = WSACreateEvent();
-	if (wsa_event == WSA_INVALID_EVENT) {
-		return FALSE;
-	}
-
-	if (WSAEventSelect(sock, wsa_event, FD_CLOSE) == SOCKET_ERROR) {
-		WSACloseEvent(wsa_event);
-		return FALSE;
-	}
-
-	ret = WaitForSingleObjectEx(wsa_event, 0, FALSE);
-	WSACloseEvent(wsa_event);
-	if (ret == WAIT_OBJECT_0) {
+	int sockaddr_size = sizeof(sock_addr);
+	if (getpeername(sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) {
 		return FALSE;
 	}
 
@@ -353,23 +344,22 @@
 
 	while (1) {
 		int ret = send(sock, (char *)ptr, (int)length, 0);
-		if (ret <= 0) {
-			if (WSAGetLastError() != WSAEWOULDBLOCK) {
-				return FALSE;
-			}
-			if (!hdhomerun_sock_wait_for_event(sock, FD_WRITE | FD_CLOSE, stop_time)) {
-				return FALSE;
-			}
-			continue;
+		if (ret >= (int)length) {
+			return TRUE;
 		}
 
-		if (ret < (int)length) {
+		if (ret > 0) {
 			ptr += ret;
 			length -= ret;
-			continue;
 		}
 
-		return TRUE;
+		if (WSAGetLastError() != WSAEWOULDBLOCK) {
+			return FALSE;
+		}
+
+		if (!hdhomerun_sock_wait_for_event(sock, FD_WRITE | FD_CLOSE, stop_time)) {
+			return FALSE;
+		}
 	}
 }
 
@@ -386,23 +376,22 @@
 		sock_addr.sin_port = htons(remote_port);
 
 		int ret = sendto(sock, (char *)ptr, (int)length, 0, (struct sockaddr *)&sock_addr, sizeof(sock_addr));
-		if (ret <= 0) {
-			if (WSAGetLastError() != WSAEWOULDBLOCK) {
-				return FALSE;
-			}
-			if (!hdhomerun_sock_wait_for_event(sock, FD_WRITE | FD_CLOSE, stop_time)) {
-				return FALSE;
-			}
-			continue;
+		if (ret >= (int)length) {
+			return TRUE;
 		}
 
-		if (ret < (int)length) {
+		if (ret > 0) {
 			ptr += ret;
 			length -= ret;
-			continue;
 		}
 
-		return TRUE;
+		if (WSAGetLastError() != WSAEWOULDBLOCK) {
+			return FALSE;
+		}
+
+		if (!hdhomerun_sock_wait_for_event(sock, FD_WRITE | FD_CLOSE, stop_time)) {
+			return FALSE;
+		}
 	}
 }
 
@@ -412,22 +401,18 @@
 
 	while (1) {
 		int ret = recv(sock, (char *)data, (int)(*length), 0);
-		if (ret < 0) {
-			if (WSAGetLastError() != WSAEWOULDBLOCK) {
-				return FALSE;
-			}
-			if (!hdhomerun_sock_wait_for_event(sock, FD_READ | FD_CLOSE, stop_time)) {
-				return FALSE;
-			}
-			continue;
+		if (ret > 0) {
+			*length = ret;
+			return TRUE;
 		}
 
-		if (ret == 0) {
+		if (WSAGetLastError() != WSAEWOULDBLOCK) {
 			return FALSE;
 		}
 
-		*length = ret;
-		return TRUE;
+		if (!hdhomerun_sock_wait_for_event(sock, FD_READ | FD_CLOSE, stop_time)) {
+			return FALSE;
+		}
 	}
 }
 
@@ -441,23 +426,19 @@
 		int sockaddr_size = sizeof(sock_addr);
 
 		int ret = recvfrom(sock, (char *)data, (int)(*length), 0, (struct sockaddr *)&sock_addr, &sockaddr_size);
-		if (ret < 0) {
-			if (WSAGetLastError() != WSAEWOULDBLOCK) {
-				return FALSE;
-			}
-			if (!hdhomerun_sock_wait_for_event(sock, FD_READ | FD_CLOSE, stop_time)) {
-				return FALSE;
-			}
-			continue;
+		if (ret > 0) {
+			*remote_addr = ntohl(sock_addr.sin_addr.s_addr);
+			*remote_port = ntohs(sock_addr.sin_port);
+			*length = ret;
+			return TRUE;
 		}
 
-		if (ret == 0) {
+		if (WSAGetLastError() != WSAEWOULDBLOCK) {
 			return FALSE;
 		}
 
-		*remote_addr = ntohl(sock_addr.sin_addr.s_addr);
-		*remote_port = ntohs(sock_addr.sin_port);
-		*length = ret;
-		return TRUE;
+		if (!hdhomerun_sock_wait_for_event(sock, FD_READ | FD_CLOSE, stop_time)) {
+			return FALSE;
+		}
 	}
 }