Retrieving the protocol of a socket in winsock - sockets

I am working in networking reliability simulation, I need to simulate packet dropping based on a quality of service percentage. Currently I have a DLL that hooks into send, sendto, recv and recvfrom. My hooks then 'drop' packets based on the quality of service.
I just need to apply the hook to UDP packets, and not disturb TCP (TCP is used for remote debugging).
Is there a way that I can query WinSock for the protocol that a socket is bound to?
int WSAAPI HookedSend(SOCKET s, const char FAR * buf, int len, int flags)
{
//if(s is UDP)
//Drop according to QOS
else
//Send TCP packets undisturbed
return send(s, buf, len, flags);
}

I think you could get the socket type by using getsockopt:
int optVal;
int optLen = sizeof(int);
getsockopt(socket,
SOL_SOCKET,
SO_TYPE,
(char*)&optVal,
&optLen);
if(optVal = SOCK_STREAM)
printf("This is a TCP socket.\n");
else if(optVal = SOCK_DGRAM)
printf("This is a UTP socket.\n");
else
printf("Error");

Related

ESP32 Multicast UDP High losses (receiving)

I'm developing device base on ESP32 module that have a UDP socket open only to receive broadcast packets on one port (7890 to be exact). The problem is that the data losses are high - around 90%. My test setup is:
ESP32 - connected to WiFi network with open UDP receing task (code belowe)
PC connected to the same netwer via LAN with UDP terminal set to brodacast to remote: 192.168.10.255:7890
Mobile phone connected to WiFi with UDP terminal set to brodacast to remote: 192.168.10.255:7890
When I send something from PC or mobile phone there is no data lossage between Mobile phone and PC but ESP32 receive around 10% of data that I transmit from both of senders. If I change from multicast to unicast on PC or Phone to send data to ESP32, it work without problem.
I know that UDP does not guarantee the delivery but 10% efficiency seems for me to be super low, especially when it seems that there is no problem with busy network because PC and mobile received the data all the time.
Do you have any suggestion to the code or some setting that can be changed in menu config ?
At the moment my application have only two tasks:
WiFi Task that after connection is just waiting for event
UDP Task that the code is below
Update 04.07.2018 (13:15)
Problem disappear when I don't initialize bluetooth. Sorry that I didn't mention previously about BT being initialized but I kept me initializing function from my normal program that have a lot more tasks (BT included) and totally forgot about this myself.
Anyway - do you think that there is some issue with sharing the resource or is it some physical interference ? I'm using ESP32-DevKitC that is on the breadboard, so no additional shielding is present.
#define PORT_NUMBER 7890
#define BUFLEN 100
void udp_task(void *pvParameter)
{
struct sockaddr_in clientAddress;
struct sockaddr_in serverAddress;
struct sockaddr_in si_other;
unsigned int slen = sizeof(si_other);
unsigned int recv_len;
char buf[BUFLEN];
int sock;
printf("UDP Task: Opening..\n");
int ret;
ret = UDP_List_Open(&clientAddress, &serverAddress, &sock);
if(ret == 0)
{
printf("UDP Task: Open\n");
}
else
{
printf("UDP Task: Can't open\n");
}
while(1)
{
memset(buf,0,100);
if ((recv_len = recvfrom(sock, buf, 100, 0, (struct sockaddr *) &si_other, &slen)) == -1)
{
printf("UDP error\n");
break;
}
sendto(sock, buf, recv_len, 0, (struct sockaddr *)&si_other, sizeof(si_other));
printf("UDP Task: Received packet from %s:%d\n", inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port));
printf("UDP Task: Data: %s -- %d\n" , buf, recv_len);
}
while(1)
{
vTaskDelay(100 / portTICK_RATE_MS);
}
}
int UDP_List_Open(struct sockaddr_in* clientAddress, struct sockaddr_in* serverAddress, int* sock)
{
// Create a socket that we will listen upon.
*sock = socket(AF_INET, SOCK_DGRAM, 0);
if (*sock < 0)
{
printf("UDP List Open: Socket error\n");
return 1;
}
// Bind our server socket to a port.
serverAddress->sin_family = AF_INET;
serverAddress->sin_addr.s_addr = htonl(INADDR_ANY);
serverAddress->sin_port = htons(PORT_NUMBER);
int rc = bind(*sock, serverAddress, sizeof(*serverAddress));
if (rc < 0)
{
printf("UDP List Open: Bind error\n");
return 2;
}
return 0;
}
Even though UDP is considered fire and forget, (unlike TCP), unicast UDP through WiFi is reliable because reliability is built into the WiFi protocol. But this can work for Unicast only because there is one known recipient. Multicast UDP is unreliable because there are no checks and retries.
I had the same problem when I was trying to use multicast UDP with the ESP8266. It caused me to dig deeper into the issue. In the end I use UDP multicast for discovery but then switch to Unicast UDP for subsequent transfers.
See Multicast Wifi Problem Statement
https://tools.ietf.org/id/draft-mcbride-mboned-wifi-mcast-problem-statement-01.html

