| #include <stdio.h> |
| #include <stdlib.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <sys/socket.h> |
| #include <arpa/inet.h> |
| #include <netdb.h> |
| #include <string.h> |
| #include "hdhomerun_http.h" |
| |
| #define HOST "google.com" |
| #define PAGE "/" |
| #define PORT 80 |
| #define USERAGENT "SAGETV 1.0" |
| |
| #define _MIN_(x, y) ((x) > (y) ? (y) : (x)) |
| |
| static char *get_ip(char *host, char *buf, int size) |
| { |
| struct hostent *hent; |
| char *ip = buf; |
| memset(ip, 0, size); |
| if ((hent = gethostbyname(host)) == NULL) { |
| herror("Can't get IP"); |
| exit(1); |
| } |
| if (inet_ntop(AF_INET, (void *)hent->h_addr_list[0], ip, size) == NULL) { |
| perror("Can't resolve host"); |
| exit(1); |
| } |
| return ip; |
| } |
| |
| static char *build_get_query(char *host, char *page) |
| { |
| char *query; |
| char *getpage = page; |
| char *tpl = "GET /%s HTTP/1.0\r\nHost: %s\r\nUser-Agent: %s\r\n\r\n"; |
| if (getpage[0] == '/') { |
| getpage = getpage + 1; |
| } |
| // -5 is to consider the %s %s %s in tpl and the ending \0 |
| query = (char *)malloc(strlen(host) + strlen(getpage) + strlen(USERAGENT) + |
| strlen(tpl) - 5); |
| sprintf(query, tpl, getpage, host, USERAGENT); |
| return query; |
| } |
| |
| int parse_http_page(char *host, char *page, parser_f parser, void *context) |
| { |
| struct sockaddr_in *remote; |
| int ret; |
| char buf[BUFSIZ + 1]; |
| int sock; |
| char *get; |
| char ip[32]; |
| if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { |
| perror("Can't create TCP socket"); |
| return -1; |
| } |
| |
| get_ip(host, ip, sizeof(ip)); |
| remote = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in *)); |
| remote->sin_family = AF_INET; |
| ret = inet_pton(AF_INET, ip, (void *)(&(remote->sin_addr.s_addr))); |
| if (ret < 0) { |
| perror("Can't set remote->sin_addr.s_addr"); |
| return -1; |
| } else if (ret == 0) { |
| fprintf(stderr, "%s is not a valid IP address\n", ip); |
| return -1; |
| } |
| remote->sin_port = htons(PORT); |
| |
| if (connect(sock, (struct sockaddr *)remote, sizeof(struct sockaddr)) < 0) { |
| perror("Could not connect"); |
| return -1; |
| } |
| get = build_get_query(host, page); |
| |
| // send the query to the server |
| int sent = 0; |
| while (sent < strlen(get)) { |
| ret = send(sock, get + sent, strlen(get) - sent, 0); |
| if (ret == -1) { |
| perror("Can't send query"); |
| break; |
| } |
| sent += ret; |
| } |
| |
| // receive page |
| int remain = 0; |
| while ((ret = recv(sock, buf + remain, BUFSIZ - remain, 0)) > 0) { |
| int used_bytes = 0; |
| if (parser != NULL && ret >= 0) { |
| *(buf + remain + ret) = 0x0; |
| used_bytes = parser(context, buf, ret + remain); |
| remain = ret + remain - used_bytes; |
| if (remain > 0) |
| memcpy(buf, buf + used_bytes, remain); |
| } |
| if (used_bytes < 0) |
| break; |
| } |
| free(get); |
| free(remote); |
| close(sock); |
| return 1; |
| } |
| |
| #ifdef HTTP_GET_APP |
| static void usage(void) |
| { |
| fprintf(stderr, |
| "USAGE: htmlget host [page]\n" |
| "\thost: the website hostname. ex: coding.debuntu.org\n" |
| "\tpage: the page to retrieve. ex: index.html, default: /\n"); |
| } |
| |
| static int noop_parser(void *context, char *buf, int bytes) |
| { |
| printf("%s", buf); |
| return bytes; |
| } |
| |
| int main(int argc, char **argv) |
| { |
| char *host; |
| char *page; |
| |
| if (argc == 1) { |
| usage(); |
| exit(2); |
| } |
| host = argv[1]; |
| if (argc > 2) { |
| page = argv[2]; |
| } else { |
| page = PAGE; |
| } |
| |
| parse_http_page(host, page, noop_parser, NULL); |
| return 0; |
| } |
| |
| #endif |