TCP KeepAlive machanism doesn't work on MacOS - macos

I have a http client on mac to upload a file to server,
using the chromium net stack which enable tcp socket keepalive default with timeout 45 seconds,
but when I switch the Wifi to 4G during the normal upload stage, capturing tcp packet using tcpdump,
there is no keepalive packets show up.
I want to know why that happened, and how to make it effective
tcp client code on macos:
#include <iostream>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
using namespace std;
int main(int args, char** argv){
int fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(fd<0) return 0;
cout << "tcp fd created: " << fd << endl;
int on = 1;
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on))) {
cout << "Failed to set SO_KEEPALIVE on fd: " << fd;
return 0;
}
int delay = 10;
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay))) {
cout << "Failed to set TCP_KEEPALIVE on fd: " << fd;
return 0;
}
struct sockaddr_in peer_addr_;
auto server = gethostbyname(argv[1]);
bzero((char*)&peer_addr_, sizeof(struct sockaddr_in));
peer_addr_.sin_family = AF_INET;
peer_addr_.sin_port = htons(7777);
bcopy((char*)server->h_addr, (char*)&peer_addr_.sin_addr.s_addr, server->h_length);
int rv = connect(fd, (struct sockaddr*)&peer_addr_, sizeof(struct sockaddr));
if(rv < 0) return 0;
while(true){
cout << "client online ..." << endl;
sleep(3);
}
return 0;
}

Related

TCP buffer parameters not being honoured on Win7 machine