Winsock TCP connection, send fine but recv firewall blocked

I have an application that sends a GET request using winsock on port 80 using a TCP socket. A few users have reported an issue where no response is received, looking at network logs and seeing the network device is getting the data just the app isn't it was clear that the firewall was blocking it.
Having disabled the firewall it then worked fine but what I don't understand is why it was getting blocked. The connection is created from the users computer, it connects fine and sends (which I assumes automatically opens a port) so how can data be lost on the same connection when received? Should I be providing additional winsock settings? Or is there simply no way around stopping the firewall blocking an already active connection?
Here is a stripped down version of the winsock code
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET)
return -1;
struct sockaddr_in client;
memset(&client, 0, sizeof(client));
client.sin_family = AF_INET;
client.sin_port = htons(80);
client.sin_addr.s_addr = inet_addr(inet_ntoa(*addr_list[0]));
if (connect(sock, (struct sockaddr *)&client, sizeof(client)) < 0){
closesocket(sock);
return -1;
}
if (send(sock, buffer, buflength, 0) != buflength){
closesocket(sock);
return -1;
}
//get response
response = "";
int resp_leng = BUFFERSIZE;
while (resp_leng == BUFFERSIZE)
{
resp_leng = recv(sock, (char*)&buffer, BUFFERSIZE, 0);
if (resp_leng > 0)
response += std::string(buffer).substr(0, resp_leng);
else
return -1;
}
closesocket(sock);
Your while loop exits if a recv() returns less than BUFFERSIZE. This is wrong -- you must always assume that recv() can return any amount of data from 1 byte up to and including the supplied buffer size.

VxWorks 6.8: setsockopt with IP_ADD_MEMBERSHIP returning EADDRNOTAVAIL

I am trying to set up a socket to receive multicast UDP packets on VxWorks 6.8.
sin.sin_len = (u_char)sizeof (sin);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
/* UDP port number to match for the received packets */
sin.sin_port = htons (mcastPort);
/* bind a port number to the socket */
if (bind(sockDesc, (struct sockaddr *)&sin, sizeof(sin)) != 0)
{
perror("bind");
status = errno;
goto cleanUp;
}
/* fill in the argument structure to join the multicast group */
/* initialize the multicast address to join */
ipMreq.imr_multiaddr.s_addr = inet_addr (mcastAddr);
/* unicast interface addr from which to receive the multicast packets */
ipMreq.imr_interface.s_addr = inet_addr (ifAddr);
printf ("Interface address on which to receive multicast packets: %s\n", ifAddr);
/* set the socket option to join the MULTICAST group */
int code = setsockopt (sockDesc, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(char *)&ipMreq,
sizeof (ipMreq));
The setsockopt() call is returning -1 and errno is being set to 49 or EADDRNOTAVAIL. On wireshark, when we perform setsockopt I can see a properly formed group unsubscribe packet being sent out from the right port/interface. All different combinations of interfaces, ports, and multicast groups give the same result.
I am unable to debug very far into setsockopt as there doesnt seem to be anything wrong before the task calls ipcom_pipe_send and ipnet_usr_sock_pipe_recv, and after the recv call errno is set. I dont know how to debug the relevant tNetTask code that may be generating the error.
It could be that there's an issue with the interface index you supplied. Define ipMreq to be a struct ip_mreq, which does not have the imr_ifindex, instead of a struct ip_mreqn and remove the ipMreq.imr_ifindex = 2; line.

