#include <fcntl.h>
#include <sys/types.h>
#include <curl/curl.h>
+#include <errno.h>
+#include <netdb.h>
#include "gridsite.h"
int modified_set;
struct grst_stream_data *common_data; } ;
-struct grst_sitecast_group { unsigned char quad1; unsigned char quad2;
- unsigned char quad3; unsigned char quad4;
- int port; int timewait; int ttl; };
+struct grst_sitecast_group { struct addrinfo *ai;
+ int timewait; int ttl; };
size_t headers_callback(void *ptr, size_t size, size_t nmemb, void *p)
/* Find the values of the return code, Content-Length, Last-Modified
return anyerror;
}
-int do_ping(struct grst_stream_data *common_data_ptr)
+static int
+parse_groups(const char *grps, struct grst_sitecast_group *sitecast_groups, int group_num, int *res_num)
{
- int request_length, response_length, i, ret, s, igroup;
- struct sockaddr_in srv, from;
- socklen_t fromlen;
-#define MAXBUF 8192
- char *request, response[MAXBUF], *p;
- GRSThtcpMessage msg;
- struct timeval start_timeval, wait_timeval, response_timeval;
- struct grst_sitecast_group sitecast_groups[HTCP_SITECAST_GROUPS];
- fd_set readsckts;
+ struct addrinfo *ai;
+ struct addrinfo hints;
+ char *groups, *p, *port, *rest, def_port[8];
+ int igroup, ret;
- /* parse common_data_ptr->groups */
-
- p = common_data_ptr->groups;
igroup = -1;
-
- for (igroup=-1; igroup+1 < HTCP_SITECAST_GROUPS; ++igroup)
- {
- sitecast_groups[igroup+1].port = GRST_HTCP_PORT;
- sitecast_groups[igroup+1].timewait = 1;
- sitecast_groups[igroup+1].ttl = 1;
-
- ret = sscanf(p, "%d.%d.%d.%d:%d:%d:%d",
- &(sitecast_groups[igroup+1].quad1),
- &(sitecast_groups[igroup+1].quad2),
- &(sitecast_groups[igroup+1].quad3),
- &(sitecast_groups[igroup+1].quad4),
- &(sitecast_groups[igroup+1].port),
- &(sitecast_groups[igroup+1].ttl),
- &(sitecast_groups[igroup+1].timewait));
-
- if (ret == 0) break; /* end of list ? */
-
- if (ret < 5)
- {
- fprintf(stderr, "Failed to parse multicast group "
- "parameter %s\n", p);
- return CURLE_FAILED_INIT;
- }
-
- ++igroup;
-
- if ((p = index(p, ',')) == NULL) break;
- ++p;
- }
+ groups = strdup(grps);
+ if (groups == NULL) {
+ perror("Error parsing multicast groups");
+ return ENOMEM;
+ }
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV | AI_NUMERICHOST;
+
+ snprintf(def_port, sizeof(def_port), "%u", GRST_HTCP_PORT);
+
+ p = strtok(groups, " ,");
+ while (p && igroup+1 < group_num) {
+ /* still IPv4 only: */
+ port = strchr(p, ':');
+ if (port == NULL) {
+ fprintf(stderr, "Failed to parse multicast group, port missing\n");
+ return CURLE_FAILED_INIT;
+ }
+ *port++ = '\0';
+
+ rest = strchr(port, ':');
+ if (rest)
+ *rest++ = '\0';
+
+ ret = getaddrinfo(p, (port) ? port : def_port, &hints, &ai);
+ if (ret) {
+ goto end_loop;
+ }
+ sitecast_groups[igroup+1].ai = ai;
+
+ sitecast_groups[igroup+1].timewait = 1;
+ sitecast_groups[igroup+1].ttl = 1;
+ if (rest) {
+ ret = sscanf(rest, "%d:%d",
+ &(sitecast_groups[igroup+1].ttl),
+ &(sitecast_groups[igroup+1].timewait));
+ if (ret < 1) {
+ fprintf(stderr, "Failed to parse multicast group "
+ "parameter %s\n", p);
+ return CURLE_FAILED_INIT;
+ }
+ }
+
+ igroup++;
+end_loop:
+ p = strtok(NULL, " ,");
+ }
+ free(groups);
if (igroup == -1)
{
fprintf(stderr, "Failed to parse multicast group parameter %s\n", p);
return CURLE_FAILED_INIT;
}
+ *res_num = igroup;
+ return 0;
+}
+
+int do_ping(struct grst_stream_data *common_data_ptr)
+{
+ int request_length, response_length, i, ret, s, igroup, max_fd;
+ struct sockaddr from;
+ socklen_t fromlen;
+#define MAXBUF 8192
+ char *request, response[MAXBUF];
+ GRSThtcpMessage msg;
+ struct timeval start_timeval, wait_timeval, response_timeval;
+ struct grst_sitecast_group sitecast_groups[HTCP_SITECAST_GROUPS];
+ fd_set readsckts, open_sckts;
+ struct addrinfo *a;
+ char host[INET6_ADDRSTRLEN];
+ char serv[8];
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ /* parse common_data_ptr->groups */
+ if (common_data_ptr->groups == NULL)
{
- fprintf(stderr, "Failed to open UDP socket\n");
+ fprintf(stderr, "No multicast groups given\n");
return CURLE_FAILED_INIT;
}
- /* loop through multicast groups and send off the NOP pings */
+ ret = parse_groups(common_data_ptr->groups, sitecast_groups, HTCP_SITECAST_GROUPS, &igroup);
+ if (ret)
+ return ret;
+ /* loop through multicast groups and send off the NOP pings */
+ GRSThtcpNOPrequestMake(&request, &request_length,
+ (int) (start_timeval.tv_usec + i));
gettimeofday(&start_timeval, NULL);
-
- for (i=0; i <= igroup; ++i)
- {
- bzero(&srv, sizeof(srv));
- srv.sin_family = AF_INET;
- srv.sin_port = htons(sitecast_groups[i].port);
- srv.sin_addr.s_addr = htonl(sitecast_groups[i].quad1*0x1000000
- + sitecast_groups[i].quad2*0x10000
- + sitecast_groups[i].quad3*0x100
- + sitecast_groups[i].quad4);
-
- GRSThtcpNOPrequestMake(&request, &request_length,
- (int) (start_timeval.tv_usec + i));
-
- sendto(s, request, request_length, 0, (struct sockaddr *) &srv,
- sizeof(srv));
- free(request);
-
- if (common_data_ptr->verbose > 0)
- fprintf(stderr, "UDP/HTCP NOP ping to %d:%d:%d:%d %d\n",
- sitecast_groups[i].quad1,
- sitecast_groups[i].quad2,
- sitecast_groups[i].quad3,
- sitecast_groups[i].quad4,
- sitecast_groups[i].port);
- }
+ FD_ZERO(&open_sckts);
+ max_fd = -1;
+ for (i=0; i <= igroup; ++i) {
+ a = sitecast_groups[i].ai;
+ for (a = sitecast_groups[i].ai; a != NULL; a = a->ai_next) {
+ s = socket(a->ai_family, a->ai_socktype, a->ai_protocol);
+ if (s < 0)
+ continue;
+
+ ret = sendto(s, request, request_length, 0, a->ai_addr, a->ai_addrlen);
+ if (ret < 0) {
+ close(s);
+ continue;
+ }
+
+ if (common_data_ptr->verbose > 0) {
+ getnameinfo(a->ai_addr, a->ai_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST);
+ fprintf(stderr, "UDP/HTCP NOP ping to %s\n", host);
+ }
+
+
+ FD_SET(s, &open_sckts);
+ if (s > max_fd)
+ max_fd = s;
+ }
+ }
+ free(request);
/* reusing wait_timeval is a Linux-specific feature of select() */
wait_timeval.tv_sec = common_data_ptr->timeout
while ((wait_timeval.tv_sec > 0) || (wait_timeval.tv_usec > 0))
{
- FD_ZERO(&readsckts);
- FD_SET(s, &readsckts);
-
- ret = select(s + 1, &readsckts, NULL, NULL, &wait_timeval);
+ readsckts = open_sckts;
+
+ ret = select(max_fd + 1, &readsckts, NULL, NULL, &wait_timeval);
gettimeofday(&response_timeval, NULL);
if (ret > 0)
{
+ for (s = 0; s <= max_fd; s++) {
+ if (FD_ISSET(s, &readsckts))
+ break;
+ }
+ if (s > max_fd)
+ break;
+
+ fromlen = sizeof(from);
response_length = recvfrom(s, response, MAXBUF,
0, &from, &fromlen);
- if (common_data_ptr->verbose > 0)
- fprintf(stderr, "UDP mesg from %s:%d\n",
- inet_ntoa(from.sin_addr), ntohs(from.sin_port));
+ getnameinfo(&from, fromlen,
+ host, sizeof(host),
+ serv, sizeof(serv), NI_NUMERICHOST);
+ if (common_data_ptr->verbose > 0) {
+ fprintf(stderr, "UDP mesg from %s:%s\n",
+ host, serv);
+ }
if ((GRSThtcpMessageParse(&msg, response, response_length)
== GRST_RET_OK) &&
(msg.trans_id >= (int) start_timeval.tv_usec) &&
(msg.trans_id <= (int) (start_timeval.tv_usec + igroup)))
{
- printf("%s:%d %.3fms\n",
- inet_ntoa(from.sin_addr),
- ntohs(from.sin_port),
+ printf("%s:%s %.3fms\n",
+ host, serv,
(((long) 1000000 * response_timeval.tv_sec) +
((long) response_timeval.tv_usec) -
((long) 1000000 * start_timeval.tv_sec) -
}
}
}
-
+ for (s = 0; s <=max_fd; s++)
+ if (FD_ISSET(s, &open_sckts))
+ close(s);
+
return GRST_RET_OK;
}
{
int isrc;
- int request_length, response_length, i, ret, s, igroup;
- struct sockaddr_in srv, from;
+ int request_length, response_length, i, ret, s, igroup, max_fd;
+ struct sockaddr from;
socklen_t fromlen;
#define MAXBUF 8192
char *request, response[MAXBUF], *p;
GRSThtcpMessage msg;
struct timeval start_timeval, wait_timeval;
struct grst_sitecast_group sitecast_groups[HTCP_SITECAST_GROUPS];
- fd_set readsckts;
+ fd_set readsckts, open_sckts;
+ struct addrinfo *a;
+ char host[INET6_ADDRSTRLEN];
+ char serv[8];
/* parse common_data_ptr->groups */
-
if (common_data_ptr->groups == NULL)
{
fprintf(stderr, "No multicast groups given\n");
return CURLE_FAILED_INIT;
}
- p = common_data_ptr->groups;
- igroup = -1;
-
- for (igroup=-1; igroup+1 < HTCP_SITECAST_GROUPS;)
- {
- sitecast_groups[igroup+1].port = GRST_HTCP_PORT;
- sitecast_groups[igroup+1].timewait = 1;
- sitecast_groups[igroup+1].ttl = 1;
-
- ret = sscanf(p, "%d.%d.%d.%d:%d:%d:%d",
- &(sitecast_groups[igroup+1].quad1),
- &(sitecast_groups[igroup+1].quad2),
- &(sitecast_groups[igroup+1].quad3),
- &(sitecast_groups[igroup+1].quad4),
- &(sitecast_groups[igroup+1].port),
- &(sitecast_groups[igroup+1].ttl),
- &(sitecast_groups[igroup+1].timewait));
-
- if (ret == 0) break; /* end of list ? */
-
- if (ret < 5)
- {
- fprintf(stderr, "Failed to parse multicast group "
- "parameter %s\n", p);
- return CURLE_FAILED_INIT;
- }
-
- ++igroup;
-
- if ((p = index(p, ',')) == NULL) break;
- ++p;
- }
-
- if (igroup == -1)
- {
- fprintf(stderr, "Failed to parse multicast group parameter %s\n", p);
- return CURLE_FAILED_INIT;
- }
-
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
- {
- fprintf(stderr, "Failed to open UDP socket\n");
- return CURLE_FAILED_INIT;
- }
+ ret = parse_groups(common_data_ptr->groups, sitecast_groups, HTCP_SITECAST_GROUPS, &igroup);
+ if (ret)
+ return ret;
/* loop through multicast groups since we need to take each
ones timewait into account */
for (i=0; i <= igroup; ++i)
{
- if (common_data_ptr->verbose)
- fprintf(stderr, "Querying multicast group %d.%d.%d.%d:%d:%d:%d\n",
- sitecast_groups[i].quad1, sitecast_groups[i].quad2,
- sitecast_groups[i].quad3, sitecast_groups[i].quad4,
- sitecast_groups[i].port, sitecast_groups[i].ttl,
- sitecast_groups[i].timewait);
-
- bzero(&srv, sizeof(srv));
- srv.sin_family = AF_INET;
- srv.sin_port = htons(sitecast_groups[i].port);
- srv.sin_addr.s_addr = htonl(sitecast_groups[i].quad1*0x1000000
- + sitecast_groups[i].quad2*0x10000
- + sitecast_groups[i].quad3*0x100
- + sitecast_groups[i].quad4);
-
- /* send off queries, one for each source file */
-
- for (isrc=0; sources[isrc] != NULL; ++isrc)
- {
- GRSThtcpTSTrequestMake(&request, &request_length,
- (int) (start_timeval.tv_usec + isrc),
- "GET", sources[isrc], "");
-
- sendto(s, request, request_length, 0,
- (struct sockaddr *) &srv, sizeof(srv));
-
- free(request);
- }
+
+ FD_ZERO(&open_sckts);
+ max_fd = -1;
+ for (a = sitecast_groups[i].ai; a != NULL; a = a->ai_next) {
+ s = socket(a->ai_family, a->ai_socktype, a->ai_protocol);
+ if (s < 0)
+ continue;
+
+ if (common_data_ptr->verbose) {
+ getnameinfo(a->ai_addr, a->ai_addrlen,
+ host, sizeof(host),
+ serv, sizeof(serv), NI_NUMERICHOST);
+ fprintf(stderr, "Querying multicast group %s:%s:%d:%d\n",
+ host, serv, sitecast_groups[i].ttl,
+ sitecast_groups[i].timewait);
+ }
+
+ /* send off queries, one for each source file */
+
+ for (isrc=0; sources[isrc] != NULL; ++isrc)
+ {
+ GRSThtcpTSTrequestMake(&request, &request_length,
+ (int) (start_timeval.tv_usec + isrc),
+ "GET", sources[isrc], "");
+
+ sendto(s, request, request_length, 0,
+ a->ai_addr, a->ai_addrlen);
+
+ free(request);
+ }
+ FD_SET(s, &open_sckts);
+ if (s > max_fd)
+ max_fd = s;
+ }
- /* reusing wait_timeval is a Linux-specific feature of select() */
- wait_timeval.tv_usec = 0;
- wait_timeval.tv_sec = sitecast_groups[i].timewait;
+ /* reusing wait_timeval is a Linux-specific feature of select() */
+ wait_timeval.tv_usec = 0;
+ wait_timeval.tv_sec = sitecast_groups[i].timewait;
- while ((wait_timeval.tv_sec > 0) || (wait_timeval.tv_usec > 0))
- {
- FD_ZERO(&readsckts);
- FD_SET(s, &readsckts);
-
- ret = select(s + 1, &readsckts, NULL, NULL, &wait_timeval);
+ while ((wait_timeval.tv_sec > 0) || (wait_timeval.tv_usec > 0))
+ {
+ readsckts = open_sckts;
+
+ ret = select(max_fd + 1, &readsckts, NULL, NULL, &wait_timeval);
if (ret > 0)
{
+ for (s = 0; s <= max_fd; s++) {
+ if (FD_ISSET(s, &readsckts))
+ break;
+ }
+ if (s > max_fd)
+ break;
+
+ fromlen = sizeof(from);
response_length = recvfrom(s, response, MAXBUF,
0, &from, &fromlen);
}
}
+ for (s = 0; s <=max_fd; s++)
+ if (FD_ISSET(s, &open_sckts))
+ close(s);
return GRST_RET_OK;
}
int translate_sitecast_url(char **source_ptr,
struct grst_stream_data *common_data_ptr)
{
- int request_length, response_length, i, ret, s, igroup;
- struct sockaddr_in srv, from;
+ int request_length, response_length, i, ret, s, igroup, max_fd;
+ struct sockaddr from;
socklen_t fromlen;
#define MAXBUF 8192
char *request, response[MAXBUF], *p;
GRSThtcpMessage msg;
struct timeval start_timeval, wait_timeval;
struct grst_sitecast_group sitecast_groups[HTCP_SITECAST_GROUPS];
- fd_set readsckts;
+ fd_set readsckts, open_sckts;
+ struct addrinfo *a;
+ char host[INET6_ADDRSTRLEN];
+ char serv[8];
/* parse common_data_ptr->groups */
return CURLE_FAILED_INIT;
}
- p = common_data_ptr->groups;
- igroup = -1;
-
- for (igroup=-1; igroup+1 < HTCP_SITECAST_GROUPS;)
- {
- sitecast_groups[igroup+1].port = GRST_HTCP_PORT;
- sitecast_groups[igroup+1].timewait = 1;
- sitecast_groups[igroup+1].ttl = 1;
-
- ret = sscanf(p, "%d.%d.%d.%d:%d:%d:%d",
- &(sitecast_groups[igroup+1].quad1),
- &(sitecast_groups[igroup+1].quad2),
- &(sitecast_groups[igroup+1].quad3),
- &(sitecast_groups[igroup+1].quad4),
- &(sitecast_groups[igroup+1].port),
- &(sitecast_groups[igroup+1].ttl),
- &(sitecast_groups[igroup+1].timewait));
-
- if (ret == 0) break; /* end of list ? */
-
- if (ret < 5)
- {
- fprintf(stderr, "Failed to parse multicast group "
- "parameter %s\n", p);
- return CURLE_FAILED_INIT;
- }
-
- ++igroup;
-
- if ((p = index(p, ',')) == NULL) break;
- ++p;
- }
-
- if (igroup == -1)
- {
- fprintf(stderr, "Failed to parse multicast group parameter %s\n", p);
- return CURLE_FAILED_INIT;
- }
-
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
- {
- fprintf(stderr, "Failed to open UDP socket\n");
- return CURLE_FAILED_INIT;
- }
+ ret = parse_groups(common_data_ptr->groups, sitecast_groups, HTCP_SITECAST_GROUPS, &igroup);
+ if (ret)
+ return ret;
/* loop through multicast groups since we need to take each
ones timewait into account */
gettimeofday(&start_timeval, NULL);
+ GRSThtcpTSTrequestMake(&request, &request_length,
+ (int) (start_timeval.tv_usec),
+ "GET", *source_ptr, "");
+
for (i=0; i <= igroup; ++i)
{
- if (common_data_ptr->verbose)
- fprintf(stderr, "Querying multicast group %d.%d.%d.%d:%d:%d:%d\n",
- sitecast_groups[i].quad1, sitecast_groups[i].quad2,
- sitecast_groups[i].quad3, sitecast_groups[i].quad4,
- sitecast_groups[i].port, sitecast_groups[i].ttl,
- sitecast_groups[i].timewait);
-
- bzero(&srv, sizeof(srv));
- srv.sin_family = AF_INET;
- srv.sin_port = htons(sitecast_groups[i].port);
- srv.sin_addr.s_addr = htonl(sitecast_groups[i].quad1*0x1000000
- + sitecast_groups[i].quad2*0x10000
- + sitecast_groups[i].quad3*0x100
- + sitecast_groups[i].quad4);
-
- /* send off queries, one for each source file */
-
- GRSThtcpTSTrequestMake(&request, &request_length,
- (int) (start_timeval.tv_usec),
- "GET", *source_ptr, "");
-
- sendto(s, request, request_length, 0,
- (struct sockaddr *) &srv, sizeof(srv));
-
+ FD_ZERO(&open_sckts);
+ max_fd = -1;
+ for (a = sitecast_groups[i].ai; a != NULL; a = a->ai_next) {
+ s = socket(a->ai_family, a->ai_socktype, a->ai_protocol);
+ if (s < 0)
+ continue;
+ if (common_data_ptr->verbose) {
+ getnameinfo(a->ai_addr, a->ai_addrlen,
+ host, sizeof(host),
+ serv, sizeof(serv), NI_NUMERICHOST);
+ fprintf(stderr, "Querying multicast group %s:%s:%d:%d\n",
+ host, serv, sitecast_groups[i].ttl,
+ sitecast_groups[i].timewait);
+ }
+
+ /* send off queries, one for each source file */
+ sendto(s, request, request_length, 0,
+ a->ai_addr, a->ai_addrlen);
+
+ FD_SET(s, &open_sckts);
+ if (s > max_fd)
+ max_fd = s;
+ }
free(request);
/* reusing wait_timeval is a Linux-specific feature of select() */
while ((wait_timeval.tv_sec > 0) || (wait_timeval.tv_usec > 0))
{
- FD_ZERO(&readsckts);
- FD_SET(s, &readsckts);
+ readsckts = open_sckts;
- ret = select(s + 1, &readsckts, NULL, NULL, &wait_timeval);
+ ret = select(max_fd + 1, &readsckts, NULL, NULL, &wait_timeval);
if (ret > 0)
{
+ for (s = 0; s <= max_fd; s++) {
+ if (FD_ISSET(s, &readsckts))
+ break;
+ }
+ if (s > max_fd)
+ break;
+
+ fromlen = sizeof(from);
response_length = recvfrom(s, response, MAXBUF,
0, &from, &fromlen);
}
}
+ for (s = 0; s <=max_fd; s++)
+ if (FD_ISSET(s, &open_sckts))
+ close(s);
return GRST_RET_OK;
}