Note: I have tagged this with both programming and windows networking tags, so please don't shout, I'm just trying to expose this to as many people as may be able to help!
I am trying to set the receive and send buffers for a small client and server I have written, so that when I perform a network capture, I see the window size I have set in the TCP handshake.
For the programmers, please consider the following very simple code for a client and server.
For the none-programmers, please skip past this section to my image.
Client:
#include <WinSock2.h>
#include <mstcpip.h>
#include <Ws2tcpip.h>
#include <thread>
#include <iostream>
using namespace std;
int OutputWindowSize(SOCKET s, unsigned int nType)
{
int buflen = 0;
int nSize = sizeof(buflen);
if (getsockopt(s, SOL_SOCKET, nType, (char *)&buflen, &nSize) == 0)
return buflen;
return -1;
}
bool SetWindowSizeVal(SOCKET s, unsigned int nSize)
{
if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&nSize, sizeof(nSize)) == 0)
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&nSize, sizeof(nSize)) == 0)
return true;
return false;
}
int main(int argc, char** argv)
{
if (argc != 3) { cout << "not enough args!\n"; return 0; }
const char* pszHost = argv[1];
const int nPort = atoi(argv[2]);
WSADATA wsaData;
DWORD Ret = 0;
if ((Ret = WSAStartup((2, 2), &wsaData)) != 0)
{
printf("WSAStartup() failed with error %d\n", Ret);
return 1;
}
struct sockaddr_in sockaddr_IPv4;
memset(&sockaddr_IPv4, 0, sizeof(struct sockaddr_in));
sockaddr_IPv4.sin_family = AF_INET;
sockaddr_IPv4.sin_port = htons(nPort);
if (!InetPtonA(AF_INET, pszHost, &sockaddr_IPv4.sin_addr)) { return 0; }
SOCKET clientSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // Create active socket: one which is passed to connect().
if (!SetWindowSizeVal(clientSock, 12345))
{
cout << "Failed to set window size " << endl;
return -1;
}
cout << "Set window size on client socket as: RECV" << OutputWindowSize(clientSock, SO_RCVBUF) <<
" SEND: " << OutputWindowSize(clientSock, SO_SNDBUF) << endl;
int nRet = connect(clientSock, (sockaddr*)&sockaddr_IPv4, sizeof(sockaddr_in));
if (nRet != 0) { return 0; }
char buf[100] = { 0 };
nRet = recv(clientSock, buf, 100, 0);
cout << "Received " << buf << " from the server!" << endl;
nRet = send(clientSock, "Hello from the client!\n", strlen("Hello from the client!\n"), 0);
closesocket(clientSock);
return 0;
}
Server:
#include <WinSock2.h>
#include <mstcpip.h>
#include <Ws2tcpip.h>
#include <iostream>
using namespace std;
int OutputWindowSize(SOCKET s, unsigned int nType)
{
int buflen = 0;
int nSize = sizeof(buflen);
if (getsockopt(s, SOL_SOCKET, nType, (char *)&buflen, &nSize) == 0)
return buflen;
return -1;
}
bool SetWindowSizeVal(SOCKET s, unsigned int nSize)
{
if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&nSize, sizeof(nSize)) == 0)
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&nSize, sizeof(nSize)) == 0)
return true;
return false;
}
int main()
{
WSADATA wsaData;
DWORD Ret = 0;
if ((Ret = WSAStartup((2, 2), &wsaData)) != 0)
{
printf("WSAStartup() failed with error %d\n", Ret);
return 1;
}
struct sockaddr_in sockaddr_IPv4;
memset(&sockaddr_IPv4, 0, sizeof(struct sockaddr_in));
sockaddr_IPv4.sin_family = AF_INET;
sockaddr_IPv4.sin_port = htons(19982);
int y = InetPton(AF_INET, L"127.0.0.1", &sockaddr_IPv4.sin_addr);
if (y != 1) return 0;
socklen_t addrlen = sizeof(sockaddr_IPv4);
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (!SetWindowSizeVal(sock, 12345))
{
cout << "Failed to set window size " << endl;
return -1;
}
cout << "Set window size on listen socket as: RECV" << OutputWindowSize(sock, SO_RCVBUF) <<
" SEND: " << OutputWindowSize(sock, SO_SNDBUF) << endl;
if (bind(sock, (sockaddr*)&sockaddr_IPv4, sizeof(sockaddr_IPv4)) != 0) { /* error */ }
if (listen(sock, SOMAXCONN) != 0) { return 0; }
while (1)
{
SOCKET sockAccept = accept(sock, (struct sockaddr *) &sockaddr_IPv4, &addrlen);
if (!SetWindowSizeVal(sockAccept, 12345))
{
cout << "Failed to set window size " << endl;
return -1;
}
cout << "Set window size as on accepted socket as: RECV" << OutputWindowSize(sock, SO_RCVBUF) <<
" SEND: " << OutputWindowSize(sock, SO_SNDBUF) << endl;
if (sockAccept == -1) return 0;
int nRet = send(sockAccept, "Hello from the server!\n", strlen("Hello from the server!\n"), 0);
if (!nRet) return 0;
char buf[100] = { 0 };
nRet = recv(sockAccept, buf, 100, 0);
cout << "Received " << buf << " from the client!" << endl;
if (nRet == 0) { cout << "client disonnected!" << endl; }
closesocket(sockAccept);
}
return 0;
}
The output from my program states that the window sizes have been set succesfully:
Set window size on listen socket as: RECV12345 SEND: 12345
Set window size as on accepted socket as: RECV12345 SEND: 12345
for the server, and for the client:
Set window size on listen socket as: RECV12345 SEND: 12345
However, when I capture the traffic using RawCap, I see that the client window size is set fine, but server's window size is not what I set it to be, it is 8192:
Now, I have read this MS link and it says to add a registry value; I did this, adding the value 0x00001234, but it still made no difference.
The interesting thing is, the same code works fine on a Windows 10 machine, which makes me think it is Windows 7 specific. However, I'm not 100% sure on my code, there might be some errors in it.
Can anyone suggest how I can get Windows to honour my requested parameters please?
These are not 'window sizes'. They are send and receive buffer sizes.
There is no such thing as 'output window size'. There is a receive window and a congestion window, and the latter is not relevant to your question.
The send buffer size has exactly nothing to do with the receive window size, and the receive buffer size only determines the maximum receive window size.
The actual receive window size is adjusted dynamically by the protocol. It is the actual size that you are seeing in Wireshark.
The platform is entitled by the specification to adjust the supplied values for the send and receive buffers up or down, and the documentation advises you to get the corresponding values if you want to be sure what they really are.
There is no problem here to solve.
NB You don't have to set the receive window size on an accepted socket if you already set it on the listening socket. It is inherited.