Winsock2 - how to open a TCP socket that allows recv() with MSG_WAITALL?

In this code:
// error checking is omitted
// init Winsock2
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
// connect to server
struct addrinfo *res = NULL, *ptr = NULL, hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
getaddrinfo(server_ip, "9999", &hints, &res);
SOCKET client_socket = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
connect(client_socket, res->ai_addr, (int)res->ai_addrlen);
freeaddrinfo(res);
res = NULL;
// read the data
unsinged int size1;
if (recv(client_socket, (char*)&size1, sizeof(int), MSG_WAITALL) == SOCKET_ERROR)
{
return WSAGetLastError();
}
(note the MSG_WAITALL flag in recv()) everything works fine, expect for recv(). WSAGetLastError() returns WSAEOPNOTSUPP.
MSDN states that
Note that if the underlying transport does not support MSG_WAITALL, or if the socket is in a non-blocking mode, then this call will fail with WSAEOPNOTSUPP. Also, if MSG_WAITALL is specified along with MSG_OOB, MSG_PEEK, or MSG_PARTIAL, then this call will fail with WSAEOPNOTSUPP. This flag is not supported on datagram sockets or message-oriented sockets.
But it doesn't look like I'm doing something from this list. Why my recv() call doesn't work?
it doesn't look like I'm doing something from this list.
Yes, you are - the very first item on the list:
the underlying transport does not support MSG_WAITALL
Microsoft's default TCP transport provider does not support MSG_WAITALL. recv(), and Winsock in general, is not limited to just Microsoft's TCP provider. It supports 3rd party providers, and any transport protocols that the provider supports - TCP, UDP, IPX, ICMP, RAW, etc.
When using Microsoft's TCP, if you want recv() to wait until all of the requested TCP data has been received, you have to set the socket to blocking mode (its default mode) and then set the flags parameter of recv() to 0. But even that is not guaranteed, recv() can return with fewer bytes than requested, so you should be prepared to call recv() in a loop until all intended bytes have actually been received.

SIP Registration Issue

