Long delay between a write and a read using UDP - c++

I have a Raspberry Pi 4 running a C++ program where it receives and sends data via UDP. The RPi is setup as a UDP server.
The code for UDP.hpp is:
#pragma once
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string>
using namespace std;
/////GLOBAL CONSTANTS/////
const int c_PORT = 8080;
class UDP
{
private:
int fdSocketUDP_; //File descriptor for UDP socket
int ClientAddressLength_; //Length of client address
struct sockaddr_in ServerAddress_; //Struct handling internet address for server
struct sockaddr_in ClientAddress_; //Struct handling internet address for client
public:
UDP(); //Initialize and bind socket
~UDP(); //Close socket
string readUDP(const int readSize); //Read via UDP protocol
void writeUDP(string message); //Write via UDP protocol
};
The code for UDP.cpp is:
#include "udp.hpp"
UDP::UDP()
{
if ((fdSocketUDP_ = socket(AF_INET, SOCK_DGRAM, 0)) < 0) //Create UDP socket
{
perror("Error - socket creation - udp.cpp");
exit(EXIT_FAILURE);
}
memset(&ServerAddress_, 0, sizeof(ServerAddress_)); //Sets ServerAddress_ to 0
memset(&ClientAddress_, 0, sizeof(ClientAddress_)); //Sets ClientAddress_ to 0
ServerAddress_.sin_family = AF_INET; //Address family, must be AF_INET = IPv4
ServerAddress_.sin_port = htons(c_PORT); //PORT number, convert PORT number to network byte order using htons()
ServerAddress_.sin_addr.s_addr = INADDR_ANY; //IP-Address of host (server IP), INADDR_ANY gets this IP Address
if (bind(fdSocketUDP_, (const struct sockaddr *)&ServerAddress_, sizeof(ServerAddress_)) < 0) //Bind the socket to ServerAddress_
{
perror("Error - socket bind - udp.cpp");
exit(EXIT_FAILURE);
}
}
UDP::~UDP()
{
close(fdSocketUDP_); //Close socket
}
string UDP::readUDP(const int readSize)
{
char readMsg[readSize] = {0}; //Read buffer
ClientAddressLength_ = sizeof(ClientAddress_);
if ((recvfrom(fdSocketUDP_, readMsg, readSize, 0, (struct sockaddr *)&ClientAddress_, (socklen_t *)&ClientAddressLength_)) < 0) //Receive data via UDP protocol
{
perror("Error - recvfrom - udp.cpp");
exit(EXIT_FAILURE);
}
string str(readMsg); //Convert char array to string
str = str.substr(0, readSize); //Make sure the string is the length of readsize
return str;
}
void UDP::writeUDP(string message)
{
//Make char array
int writeSize = message.size();
char writeMsg[writeSize + 1] = {'\0'};
//Convert string message to char array
for (int i = 0; i < writeSize; i++)
{
writeMsg[i] = message[i];
}
if ((sendto(fdSocketUDP_, writeMsg, writeSize, 0, (const struct sockaddr *)&ClientAddress_, (socklen_t)ClientAddressLength_)) < 0) //Send data via UDP protocol
{
perror("Error - sendto - udp.cpp");
exit(EXIT_FAILURE);
}
}
I then have a windows 10 laptop, running a Labview program that also receives and sends data via UDP. The laptop is setup as a UDP client. Below are som examples of the UDP setup in Labview.
Image 1 (Open UDP connection):
Image 2 (Close UDP connection):
Image 3 (Write and read UDP in Labview):
Above, the Labview program on the laptop sends 3 ("103") + 37 (not shown) bytes of data to the RPi, and then receives 16 bytes of data from the RPi.
The laptop and RPi are connected via a LAN-cable on a local network. The RPi uses IP-address 10.10.10.10 and port 8080, and the laptop uses IP-address 10.10.10.1 and port 1000.
Below are a Wireshark measurement, that measures the time between the different send and receive commands between the RPi and laptop.
Image 4 (wireshark measurement):
The "Len=3" is used by the RPi to determine what function to run in the C++ code. The "Len=52" and "Len=37" is data sent from the laptop (Labview) to the RPi (C++ code). The "Len=16" is data sent from the RPi to the laptop.
The laptop first sends 3+52 bytes of data to the RPi (client sends data to server). The laptop then sends 3+37 bytes of data to the RPi (client sends data to server). The RPi then sends 16 bytes of data back to the laptop (server sends data to client)... and so on.
One command (3+52 bytes or 3+37+16 bytes) takes about ~8ms to finish, with ~2ms latency (on average) between each command. As you can see, the data sizes between the RPi and laptop are "relatively" small (3/37/52 bytes).
Now my problem: Sometimes there is a delay of ~20ms between the commands (10 times longer than the average of ~2ms), and I don't know why... (this is shown with the red dots on image 4). This delay often comes after the RPi (UDP server) sends data to the laptop (UDP client - the 16 bytes of data), but it can happen at different places, as shown on image 4 (after the laptop sends 52 bytes to the RPi). I think it has something to do with the UDP, maybe the setup, maybe it has something to do with ARP, but I don't know. I have tried overclocking the RPi, tweaking the priority of the C++ program on the RPi, tweaking the C++ code, but that doesn't seem to be the bottleneck.
It's like the UDP connection between the laptop and RPi is "lost" or "paused" sometimes and it then takes some time for the connection to come back on track.