How to read i2c with out i2cget command?

I am currently using Kontron smarc-samx6i board and I am running this board with Yocto kernel. Here the kernel is not supporting the command i2cget to check i2c data to read from sensor. So, is there any other possible ways to read i2c data from the sensors?
You can add "i2c-tools" to your image:
IMAGE_INSTALL_append = " i2c-tools"
They include i2cget.c.
The recipe can be found in: /meta/recipes-devtools/i2c-tools/
You might also want to look into writing your own application using the i2c dev interface. See the kernel documentation on i2c.
read:
#include <stdio.h>
#include <fcntl.h>
#include <linux/i2c-dev.h>
#include <errno.h>
#define I2C_ADDR 0x20
int main (void) {
char buffer[1];
int fd;
fd = open("/dev/i2c-0", O_RDWR);
if (fd < 0) {
printf("Error opening file: %s\n", strerror(errno));
return 1;
}
if (ioctl(fd, I2C_SLAVE, I2C_ADDR) < 0) {
printf("ioctl error: %s\n", strerror(errno));
return 1;
}
buffer[0]=0xFF;
write(fd, buffer, 1);
read(fd, buffer, 1);
printf("0x%02X\n", buffer[0]);
return 0;
}
write:
#include <stdio.h>
#include <fcntl.h>
#include <linux/i2c-dev.h>
#include <errno.h>
#define I2C_ADDR 0x20
int main (void) {
int value;
int fd;
fd = open("/dev/i2c-0", O_RDWR);
if (fd < 0) {
printf("Error opening file: %s\n", strerror(errno));
return 1;
}
if (ioctl(fd, I2C_SLAVE, I2C_ADDR) < 0) {
printf("ioctl error: %s\n", strerror(errno));
return 1;
}
for (value=0; value<=255; value++) {
if (write(fd, &value, 1) != 1) {
printf("Error writing file: %s\n", strerror(errno));
}
usleep(100000);
}
return 0;
}

ReadProcessMemory returns the same data for any address