I am currently working on SIP sample application.
I am trying to do the registration using C based Socket programming on Unix. I have been successfully being able to get register with PJSIP, but when the same parameters I am sending with normal socket programming, then I am not being able to receive any response from server.
Here is the source code:
char *server = (char *)serverAddress; // First arg: server address/name
char *echoString = "Request msg REGISTER/cseq=46476 (tdta0x8857200)\r\nREGISTER sip:DOMAIN_NAME SIP/2.0\r\nVia: SIP/2.0/UDP 192.168.1.120:51648;rport;branch=z9hG4bKPjwEt4VvIVdjIJKRmEJbkidYDAu-zQbIqv\r\nMax-Forwards: 70\r\nFrom: <sip:USER_NAME#DOMAIN_NAME>;tag=epCBN7JXsQE1nnI5d5SOZe9a5ujRyI67\r\nTo: <sip:USER_NAME#DOMAIN_NAME>\r\nCall-ID: .5yYCqh2jEYdy5T4kxhzxwDYEkCO1XlD\r\nCSeq: 46476 REGISTER\r\nContact: <sip:USER_NAME#192.168.1.120:51648;ob>\r\nExpires: 300\r\nAllow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS\r\nAuthorization: Digest username=\"USER_NAME\", realm=\"asterisk\", nonce=\"3b63254c\", uri=\"sip:DOMAIN_NAME\", response=\"9e8fc78829d143a58fba5a79f6ad44fd\", algorithm=MD5\r\nContent-Length: 0";
size_t echoStringLen = strlen(echoString);
// Third arg (optional): server port/service
char *servPort = (char *)service;
// Tell the system what kind(s) of address info we want
struct addrinfo addrCriteria; // Criteria for address match
memset(&addrCriteria, 0, sizeof(addrCriteria)); // Zero out structure
addrCriteria.ai_family = AF_UNSPEC; // For the following fields, a zero value means
// Any address family "don't care"
addrCriteria.ai_socktype = SOCK_DGRAM; // Only datagram sockets
addrCriteria.ai_protocol = IPPROTO_UDP; // Only UDP protocol
// Get address(es)
struct addrinfo *servAddr; // List of server addresses
int rtnVal = getaddrinfo(server, servPort, &addrCriteria, &servAddr);
if (rtnVal != 0)
DieWithUserMessage("getaddrinfo() failed", gai_strerror(rtnVal));
// Create a datagram/UDP socket
int sock = socket(servAddr->ai_family, servAddr->ai_socktype,
servAddr->ai_protocol); // Socket descriptor for client
if (sock < 0)
DieWithSystemMessage("socket() failed");
// Send the string to the server
ssize_t numBytes = sendto(sock, echoString, echoStringLen, 0,
servAddr->ai_addr, servAddr->ai_addrlen);
if (numBytes < 0)
DieWithSystemMessage("sendto() failed");
else if (numBytes != echoStringLen)
DieWithUserMessage("sendto() error", "sent unexpected number of bytes");
// Receive a response
struct sockaddr_storage fromAddr; // Source address of server
// Set length of from address structure (in-out parameter)
socklen_t fromAddrLen = sizeof(fromAddr);
char buffer[100 + 1]; // I/O buffer
numBytes = recvfrom(sock, buffer, 100, 0,
(struct sockaddr *) &fromAddr, &fromAddrLen);
if (numBytes < 0)
DieWithSystemMessage("recvfrom() failed");
else if (numBytes != 100)
DieWithUserMessage("recvfrom() error", "received unexpected number of bytes");
// Verify reception from expected source
int value = SockAddrsEqual(servAddr->ai_addr, (struct sockaddr *) &fromAddr);
if (value == 0)
DieWithUserMessage("recvfrom()", "received a packet from unknown source");
freeaddrinfo(servAddr);
buffer[echoStringLen] = '\0'; // Null-terminate received data
printf("Received: %s\n", buffer); // Print the echoed string
close(sock);
exit(0);
When I am trying to debug the code, then the breakpoint gets disappeared from recvfrom method call as follows.
numBytes = recvfrom(sock, buffer, 100, 0, (struct sockaddr *) &fromAddr, &fromAddrLen);
Thanks in advance for your co-operation.
If you are not getting a response from the Registrar server it's most likely because it couldn't understand the REGISTER request you sent it or rejected it as a duplicate. More that likely you will need to get a bit more sophisticated about how you are constructing your REGISTER request rather than simply sending a hard coded string.
Apart from that one obvious thing you could try is to add the required \r\n\r\n onto the end of your echoString. All SIP requests are required to end the header portion with a double line break and that is missing from your string.
recvfrom() blocks until a response is received, unless you set the socket to non-blocking. A better approach would be to use select() with a timeout (like a second or two). Better still would be to then put the entire thing into a loop which retries some number of times (like three or four).
Remember that UDP makes no guarantees that your datagram will be delivered: it is entirely up to you to decide when you've waited long enough and need to try again.
Also, check that the values being set in servAddr by getaddrinfo() make sense. If the address or port number is wrong, your packet may silently disappear.
If you confirm that this is socket issue then good to trace.
But if you are not sure then for this kind of issue use network analyze application (wireshark) & see the packet you send & receive. Then look into socket issue.