I found a solution to my problem. To solve the long delay, i had to lower the UDP read buffer, since i'm only sending small packages via UDP.
To do this, i formatted the sysctl.conf file on the RPi, located in the /etc folder.
I added the lines:
net.core.rmem_default = 4096
net.core.rmem_max = 4096

Related

How to receive a UDP broadcast sent to 255.255.255.255 using boost asio?

I have written a device discovery program that can run in client or server mode. In client mode it sends a UDP broadcast packet to 255.255.255.255 on port 30000 and then listens for responses on port 30001. In server mode it listens for a UDP broadcast on port 30000 and sends a UDP broadcast packet to 255.255.255.255 on port 30001 in response.
When I run this program on 2 devices with IP addresses 192.168.10.61 and 192.168.10.62 it all works perfectly. The whole point of this program is to allow devices with unknown IP addresses to discover one another so long as they are connected to the same physical network. So to test that, I changed the IP address of the first device to something random like 12.34.56.42/255.255.240. And now it stops working.
Using tcpdump on the 192.168.10.62 machine I can see that the UDP packet from the 12.134.56.42 machine was received:
# tcpdump -i eth0 port 30000 -c 1 -v
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
17:38:02.552427 IP (tos 0x0, ttl 64, id 18835, offset 0, flags [DF], proto UDP (17), length 49)
12.34.56.42.56815 > 255.255.255.255.30000: UDP, length 21
1 packet captured
6 packets received by filter
0 packets dropped by kernel
but my discovery program no longer receives it. This is the code I am using to receive the UDP broadcast packets:
int WaitForPacket(uint16_t portNum, vector<char>& udpBuf, udp::endpoint& remoteEndpoint, const chrono::milliseconds timeout)
{
io_service ioService;
udp::socket socket(ioService, udp::endpoint(boost::asio::ip::address_v4::any(), portNum));
socket.set_option(socket_base::broadcast(true));
boost::system::error_code error;
int numBytes = receive_from(socket, buffer(udpBuf), remoteEndpoint, error, timeout);
if (error && error != error::message_size && error != error::timed_out)
{
printf("Got error: %s\n", error.message().c_str());
return -1;
}
return numBytes;
}
/*
* The boost asio library does not provide a blocking read with timeout function so we have to roll our own.
*/
int receive_from(
boost::asio::ip::udp::socket& socket,
const boost::asio::mutable_buffers_1& buf,
boost::asio::ip::udp::endpoint& remoteEndpoint,
boost::system::error_code& error,
chrono::milliseconds timeout)
{
volatile bool ioDone = false;
int numBytesReceived = 0;
boost::asio::io_service& ioService = socket.get_io_service();
socket.async_receive_from(buf, remoteEndpoint,
[&error, &ioDone, &numBytesReceived](const boost::system::error_code& errorAsync, size_t bytesReceived)
{
ioDone = true;
error = errorAsync;
numBytesReceived = bytesReceived;
});
this_thread::sleep_for(chrono::milliseconds(100));
ioService.reset();
ioService.poll_one();
auto endTime = chrono::system_clock::now() + timeout;
while (!ioDone)
{
ioService.reset();
this_thread::sleep_for(chrono::milliseconds(100));
auto now = chrono::system_clock::now();
if (now > endTime)
{
socket.cancel();
error = error::timed_out;
return 0;
}
ioService.poll_one();
}
ioService.reset();
return numBytesReceived;
}
I checked similar questions on Stack Overflow and found some that said the receiving socket has to be bound to INADDR_ANY in order to receive broadcast packets. I was originally creating the socket like this udp::socket socket(ioService, udp::endpoint(udp::v4(), portNum)); but have now changed it to use ip::address_v4::any() instead. That didn't make any difference.
Can anybody tell me what I need to change in order to receive the UDP broadcast packet as expected ?
I am running this on iMX6 devices running Linux and am compiling using boost 1.58.
I finally discovered why my code was never seeing the broadcast packets even though tcpdump proved that they were being received. After finding this StackOverflow question:
Disable reverse path filtering from Linux kernel space
it seems that I just needed to disable Reverse Path Filtering on both hosts like this:
echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter
echo 0 > /proc/sys/net/ipv4/conf/eth0/rp_filter
and then my code worked perfectly with no modifications. Hopefully this will help other people wondering why they can't get UDP broadcasts to the network broadcast address (255.255.255.255) to work.