Working on WinXP SP3.
Visual Studio 2005.
Trying to read memory of another process.
std::cout<<"Reading Process Memory\n";
const DWORD pid = 3476;
HANDLE handle = OpenProcess(PROCESS_VM_READ,FALSE,pid);
if(handle == NULL) {std::cout<<"Failed to open process\n";return 0;}
char* buffer1 = new char[256];
char* buffer2 = new char[256];
memset(buffer1,0,256*sizeof(char));
memset(buffer2,0,256*sizeof(char));
DWORD nbr = 0;
int address = 0x400000;
BOOL result = ReadProcessMemory(handle,&address,buffer1,32,&nbr);
if(result!=1) std::cout<<"Failed to read memory\n";
address = 0x400000+0x1000;
result = ReadProcessMemory(handle,&address,buffer2,32,&nbr);
if(result!=1) std::cout<<"Failed to read memory\n";
int i = 0;
while(i++<10)
{
if(buffer1[i]!=buffer2[i]) {std::cout<<"Buffers are different\n";break;}
}
delete[] buffer1;
delete[] buffer2;
CloseHandle(handle);
std::cin>>i;
return 0;
The problem is that both buffers are getting the same values. ReadProcMemory returns 1 and number of bytes read is the same as requested.
Your calls to ReadProcessMemory are incorrect. You should be using address directly, not &address. You may need to cast it to a const void *.
result = ReadProcessMemory(handle, reinterpret_cast<const void *>(address), buffer, 32, &nbr);
And you probably should declaring address as a type large enough to handle a pointer, like std::ssize_t or INT_PTR.
INT_PTR address = 0x400000;
buffer couldn't be a char, it has to be int, thats a working example
#include <windows.h>
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
int point1=0;
int i=0;
int d=0;
char* value[4];
SIZE_T stBytes = 0;
HWND hwnd;
HANDLE phandle;
DWORD pid;
hwnd = FindWindow(NULL, "calc"); // calc is the name of the windows process
if (hwnd != 0) {
GetWindowThreadProcessId(hwnd, &pid);
phandle = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
} else {
cout << "process is not executing";
cin.get();
return 0;
}
if (phandle != 0) {
for(i=0;i<4;i++) // 4 or wathever
{
cout << "The pointer is 0x1001000" << endl; //Print the pointer
ReadProcessMemory(phandle, (LPVOID)0x1001000+i, &point1, 4, &stBytes); //Get the content from 0x1001000 and store it in point1
cout << "decimal content point1 " << point1 << " (DEC)" << endl; //Print the decimal content of point1
printf("%x \n",point1); // print hexadecimal content of point1
char *p=(char*)&point1; // point point1 buffer
for(d=0;d<4;d++)
printf("%x",(unsigned int)(unsigned char) *(p+d)); // print backwards (because the buffer is like a LIFO) and see the dbg debugger
}
ReadProcessMemory(phandle, (LPVOID)point1, &value, 6, &stBytes); //Get the value that is in the address pointed by the pointer
cout << "The value in the non-static address is " << (char*)value << endl << endl; //Print the value
cout << "Press ENTER to exit." << endl;
cin.get();
} else {
cout << "Couldn't get a handle";
cin.get();
// address 0x1001000 content hex 5278DA77
}
}

SO_REUSEADDR and UDP behavior in Windows

I'm aware that using SO_REUSEADDR with UDP in a *NIX environment, behaves like a multicast, where multiple clients bound to the same port can listen and receive broadcast datagrams simultaneously. Is this the behavior on Windows as well?
Multiple UDP sockets on Windows bound to the same port will all receive broadcast packets together.
Here's a demo program you can build for windows and Linux with GCC and test with Netcat as mentioned. In both systems, only one socket (either A or B) receives each datagram when a unicast address is used as the target. If a broadcast address is used then both sockets will receive the message.
/* Tested on linux and windows 7.
* On windows use mingw-gcc:
* gcc -Wall -g -o udplisten udplisten.c -lws2_32
* Test with:
* echo hello | netcat -u machinename 9898 (unicast)
* echo hello | netcat -u 172.16.255.255 9898 (broadcast)
*/
#ifdef WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <sys/select.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define SOCKET int
#define INVALID_SOCKET -1
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#undef max
#define max(x,y) ((x) > (y) ? (x) : (y))
static void
die(const char *str)
{
perror(str);
exit(1);
}
static SOCKET
mksocket(struct sockaddr_in *addr)
{
SOCKET sock = INVALID_SOCKET;
int opt = 1;
if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
die("socket");
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt)) < 0)
die("setsockopt");
if (bind(sock, (struct sockaddr *)addr, sizeof(struct sockaddr_in)) < 0)
die("bind");
return sock;
}
static void
process(SOCKET sock, const char *label)
{
char buffer[8192];
struct sockaddr_in caddr;
socklen_t caddr_size = sizeof(caddr);
memset(&caddr, 0, caddr_size);
int count = recvfrom(sock, buffer, sizeof(buffer), 0,
(struct sockaddr *)&caddr, &caddr_size);
if (count < 0) die(label);
printf("%s %d '", label, count);
fwrite(buffer, 1, count, stdout);
printf("'\n");
}
int
main(int argc, char *argv[])
{
struct sockaddr_in addr;
SOCKET socka = INVALID_SOCKET, sockb = INVALID_SOCKET;
fd_set read_set;
#ifdef WIN32
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2,2), &wsaData))
return -1;
#endif
addr.sin_family = AF_INET;
addr.sin_port = htons(9898);
addr.sin_addr.s_addr = INADDR_ANY;
socka = mksocket(&addr);
sockb = mksocket(&addr);
for (;;) {
FD_ZERO(&read_set);
FD_SET(socka, &read_set);
FD_SET(sockb, &read_set);
if (select(max(socka,sockb)+1, &read_set, NULL, NULL, NULL) < 0)
die("select");
if (FD_ISSET(socka, &read_set))
process(socka, "A");
if (FD_ISSET(sockb, &read_set))
process(sockb, "B");
}
return 0;
}

