|
MythTV
0.26-pre
|
00001 /* 00002 * hdhomerun_sock_windows.c 00003 * 00004 * Copyright © 2010 Silicondust USA Inc. <www.silicondust.com>. 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 3 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 00018 * 00019 * As a special exception to the GNU Lesser General Public License, 00020 * you may link, statically or dynamically, an application with a 00021 * publicly distributed version of the Library to produce an 00022 * executable file containing portions of the Library, and 00023 * distribute that executable file under terms of your choice, 00024 * without any of the additional requirements listed in clause 4 of 00025 * the GNU Lesser General Public License. 00026 * 00027 * By "a publicly distributed version of the Library", we mean 00028 * either the unmodified Library as distributed by Silicondust, or a 00029 * modified version of the Library that is distributed under the 00030 * conditions defined in the GNU Lesser General Public License. 00031 */ 00032 00033 /* 00034 * Implementation notes: 00035 * 00036 * API specifies timeout for each operation (or zero for non-blocking). 00037 * 00038 * It is not possible to rely on the OS socket timeout as this will fail to 00039 * detect the command-response situation where data is sent successfully and 00040 * the other end chooses not to send a response (other than the TCP ack). 00041 * 00042 * Windows supports select() however native WSA events are used to: 00043 * - avoid problems with socket numbers above 1024. 00044 * - wait without allowing other events handlers to run (important for use 00045 * with win7 WMC). 00046 */ 00047 00048 #include "hdhomerun.h" 00049 #include <windows.h> 00050 #include <iphlpapi.h> 00051 00052 int hdhomerun_local_ip_info(struct hdhomerun_local_ip_info_t ip_info_list[], int max_count) 00053 { 00054 PIP_ADAPTER_INFO AdapterInfo; 00055 ULONG AdapterInfoLength = sizeof(IP_ADAPTER_INFO) * 16; 00056 00057 while (1) { 00058 AdapterInfo = (IP_ADAPTER_INFO *)malloc(AdapterInfoLength); 00059 if (!AdapterInfo) { 00060 return -1; 00061 } 00062 00063 ULONG LengthNeeded = AdapterInfoLength; 00064 DWORD Ret = GetAdaptersInfo(AdapterInfo, &LengthNeeded); 00065 if (Ret == NO_ERROR) { 00066 break; 00067 } 00068 00069 free(AdapterInfo); 00070 00071 if (Ret != ERROR_BUFFER_OVERFLOW) { 00072 return -1; 00073 } 00074 if (AdapterInfoLength >= LengthNeeded) { 00075 return -1; 00076 } 00077 00078 AdapterInfoLength = LengthNeeded; 00079 } 00080 00081 int count = 0; 00082 PIP_ADAPTER_INFO Adapter = AdapterInfo; 00083 while (Adapter) { 00084 IP_ADDR_STRING *IPAddr = &Adapter->IpAddressList; 00085 while (IPAddr) { 00086 uint32_t ip_addr = ntohl(inet_addr(IPAddr->IpAddress.String)); 00087 uint32_t subnet_mask = ntohl(inet_addr(IPAddr->IpMask.String)); 00088 00089 if (ip_addr == 0) { 00090 IPAddr = IPAddr->Next; 00091 continue; 00092 } 00093 00094 struct hdhomerun_local_ip_info_t *ip_info = &ip_info_list[count++]; 00095 ip_info->ip_addr = ip_addr; 00096 ip_info->subnet_mask = subnet_mask; 00097 00098 if (count >= max_count) { 00099 break; 00100 } 00101 00102 IPAddr = IPAddr->Next; 00103 } 00104 00105 if (count >= max_count) { 00106 break; 00107 } 00108 00109 Adapter = Adapter->Next; 00110 } 00111 00112 free(AdapterInfo); 00113 return count; 00114 } 00115 00116 hdhomerun_sock_t hdhomerun_sock_create_udp(void) 00117 { 00118 /* Create socket. */ 00119 hdhomerun_sock_t sock = (hdhomerun_sock_t)socket(AF_INET, SOCK_DGRAM, 0); 00120 if (sock == -1) { 00121 return HDHOMERUN_SOCK_INVALID; 00122 } 00123 00124 /* Set non-blocking */ 00125 unsigned long mode = 1; 00126 if (ioctlsocket(sock, FIONBIO, &mode) != 0) { 00127 closesocket(sock); 00128 return HDHOMERUN_SOCK_INVALID; 00129 } 00130 00131 /* Allow broadcast. */ 00132 int sock_opt = 1; 00133 setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&sock_opt, sizeof(sock_opt)); 00134 00135 /* Success. */ 00136 return sock; 00137 } 00138 00139 hdhomerun_sock_t hdhomerun_sock_create_tcp(void) 00140 { 00141 /* Create socket. */ 00142 hdhomerun_sock_t sock = (hdhomerun_sock_t)socket(AF_INET, SOCK_STREAM, 0); 00143 if (sock == -1) { 00144 return HDHOMERUN_SOCK_INVALID; 00145 } 00146 00147 /* Set non-blocking */ 00148 unsigned long mode = 1; 00149 if (ioctlsocket(sock, FIONBIO, &mode) != 0) { 00150 closesocket(sock); 00151 return HDHOMERUN_SOCK_INVALID; 00152 } 00153 00154 /* Success. */ 00155 return sock; 00156 } 00157 00158 void hdhomerun_sock_destroy(hdhomerun_sock_t sock) 00159 { 00160 closesocket(sock); 00161 } 00162 00163 int hdhomerun_sock_getlasterror(void) 00164 { 00165 return WSAGetLastError(); 00166 } 00167 00168 uint32_t hdhomerun_sock_getsockname_addr(hdhomerun_sock_t sock) 00169 { 00170 struct sockaddr_in sock_addr; 00171 int sockaddr_size = sizeof(sock_addr); 00172 00173 if (getsockname(sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) { 00174 return 0; 00175 } 00176 00177 return ntohl(sock_addr.sin_addr.s_addr); 00178 } 00179 00180 uint16_t hdhomerun_sock_getsockname_port(hdhomerun_sock_t sock) 00181 { 00182 struct sockaddr_in sock_addr; 00183 int sockaddr_size = sizeof(sock_addr); 00184 00185 if (getsockname(sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) { 00186 return 0; 00187 } 00188 00189 return ntohs(sock_addr.sin_port); 00190 } 00191 00192 uint32_t hdhomerun_sock_getpeername_addr(hdhomerun_sock_t sock) 00193 { 00194 struct sockaddr_in sock_addr; 00195 int sockaddr_size = sizeof(sock_addr); 00196 00197 if (getpeername(sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) { 00198 return 0; 00199 } 00200 00201 return ntohl(sock_addr.sin_addr.s_addr); 00202 } 00203 00204 uint32_t hdhomerun_sock_getaddrinfo_addr(hdhomerun_sock_t sock, const char *name) 00205 { 00206 struct addrinfo hints; 00207 memset(&hints, 0, sizeof(hints)); 00208 hints.ai_family = AF_INET; 00209 hints.ai_socktype = SOCK_STREAM; 00210 hints.ai_protocol = IPPROTO_TCP; 00211 00212 struct addrinfo *sock_info; 00213 if (getaddrinfo(name, "", &hints, &sock_info) != 0) { 00214 return 0; 00215 } 00216 00217 struct sockaddr_in *sock_addr = (struct sockaddr_in *)sock_info->ai_addr; 00218 uint32_t addr = ntohl(sock_addr->sin_addr.s_addr); 00219 00220 freeaddrinfo(sock_info); 00221 return addr; 00222 } 00223 00224 bool_t hdhomerun_sock_bind(hdhomerun_sock_t sock, uint32_t local_addr, uint16_t local_port, bool_t allow_reuse) 00225 { 00226 int sock_opt = allow_reuse; 00227 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&sock_opt, sizeof(sock_opt)); 00228 00229 struct sockaddr_in sock_addr; 00230 memset(&sock_addr, 0, sizeof(sock_addr)); 00231 sock_addr.sin_family = AF_INET; 00232 sock_addr.sin_addr.s_addr = htonl(local_addr); 00233 sock_addr.sin_port = htons(local_port); 00234 00235 if (bind(sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) { 00236 return FALSE; 00237 } 00238 00239 return TRUE; 00240 } 00241 00242 bool_t hdhomerun_sock_connect(hdhomerun_sock_t sock, uint32_t remote_addr, uint16_t remote_port, uint64_t timeout) 00243 { 00244 WSAEVENT wsa_event = WSACreateEvent(); 00245 if (wsa_event == WSA_INVALID_EVENT) { 00246 return FALSE; 00247 } 00248 00249 if (WSAEventSelect(sock, wsa_event, FD_CONNECT) == SOCKET_ERROR) { 00250 WSACloseEvent(wsa_event); 00251 return FALSE; 00252 } 00253 00254 /* Connect (non-blocking). */ 00255 struct sockaddr_in sock_addr; 00256 memset(&sock_addr, 0, sizeof(sock_addr)); 00257 sock_addr.sin_family = AF_INET; 00258 sock_addr.sin_addr.s_addr = htonl(remote_addr); 00259 sock_addr.sin_port = htons(remote_port); 00260 00261 if (connect(sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) { 00262 if (WSAGetLastError() != WSAEWOULDBLOCK) { 00263 WSACloseEvent(wsa_event); 00264 return FALSE; 00265 } 00266 } 00267 00268 /* Wait for connect to complete (both success and failure will signal). */ 00269 DWORD ret = WaitForSingleObjectEx(wsa_event, (DWORD)timeout, FALSE); 00270 WSACloseEvent(wsa_event); 00271 00272 if (ret != WAIT_OBJECT_0) { 00273 return FALSE; 00274 } 00275 00276 /* Detect success/failure. */ 00277 int sockaddr_size = sizeof(sock_addr); 00278 if (getpeername(sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) { 00279 return FALSE; 00280 } 00281 00282 return TRUE; 00283 } 00284 00285 static bool_t hdhomerun_sock_wait_for_event(hdhomerun_sock_t sock, long event_type, uint64_t stop_time) 00286 { 00287 uint64_t current_time = getcurrenttime(); 00288 if (current_time >= stop_time) { 00289 return FALSE; 00290 } 00291 00292 WSAEVENT wsa_event = WSACreateEvent(); 00293 if (wsa_event == WSA_INVALID_EVENT) { 00294 return FALSE; 00295 } 00296 00297 if (WSAEventSelect(sock, wsa_event, event_type) == SOCKET_ERROR) { 00298 WSACloseEvent(wsa_event); 00299 return FALSE; 00300 } 00301 00302 DWORD ret = WaitForSingleObjectEx(wsa_event, (DWORD)(stop_time - current_time), FALSE); 00303 WSACloseEvent(wsa_event); 00304 00305 if (ret != WAIT_OBJECT_0) { 00306 return FALSE; 00307 } 00308 00309 return TRUE; 00310 } 00311 00312 bool_t hdhomerun_sock_send(hdhomerun_sock_t sock, const void *data, size_t length, uint64_t timeout) 00313 { 00314 uint64_t stop_time = getcurrenttime() + timeout; 00315 const uint8_t *ptr = (uint8_t *)data; 00316 00317 while (1) { 00318 int ret = send(sock, (char *)ptr, (int)length, 0); 00319 if (ret >= (int)length) { 00320 return TRUE; 00321 } 00322 00323 if (ret > 0) { 00324 ptr += ret; 00325 length -= ret; 00326 } 00327 00328 if (WSAGetLastError() != WSAEWOULDBLOCK) { 00329 return FALSE; 00330 } 00331 00332 if (!hdhomerun_sock_wait_for_event(sock, FD_WRITE | FD_CLOSE, stop_time)) { 00333 return FALSE; 00334 } 00335 } 00336 } 00337 00338 bool_t hdhomerun_sock_sendto(hdhomerun_sock_t sock, uint32_t remote_addr, uint16_t remote_port, const void *data, size_t length, uint64_t timeout) 00339 { 00340 uint64_t stop_time = getcurrenttime() + timeout; 00341 const uint8_t *ptr = (uint8_t *)data; 00342 00343 while (1) { 00344 struct sockaddr_in sock_addr; 00345 memset(&sock_addr, 0, sizeof(sock_addr)); 00346 sock_addr.sin_family = AF_INET; 00347 sock_addr.sin_addr.s_addr = htonl(remote_addr); 00348 sock_addr.sin_port = htons(remote_port); 00349 00350 int ret = sendto(sock, (char *)ptr, (int)length, 0, (struct sockaddr *)&sock_addr, sizeof(sock_addr)); 00351 if (ret >= (int)length) { 00352 return TRUE; 00353 } 00354 00355 if (ret > 0) { 00356 ptr += ret; 00357 length -= ret; 00358 } 00359 00360 if (WSAGetLastError() != WSAEWOULDBLOCK) { 00361 return FALSE; 00362 } 00363 00364 if (!hdhomerun_sock_wait_for_event(sock, FD_WRITE | FD_CLOSE, stop_time)) { 00365 return FALSE; 00366 } 00367 } 00368 } 00369 00370 bool_t hdhomerun_sock_recv(hdhomerun_sock_t sock, void *data, size_t *length, uint64_t timeout) 00371 { 00372 uint64_t stop_time = getcurrenttime() + timeout; 00373 00374 while (1) { 00375 int ret = recv(sock, (char *)data, (int)(*length), 0); 00376 if (ret > 0) { 00377 *length = ret; 00378 return TRUE; 00379 } 00380 00381 if (WSAGetLastError() != WSAEWOULDBLOCK) { 00382 return FALSE; 00383 } 00384 00385 if (!hdhomerun_sock_wait_for_event(sock, FD_READ | FD_CLOSE, stop_time)) { 00386 return FALSE; 00387 } 00388 } 00389 } 00390 00391 bool_t hdhomerun_sock_recvfrom(hdhomerun_sock_t sock, uint32_t *remote_addr, uint16_t *remote_port, void *data, size_t *length, uint64_t timeout) 00392 { 00393 uint64_t stop_time = getcurrenttime() + timeout; 00394 00395 while (1) { 00396 struct sockaddr_in sock_addr; 00397 memset(&sock_addr, 0, sizeof(sock_addr)); 00398 int sockaddr_size = sizeof(sock_addr); 00399 00400 int ret = recvfrom(sock, (char *)data, (int)(*length), 0, (struct sockaddr *)&sock_addr, &sockaddr_size); 00401 if (ret > 0) { 00402 *remote_addr = ntohl(sock_addr.sin_addr.s_addr); 00403 *remote_port = ntohs(sock_addr.sin_port); 00404 *length = ret; 00405 return TRUE; 00406 } 00407 00408 if (WSAGetLastError() != WSAEWOULDBLOCK) { 00409 return FALSE; 00410 } 00411 00412 if (!hdhomerun_sock_wait_for_event(sock, FD_READ | FD_CLOSE, stop_time)) { 00413 return FALSE; 00414 } 00415 } 00416 }
1.7.6.1