Bluetooth can receive data but cannot transmit it (socket programming in C++ to communicate Matlab)

I am using Raspberry Pi 3's internal bluetooth and I am writing a c++ code to connect the bluetooth of my windows PC. On the PC side, I use Matlab and I am able to send bytes to raspberry. However when I try to send bytes from raspberry to PC, I get the following error:
"Transport endpoint is not connected"
and Matlab says "Unsuccessful read: the specified amount of data was not returned within the timeout period".
Another interesting thing is that, when I try to send more than three bytes from Matlab, raspberry only receives the first three as if the rest did not exist. If I use two reads in a row, I am able to get 6 bytes and so on. Just pointing this odd fact since I thought it might be connected with my main problem and be a clue.
I have also tried to send a file manually, using the bluetooth symbol on menubar and it worked. So c++ code should be doing something different to cause this problem.
What is likely to be the cause of my problem? How can I send data from raspberry to my computer using c++?
My code is as follows:
(Referred website: http://people.csail.mit.edu/albert/bluez-intro/index.html)
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>
int main(int argc, char **argv)
{
struct sockaddr_rc loc_addr = { 0 }, rem_addr = { 0 };
char buf[1024] = { 0 };
int s, client, bytes_read;
socklen_t opt = sizeof(rem_addr);
// allocate socket
s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
bdaddr_t tempBDADDR = {0};
// bind socket to port 1 of the first available
// local bluetooth adapter
loc_addr.rc_family = AF_BLUETOOTH;
loc_addr.rc_bdaddr = tempBDADDR;
loc_addr.rc_channel = (uint8_t) 1;
bind(s, (struct sockaddr *)&loc_addr, sizeof(loc_addr));
// put socket into listening mode
listen(s, 1);
// accept one connection
client = accept(s, (struct sockaddr *)&rem_addr, &opt);
ba2str( &rem_addr.rc_bdaddr, buf );
fprintf(stderr, "accepted connection from %s\n", buf);
memset(buf, 0, sizeof(buf));
// read data from the client
bytes_read = read(client, buf, sizeof(buf));
if( bytes_read > 0 ) {
printf("received [%s]\n", buf);
}
int status = 0;
// send a message
if( status == 0 ) {
status = write(s, "hello!", 6);
}
if( status < 0 ) perror("uh oh");
// close connection
close(client);
close(s);
return 0;
}
Matlab side is as straight forward as:
b = Bluetooth('raspberrypi', 1);
fopen(b);
fwrite(b, uint('1234'));
input = fread(b,6)
fclose(b);
clear('b');
EDIT:
Just figured that I do not get the "Transport endpoint is not connected" when I use the following line. However this only allows me to connect as client, whereas matlab only has a client type of connection. So now, I am able to send data to my computer from another socket without getting any errors, but cannot read it with matlab.
status = connect(s, (struct sockaddr *)&addr, sizeof(addr));
Just figured it out. Leaving this here in case it helps someone else as well.
When a connection is accepted, a new descriptor is returned (along with a new socket). This is a significant difference from connect(). So I was wrong at the following line.
status = write(s, "hello!", 6);
changing it to
status = write(client, "hello!", 6);
worked like a charm.
(Reference: http://users.pja.edu.pl/~jms/qnx/help/tcpip_4.25_en/prog_guide/sock_advanced_tut.html)

Simple FTP Client C++

I'm attempting to create a simple FTP client in C/C++ that will do simple operations (connect, retrieve file). What I have working so far is the connection and login. I connect using sockets onto port 21, like any regular FTP client. The trouble I'm having is connecting to the port that is specified when the command PASV is entered. I get the message, parse it, then calculate the port from the replay message when PASV is entered.
227 Entering Passive Mode (a1, a2, a3, a4, p1, p2)
DataPort = (p1 * 256) + p2
Once I have the port, I try to create another socket and connecting to it the same way. That's where my issues are. My code so far is posted below. I don't know if I need to get the server address again the same way. I'm not getting a response back from the server (if I'm actually suppose to get one, I don't know) Please ask any questions or concerns, thanks.
const int FTP_PORT = 21; // Server Port
const int SIZE = 1024; // Size of Buffers
char receiveBuff[SIZE]; // Buffer to send to the server
char sendBuff[SIZE]; // Buffer to receive from server
char pasvBuff[] = "pasv"; // Buffer to see if PASV Command was entered
char quitBuff[] = "QUIT"; // Buffer to see if QUIT Command was entered
char pasvMessage[100]; // String for PASV information
int main(int argc, char *argv[])
{
int length = 0, i=0;
int a1, a2, a3, a4, p1, p2, dataPort; //PASV Information
/* Get Server Name from User */
if (argc != 2)
{
cerr << "Usage: " << argv[0] << " server" << endl;
return 1;
}
/* Obtain Host (Server) Info */
struct hostent *host;
host = gethostbyname(argv[1]);
if (host == (struct hostent *)NULL)
{
perror("Client: gethostbyname");
return 2;
}
/* Add Server Information */
struct sockaddr_in servAdr; // Internet address of server
memset(&servAdr, 0, sizeof(servAdr)); // Clear structure
servAdr.sin_family = AF_INET; // Set address typedef
memcpy(&servAdr.sin_addr, host->h_addr, host->h_length);
servAdr.sin_port = htons(FTP_PORT); // Use FTP port
/* Create Socket to Connect to FTP Server */
int origSock; // Original socket in client
if ((origSock = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Client: generate error");
return 3;
}
/* Connect to FTP Server on Port 21 */
if (connect(origSock, (struct sockaddr *)&servAdr, sizeof(servAdr)) < 0)
{
perror("Client: connect error");
return 4;
}
/* Get Conenct Message and Print to Screen */
read(origSock, receiveBuff, sizeof(receiveBuff) - 1);
write(fileno(stdout), receiveBuff, sizeof(receiveBuff) - 1);
do
{
/* Clear Buffers */
memset(receiveBuff, 0, SIZE);
memset(sendBuff, 0, SIZE);
write(fileno(stdout), "Please enter a FTP Command: ", 28); // Write User Interface
read(fileno(stdin), sendBuff, SIZE); // Read Command from User
send(origSock, sendBuff, strlen(sendBuff) , 0); // Send Command to Server
read(origSock, receiveBuff, sizeof(receiveBuff) - 1); // Read Response from Server
write(fileno(stdout), receiveBuff, sizeof(receiveBuff) - 1); // Print Response from Server to screen
/* If PASV Command was Entered */
if (strncmp(sendBuff, pasvBuff, 4) == 0)
{
sscanf(receiveBuff, "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)", &a1,&a2,&a3,&a4,&p1,&p2);
dataPort = (p1 * 256) + p2;
struct sockaddr_in servAdr2; // Internet address of server
memset(&servAdr2, 0, sizeof(servAdr2)); // Clear structure
servAdr2.sin_family = AF_INET; // Set address typedef
memcpy(&servAdr2.sin_addr, host->h_addr, host->h_length);
servAdr.sin_port = htons(dataPort); // Use FTP port
/* Create Socket to Connect to FTP Server */
int dataSock; // Data socket in client
if ((dataSock = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Client: generate error");
return 3;
}
/* Connect to FTP Server on Data Port */
if (connect(dataSock, (struct sockaddr *)&servAdr, sizeof(servAdr)) < 0)
{
perror("Client: connect error");
return 4;
}
read(dataSock, receiveBuff, sizeof(receiveBuff) - 1);
write(fileno(stdout), receiveBuff, sizeof(receiveBuff) - 1);
}
} while (strncmp(sendBuff, quitBuff, 4) != 0); // Go until QUIT Command is entered
close(origSock);
return 0;
}
When you are parsing the PASV reply, you are populating the servAdr2 variable, except for its sin_port field. You are assigning the reported port to the servAdr.sin_port field instead. You are then connecting the data socket using servAdr instead of servAdr2. So, you are effectively connecting the data socket to the original IP address of the server on the reported port, instead of connecting to the reported IP address (which can be different than the server IP). a1-a4 are the IPv4 octets of the IP address you should be connecting to.
That said, if the server supports the EPSV command, you really should use that instead. It is much easier to parse then PASV, as PASV does not have a standardized format (so be prepared to parse multiple vendor-specific formats). EPSV solves that problem by standardizing the format in a machine-parsable manner.
As for why you are not getting any response, it is because you are not telling the server to send any files over the open data connection. Sending PASV merely opens the server's data port. After you connect to it, you then have to send a STOR or RETR command on the control socket to actually perform a file transfer over the data socket. You also have to read the server's final response on the control socket after the transfer is finished, before you can then send any new commands.
This is a C++ sockets library I wrote that does that has a FTP client (connect, retrieve list and files). The comments in the code explain
https://github.com/pedro-vicente/lib_netsockets
Basically:
FTP uses two TCP connections to transfer files : a control connection and a data connection
connect a socket(control socket) to a ftp server on the port 21
receive on the socket a message from the ftp server(code : 220)
send login to the ftp server using the command USER and wait for confirmation
(331)
send password using the command PASS and wait for confirmation that you are logged on the server (230)
receive file:
use the passive mode: send command PASV
receive answer with an IP address and a port (227), parse this message.
connect a second socket(a data socket) with the given configuration
use the command RETR on the control socket
receive data through the data socket, close data socket.
leave session using on the control socket the command QUIT.

HTTP server using BSD sockets not closing connection or communicating with Windows browser

I'm attempting to use a simple HTTP server written in C that makes use of UNIX BSD sockets. I've got it working somewhat but am having the following issues.
The server only prints "hello world!" on Linux browsers and not on windows browsers; i.e., I can make use of Chrome / Firefox on Linux and see the text in the browser, but not on a Windows machine in the same browsers.
Rather then sending "hello world" with all of the response headers and closing the connection like a normal web page, what I'm seeing is that when I test the server page (localhost:xxxx) I am presented with the text and HTTP responses in the code but the page is in a continuous load (tab keeps spinning). Then the moment I turn the server off the page returns "failed to connect to server".
My question is, given the below code, why does this not display out to browsers on Windows and why does it not close the connection whilst leaving the client with the information sent?
This uses simple BSD sockets.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> //definitions for system variables
#include <sys/socket.h> //definitions / structures for sockets
#include <netinet/in.h> //const's and structures used by internet domain
void error(const char *msg) //takes litteral msg passed in and prints, then exits.
{
perror(msg); //man perror
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, // socket file descriptor 1. both return values from system
newsockfd, // socket file descriptor 2
portno; // port number to associate with this socket
socklen_t clilen; //stored address size of each client
char buffer[256]; //stores chars from socket buffer
struct sockaddr_in serv_addr, cli_addr;
/*sockaddr_in, structure containing an internet address. most of the magic DEFINED BELOW
struct sockaddr_in
{
short sin_family; /* must be AF_INET
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8]; /* Not used, must be zero
};
*/
int n; //stores return values of read() / write() system calls)
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
} //self explanitory
/*socket() creates a new socket and takes 3 arguments, the first being the address domain of the socket
* Sockets in this case can use two types of domains which are both system constants
* AF_UNIX - Used for parent child prc's on the same machine
* AF_INET - Used for host to host communication, Ie internet communication
*
* The second option SOCKET_STREAM is the type of stream/communication used in the socket. ie TCP/UDP, Being
* SOCK_STREAM - TCP - A continuous stream/connection during the life span of the sockets communication
* SOCK_DGRAM - UDP - A connectionless strea/connection which uses less resources/is faster but possible byte loss
*
* The third option is the protocol used, due to specifying the type of stream this is almost always left to 0
* Leaving the arg at 0 implies that the operating system will make the best call and due to setting the stream it will
* more then likely choose to use the requested method
*
* This socket() in general returns a value for the subsequent descriptor for reference. If on failure, the socket()
* will return -1 and fail hence if(sockfd<0){}
*
* man socket() for information Andrew,
*/
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
/*bzero() sets all values in buffer to 0(00000000)*/
bzero(
(char *) &serv_addr,
sizeof(serv_addr)
); //Deref &serv_addr, and ensures to 0 out all bytes in buffer(entire struct)
portno = atoi(argv[1]);//port number to be used for communication,
serv_addr.sin_family = AF_INET; //set to internet. sin_family is stored in sockadr_in structure
serv_addr.sin_addr.s_addr = INADDR_ANY; //structure in structure. s_addr holds the host address. IN_ADDR is always the systems ip
serv_addr.sin_port = htons(portno); //convert to network byte order. Holds th eport number, places into readable format
/*
* checks and binds to new file descripter, socketaddr(deref) and allocates the size of the address bound to.
* If less then zero. it will fail(-1)
*/
if (bind(sockfd,
(struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5); // listens on bound socket/descriptor and allows up to 5 connections to be waiting in queue(max allowed on system
clilen = sizeof(cli_addr); // assigns value based on size of bytes in clients address
newsockfd = accept(sockfd, // new descripter to use when accepting a client
(struct sockaddr *) &cli_addr, //gathers client connection information for arg(deref)
&clilen); // Passes in clilen, for lenght of client address. not a copy, the real shiz
if (newsockfd < 0)
error("ERROR on accept"); // again, don't be a fucking dick.
bzero(buffer,256); // ensure buffer is not tampered at this point or gross
n = read(newsockfd,buffer,255); // use sys-call read() to store data in buffer from client. use 255bytes or client input
// which ever is less.
if (n < 0) error("ERROR reading from socket"); // if failed as fuck, let's cry
n = write(newsockfd,"HTTP/1.0 200 OK\n",16); // Write back to client. to bound socket from client. they see this shit.
n = write(newsockfd,"Connection: Keep-alive\n",23);
n = write(newsockfd,"Connection: close\n",18);
n = write(newsockfd,"Content-type: text/html; charset=UTF-8\n",39);
n = write(newsockfd,"\n",1);
n = write(newsockfd,"<!DOCTYPE HTML>\n<html><head><title>Hello World!</title></head>\n",62);
n = write(newsockfd,"<body><h1>Hello World!</h1>\n",28);
n = write(newsockfd,"</body></html>\n",15);
if (n < 0) error("ERROR writing to socket"); // duh
// cleaning up...
//close(newsockfd);
// close(sockfd);
getchar();
return 0;
}
There are lots of things wrong with your code. The main problem you probably have is that you are not telling the client when the end of the response body is reached, so that the client does not know that the body is done and thus will try to read more data forever and not display what it already has. The usual ways are specifying a Content-Length, using chunked transfer encoding (HTTP/1.1+ only), or closing the socket after the body is done. See RFC 2616 Section 4.4 "Message Length" for specific details.
Apart from that (some of the things are already pointed out by EJP in the comments):
wrong line endings, e.g. LF instead of CR LF
conflicting information in the Connection header
you don't properly read the request, but just assume it will be in the first packet and no longer than 255 byte
no proper error checking: write() is not guaranteed to write the whole buffer
I obtained the response codes based on website requests through inspect header information
Please don't do an implementation by only looking at a few samples of traffic without even understanding them properly. There are already enough broken HTTP servers out there and enough clients which work around these servers and all this is causing lots of trouble. Usually these servers are also only tested against a few selected clients and then the trouble starts once this kind of servers are rolled out and then surprisingly break with other clients. Please read the actual HTTP specification and write your server to conform to it.

Mac/iOS cannot receive UDP broadcast packet, but can send UDP broadcast packet

I am working on a cross-platform game using C/C++ and socket. I am using UDP broadcast (e.g. send to xx.xx.xx.255 if on a C-type LAN address) for discovering of nearby players in LAN game playing.
The issue is the Mac/iOS version can not receive broadcast UDP packet that sent by others (neither from Mac/iOS , nor from windows), while windows version is able the receive broadcast packet from Mac/iOS. Thus Mac/iOS can not discover any nearby players while windows can discover all nearby players. On the same socket handle, sending/receiving normal UDP packet works on all platforms (sent to a specific address instead of the broadcast address).
Every testing device has only one NIC, which is connected to a single WIFI router. Addresses are dynamically allocated by DHCP on the WIFI router. The socket is bind to exact local address instead of 0.0.0.0, and I am using port 19190. [ Thanks for reading my question :) ]
Following is the code for initializing the socket on all platforms. I do set the SO_BROADCAST flag on Mac/iOS otherwise UDP broadcast packet won't be sent successfully.
BOOL Socket::__Create(const struct sockaddr &BindTo, int addr_len, int nSocketType, BOOL reuse_addr, int AF)
{
ASSERT(m_hSocket == INVALID_SOCKET);
m_hSocket = socket(AF, nSocketType, 0);
if(INVALID_SOCKET != m_hSocket)
{
int on = 1;
if(SOCK_STREAM == nSocketType)
{ linger l = {1,0};
VERIFY(0==::setsockopt(m_hSocket,SOL_SOCKET,SO_LINGER,(char*)&l,sizeof(linger)));
#if defined(PLATFORM_MAC) || defined(PLATFORM_IOS)
VERIFY(0==::setsockopt(m_hSocket,SOL_SOCKET,SO_NOSIGPIPE,(void *)&on, sizeof(on)));
#endif
}
#if defined(PLATFORM_MAC) || defined(PLATFORM_IOS)
else if(SOCK_DGRAM == nSocketType)
{
VERIFY(0==::setsockopt(m_hSocket,SOL_SOCKET,SO_BROADCAST,(void *)&on, sizeof(on)));
}
#endif
if(reuse_addr)
{ VERIFY(0==setsockopt(m_hSocket,SOL_SOCKET,SO_REUSEADDR,(char*)&on,sizeof(on)));
}
if(0==bind(m_hSocket,&BindTo,addr_len))
{
return TRUE;
}
}
_LOG_WARNING("Socket Error = "<<GetLastError());
Close();
return FALSE;
}
Here is the receiving code:
BOOL Socket::__RecvFrom(LPVOID pData, UINT len, UINT& len_out, struct sockaddr &target, int addr_len, BOOL Peek)
{
SOCKET_SIZE_T la = addr_len;
int l = (int)recvfrom(m_hSocket,(char*)pData,len,Peek?MSG_PEEK:0,&target,&la);
if(l==SOCKET_ERROR)return FALSE;
len_out = l;
return la == addr_len;
}
Did you try to bind the socket to the broadcast address (the one you are sending to) ? – ElderBug
Also, it's not working when you bind to 0.0.0.0 ? – ElderBug