socket "read" hanging if the MacBook sleeps more than 10 minutes

I am writing an app, where a socket is connecting to a host and downloading a file.
The application runs in Mac.
Now, while the app is downloading, if I put the MacBook in sleep mode for more than 10 minutes, 60% of the time the app hangs when the computer wakes up.
The stack trace shows that, it has hanged in the "read" call. I am able to reproduce this with a sample program also. Below, I have pasted the code of the sample program and the stack where it is hanging. How to solve this hanging?
Also, this is not just TCP/IP waiting that will come out in few minutes. I have waited for more than 12 hours, it did not come out.
The stack trace: -
Call graph:
2466 Thread_2507
2466 start
2466 read$UNIX2003
2466 read$UNIX2003
The program :-
#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <sys/socket.h>
#include <unistd.h>
#define buflen 131072
unsigned int portno = 80;
char hostname[] = "192.168.1.9";
int main()
{
int sd = socket(AF_INET, SOCK_STREAM, 0); /* init socket descriptor */
struct sockaddr_in sin;
struct hostent *host = gethostbyname(hostname);
char buf[buflen];
int len;
int ret;
FILE *fp;
int i;
if(sd == -1){
printf("Could not create client socket\n");
return 1;
}
/*set keep alive*/
int optval = 1;
int optlen = sizeof(optval);
ret = setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen);
if(ret != 0){
printf("could not set socket option.\n");
return 1;
}
/*** PLACE DATA IN sockaddr_in struct ***/
memcpy(&sin.sin_addr.s_addr, host->h_addr, host->h_length);
sin.sin_family = AF_INET;
sin.sin_port = htons(portno);
/*** CONNECT SOCKET TO THE SERVICE DESCRIBED BY sockaddr_in struct ***/
if (connect(sd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
perror("connecting");
return 1;
}
char *str = "GET /general-log.exe / HTTP/1.0\n\n";
ret = write(sd, str, strlen(str));
if(ret < 0){
printf("error while writing\n");
return 1;
}
fp = fopen("downloaded.file", "wb+");
if(fp == NULL){
printf("not able to open the file.\n");
return 1;
}
i = 0;
while ((len = read(sd, buf, buflen)) > 0) {
printf("%d\t%d\n", i++, len);
fwrite(buf, len, 1, fp); //we should check for return
}
if(len < 0){
printf("Error while reading\n");
}
fclose(fp);
close(sd);
return 0;
}
Update apparently the SO_RCVTIMEOUT is solving the problem.
struct timeval tv;
tv.tv_sec=10;
tv.tv_usec=0;
setsockopt ( m_sock, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv, sizeof ( tv ) );
Is it okay to use SO_RCVTIMEO?
TCP/IP connections don't survive sleep mode. SO_KEEPALIVE doesn't help in this case since it has no effect on the server side. Just wait two minutes and the read will time out. After the timeout, you can connect again.
And that sleep(1) is unnecessary. The server will respond as soon as the data is available. If you don't fetch is right away, you'll allocate a connection on the server for longer than you need.
I couldn't solve it using blocking sockets. I had to change the IMAP library to non-blocking sockets.

Resources