Http Request : Winsock - http

When coding http requests, i used Visual Studio for c++, now my code goes like this,
#define WIN32_LEAN_AND_MEAN
#include "stdafx.h"
#include <cstdio>
#include <cstdlib>
#include <Winsock2.h>
#include <WS2tcpip.h>
#include <windows.h>
#pragma comment (lib,"ws2_32")
int _tmain(int argc, _TCHAR* argv[])
{
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2,2),&wsaData);
SOCKET m_socket;
m_socket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(m_socket==INVALID_SOCKET)
{
printf("Invalid Socket :WSAGetLastError()");
}
sockaddr_in clientService;
clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr("127.0.0.1");
clientService.sin_port = htons(5357);
LPHOSTENT host = gethostbyname("72.144.89.32");
if(connect(m_socket,(SOCKADDR*)&clientService,sizeof(clientService))==SOCKET_ERROR)
{
printf("Connection Failure");
WSACleanup();
return 1;
}
char buffer[2048];
strcpy(buffer,"POST /dbarea.php HTTP/1.1\n");
strcat(buffer,"Content - Type:application/x-www-form-urlencoded\n");
strcat(buffer,"Host: localost\n");
strcat(buffer,"content-Length:32\n");
strcat(buffer,"\n");
strcat(buffer,"username=emeka1&password=laikan112");
//int n = write(SOCKADDR*,buffer,strlen(buffer));
printf("Data Sent Successfully..");
return 0;
}
Now my php is like this
<?php
session_start();
$username = urldecode($_POST['username']);
$password = urldecode($_POST['password']);
echo "Username: $username\nPassword:$password";
?>
Now i have an issue on the php area , its not receiving information and printing it again for us to see, what could possibly be the problem?

There are several errors in your HTTP request.
You need to use \r\n instead of \n.
Content - Type needs to be Content-Type.
localost needs to be localhost.
content-Length:32 needs to be Content-Length: 34
Try this:
int _tmain(int argc, _TCHAR* argv[])
{
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0)
{
printf("WinSock startup error: %d\n", iResult);
return 1;
}
SOCKET m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_socket == INVALID_SOCKET)
{
printf("Socket creation error: %d\n", WSAGetLastError());
WSACleanup();
return 1;
}
sockaddr_in clientService = {0};
clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr("127.0.0.1");
clientService.sin_port = htons(5357);
if (connect(m_socket, (SOCKADDR*)&clientService, sizeof(clientService)) == SOCKET_ERROR)
{
printf("Connection error: %d\n", WSAGetLastError());
closesocket(m_socket);
WSACleanup();
return 1;
}
char buffer[2048];
strcpy(buffer, "POST /dbarea.php HTTP/1.1\r\n");
strcat(buffer, "Content-Type: application/x-www-form-urlencoded\r\n");
strcat(buffer, "Host: localhost:5357\r\n");
strcat(buffer, "Content-Length: 34\r\n");
strcat(buffer, "\r\n");
strcat(buffer, "username=emeka1&password=laikan112");
char ptr = buffer;
int len = strlen(buffer);
do
{
int n = send(m_socket, ptr, len, 0);
if (n < 1)
{
if (n == SOCKET_ERROR)
printf("Send error: %d\n", WSAGetLastError());
else
printf("disconnected by server\n");
closesocket(m_socket);
WSACleanup();
return 1;
}
ptr += n;
len -= n;
}
while (len > 0);
printf("Data Sent Successfully..\n");
closesocket(m_socket);
WSACleanup();
return 0;
}
You really should not write your own HTTP code from scratch like this, when there are better alternatives available, such as Microsoft's WinInet/WinHTTP APIs, the curl library, etc. Let them do the hard work for you.
#include <WinInet.h>
#include <tchar.h>
void ReportWinInetError(const char *operation)
{
DWORD dwErr = GetLastError();
if (dwErr == ERROR_INTERNET_EXTENDED_ERROR)
{
LPTSTR szBuffer = NULL;
DWORD dwLength = 0;
BOOL bRet = InternetGetLastResponseInfo(&dwErr, NULL, &dwLength);
if ((bRet == FALSE) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
{
szBuffer = new TCHAR[dwLength+1];
bRet = InternetGetLastResponseInfo(&dwErr, szBuffer, &dwLength);
}
if (bRet)
_tprintf(_T("WinInet error while %hs: %u %*s"), operation, dwErr, dwLength, szBuffer);
else
printf("Unknown WinInet error while %s", operation);
delete[] szBuffer;
}
else
printf("WinInet error while %s: %u", operation, dwErr);
}
int _tmain(int argc, _TCHAR* argv[])
{
HINTERNET hInternet = InternetOpen(TEXT("MyApp"), INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (!hInternet)
{
ReportWinInetError("opening session");
return 1;
}
HINTERNET hConnect = InternetConnect(hInternet, TEXT("127.0.0.1"), 5357, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
if (!hConnect)
{
ReportWinInetError("connecting session");
InternetCloseHandle(hInternet);
return 1;
}
HINTERNET hRequest = HttpOpenRequest(hConnect, TEXT("POST"), TEXT("/dbarea.php"), TEXT("HTTP/1.1"), NULL, NULL, 0, 0);
if (!hRequest)
{
ReportWinInetError("opening request");
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
return 1;
}
if (!HttpSendRequest(hRequest, TEXT("Content-Type: application/x-www-form-urlencoded"), -1, "username=emeka1&password=laikan112", 34))
{
ReportWinInetError("sending request");
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
return 1;
}
printf("Data Sent Successfully..\n");
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
return 0;
}
#include <curl/curl.h>
int _tmain(int argc, _TCHAR* argv[])
{
CURLCode ret = curl_global_init(CURL_GLOBAL_DEFAULT);
if (ret != CURLE_OK)
{
printf("Curl init error: %d\n", ret);
return 1;
}
CURL *curl = curl_easy_init();
if (!curl)
{
printf("Curl request creation error\n");
curl_global_cleanup();
return 1;
}
curl_easy_setopt(curl, CURLOPT_URL, "http://127.0.0.1:5357/dbarea.php");
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "username=emeka1&password=laikan112");
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, -1);
ret = curl_easy_perform(curl);
if (ret != CURLE_OK)
{
printf("Curl send error: %d\n", ret);
curl_easy_cleanup(curl);
curl_global_cleanup();
return 1;
}
printf("Data Sent Successfully..\n");
curl_easy_cleanup(curl);
curl_global_cleanup();
}

Related

Termios transmitting user name before data

I am trying to use serial communication in Raspberry Pi. I found this link. I made only one change in the code and increase the buffer value to 30. Here my edited code:-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
int main(int argc, char* argv[]) {
struct termios serial;
char* str = "Hello";
char buffer[30];
if (argc == 1) {
printf("Usage: %s [device]\n\n", argv[0]);
return -1;
}
printf("Opening %s\n", argv[1]);
int fd = open(argv[1], O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1) {
perror(argv[1]);
return -1;
}
if (tcgetattr(fd, &serial) < 0) {
perror("Getting configuration");
return -1;
}
// Set up Serial Configuration
serial.c_iflag = 0;
serial.c_iflag = 0;
serial.c_oflag = 0;
serial.c_lflag = 0;
serial.c_cflag = 0;
serial.c_cc[VMIN] = 0;
serial.c_cc[VTIME] = 0;
serial.c_cflag = B115200 | CS8 | CREAD;
tcsetattr(fd, TCSANOW, &serial); // Apply configuration
// Attempt to send and receive
printf("Sending: %s\n", str);
//int wcount = write(fd, &str, strlen(str));
int wcount = write(fd, str, strlen(str));
if (wcount < 0) {
perror("Write");
return -1;
}
else {
printf("Sent %d characters\n", wcount);
}
// int rcount = read(fd, &buffer, sizeof(buffer));
int rcount = read(fd, buffer, sizeof(buffer));
if (rcount < 0) {
perror("Read");
return -1;
}
else {
printf("Received %d characters\n", rcount);
}
buffer[rcount] = '\0';
printf("Received: %s\n", buffer);
close(fd);
}
I short Rx and Tx pin and run this code. I should receive "Hello" but I am getting this:-
Received: pi#raspberrypi:~$ Hello
So, it is clear that I am receiving "Hello" but additionally I am automatically transmitting
pi#raspberrypi:~$
So, please tell me I to stop transmitting my user name.

Peer credentials through unix domain socket ipc mechanism

I'm writing a code for extraction of peer credential by the server process connected through ipc using domain sockets to the client process. There is no error in the code but while running it I don't get the euid and gid of the peer process.
Code for server process is:
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
//#include<ucred.h>
#define SCM_CREDENTIALS
# define UNIX_PATH_MAX 100
int getpeereid(int connection_fd,uid_t euid,gid_t gid)
{
struct ucred cred;
socklen_t len = sizeof(cred);
if (getsockopt(connection_fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) < 0)
return (-1);
euid =cred.uid;
gid = cred.gid;
//int passcred=1;
//setsockopt(connection_fd,SOL_SOCKET,SO_PASSCRED,(void *)&passcred,sizeof(passcred));
printf("effective user id", euid);
printf("effective group id",gid);
return 0;
}
int connection_handler(int connection_fd)
{
int nbytes;
char buffer[1024];
char msg[256];
//while(cont=recv(connection_fd,buffer,sizeof(buffer),0)>0)
//{
//write(1,buffer,cont)
nbytes = read(connection_fd, buffer, 256);
buffer[nbytes] = 0;
printf("MESSAGE FROM CLIENT: %s\n", buffer);
printf("enter the message");
scanf("%s",msg);
nbytes = snprintf(buffer, 256,msg);
write(connection_fd, buffer, nbytes);
//}
close(connection_fd);
return 0;
}
int main(void)
{
struct sockaddr_un address;
int socket_fd, connection_fd,res;
socklen_t address_length;
pid_t child;
uid_t eid;
gid_t gid;
socket_fd = socket(PF_UNIX, SOCK_STREAM, 0);
if(socket_fd < 0)
{
printf("socket() failed\n");
return 1;
}
printf("socket created\n");
unlink("./demo_socket");
/* start with a clean address structure */
memset(&address, 0, sizeof(struct sockaddr_un));
address.sun_family = AF_UNIX;
snprintf(address.sun_path, UNIX_PATH_MAX, "./demo_socket");
if(bind(socket_fd,
(struct sockaddr *) &address,
sizeof(struct sockaddr_un)) != 0)
{
printf("bind() failed\n");
return 1;
}
if(listen(socket_fd, 5) != 0)
{
printf("listen() failed\n");
return 1;
}
while((connection_fd = accept(socket_fd,
(struct sockaddr *) &address,
&address_length)) > -1)
{
// get the credentials
res=getpeereid(connection_fd,geteuid(),getgid());
if (res==0)
{
//if(res==0)
//{
child = fork();
if(child == 0)
{
/* now inside newly created connection handling process */
return connection_handler(connection_fd);
}
}
/* still inside server process */
close(connection_fd);
//}
}
close(socket_fd);
unlink("./demo_socket");
return 0;
}
the code for client
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <string.h>
#define UNIX_PATH_MAX 100
int connection_handler(int socket_fd)
{
int nbytes;
char buffer[1024];
char mesg[256];
printf("enter the message");
scanf("%s",mesg);
//printf("message is %s",mesg);
nbytes = snprintf(buffer, 256,mesg);
//fgets(buffer,256,mesg);
//i=atoi(mesg);
write(socket_fd,buffer,nbytes);
//send(socket_fd,mesg,sizeof(mesg),0);
}
//nbytes = read(socket_fd, buffer, 256);
//buffer[nbytes] = 0;
//printf("MESSAGE FROM SERVER: %s\n", buffer);
//}
int main(void)
{
struct sockaddr_un address;
int socket_fd, nbytes,i;
pid_t child;
char buffer[256];
//char mesg[100];
socket_fd = socket(PF_UNIX, SOCK_STREAM, 0);
if(socket_fd < 0)
{
printf("socket() failed\n");
return 1;
}
printf("socket created\n");
/* start with a clean address structure */
memset(&address, 0, sizeof(struct sockaddr_un));
address.sun_family = AF_UNIX;
snprintf(address.sun_path, UNIX_PATH_MAX, "./demo_socket");
if(connect(socket_fd,
(struct sockaddr *) &address,
sizeof(struct sockaddr_un)) != 0)
{
printf("connect() failed\n");
return 1;
}
child=fork();
while(child==0)
{
return connection_handler(socket_fd);
//printf("connection established\n");
//printf("enter the message");
//scanf("%s",mesg);
//printf("message is %s",mesg);
//bytes = snprintf(buffer, 256,mesg);
//fgets(buffer,256,mesg);
//i=atoi(mesg);
//write(socket_fd,buffer,nbytes);
//send(socket_fd,mesg,sizeof(mesg),0);
}
nbytes = read(socket_fd, buffer, 256);
buffer[nbytes] = 0;
printf("MESSAGE FROM SERVER: %s\n", buffer);
close(socket_fd);
return 0;
}
See http://www.thomasstover.com/uds.html for good overview.
If the server is Linux, the main problem is missing _GNU_SOURCE. Full patch below, it has a few minor changes just to get rid of gcc -Wall -Werror -pedantic -std=c99 errors and warnings.
--- server.c.orig 2014-12-06 13:23:09.138472871 +0200
+++ server.c 2014-12-06 13:21:31.962475754 +0200
## -1,3 +1,4 ##
+#define _GNU_SOURCE
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
## -5,7 +6,6 ##
#include <unistd.h>
#include <string.h>
//#include<ucred.h>
-#define SCM_CREDENTIALS
# define UNIX_PATH_MAX 100
int getpeereid(int connection_fd,uid_t euid,gid_t gid)
## -20,8 +20,8 ##
//int passcred=1;
//setsockopt(connection_fd,SOL_SOCKET,SO_PASSCRED,(void *)&passcred,sizeof(passcred));
-printf("effective user id", euid);
-printf("effective group id",gid);
+printf("effective user id %d", euid);
+printf("effective group id %d",gid);
return 0;
}
## -40,7 +40,7 ##
printf("MESSAGE FROM CLIENT: %s\n", buffer);
printf("enter the message");
scanf("%s",msg);
-nbytes = snprintf(buffer, 256,msg);
+nbytes = snprintf(buffer, 256, "%s", msg);
write(connection_fd, buffer, nbytes);
//}
close(connection_fd);
## -54,8 +54,6 ##
int socket_fd, connection_fd,res;
socklen_t address_length;
pid_t child;
-uid_t eid;
-gid_t gid;
socket_fd = socket(PF_UNIX, SOCK_STREAM, 0);
if(socket_fd < 0)

How to use and interpret MPI-IO Error codes?

#include <stdio.h>
#include <iostream>
#include <Windows.h>
#include <C:\Program Files\Microsoft MPI\Inc\mpi.h>
using namespace std;
#define BUFSIZE 128
int main (int argc, char *argv[])
{
int err;
int rank;
int size;
double start_time = 0.0;
double end_time;
MPI_Comm comm = MPI_COMM_WORLD;
MPI_File file;
char cbuf[BUFSIZE];
for(int i = 0; i < BUFSIZE; i++)
{
cbuf[i] = 'a' + i;
}
if(err = MPI_Init(&argc, &argv))
{
printf("%s \n", "Error! MPI is halted!");
MPI_Abort(comm, err);
}
MPI_Comm_size(comm, &size);
MPI_Comm_rank(comm, &rank);
if(rank == 0)
{
start_time = MPI_Wtime();
}
err = MPI_File_open(comm, "testfile", MPI_MODE_CREATE | MPI_MODE_RDWR, MPI_INFO_NULL, &file);
if(err != MPI_SUCCESS)
{
printf("Error %d! Can't open the file!\n", err);
MPI_Abort(comm, err);
return EXIT_FAILURE;
}
err = MPI_File_set_view(file, (MPI_Offset) (rank * BUFSIZE * sizeof(char)), MPI_CHAR, MPI_CHAR, "native", MPI_INFO_NULL);
if(err != MPI_SUCCESS)
{
printf("%s \n", "Error! Can't set the view!");
MPI_Abort(comm, err);
return EXIT_FAILURE;
}
err = MPI_File_write(file, cbuf, BUFSIZE, MPI_CHAR, MPI_STATUSES_IGNORE);
if(err != MPI_SUCCESS)
{
printf("%s \n", "Error! Problems with writing!");
MPI_Abort(comm, err);
return EXIT_FAILURE;
}
MPI_File_close(&file);
if(rank == 0)
{
end_time = MPI_Wtime();
printf("Time elapsed : %f seconds", (end_time - start_time) * 1000);
}
MPI_Finalize();
return EXIT_SUCCESS;
}
I'm trying to write some symbols to a file with MPI. When I do that, I get an errorcode of 288 and the file can't be opened. I used command line: mpiexec -n 10 myapp.exe. I was searching for the errorcode but didn't find anything at all.
Go one step further. Your error code doesn't mean anything by itself. But, you can feed that code to MPI_Error_string and get something more human readable. I have this function in every MPI-IO code I write:
static void handle_error(int errcode, char *str)
{
char msg[MPI_MAX_ERROR_STRING];
int resultlen;
MPI_Error_string(errcode, msg, &resultlen);
fprintf(stderr, "%s: %s\n", str, msg);
MPI_Abort(MPI_COMM_WORLD, 1);
}
And then define this macro:
#define MPI_CHECK(fn) { int errcode; errcode = (fn);\
if (errcode != MPI_SUCCESS) handle_error (errcode, #fn ); }
So I can call routines like this:
CHECK(MPI_File_open(comm, "testfile",
MPI_MODE_CREATE | MPI_MODE_RDWR, MPI_INFO_NULL, &file) );

TCP optimisation

I've written a code using SOL_SOCKET protocol but getting error as 10043 (error in socket).
The code is as follows:
#include <QCoreApplication>
#include<QDebug>
//#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
/****************************************/
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")
/****************************************/
#define DEFAULT_BUFLEN 512
int recvbuflen = DEFAULT_BUFLEN;
char recvbuf[DEFAULT_BUFLEN];
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
WSADATA wsaData;
int iResult;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
struct addrinfo *result = NULL,
*ptr = NULL,
hints;
ZeroMemory( &hints, sizeof(hints) );
//hints.ai_family = AF_UNSPEC;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = SOL_SOCKET;
//hints.ai_protocol = IPPROTO_TCP;
#define DEFAULT_PORT "10990"
// Resolve the server address and port
iResult = getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed: %d\n", iResult);
WSACleanup();
return 1;
}
SOCKET ConnectSocket = INVALID_SOCKET;
// Attempt to connect to the first address returned by
// the call to getaddrinfo
ptr=result;
// Create a SOCKET for connecting to server
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET) {
printf("Error at socket(): %ld\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
int rcvbuf = 8192; /* recv buffer size */
int z = setsockopt(ConnectSocket,SOL_SOCKET,SO_RCVBUF,
(char*)&rcvbuf,sizeof(rcvbuf));
do {
iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
if (iResult > 0)
printf("Bytes received: %d\n", iResult);
else if (iResult == 0)
printf("Connection closed\n");
else
printf("recv failed: %d\n", WSAGetLastError());
} while (iResult > 0);
return a.exec();
}
When I run it shows::
Error in socket:10043
I googled it and found that the error is because of wrong protocol for the socket type,I tried to find the correct protocol and socket type match but couldn't find.I tried every possible socket option and protocol match.
Any body facing the same problem?
You're putting the wrong value in the ai_protocol field. It needs to be one of the IPPROTO_ constants (like e.g. IPPROTO_TCP or IPPROTO_ICMP).
SOL_SOCKET is used to set socket options (like you do later in the code).
You should normally not set that member, except to zero.

Why recv() in winsock client cannot get any data once httpRetransmition happens?

I am trying to record the time between 'http request' package and 'http response' package.
I write an socket client using winsock. The code is below
if (send(sock, request.c_str(), request.length(), 0) != request.length())
die_with_error("send() sent a different number of bytes than expected");
// Record the time of httpRequestSent
::QueryPerformanceCounter(&httpRequestSent);
::QueryPerformanceFrequency(&frequency);
//get response
response = "";
resp_leng= BUFFERSIZE;
http_leng= 381;
while(resp_leng==BUFFERSIZE||http_leng>0)
{
resp_leng= recv(sock, (char*)&buffer, BUFFERSIZE, 0);
http_leng= http_leng - resp_leng;
if (resp_leng>0)
response+= string(buffer).substr(0,resp_leng);
//note: download lag is not handled in this code
}
::QueryPerformanceCounter(&httpResponseGot);
//display response
cout << response << endl;
// Display the HTTP duration
httpDuration = (double)(httpResponseGot.QuadPart - httpRequestSent.QuadPart) / (double)frequency.QuadPart;
printf("The HTTP duration is %lf\n", httpDuration);
The code works nicely except one situation: HTTP Retransmition. I used wireshark to monitor packages and found out once there is a retransmition the code seems block on recv(), but cannot get any data from the socket buffer. I wonder why would this happen. Could somebody explain the reasons?
Any help will be appreciated.
Here is a second answer with more dynamic buffer handling and more error checking:
void send_data(SOCKET sock, void *data, unsigned int data_len)
{
unsigned char *ptr = (unsigned char*) data;
while (data_len > 0)
{
int num_to_send = (int) std::min(1024*1024, data_len);
int num_sent = send(sock, ptr, num_to_send, 0);
if (num_sent < 0)
{
if ((num_sent == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK))
continue;
die_with_error("send() failed");
}
if (num_sent == 0)
die_with_error("socket disconnected");
ptr += num_sent;
data_len -= num_sent;
}
}
unsigned int recv_data(SOCKET sock, void *data, unsigned int data_len, bool error_on_disconnect = true)
{
unsigned char *ptr = (unsigned char*) data;
unsigned int total = 0;
while (data_len > 0)
{
int num_to_recv = (int) std::min(1024*1024, data_len);
int num_recvd = recv(sock, ptr, num_to_recv, 0);
if (num_recvd < 0)
{
if ((num_recvd == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK))
continue;
die_with_error("recv() failed");
}
if (num_recvd == 0)
{
if (error_on_disconnect)
die_with_error("socket disconnected");
break;
}
ptr += num_recvd;
datalen -= num_recvd;
total += num_recvd;
}
while (true);
return total;
}
std::string recv_line(SOCKET sock)
{
std::string line;
char c;
do
{
recv_data(sock, &c, 1);
if (c == '\r')
{
recv_data(sock, &c, 1);
if (c == '\n')
break;
line += '\r';
}
else if (c == '\n')
break;
line += c;
}
return line;
}
void recv_headers(SOCKET sock, std::vector<std::string> *hdrs)
{
do
{
std::string line = recv_line(sock);
if (line.length() == 0)
return;
if (hdrs)
hdrs->push_back(line);
}
while (true);
}
unsigned int recv_chunk_size(SOCKET sock)
{
std::string line = recv_line(sock);
size_t pos = line.find(";");
if (pos != std::string::npos)
line.erase(pos);
char *endptr;
unsigned int value = strtoul(line.c_str(), &endptr, 16);
if (*endptr != '\0')
die_with_error("bad Chunk Size received");
return value;
}
std::string find_header(const std::vector<std::string> &hrds, const std::string &hdr_name)
{
std::string value;
for(size_t i = 0; i < hdrs.size(); ++i)
{
const std::string hdr = hdrs[i];
size_t pos = hdr.find(":");
if (pos != std::string::npos)
{
if (hdr.compare(0, pos-1, name) == 0)
{
pos = hdr.find_first_not_of(" ", pos+1);
if (pos != std::string::npos)
return hdr.substr(pos);
break;
}
}
}
return "";
}
{
// send request ...
std::string request = ...;
send_data(sock, request.c_str(), request.length());
// Record the time of httpRequestSent
::QueryPerformanceCounter(&httpRequestSent);
::QueryPerformanceFrequency(&frequency);
// get response ...
std::vector<std::string> resp_headers;
std::vector<unsigned char> resp_data;
recv_headers(sock, &resp_headers);
std::string transfer_encoding = find_header(resp_headers, "Transfer-Encoding");
if (transfer_encoding.find("chunked") != std::string::npos)
{
unsigned int chunk_len = recv_chunk_size(sock);
while (chunk_len != 0)
{
size_t offset = resp_data.size();
resp_data.resize(offset + chunk_len);
recv_data(sock, &resp_data[offset], chunk_len);
recv_line(sock);
chunk_len = recv_chunk_size(sock);
}
recv_headers(sock, NULL);
}
else
{
std::string content_length = find_header(resp_headers, "Content-Length");
if (content_length.length() != 0)
{
char *endptr;
unsigned int content_length_value = strtoul(content_length.c_str(), &endptr, 10);
if (*endptr != '\0')
die_with_error("bad Content-Length value received");
if (content_length_value > 0)
{
resp_data.resize(content_length_value);
recv_data(sock, &resp_data[0], content_length_value);
}
}
else
{
unsigned char buffer[BUFFERSIZE];
do
{
unsigned int buffer_len = recv_data(sock, buffer, BUFFERSIZE, false);
if (buffer_len == 0)
break;
size_t offset = resp_data.size();
resp_data.resize(offset + buffer_len);
memcpy(&resp_data[offset], buffer, buffer_len);
}
while (true)
}
}
::QueryPerformanceCounter(&httpResponseGot);
// process resp_data as needed
// may be compressed, encoded, etc...
// Display the HTTP duration
httpDuration = (double)(httpResponseGot.QuadPart - httpRequestSent.QuadPart) / (double)frequency.QuadPart;
printf("The HTTP duration is %lf\n", httpDuration);
}
You are not doing adequate error checking on the calls to send() and recv(). Try something like this instead:
char *req_ptr = request.c_str();
int req_leng = request.length();
int req_index = 0;
do
{
int req_sent = send(sock, req_ptr, req_leng, 0);
if (req_sent < 1)
{
if ((req_sent == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK))
continue;
die_with_error("send() failed");
}
req_ptr += req_sent;
req_leng -= req_sent;
}
while (req_leng > 0);
// Record the time of httpRequestSent
::QueryPerformanceCounter(&httpRequestSent);
::QueryPerformanceFrequency(&frequency);
//get response
std::string response;
int resp_leng = BUFFERSIZE;
int http_leng = -1;
bool http_leng_needed = true;
do
{
if (http_leng_needed)
{
std::string::size_type pos = response.find("\r\n\r\n");
if (pos != std::string::npos)
{
std::string resp_hdrs = response.substr(0, pos);
// look for a "Content-Length" header to see
// if the server sends who many bytes are
// being sent after the headers. Note that
// the server may use "Transfer-Encoding: chunked"
// instead, which has no "Content-Length" header...
//
// I will leave this as an excercise for you to figure out...
http_leng = ...;
// in case body bytes have already been received...
http_leng -= (response.length() - (pos+4));
http_leng_needed = false;
}
}
if (http_leng_needed)
resp_leng = BUFFERSIZE;
else
resp_leng = min(http_leng, BUFFERSIZE);
if (resp_leng == 0)
break;
resp_leng = recv(sock, buffer, resp_leng, 0);
if (resp_leng < 1)
{
if ((resp_leng == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK))
continue;
die_with_error("send() failed");
}
response += string(buffer, resp_leng);
if (!http_leng_needed)
http_leng -= resp_leng;
}
while ((http_leng_needed) || (http_leng > 0));
::QueryPerformanceCounter(&httpResponseGot);
//display response
cout << response << endl;
// Display the HTTP duration
httpDuration = (double)(httpResponseGot.QuadPart - httpRequestSent.QuadPart) / (double)frequency.QuadPart;
printf("The HTTP duration is %lf\n", httpDuration);
With this said, the "correct" way to handle HTTP in general is to read the inbound data line by line, rather than buffer by buffer, until you encounter the end of the response headers, then you can read the rest of the data buffer by buffer based on the data length indicated by the headers.

Resources