My Client Socket Program not receiving response
I created a simple http client socket program that fetches data via a GET Request. Sadly, it does not seem to be returning a http response (it seems to freeze). The request appears t be valid and the http protocol version is 1.1. Here is the code in C++
Code:
#include <fstream>
#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string>
#include <cstring>
using namespace std;
string resolveToIPAddress(string, string);
int getPortNum(string);
string getUrlPath(string);
string getDomain(string);
string getDomainWithFile(string);
string getUrlWithNoPort(string);
string getFileFromURL(string);
bool hasHTTPProtocol(string);
bool hasPortNum(string);
bool checkIfValidIPAddress(string);
int main(int argc, char **argv)
{
//Create a file to be opened for output
ofstream out_file;
out_file.open("output.txt", ios::out);
int connection_port = 0, send_req, recv_req;
string ip_addr = "", domain = "", ipFromDomain = "", file_to_get = "";
ip_addr = argv[1]; //point ip address argument to the 2nd indice in the arguments
//if there is a port number, Get port number (extract it from URL)
if (hasPortNum(ip_addr)) {
connection_port = getPortNum(ip_addr);
domain = getDomain(ip_addr);
}
//if there is no port number, set default port number = 80 and set domain to truncated ip address
else {
connection_port = 80;
domain = getDomain(ip_addr);
}
file_to_get = getFileFromURL(ip_addr);
cout << "Domain: " << domain << endl;
cout << "Port Number: " << connection_port << endl;
cout << "File requested: " << file_to_get << endl;
//resolve domain to ipAddress
ipFromDomain = resolveToIPAddress(domain, to_string(connection_port));
//Connect to iP Address with port and return metadata
//Create the socket
int http_client_socket = socket(AF_INET, SOCK_STREAM, 0);
// connect address and contain socket
struct sockaddr_in connection_addr;
connection_addr.sin_family = AF_INET; //set the addressfamily type to INET
connection_addr.sin_port = htons(connection_port); //set socket to parsed port number
cout << "ip address: " << ipFromDomain << endl; //checking to see if ip address is well converted
inet_aton(ipFromDomain.c_str(), &connection_addr.sin_addr); //convert ip address from IPV4 notation string and store it into structure
//Connect to server address
if (connect
(http_client_socket, (struct sockaddr *) &connection_addr,
sizeof(connection_addr)) != 0) {
cout << "Connection with the server failed..." << endl;
exit(0);
}
//Logic for HTTP GET Request
string http_request = "GET /" + file_to_get + " HTTP/1.1\r\n\r\n";
cout << http_request << endl;
//string http_response;
string http_response;
send(http_client_socket, http_request.c_str(), sizeof(http_request), 0);
recv(http_client_socket, &http_response, 999999999, 0);
out_file << http_response << endl;
//close the file
out_file.close();
//close the socket
close(http_client_socket);
return 0;
}
string getUrlWithNoPort(string url)
{
if (hasHTTPProtocol(url))
return url.substr(7, url.length() - 7);
return url;
}
//Get URL without port and path
string getDomain(string url)
{
string urlWithoutPortandPath = "";
int i = 0;
//Check if full URL has a protocol
if (hasHTTPProtocol(url)) {
//if it has a protocol truncate the protocol from FQDN
i = 7;
while (url != '/') {
//for (int i = 7; i < url.length(); i++) {
if (url == ':') {
break;
}
urlWithoutPortandPath += url;
i++;
//}
}
return urlWithoutPortandPath;
}
//if it does not have a protocol remove port number and path
while (url != '/') {
//for (int i = 0; i < url.length(); i++) {
if (url == ':') {
break;
}
urlWithoutPortandPath += url;
i++;
}
return urlWithoutPortandPath;
}
string getDomainWithFile(string url)
{
string urlWithoutPortandPath = "";
//Check if full URL has a protocol
if (hasHTTPProtocol(url)) {
//if it has a protocol truncate the protocol from FQDN
for (int i = 7; i < url.length(); i++) {
if (url == ':') {
break;
}
urlWithoutPortandPath += url;
}
return urlWithoutPortandPath;
}
//if it does not have a protocol remove port number and path
for (int i = 0; i < url.length(); i++) {
if (url == ':') {
break;
}
urlWithoutPortandPath += url;
}
return urlWithoutPortandPath;
}
bool hasHTTPProtocol(string url)
{
string httpProtocol = url.substr(0, 7);
if (httpProtocol == "http://")
return true;
return false;
}
int getPortNum(string url)
{
string port = "";
int portNum, portIdx = 0, pathIdx = 0, portEndIdx = 0;
if (hasHTTPProtocol(url)) {
for (int i = 7; i < url.length(); i++) {
if (url == ':')
portIdx = i + 1;
}
}
string fromPortToPath = url.substr(portIdx, url.length() - portIdx);
cout << "Port to Path: " << fromPortToPath << endl;
for (int i = 0; i < fromPortToPath.length(); i++) {
if (fromPortToPath == '/') {
pathIdx = i + 1;
portEndIdx = i;
break;
}
}
port = fromPortToPath.substr(0, portEndIdx);
portNum = stoi(port);
return portNum;
}
string getUrlPath(string url)
{
string urlPath = "";
int pathIdx = 0, portIdx = 0, portEndIdx = 0;
if (hasHTTPProtocol(url)) {
for (int i = 7; i < url.length(); i++) {
if (url == ':')
portIdx = i + 1;
}
}
string fromPortToPath = url.substr(portIdx, url.length() - portIdx);
cout << "Port to Path: " << fromPortToPath << endl;
for (int i = 0; i < fromPortToPath.length(); i++) {
if (fromPortToPath == '/') {
pathIdx = i + 1;
portEndIdx = i;
break;
}
}
urlPath =
fromPortToPath.substr(portEndIdx + 1, fromPortToPath.length() - pathIdx);
return urlPath;
}
bool hasPortNum(string url)
{
if (hasHTTPProtocol(url)) {
for (int i = 7; i < url.length(); i++) {
if (url == ':')
return true;
}
} else {
for (int i = 0; i < url.length(); i++) {
if (url == ':')
return true;
}
}
return false;
}
//Resolves a string hostname e.g. google.com into an ipaddress (practically a DNS function)
string resolveToIPAddress(string urlString, string portNum)
{
struct addrinfo hints, *results;
struct addrinfo *result;
int error, sock_id;
string numericalIPS[100];
//set all bits in hints to zero
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if ((error =
getaddrinfo(urlString.c_str(), portNum.c_str(), &hints,
&results)) != 0) {
cout << "error " << error << ":" << gai_strerror(error) << endl;
}
int i = 0;
//loop through results
for (result = results; result != nullptr; result = result->ai_next) {
struct sockaddr_in *ip_addr;
ip_addr = (struct sockaddr_in *) result->ai_addr;
numericalIPS = inet_ntoa(ip_addr->sin_addr);
i++;
}
return numericalIPS[0];
}
string getFileFromURL(string url)
{
int idxToFile;
string file_request;
string path_to_file = getDomainWithFile(url);
for (int i = 0; i < path_to_file.length(); i++) {
if (path_to_file == '/') {
idxToFile = i + 1;
}
}
file_request =
path_to_file.substr(idxToFile, path_to_file.length() - idxToFile);
return file_request;
}
I took the following measures to debug the application:
- Stepping through the code
- adding print statements to make sure that the domain, port number, the ip address the domain resolves to via DNS, and the file that is requested are correct...They appear to be.
The way I dissected the data one by one is by getting the domain, port number, path to the file. I went ahead and used DNS to resolve the hostname to an IPv4 address. I am still running into problems. Thanks!