I'm modifying UDP to implement a custom protocol. After UDP connect establishes a route, I want to send a custom UDP packet to the destination (like a SYN packet in TCP). When I try the connect() socket function on a machine running my custom kernel, it freezes without writing out anything to the kernel log. Here's my code
int quic_connect(struct sock *sk, struct flowi4 *fl4, struct rtable *rt){
struct sk_buff *skb, *buff;
struct inet_cork cork;
struct ipcm_cookie ipc;
struct sk_buff_head queue;
char *hello;
int err = 0, exthdrlen, hh_len, datalen, trailerlen;
char *data;
hh_len = LL_RESERVED_SPACE(rt->dst.dev);
exthdrlen = rt->dst.header_len;
trailerlen = rt->dst.trailer_len;
datalen = 200;
//Create a buffer to be send without fragmentation
skb = sock_alloc_send_skb(sk,
exthdrlen + datalen + hh_len + trailerlen + 15,
MSG_DONTWAIT, &err);
if (skb == NULL)
goto out;
skb->ip_summed = CHECKSUM_PARTIAL; // Use hardware checksum
skb->csum = 0;
skb_reserve(skb, hh_len);
skb_shinfo(skb)->tx_flags = 1; //Time stamp the packet
/*
* Find where to start putting bytes.
*/
data = skb_put(skb, datalen + exthdrlen);
skb_set_network_header(skb, exthdrlen);
skb->transport_header = (skb->network_header +
sizeof(struct iphdr));
__skb_queue_head_init(&queue);
/*
* Put the packet on the pending queue.
*/
__skb_queue_tail(&queue, skb);
cork.flags = 0;
cork.addr = 0;
cork.opt = NULL;
ipc.opt = NULL;
ipc.tx_flags = 0;
ipc.ttl = 0;
ipc.tos = -1;
ipc.addr = fl4->daddr;
err = ip_setup_cork(sk, &cork, &ipc, &rt);
buff = __ip_make_skb(sk, fl4, &queue, &cork);
kfree(skb);
err = PTR_ERR(buff);
if (!IS_ERR_OR_NULL(buff))
err = udp_send_skb(buff, fl4);
out:
return err;
}
The function quic_connect is called at the end of the ip4_datagram_connect function which is the registered handler for UDP connect.
There is absolutely nothing in the kernel log.
What am I doing wrong here?
**EDIT 1: **The problem occurs at err = udp_send_skb(buff, fl4); as there is no issue when I comment out that line. so I'm assuming my sk_buff has not been formed correctly. Any ideas why?
Related
I'm sending messages on Unix domain sockets on Mac with sendmsg(). However, it sometimes hangs forever.
I've called getsockopt(socket, SOL_SOCKET, SO_SNDBUF, ...) to get the size of the send buffer. (The default is 2048).
If I try sending a message larger than 2048 bytes, I correctly get
EMSGSIZE and know I need to send a smaller message.
If I try sending a message less than 2036 bytes, the message is sent fine.
If I try sending a message between 2036 and 2048 bytes, the
sendmsg call...hangs forever.
What's going on here? What's the correct way to deal with this? Is it safe to just subtract 13 bytes from the maximum size I try sending, or could I run into issues if e.g. there's other messages in the buffer already?
Here's the (simplified) code I'm using:
// Get the maximum message size
int MaxMessageSize(int socket) {
int sndbuf = 0;
socklen_t optlen = sizeof(sndbuf);
if (getsockopt(socket, SOL_SOCKET, SO_SNDBUF, &sndbuf, &optlen) < 0) {
return -1;
}
return sndbuf;
}
// Send a message
static int send_chunk(int socket, const char *data, size_t size) {
struct msghdr msg = {0};
char buf[CMSG_SPACE(0)];
memset(buf, '\0', sizeof(buf));
int iov_len = size;
if (iov_len > 512) {
int stat = send_size(socket, iov_len);
if (stat < 0) return stat;
}
char iov_buf[iov_len];
memcpy(iov_buf, data, size);
struct iovec io = {.iov_base = (void *)iov_buf, .iov_len = iov_len};
msg.msg_iov = &io;
msg.msg_iovlen = 1;
msg.msg_control = buf;
msg.msg_controllen = sizeof(buf);
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(0);
msg.msg_controllen = CMSG_SPACE(0);
std::cerr << "Attempting to send message of size " << iov_len << std::endl;
ssize_t ret = sendmsg(socket, &msg, 0);
std::cerr << "sendmsg returned: " << ret << std::endl;
return ret;
}
During the attempt to write my own simple usb driver for an usb-flash-drive, I got stuck reading the data that I wrote to the device.
So, my first question is:
How is the transfer and the storage on a device going on? (in detail)
I know I have to perform the following steps:
Create an urb (USB request block)
Allocate a DMA buffer
Transfer the data from the user-space into the DMA buffer
Send the data through a pipe to the device
I couldn't find any documentation on how a device handles this data.
Is this even possible to write such a driver, or would it be necessary to disassemble the usb device, to send special commands?
The code I have written looks something like the following and is from the ldd3 and "http://lxr.free-electrons.com/source/drivers/usb/usb-skeleton.c". It only shows a shortened version of the important functions.
After loading the driver into the kernel, I can write to the device without any error, but if I read, an EPIPE error occurs. Ldd3 mentions that the usb_clear_halt() could solve this problem, but it doesn't.
// This function is called when the device is plugged in
static int my_driver_probe(struct usb_interface* interface, const struct usb_device_id* id)
{
struct usb_skel* dev = NULL;
struct usb_device* udev = interface_to_usbdev(interface);
struct usb_host_interface* iface_desc;
struct usb_endpoint_descriptor* endpoint;
int retval = -ENODEV;
int i = 0;
size_t buffer_size;
dev = kzalloc(sizeof(struct usb_skel), GFP_KERNEL);
// Check vendor and product id
// …
dev->udev = udev;
dev->interface = interface;
// Set up the endpoint information
iface_desc = interface->cur_altsetting;
for(i=0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
if(!dev->bulk_in_endpointAddr && usb_endpoint_is_bulk_in(endpoint)) {
buffer_size = endpoint->wMaxPacketSize;
dev->bulk_in_size = buffer_size;
dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
if(!dev->bulk_in_buffer) {
printk("Could not allocate bulk_in_buffer\n");
goto error;
}
dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL);
}
if(!dev->bulk_out_endpointAddr && usb_endpoint_is_bulk_out(endpoint))
dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
}
// Check that the endpoints are set
// …
// Save our data pointer in this interface device
usb_set_intfdata(interface, dev);
// Register the device
retval = usb_register_dev(interface, &class_descr);
return retval;
}
// Is called when another program writes into /dev/my_usb_driver
static ssize_t my_driver_write( struct file* file, const char __user* user_buffer, size_t count, loff_t* offs)
{
struct usb_skel* dev = file->private_data;
struct urb* urb = NULL;
char* buf = NULL;
int retval = 0;
size_t writesize = min(count, (size_t)MAX_TRANSFER);
// Create a urb, and a buffer for it, and copy the data to the urb
urb = usb_alloc_urb(0, GFP_KERNEL);
// Creates a DMA buffer
buf = usb_alloc_coherent(dev->udev, writesize, GFP_KERNEL, &urb->transfer_dma);
// The data that is passed to the driver should be copied into the DMA buffer
copy_from_user(buf, user_buffer, writesize;
// Initialize the urb proberly
usb_fill_bulk_urb(urb, dev->udev,
usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
buf, writesize, (void*)my_write_bulk_callback, dev);
// Send the data out the bulk port
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
usb_submit_urb(urb, GFP_KERNEL);
return writesize;
}
// Is called when another program reads from /dev/my_usb_driver
static ssize_t my_driver_read( struct file *file, char* buffer, size_t count, loff_t* offs)
{
struct usb_skel* dev = file->private_data;
int retval = 0;
// Check that we have data to read
// …
usb_fill_bulk_urb(dev->bulk_in_urb, dev->udev,
usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
dev->bulk_in_buffer,
min(dev->bulk_in_size, count), read_bulk_callback, dev);
retval = usb_submit_urb(dev->bulk_in_urb, GFP_KERNEL);
// If the read was succesful, copy the data to user space
copy_to_user(buffer, dev->bulk_in_buffer, count);
return retval;
}
USB is just a transport layer. Storage devices generally implement SCSI protocol. Create a SCSI command for reading or writing from the data that user space has sent. Then create URB for the SCSI command and send it to the USB device.
SCSI is a huge protocol, for learning USB device driver development it is better to start with simple devices like USB to serial devices.
External controller sends 120-bytes message through TCP/IP socket every 30ms.
Application receives this messages through standard tcp/ip socket recv function.
It works perfectly under Linux & OSX (recv returns 120-bytes messages every 30ms).
Under Windows recv returns ~3500 bytes buffer about every 1 sec. Rest of time it returns 0.
Wireshark under Windows shows messages indeed coming every 30ms.
How to make windows tcp socket work properly (without delay) ?
PS: I've played with TCP_NODELAY & TcpAckFrequency already. Wireshark shows everything is ok. So I think it's some Windows optimization, that should be turned off.
Reading--
int WMaster::DataRead(void)
{
if (!open_ok) return 0;
if (!CheckSocket())
{
PrintErrNo();
return 0;
}
iResult = recv(ConnectSocket, (char *)input_buff,sizeof(input_buff),0);
nError=WSAGetLastError();
if(nError==0) return iResult;
if(nError==WSAEWOULDBLOCK) return iResult;
PrintErrNo();
return 0;
}
Initialization-
ConnectSocket = INVALID_SOCKET;
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
ZeroMemory(&clientService, sizeof(clientService));
clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr( deviceName.toLatin1().constData() );
clientService.sin_port = htons( port);
iResult = setsockopt(ConnectSocket, IPPROTO_TCP, TCP_NODELAY, (char *) &flag,
sizeof (int));
u_long iMode=1;
iResult=ioctlsocket(ConnectSocket,FIONBIO,&iMode);
iResult = ::connect( ConnectSocket, (SOCKADDR*) &clientService,
sizeof(clientService) );
CheckSocket -
bool WMaster::CheckSocket(void)
{
socklen_t len = sizeof (int);
int retval = getsockopt (ConnectSocket, SOL_SOCKET, SO_ERROR, (char*)(&valopt), &len );
if (retval!=0)
{
open_ok=false;
return false;
};
return true;
}
Consider disabling the Nagle algorithm. 120-bytes is quite small and its possible that data is being buffered before being sent. Another reason I think it is the Nagle Algorithm is that about 33 sends should happen in 1 second. That corresponds with 33*120 = 3960 bytes / sec very similar to the 3500 you are seeing.
Change your dataread function as follows such that WSAGetLastError is only called when there is an error.
int WMaster::DataRead(void)
{
if (!open_ok) return 0;
if (!CheckSocket())
{
PrintErrNo();
return 0;
}
iResult = recv(ConnectSocket, (char *)input_buff,sizeof(input_buff),0);
if(iResult >= 0)
{
return iResult;
}
nError=WSAGetLastError();
if(nError==WSAEWOULDBLOCK) return iResult;
PrintErrNo();
return 0;
}
The fact that you are polling the socket every millisecond may have something to do with your performance problem. But I'd like to see the source to CheckSocket before concluding that as the problem.
It looks like from my testing I am hitting a performance wall on my 10gb network. I seem to be unable to read more than 180-200k packets per second. Looking at perfmon, or task manager I can receive up to a million packets / second if not more. Testing 1 socket or 10 or 100, doesn't seem to change this limit of 200-300k packets a second. I've fiddled with RSS and the like without success. Unicast vs multicast doesn't seem to matter, overlapped i/o vs synchronous doesn't make a difference either. Size of packet doesn't matter either. There just seems to be a hard limit to the number of packets windows can copy from the nic to the buffer. This is a dell r410. Any ideas?
#include "stdafx.h"
#include <WinSock2.h>
#include <ws2ipdef.h>
static inline void fillAddr(const char* const address, unsigned short port, sockaddr_in &addr)
{
memset( &addr, 0, sizeof( addr ) );
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr( address );
addr.sin_port = htons(port);
}
int _tmain(int argc, _TCHAR* argv[])
{
#ifdef _WIN32
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 1, 1 );
err = WSAStartup( wVersionRequested, &wsaData );
#endif
int error = 0;
const char* sInterfaceIP = "10.20.16.90";
int nInterfacePort = 0;
//Create socket
SOCKET m_socketID = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
//Re use address
struct sockaddr_in addr;
fillAddr( "10.20.16.90", 12400, addr ); //"233.43.202.1"
char one = 1;
//error = setsockopt(m_socketID, SOL_SOCKET, SO_REUSEADDR , &one, sizeof(one));
if( error != 0 )
{
fprintf( stderr, "%s: ERROR setsockopt returned %d.\n", __FUNCTION__, WSAGetLastError() );
}
//Bind
error = bind( m_socketID, reinterpret_cast<SOCKADDR*>( &addr ), sizeof( addr ) );
if( error == -1 )
{
fprintf(stderr, "%s: ERROR %d binding to %s:%d\n",
__FUNCTION__, WSAGetLastError(), sInterfaceIP, nInterfacePort);
}
//Join multicast group
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr("225.2.3.13");//( "233.43.202.1" );
mreq.imr_interface.s_addr = inet_addr("10.20.16.90");
//error = setsockopt( m_socketID, IPPROTO_IP, IP_ADD_MEMBERSHIP, reinterpret_cast<char*>( &mreq ), sizeof( mreq ) );
if (error == -1)
{
fprintf(stderr, "%s: ERROR %d trying to join group %s.\n", __FUNCTION__, WSAGetLastError(), "233.43.202.1" );
}
int bufSize = 0, len = sizeof(bufSize), nBufferSize = 10*1024*1024;//8192*1024;
//Resize the buffer
getsockopt(m_socketID, SOL_SOCKET, SO_RCVBUF, (char*)&bufSize, &len );
fprintf(stderr, "getsockopt size before %d\n", bufSize );
fprintf(stderr, "setting buffer size %d\n", nBufferSize );
error = setsockopt(m_socketID, SOL_SOCKET, SO_RCVBUF,
reinterpret_cast<const char*>( &nBufferSize ), sizeof( nBufferSize ) );
if( error != 0 )
{
fprintf(stderr, "%s: ERROR %d setting the receive buffer size to %d.\n",
__FUNCTION__, WSAGetLastError(), nBufferSize );
}
bufSize = 1234, len = sizeof(bufSize);
getsockopt(m_socketID, SOL_SOCKET, SO_RCVBUF, (char*)&bufSize, &len );
fprintf(stderr, "getsockopt size after %d\n", bufSize );
//Non-blocking
u_long op = 1;
ioctlsocket( m_socketID, FIONBIO, &op );
//Create IOCP
HANDLE iocp = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, NULL, 1 );
HANDLE iocp2 = CreateIoCompletionPort( (HANDLE)m_socketID, iocp, 5, 1 );
char buffer[2*1024]={0};
int r = 0;
OVERLAPPED overlapped;
memset(&overlapped, 0, sizeof(overlapped));
DWORD bytes = 0, flags = 0;
// WSABUF buffers[1];
//
// buffers[0].buf = buffer;
// buffers[0].len = sizeof(buffer);
//
// while( (r = WSARecv( m_socketID, buffers, 1, &bytes, &flags, &overlapped, NULL )) != -121 )
//sleep(100000);
while( (r = ReadFile( (HANDLE)m_socketID, buffer, sizeof(buffer), NULL, &overlapped )) != -121 )
{
bytes = 0;
ULONG_PTR key = 0;
LPOVERLAPPED pOverlapped;
if( GetQueuedCompletionStatus( iocp, &bytes, &key, &pOverlapped, INFINITE ) )
{
static unsigned __int64 total = 0, printed = 0;
total += bytes;
if( total - printed > (1024*1024) )
{
printf( "%I64dmb\r", printed/ (1024*1024) );
printed = total;
}
}
}
while( r = recv(m_socketID,buffer,sizeof(buffer),0) )
{
static unsigned int total = 0, printed = 0;
if( r > 0 )
{
total += r;
if( total - printed > (1024*1024) )
{
printf( "%dmb\r", printed/ (1024*1024) );
printed = total;
}
}
}
return 0;
}
I am using Iperf as the sender and comparing the amount of data received to the amount of data sent: iperf.exe -c 10.20.16.90 -u -P 10 -B 10.20.16.51 -b 1000000000 -p 12400 -l 1000
edit: doing iperf to iperf the performance is closer to 180k or so without dropping (8mb client side buffer). If I am doing tcp I can do about 200k packets/second. Here's what interesting though - I can do far more than 200k with multiple tcp connections, but multiple udp connections do not increase the total (I test udp performance with multiple iperfs, since a single iperf with multiple threads doesn't seem to work). All hardware acceleration is tuned on in the drivers.. It seems like udp performance is simply subpar?
I've been doing some UDP testing with similar hardware as I investigate the performance gains that can be had from using the Winsock Registered I/O network extensions, RIO, in Windows 8 Server. For this I've been running tests on Windows Server 2008 R2 and on Windows Server 8.
I've yet to get to the point where I've begun testing with our 10Gb cards (they've only just arrived) but the results of my earlier tests and the example programs used to run them can be found here on my blog.
One thing that I might suggest is that with a simple test like the one you show where there's very little work being done to each datagram you may find that old fashioned, synchronous I/O, is faster than the IOCP design. Whilst the IOCP design steps ahead as the
workload per datagram rises and you can fully utilise the multiple threads.
Also, are your test machines wired back to back (i.e. without a switch) or do they run through a switch; if so, could the issue be down to the performance of your switch rather than your test machines? If you're using a switch, or have multiple nics in the server, can you run multiple clients against the server, could the issue be on the client rather than the server?
What CPU usage are you seeing on the sending and receiving machines? Have you looked at the machine's cpu usage with Process Explorer? This is more accurate than Task Manager. Which CPU is handling the nic interrupts, can you improve things by binding these to another cpu? or changing the affinity of your test program to run on another cpu? Is your IOCP example spreading its threads across multiple NUMA nodes or are you locking all of them to one node?
I'm hoping to get to run some more tests next week and will update my answer when I have done so.
Edit: For me the problem was due to the fact that the NIC drivers had "flow control" enabled and this caused the sender to run at the speed of the receiver. This had some undesirable "non-paged pool" usage characteristics and turning off flow control allows you to see how fast the sender can go (and the difference in network utilisation between the sender and receiver clearly shows how much data is being lost). See my blog posting here for more details.
I have made the following win32 socket program to browse web pages. I am using wingw to avoid dependency on any runtime. To get ipaddresses I ping urls such as www.google.com, www.yahoo.com through command prompt and use those ip addreses in my program. Port is ofcourse 80.
I am able to get default pages of google, yahoo etc by using "GET /\r\n". I am also able to get non-default pages, even those inside directories, such as http://yasini.com/newsite/index.aspx by using "GET /newsite/index.aspx". The output of the program is in the form of html received from webserver, saved on hard disk. This file is later opened in firefox to see how did the communication go.
I have made a test webpage, http://a.domaindlx.com/trysite/hello.asp, which I can open in firefox. Then I ping the domain, a.domaindlx.com and get this ipaddress, 66.36.238.30. I try to access the said page by using "GET /trysite/hello.asp" but get this in response, "No web site is configured at this address. No web site is configured at this address."
I know that the said response is sent by the webserver, so I was able to connect to the webserver. The problem is that the webserver is not recognizing the url I am trying to access. I have used different webpages, both htm and asp and none is accessible.
When trying to open website using ipaddress directly in browser, I get the same error, "No website is configured...".
The basic puzzle is, why are these pages accessible through a browser such as firefox, but not through my code, when my code is essentially a browser, mean open connection with webserver at port 80.
#include windows.h
#include stdio.h
WSADATA ws;
int d;
char aa[1000];
struct sockaddr_in a;
SOCKET s;
int li;
void abc(char *p)
{
FILE *fp = fopen("c:\\data.htm", "a+");
fprintf(fp, "%s\n", p);
fclose(fp);
}
_stdcall WinMain (HINSTANCE i, HINSTANCE j, char * k, int l)
{
d = WSAStartup(0x101, &ws);
sprintf(aa, "WSASTARTUP = %d", d);
abc(aa);
s = socket(AF_INET, SOCK_STREAM, 0);
sprintf(aa, "SOCKET = %d", s);
abc(aa);
a.sin_family = AF_INET;
a.sin_port = htons(80);
//a.sin_addr.s_addr = inet_addr("74.125.236.145");
a.sin_addr.s_addr = inet_addr("66.36.238.30"); //a.domaindlx.com
//a.sin_addr.s_addr = inet_addr("206.225.85.18"); //www.domaindlx.com
//a.sin_addr.s_addr = inet_addr("87.248.122.122"); //www.yahoo.com
//a.sin_addr.s_addr = inet_addr("72.167.153.9"); //www.yasini.com
d = connect(s, (struct sockaddr *) &a, sizeof(a));
strcpy(aa, "GET /trysite/hello.asp\r\n");
strcat(aa, "HTTP 1.0 \r\n\r\n");
send(s, aa, sizeof(aa), 0);
li = 1;
while(li != 0)
{
li = recv(s, aa, 1000, 0);
abc(aa);
}
}
Note: Please enclose the header file names in the include line in angle brackets for the code to work. I had to remove that to property format the html.
The troublesome URL is running on a subdomain. The successful URLs are not. Many webservers host multiple accounts on the same physical IP(s), so they need to know which particular domain/subdomain is being requested in order to access the correct account. You need to include a Host header in your request.
Also note that when you call send() to send the request, you are sending the entire 1000 bytes of the aa buffer, which is wrong. You need to send only what you actualy filled in.
Lastly, you are not really managing the socket very well in general. You need better error handling.
Try this:
#include <windows.h>
#include <stdio.h>
void abc(char *p, int l = -1)
{
FILE *fp = fopen("c:\\data.htm", "a+");
if (fp)
{
if (l == -1) l = strlen(p);
fwrite(p, 1, l, fp);
fclose(fp);
}
}
int WINAPI WinMain (HINSTANCE i, HINSTANCE j, char * k, int l)
{
char aa[1000];
WSADATA ws;
int d = WSAStartup(0x101, &ws);
sprintf(aa, "WSASTARTUP = %d\n", d);
abc(aa);
if (d == 0)
{
SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
sprintf(aa, "SOCKET = %d\n", s);
abc(aa);
if (s != INVALID_SOCKET)
{
char *host = "a.domaindlx.com";
char *file = "/trysite/hello.asp";
struct sockaddr_in a;
memset(&a, 0, sizeof(a));
a.sin_family = AF_INET;
a.sin_port = htons(80);
struct hostent *h = gethostbyname(host);
if (!h)
{
sprintf(aa, "gethostbyname(\"%s\") FAILED\n", host);
abc(aa);
}
else
{
sprintf(aa, "gethostbyname(\"%s\") TYPE = %d\n", host, h->h_addrtype);
abc(aa);
if (h->h_addrtype == AF_INET)
{
a.sin_addr = * (struct in_addr*) h->h_addr;
sprintf(aa, "gethostbyname(\"%s\") IP = %s\n", host, inet_ntoa(a.sin_addr));
abc(aa);
d = connect(s, (struct sockaddr *) &a, sizeof(a));
sprintf(aa, "CONNECT = %d\n", d);
abc(aa);
if (d == 0)
{
sprintf(aa,
"GET %s HTTP/1.0\r\n"
"Host: %s\r\n"
"Connection: close\r\n"
"\r\n",
file, host);
char *p = aa;
int t = strlen(aa);
int li;
do
{
li = send(s, p, t, 0);
if (li < 1)
break;
p += li;
t -= li;
}
while (t > 0);
if (t != 0)
{
abc("SEND FAILED\n");
}
else
{
abc("SEND OK\n");
do
{
li = recv(s, aa, sizeof(aa), 0);
if (li < 1)
break;
abc(aa, li);
}
while (true);
}
}
}
}
closesocket(s);
}
WSACleanup();
}
return 0;
}
I strongly suggest you get a packet sniffer, such as Wireshark. Then you can see EXACTLY what webbrowsers (or any other socket app) is actually sending and receiving. Then you can match that in your code as needed.
There are two problems with your code. The first one is that there should be a space not \r\n before HTTP 1.0. Without this your are sending HTTP 0.9.
The second problem is that some IP addresses are used to host multiple sites and require sending a Host header.
The site that tells you "No web site is configured at this address" may work better if you add the Host: header. Your request to that site should look like this:
"GET /trysite/hello.asp HTTP 1.0\r\nHost: a.domaindlx.com\r\n\r\n"
You're not following the protocol correctly. You want GET /trysite/hello.asp HTTP/1.0\r\n\r\n See here for the full spec.