Created
October 7, 2011 14:57
-
-
Save aslatter/1270448 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This flag has us build with windows sockets | |
// instead of cygwin sockets. Needs to be linked | |
// with ws2_32 as well. | |
// #define WINDOWS | |
#ifdef WINDOWS | |
#define WIN32_LEAN_AND_MEAN | |
#define NOGDI | |
#include <windows.h> | |
#include <winsock2.h> | |
#include <ws2tcpip.h> | |
#endif | |
#include <errno.h> | |
#include <signal.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <stdarg.h> | |
#include <strings.h> | |
#include <sys/types.h> | |
#ifndef WINDOWS | |
#include <sys/socket.h> | |
#include <netdb.h> | |
#endif | |
/* size of the socket receive buffer */ | |
#define RECV_BUFF_LEN 8000 | |
/* Print an error message to the user and quit. */ | |
void error(char *msg); | |
/* Print an error related to address info construction | |
and quit. */ | |
void addrError(char *msg, int errCode); | |
/* Print a windows error and quit. */ | |
#ifdef WINDOWS | |
void winError(char *msg, int errCode); | |
#endif | |
/* Load/Cleanup Winsock */ | |
void init_sockets(); | |
void destroy_sockets(); | |
/* returns true on success. */ | |
int writef(int fd, size_t size, char *fmt, ...); | |
/* Exits on failure */ | |
void parse_args(int argc, char** argv, | |
char** host_name, char** document, char** service); | |
int main(int argc, char** argv) | |
{ | |
int ret_val; | |
char *host_name; | |
char *document; | |
char *service = "http"; | |
parse_args(argc, argv, &host_name, &document, &service); | |
/* Setup socket */ | |
init_sockets(); | |
int sockfd = socket(AF_INET, SOCK_STREAM, 0); | |
if (sockfd < 0) error("Error creating socket"); | |
int sock_buff_size = RECV_BUFF_LEN; | |
ret_val = setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, | |
(char*)&sock_buff_size, (int)sizeof(sock_buff_size)); | |
if (ret_val != 0) error("Error setting socket options"); | |
/* Set a linger of zero. | |
This can cause a harder close than turning off linger. | |
*/ | |
struct linger linger_opts; | |
linger_opts.l_onoff = 1; | |
linger_opts.l_linger = 0; | |
ret_val = setsockopt(sockfd, SOL_SOCKET, SO_LINGER, | |
(char*)&linger_opts, sizeof(linger_opts)); | |
if (ret_val != 0) error("Error setting socket options"); | |
// todo - set TCP_NODELAY to 1, on IPPROTO_TCP ? | |
/* Lookup host */ | |
struct addrinfo *server; | |
ret_val = getaddrinfo(host_name, service, NULL, &server); | |
if (ret_val != 0) | |
addrError("Error constructing address info", ret_val); | |
/* Connect socket */ | |
ret_val = connect(sockfd, server->ai_addr, server->ai_addrlen); | |
if (ret_val != 0) error("Error connecting socket"); | |
/* Do an HTTP request */ | |
writef(sockfd, 255, "GET %s HTTP/1.1\r\n", document); | |
writef(sockfd, 255, "Host: %s\r\n", host_name); | |
writef(sockfd, 255, "User-Agent: HappyBot\r\n"); | |
//writef(sockfd, 255, "Range: bytes=100-5866155\r\n"); | |
writef(sockfd, 255, "\r\n\r\n"); | |
/* Print the first few bytes of response */ | |
char buff[ RECV_BUFF_LEN ]; | |
ret_val = recv(sockfd, buff, sizeof(buff), 0); | |
if(ret_val > 0) | |
{ | |
printf("Read %d bytes:\n", ret_val); | |
fwrite(buff, sizeof(char), ret_val, stdout); | |
} | |
else | |
error("Unable to read from socket"); | |
printf("\n\n"); | |
raise(SIGKILL); | |
/* | |
closesocket(sockfd); | |
destroy_sockets(); | |
return 0; | |
*/ | |
} | |
void parse_args(int argc, char** argv, | |
char** host_name, char** document, char** service) | |
{ | |
if(!(argc == 3 || argc == 4)) | |
{ | |
fprintf(stderr, "USAGE: %s HOST PATH [SERVICE]\n", argv[0]); | |
exit(1); | |
} | |
*host_name = argv[1]; | |
*document = argv[2]; | |
if (argc==4) | |
*service = argv[3]; | |
} | |
int writef(int sock, size_t size, char *fmt, ...) | |
{ | |
va_list ap; | |
int success = 0; | |
va_start(ap, fmt); | |
char buffer[ size ]; | |
int real_size = vsnprintf(buffer, size, fmt, ap); | |
if (real_size <= size) | |
{ | |
// also log to stdout | |
fwrite(buffer, sizeof(char), real_size, stdout); | |
ssize_t retval = 0; | |
size_t written = 0; | |
do | |
{ | |
retval = send(sock, &buffer[written], real_size - written, 0); | |
if (retval > 0) written += retval; | |
} while (retval >= 0 && written < real_size); | |
if (retval >= 0) success = 1; | |
} | |
va_end(ap); | |
/* because I'm lazy */ | |
if (!success) error("Error writing to socket"); | |
return success; | |
} | |
void addrError(char *msg, int errCode) | |
{ | |
#ifdef WINDOWS | |
error(msg); // WSAGetLastError works here | |
#else | |
fprintf(stdout, "%s: %s\n", msg, gai_strerror(errCode)); | |
exit(1); | |
#endif | |
} | |
void error(char *msg) | |
{ | |
#ifdef WINDOWS | |
int winErrCode = WSAGetLastError(); | |
if(winErrCode) | |
winError(msg, winErrCode); | |
else | |
#endif | |
{ | |
perror(msg); | |
exit(1); | |
} | |
} | |
#ifdef WINDOWS | |
void winError(char *msg, int errCode) | |
{ | |
static char message[1024]; | |
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | | |
FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, errCode, | |
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | |
message, 1024, NULL); | |
fprintf(stderr,"%s: %s\n", msg, message); | |
exit(1); | |
} | |
#endif | |
void init_sockets() | |
{ | |
#ifdef WINDOWS | |
WSADATA wsaData; | |
int ret_val = WSAStartup(MAKEWORD(2,2), &wsaData); | |
if (ret_val != 0) winError("Error starting up Winsock", ret_val); | |
#endif | |
} | |
void destroy_sockets() | |
{ | |
#ifdef WINDOWS | |
int ret_val = WSACleanup(); | |
if (ret_val != 0) winError("Error shutting down Winsock", ret_val); | |
#endif | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment