00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049 #include "hdhomerun.h"
00050
00051 #include <net/if.h>
00052 #include <sys/ioctl.h>
00053 #ifndef SIOCGIFCONF
00054 #include <sys/sockio.h>
00055 #endif
00056 #ifndef _SIZEOF_ADDR_IFREQ
00057 #define _SIZEOF_ADDR_IFREQ(x) sizeof(x)
00058 #endif
00059
00060 int hdhomerun_local_ip_info(struct hdhomerun_local_ip_info_t ip_info_list[], int max_count)
00061 {
00062 int sock = socket(AF_INET, SOCK_DGRAM, 0);
00063 if (sock == HDHOMERUN_SOCK_INVALID) {
00064 return -1;
00065 }
00066
00067 struct ifconf ifc;
00068 size_t ifreq_buffer_size = 1024;
00069
00070 while (1) {
00071 ifc.ifc_len = ifreq_buffer_size;
00072 ifc.ifc_buf = (char *)malloc(ifreq_buffer_size);
00073 if (!ifc.ifc_buf) {
00074 close(sock);
00075 return -1;
00076 }
00077
00078 memset(ifc.ifc_buf, 0, ifreq_buffer_size);
00079
00080 if (ioctl(sock, SIOCGIFCONF, &ifc) != 0) {
00081 free(ifc.ifc_buf);
00082 close(sock);
00083 return -1;
00084 }
00085
00086 if (ifc.ifc_len < ifreq_buffer_size) {
00087 break;
00088 }
00089
00090 free(ifc.ifc_buf);
00091 ifreq_buffer_size += 1024;
00092 }
00093
00094 char *ptr = ifc.ifc_buf;
00095 char *end = ifc.ifc_buf + ifc.ifc_len;
00096
00097 int count = 0;
00098 while (ptr <= end) {
00099 struct ifreq *ifr = (struct ifreq *)ptr;
00100 ptr += _SIZEOF_ADDR_IFREQ(*ifr);
00101
00102 if (ioctl(sock, SIOCGIFADDR, ifr) != 0) {
00103 continue;
00104 }
00105
00106 struct sockaddr_in *ip_addr_in = (struct sockaddr_in *)&(ifr->ifr_addr);
00107 uint32_t ip_addr = ntohl(ip_addr_in->sin_addr.s_addr);
00108 if (ip_addr == 0) {
00109 continue;
00110 }
00111
00112 if (ioctl(sock, SIOCGIFNETMASK, ifr) != 0) {
00113 continue;
00114 }
00115
00116 struct sockaddr_in *subnet_mask_in = (struct sockaddr_in *)&(ifr->ifr_addr);
00117 uint32_t subnet_mask = ntohl(subnet_mask_in->sin_addr.s_addr);
00118
00119 struct hdhomerun_local_ip_info_t *ip_info = &ip_info_list[count++];
00120 ip_info->ip_addr = ip_addr;
00121 ip_info->subnet_mask = subnet_mask;
00122
00123 if (count >= max_count) {
00124 break;
00125 }
00126 }
00127
00128 free(ifc.ifc_buf);
00129 close(sock);
00130 return count;
00131 }
00132
00133 hdhomerun_sock_t hdhomerun_sock_create_udp(void)
00134 {
00135
00136 hdhomerun_sock_t sock = (hdhomerun_sock_t)socket(AF_INET, SOCK_DGRAM, 0);
00137 if (sock == -1) {
00138 return HDHOMERUN_SOCK_INVALID;
00139 }
00140
00141
00142 if (fcntl(sock, F_SETFL, O_NONBLOCK) != 0) {
00143 close(sock);
00144 return HDHOMERUN_SOCK_INVALID;
00145 }
00146
00147
00148 int sock_opt = 1;
00149 setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&sock_opt, sizeof(sock_opt));
00150
00151
00152 return sock;
00153 }
00154
00155 hdhomerun_sock_t hdhomerun_sock_create_tcp(void)
00156 {
00157
00158 hdhomerun_sock_t sock = (hdhomerun_sock_t)socket(AF_INET, SOCK_STREAM, 0);
00159 if (sock == -1) {
00160 return HDHOMERUN_SOCK_INVALID;
00161 }
00162
00163
00164 if (fcntl(sock, F_SETFL, O_NONBLOCK) != 0) {
00165 close(sock);
00166 return HDHOMERUN_SOCK_INVALID;
00167 }
00168
00169
00170 return sock;
00171 }
00172
00173 void hdhomerun_sock_destroy(hdhomerun_sock_t sock)
00174 {
00175 close(sock);
00176 }
00177
00178 int hdhomerun_sock_getlasterror(void)
00179 {
00180 return errno;
00181 }
00182
00183 uint32_t hdhomerun_sock_getsockname_addr(hdhomerun_sock_t sock)
00184 {
00185 struct sockaddr_in sock_addr;
00186 socklen_t sockaddr_size = sizeof(sock_addr);
00187
00188 if (getsockname(sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) {
00189 return 0;
00190 }
00191
00192 return ntohl(sock_addr.sin_addr.s_addr);
00193 }
00194
00195 uint16_t hdhomerun_sock_getsockname_port(hdhomerun_sock_t sock)
00196 {
00197 struct sockaddr_in sock_addr;
00198 socklen_t sockaddr_size = sizeof(sock_addr);
00199
00200 if (getsockname(sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) {
00201 return 0;
00202 }
00203
00204 return ntohs(sock_addr.sin_port);
00205 }
00206
00207 uint32_t hdhomerun_sock_getpeername_addr(hdhomerun_sock_t sock)
00208 {
00209 struct sockaddr_in sock_addr;
00210 socklen_t sockaddr_size = sizeof(sock_addr);
00211
00212 if (getpeername(sock, (struct sockaddr *)&sock_addr, &sockaddr_size) != 0) {
00213 return 0;
00214 }
00215
00216 return ntohl(sock_addr.sin_addr.s_addr);
00217 }
00218
00219 uint32_t hdhomerun_sock_getaddrinfo_addr(hdhomerun_sock_t sock, const char *name)
00220 {
00221 struct addrinfo hints;
00222 memset(&hints, 0, sizeof(hints));
00223 hints.ai_family = AF_INET;
00224 hints.ai_socktype = SOCK_STREAM;
00225 hints.ai_protocol = IPPROTO_TCP;
00226
00227 struct addrinfo *sock_info;
00228 if (getaddrinfo(name, "", &hints, &sock_info) != 0) {
00229 return 0;
00230 }
00231
00232 struct sockaddr_in *sock_addr = (struct sockaddr_in *)sock_info->ai_addr;
00233 uint32_t addr = ntohl(sock_addr->sin_addr.s_addr);
00234
00235 freeaddrinfo(sock_info);
00236 return addr;
00237 }
00238
00239 bool_t hdhomerun_sock_bind(hdhomerun_sock_t sock, uint32_t local_addr, uint16_t local_port, bool_t allow_reuse)
00240 {
00241 int sock_opt = allow_reuse;
00242 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&sock_opt, sizeof(sock_opt));
00243
00244 struct sockaddr_in sock_addr;
00245 memset(&sock_addr, 0, sizeof(sock_addr));
00246 sock_addr.sin_family = AF_INET;
00247 sock_addr.sin_addr.s_addr = htonl(local_addr);
00248 sock_addr.sin_port = htons(local_port);
00249
00250 if (bind(sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) {
00251 return FALSE;
00252 }
00253
00254 return TRUE;
00255 }
00256
00257 static bool_t hdhomerun_sock_wait_for_read_event(hdhomerun_sock_t sock, uint64_t stop_time)
00258 {
00259 uint64_t current_time = getcurrenttime();
00260 if (current_time >= stop_time) {
00261 return FALSE;
00262 }
00263
00264 if (sock < FD_SETSIZE) {
00265 uint64_t timeout = stop_time - current_time;
00266 struct timeval t;
00267 t.tv_sec = timeout / 1000;
00268 t.tv_usec = (timeout % 1000) * 1000;
00269
00270 fd_set readfds;
00271 FD_ZERO(&readfds);
00272 FD_SET(sock, &readfds);
00273
00274 fd_set errorfds;
00275 FD_ZERO(&errorfds);
00276 FD_SET(sock, &errorfds);
00277
00278 if (select(sock + 1, &readfds, NULL, &errorfds, &t) <= 0) {
00279 return FALSE;
00280 }
00281 if (!FD_ISSET(sock, &readfds)) {
00282 return FALSE;
00283 }
00284 } else {
00285 uint64_t delay = stop_time - current_time;
00286 if (delay > 5) {
00287 delay = 5;
00288 }
00289
00290 msleep_approx(delay);
00291 }
00292
00293 return TRUE;
00294 }
00295
00296 static bool_t hdhomerun_sock_wait_for_write_event(hdhomerun_sock_t sock, uint64_t stop_time)
00297 {
00298 uint64_t current_time = getcurrenttime();
00299 if (current_time >= stop_time) {
00300 return FALSE;
00301 }
00302
00303 if (sock < FD_SETSIZE) {
00304 uint64_t timeout = stop_time - current_time;
00305 struct timeval t;
00306 t.tv_sec = timeout / 1000;
00307 t.tv_usec = (timeout % 1000) * 1000;
00308
00309 fd_set writefds;
00310 FD_ZERO(&writefds);
00311 FD_SET(sock, &writefds);
00312
00313 fd_set errorfds;
00314 FD_ZERO(&errorfds);
00315 FD_SET(sock, &errorfds);
00316
00317 if (select(sock + 1, NULL, &writefds, &errorfds, &t) <= 0) {
00318 return FALSE;
00319 }
00320 if (!FD_ISSET(sock, &writefds)) {
00321 return FALSE;
00322 }
00323 } else {
00324 uint64_t delay = stop_time - current_time;
00325 if (delay > 5) {
00326 delay = 5;
00327 }
00328
00329 msleep_approx(delay);
00330 }
00331
00332 return TRUE;
00333 }
00334
00335 bool_t hdhomerun_sock_connect(hdhomerun_sock_t sock, uint32_t remote_addr, uint16_t remote_port, uint64_t timeout)
00336 {
00337 struct sockaddr_in sock_addr;
00338 memset(&sock_addr, 0, sizeof(sock_addr));
00339 sock_addr.sin_family = AF_INET;
00340 sock_addr.sin_addr.s_addr = htonl(remote_addr);
00341 sock_addr.sin_port = htons(remote_port);
00342
00343 if (connect(sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) == 0) {
00344 return TRUE;
00345 }
00346
00347 uint64_t stop_time = getcurrenttime() + timeout;
00348
00349
00350
00351
00352
00353
00354
00355 if (!hdhomerun_sock_wait_for_write_event(sock, stop_time)) {
00356 return FALSE;
00357 }
00358
00359 while (1) {
00360 struct sockaddr_in sock_addr;
00361 socklen_t sockaddr_size = sizeof(sock_addr);
00362 if (getpeername(sock, (struct sockaddr *)&sock_addr, &sockaddr_size) == 0) {
00363 return TRUE;
00364 }
00365
00366 if (errno != ENOTCONN) {
00367 return FALSE;
00368 }
00369
00370 if (!hdhomerun_sock_wait_for_write_event(sock, stop_time)) {
00371 return FALSE;
00372 }
00373 }
00374 }
00375
00376 bool_t hdhomerun_sock_send(hdhomerun_sock_t sock, const void *data, size_t length, uint64_t timeout)
00377 {
00378 uint64_t stop_time = getcurrenttime() + timeout;
00379 const uint8_t *ptr = (const uint8_t *)data;
00380
00381 while (1) {
00382 int ret = send(sock, ptr, length, 0);
00383 if (ret >= (int)length) {
00384 return TRUE;
00385 }
00386
00387 if (ret > 0) {
00388 ptr += ret;
00389 length -= ret;
00390 }
00391
00392 if (errno == EINPROGRESS) {
00393 errno = EWOULDBLOCK;
00394 }
00395 if (errno != EWOULDBLOCK) {
00396 return FALSE;
00397 }
00398
00399 if (!hdhomerun_sock_wait_for_write_event(sock, stop_time)) {
00400 return FALSE;
00401 }
00402 }
00403 }
00404
00405 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)
00406 {
00407 uint64_t stop_time = getcurrenttime() + timeout;
00408 const uint8_t *ptr = (const uint8_t *)data;
00409
00410 while (1) {
00411 struct sockaddr_in sock_addr;
00412 memset(&sock_addr, 0, sizeof(sock_addr));
00413 sock_addr.sin_family = AF_INET;
00414 sock_addr.sin_addr.s_addr = htonl(remote_addr);
00415 sock_addr.sin_port = htons(remote_port);
00416
00417 int ret = sendto(sock, ptr, length, 0, (struct sockaddr *)&sock_addr, sizeof(sock_addr));
00418 if (ret >= (int)length) {
00419 return TRUE;
00420 }
00421
00422 if (ret > 0) {
00423 ptr += ret;
00424 length -= ret;
00425 }
00426
00427 if (errno == EINPROGRESS) {
00428 errno = EWOULDBLOCK;
00429 }
00430 if (errno != EWOULDBLOCK) {
00431 return FALSE;
00432 }
00433
00434 if (!hdhomerun_sock_wait_for_write_event(sock, stop_time)) {
00435 return FALSE;
00436 }
00437 }
00438 }
00439
00440 bool_t hdhomerun_sock_recv(hdhomerun_sock_t sock, void *data, size_t *length, uint64_t timeout)
00441 {
00442 uint64_t stop_time = getcurrenttime() + timeout;
00443
00444 while (1) {
00445 int ret = recv(sock, data, *length, 0);
00446 if (ret > 0) {
00447 *length = ret;
00448 return TRUE;
00449 }
00450
00451 if (errno == EINPROGRESS) {
00452 errno = EWOULDBLOCK;
00453 }
00454 if (errno != EWOULDBLOCK) {
00455 return FALSE;
00456 }
00457
00458 if (!hdhomerun_sock_wait_for_read_event(sock, stop_time)) {
00459 return FALSE;
00460 }
00461 }
00462 }
00463
00464 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)
00465 {
00466 uint64_t stop_time = getcurrenttime() + timeout;
00467
00468 while (1) {
00469 struct sockaddr_in sock_addr;
00470 memset(&sock_addr, 0, sizeof(sock_addr));
00471 socklen_t sockaddr_size = sizeof(sock_addr);
00472
00473 int ret = recvfrom(sock, data, *length, 0, (struct sockaddr *)&sock_addr, &sockaddr_size);
00474 if (ret > 0) {
00475 *remote_addr = ntohl(sock_addr.sin_addr.s_addr);
00476 *remote_port = ntohs(sock_addr.sin_port);
00477 *length = ret;
00478 return TRUE;
00479 }
00480
00481 if (errno == EINPROGRESS) {
00482 errno = EWOULDBLOCK;
00483 }
00484 if (errno != EWOULDBLOCK) {
00485 return FALSE;
00486 }
00487
00488 if (!hdhomerun_sock_wait_for_read_event(sock, stop_time)) {
00489 return FALSE;
00490 }
00491 }
00492 }