Recvfrom() keeps returning wrong value - c

I call udpclient in main where i pass "this is a test" as the parameter message.
#define MAX_BUFFER 128
void udpclient(char *message, char *target_ip, int target_port){
///* address of server we trying to reach */
struct sockaddr_in targetaddress;
/* buffer to receive echo */
char buffer[MAX_BUFFER];
/* create socket */
int socketfd;
socketfd = socket(AF_INET, SOCK_DGRAM, 0);
if(socketfd == -1)
socketerror();
/* target server informations */
memset(&targetaddress, 0, sizeof(targetaddress));
targetaddress.sin_family = AF_INET;
targetaddress.sin_port = htons(target_port);
targetaddress.sin_addr.s_addr = inet_addr(target_ip);
After i send message to server, the server must reply "echo: this is a test", but recvfrom() for some reason is returning n = 8, so when i do write(1, buffer, n) it truncates buffer.
/* send message to targetaddress */
ssize_t n;
n = sendto(socketfd, message, sizeof(message), 0, (const struct sockaddr *) &targetaddress, sizeof(targetaddress));
if(n == -1)
udpsenderror();
printf("%i\n", n);
socklen_t addrlen;
addrlen = sizeof(targetaddress);
/* receive echo from targetaddress */
n = recvfrom(socketfd, buffer, MAX_BUFFER, 0, (struct sockaddr *) &targetaddress, &addrlen);
if(n == -1)
udpechoerror();
printf("%i\n", n);
write(1, "echo: ", 6);
write(1, buffer, n);
return;
}
Recvfrom() should be returning the lenght of message if i'm not mistaken, I don't know where i'm doing wrong! Help!?

n = sendto(socketfd, message, sizeof(message), 0, (const struct sockaddr *) &targetaddress, sizeof(targetaddress));
Since message is a char *, sizeof(message) gives the number of bytes a char * takes on your platform. Apparently, that's 8 bytes, so you sent an 8-byte message.

Related

C sockaddr function call for sendto?

I'm currently setting up a UDP socket for a school assignment but I can't figure out how to properly send sockaddr as a parameter into a function. The input arguments for SendData is defined the same way they are in the sendto function.
void SendData(int fileDescriptor, const struct sockaddr_in *destAddrUdp, unsigned char buffer[MAXMSG])
{
/* crc */
int strlength = strlen(buffer);
unsigned char SCRC = CRC(buffer, strlength-1);
buffer[strlength-1] = SCRC;
buffer[strlength] = '\0';
/* send */
if (sendto(fileDescriptor, buffer, strlen(buffer), 0, (struct sockaddr*) &destAddrUdp,sizeof(destAddrUdp)) < 0) {
fprintf(stderr, "Could not send data\n");
}
} `
When the below code is called from main it works however when it's called from SendData the return value from sendto is -1.
if (sendto(fileDescriptor, buffer, strlen(buffer), 0, (struct sockaddr*) &destAddrUdp,sizeof(destAddrUdp)) < 0) {
fprintf(stderr, "Could not send data\n");
}
If the program is compiled I get warning: passing argument 5 of ‘recvfrom’ from incompatible pointer type. on the sendto functioncall in SendData.
The function call for SendData in my main program is: SendData(sockfd, (struct sockaddr *) &destAddrUdp, buffer);
The main program in case it is relevant:
unsigned char SCRC;
unsigned char strlength;
unsigned char buffer[MAXMSG-5];
unsigned char header[MAXMSG];
struct rtp_struct *sendstruct;
/* option 2 */
struct sockaddr_in destAddrUdp;
int sockfd;
char dstHost[15];
printf("input host IP:\n>");
fgets(dstHost, 15, stdin);
/* Create socket */
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
fprintf(stderr, "Can't create UDP socket\n");
/* set configurations */
memset (&destAddrUdp, 0, sizeof(destAddrUdp)); //set zero
destAddrUdp.sin_family = AF_INET; //internet use
destAddrUdp.sin_addr.s_addr = inet_addr(dstHost); //set so anyone can connect
destAddrUdp.sin_port = htons(dstUdpPort); //set the port to use
/* Generate CRC table */
GenerateCRCTable();
/* get string and send */
while(1) {
printf("\n>");
fgets(buffer, MAXMSG, stdin);
if(strncmp(buffer,"quit\n",MAXMSG) != 0){ //if read string == quit, see else
strlength = strlen(buffer);
SCRC = CRC(buffer, strlength-1);
buffer[strlength-1] = SCRC;
buffer[strlength] = '\0';
SendData(sockfd, (struct sockaddr *) &destAddrUdp, buffer);
/*if (sendto(sockfd, buffer, strlength, 0, (struct sockaddr *) &destAddrUdp,sizeof(destAddrUdp)) < 0){
fprintf(stderr, "Could not send data\n");}*/
}
else {
close(sockfd);
exit(EXIT_SUCCESS);
}
}
}
In your SendData function, the parameter destAddrUdp has type const struct sockaddr_in *. When you then make this call:
sendto(fileDescriptor, buffer, strlen(buffer), 0,
(struct sockaddr*) &destAddrUdp, sizeof(destAddrUdp)
The expression &destAddrUdp has type const struct sockaddr_in **, so the pointer type is incompatible. Also, sizeof(destAddrUdp) is returning the size of a pointer, not the size of the struct.
You failed to account for the differing types of destAddrUdp in SendData and main. The correct call to sendto would be:
sendto(fileDescriptor, buffer, strlen(buffer), 0,
(struct sockaddr*) destAddrUdp, sizeof(*destAddrUdp)
The problem is the sizeof(destAddrUdp) and the (struct sockaddr*) &destAddrUdp.
In your main, destAddrUdp is an struct sockaddr_in, in your function however, its a sockaddr_in* so you can't use them equally. First, sizeof(destAddrUdp) in your function will give you the size of a pointer, second, &destAddrUdp in your function will give you a destAddrUdp**. Thats not what you want.
Try sendto(fileDescriptor, buffer, strlen(buffer), 0, (struct sockaddr*) destAddrUdp,sizeof(*destAddrUdp))

Multi-threaded TFTP Server - Issue With pthreads

I created a simple tftp server that only handles read requests (RRQ). Everything was working fine until I started to make a multi-threaded version of the server. In the application, I simply receive requests in the main thread and I then forward the request to a new thread that does the packet analysis. Therefore, I need to forward the socket, the received packet and the sockaddr_in struct that contains the client information to the thread. With that said, I created a struct that holds all of these and forward them to the pthread.
I get two identical error messages, one in the main and the other in the connection handler. The problems seems to be in the referencing these variables in the struct and retrieving them in the thread. It seems the problem is in the following statements: in connection_handler(): buffer = cthread->buffer; and in the main(): clientT.buffer = buffer;
Here's the code, I've written so far...
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#define TIMEOUT 5000
#define RETRIES 3
void *connection_handler(void *);
struct clientThread
{
int clientSock;
char opcode;
char buffer[1024];
struct sockaddr_in client;
};
int main()
{
char buffer[1024];
int udpSocket, client_socket, nBytes;
struct sockaddr_in serverAddr, client;
socklen_t addr_size;
udpSocket = socket(AF_INET, SOCK_DGRAM, 0);
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(69);
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
bind(udpSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr));
while(1)
{
memset(buffer, 0, 1024);
nBytes = recvfrom(udpSocket,buffer,1024,0,(struct sockaddr *)&client, &addr_size);
// Creating a thread and passing the packet received, the socket and the sockaddr_in struct...
pthread_t client_thread;
struct clientThread clientT;
strcpy(clientT.buffer,buffer);
clientT.clientSock = udpSocket;
clientT.client = client;
pthread_create(&client_thread, NULL, connection_handler, &clientT);
}
return 0;
}
void* connection_handler (void *clientThreaded)
{
char buffer[1024], filename[200], mode[20], *bufindex, opcode;
struct clientThread *cthread = clientThreaded;
int udpSocket = cthread->clientSock;
strcpy(buffer, cthread->buffer);
//opcode = cthread->opcode;
struct sockaddr_in client = cthread->client;
bufindex = buffer;
bufindex++;
// Extracting the opcode from the packet...
opcode = *bufindex++;
// Extracting the filename from the packet...
strncpy(filename, bufindex, sizeof(filename)-1);
bufindex += strlen(filename) + 1;
// Extracting the mode from the packet...
strncpy(mode, bufindex, sizeof(mode)-1);
// If we received an RRQ...
if (opcode == 1)
{
puts("Received RRQ Request");
struct timeval tv;
tv.tv_sec = 5;
char path[70] = "tmp/";
char filebuf [1024];
int count = 0, i; // Number of data portions sent
unsigned char packetbuf[1024];
char recvbuf[1024];
socklen_t recv_size;
socklen_t optionslength = sizeof(tv);
setsockopt(udpSocket, SOL_SOCKET, SO_RCVTIMEO, &tv, optionslength);
FILE *fp;
char fullpath[200];
strcpy(fullpath, path);
strncat(fullpath, filename, sizeof(fullpath) -1);
fp = fopen(fullpath, "r");
if (fp == NULL)
perror("");
memset(filebuf, 0, sizeof(filebuf));
while (1)
{
int acked = 0;
int ssize = fread(filebuf, 1 , 512, fp);
count++;
sprintf((char *) packetbuf, "%c%c%c%c", 0x00, 0x03, 0x00, 0x00);
memcpy((char *) packetbuf + 4, filebuf, ssize);
packetbuf[2] = (count & 0xFF00) >> 8;
packetbuf[3] = (count & 0x00FF);
int len = 4 + ssize;
memset(recvbuf, 0, 1024);
printf("\nSending Packet #%i", count);
sendto(udpSocket, packetbuf, len, 0, (struct sockaddr *) &client, sizeof(client));
for (i=0; i<RETRIES; i++)
{
int result = recvfrom(udpSocket, recvbuf, 1024, 0, (struct sockaddr *) &client, &recv_size);
if ((result == -1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
{
sendto(udpSocket, packetbuf, len, 0, (struct sockaddr *) &client, sizeof(client));
printf("\nRetransmitting Packet #%i", count);
}
else if (result == -1)
{
// Handle Error
}
else
{
acked++;
printf("\nReceived ACK For Data Packet #%i", count);
break;
}
}
if (acked!=1)
{
puts("\nGave Up Transmission After 3 Retries");
break;
}
if (ssize != 512)
break;
}
}
return 0;
}
Thanks in advance :)
In the main loop, the variable clientT is local inside that loop, once the loop iterates the variable will go out of scope and any pointer to it will become invalid. Dereferencing such a pointer will lead to undefined behavior.
Instead what you should to is to dynamically allocate the structure using malloc, and pass that pointer instead. Don't forget to free the structure once you're done with it in the thread.
the current posted code, 7pm PDT,
causes the compiler to emit several warnings
(all of which need to be fixed)
plus some errors.
Errors like: 'buffer = cthread->buffer;'
is copying the address of 'cthread->buffer' to the address of the array 'buffer'.
That probably is not what is wanted.
suggest something similar to: strcpy(buffer, cthread->buffer);
#include <time.h> is missing
so this line: 'struct timeval tv;' is referencing an undefined struct.
The compiler needs to be run with all warnings enabled.
then fix the warnings and the errors.
as a minimum, for gcc, use the parameters:
-Wall -Wextra -Wshadow -pedantic
There are plenty of other error/warning messages that can be enabled
but the above list will catch ~99percent of all errors/warnings
Some googling should find info on how to fix the current errors and warnings.
(although to me, the error/warning messages
make it very clear as to the root cause of the problem.
however, I have been programming for 40 some years)
Each compiler message indicates:
1) which line in the current translation unit (file)
2) and what is wrong with that line.

TFTP Server - Issue With Threaded Version

I created a simple tftp server that only handles read requests (RRQ). Everything was working fine until I started to make a multi-threaded version of the server. In the application, I simply receive requests in the main thread and I then forward the request to a new thread that does the packet analysis. Therefore, I need to forward the socket, the received packet and the sockaddr_in struct that contains the client information to the thread. With that said, I created a struct that holds all of these and forward them to the pthread.
I suspect the problem to be in the struct clientThread initialization part and forwarding part; since I'm certain of the correctness of the processing inside connection_handler.
Note: You can use the tftp client that comes with linux to test it.
Here's the code I've written so far (Threaded Version). Please compile it with the -pthread flag...
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <time.h>
#define TIMEOUT 5000
#define RETRIES 3
void *connection_handler(void *);
struct clientThread
{
int clientSock;
char buffer[1024];
struct sockaddr_in client;
};
int main()
{
char buffer[1024];
int udpSocket, client_socket, nBytes;
struct sockaddr_in serverAddr, client;
socklen_t addr_size;
udpSocket = socket(AF_INET, SOCK_DGRAM, 0);
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(69);
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
bind(udpSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr));
while(1)
{
memset(buffer, 0, 1024);
nBytes = recvfrom(udpSocket,buffer,1024,0,(struct sockaddr *)&client, &addr_size);
// Creating a thread and passing the packet received, the socket and the sockaddr_in struct...
pthread_t client_thread;
struct clientThread clientT;
strcpy(clientT.buffer,buffer);
clientT.clientSock = udpSocket;
clientT.client = client;
pthread_create(&client_thread, NULL, connection_handler, &clientT);
}
return 0;
}
void* connection_handler (void *clientThreaded)
{
char buffer[1024], filename[200], mode[20], *bufindex, opcode;
struct clientThread *cthread = clientThreaded;
int udpSocket = cthread->clientSock;
strcpy(buffer, cthread->buffer);
struct sockaddr_in client = cthread->client;
bufindex = buffer;
bufindex++;
// Extracting the opcode from the packet...
opcode = *bufindex++;
// Extracting the filename from the packet...
strncpy(filename, bufindex, sizeof(filename)-1);
bufindex += strlen(filename) + 1;
// Extracting the mode from the packet...
strncpy(mode, bufindex, sizeof(mode)-1);
// If we received an RRQ...
if (opcode == 1)
{
puts("Received RRQ Request");
struct timeval tv;
tv.tv_sec = 5;
char path[70] = "tmp/";
char filebuf [1024];
int count = 0, i; // Number of data portions sent
unsigned char packetbuf[1024];
char recvbuf[1024];
socklen_t recv_size;
socklen_t optionslength = sizeof(tv);
setsockopt(udpSocket, SOL_SOCKET, SO_RCVTIMEO, &tv, optionslength);
FILE *fp;
char fullpath[200];
strcpy(fullpath, path);
strncat(fullpath, filename, sizeof(fullpath) -1);
fp = fopen(fullpath, "r");
if (fp == NULL)
perror("");
memset(filebuf, 0, sizeof(filebuf));
while (1)
{
int acked = 0;
int ssize = fread(filebuf, 1 , 512, fp);
count++;
sprintf((char *) packetbuf, "%c%c%c%c", 0x00, 0x03, 0x00, 0x00);
memcpy((char *) packetbuf + 4, filebuf, ssize);
packetbuf[2] = (count & 0xFF00) >> 8;
packetbuf[3] = (count & 0x00FF);
int len = 4 + ssize;
memset(recvbuf, 0, 1024);
printf("\nSending Packet #%i", count);
sendto(udpSocket, packetbuf, len, 0, (struct sockaddr *) &client, sizeof(client));
for (i=0; i<RETRIES; i++)
{
int result = recvfrom(udpSocket, recvbuf, 1024, 0, (struct sockaddr *) &client, &recv_size);
if ((result == -1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
{
sendto(udpSocket, packetbuf, len, 0, (struct sockaddr *) &client, sizeof(client));
printf("\nRetransmitting Packet #%i", count);
}
else if (result == -1)
{
// Handle Error
}
else
{
acked++;
printf("\nReceived ACK For Data Packet #%i", count);
break;
}
}
if (acked!=1)
{
puts("\nGave Up Transmission After 3 Retries");
break;
}
if (ssize != 512)
break;
}
}
return 0;
}
Here's my code for the Non-threaded version...
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#define TIMEOUT 5000
#define RETRIES 3
int main()
{
int udpSocket, nBytes;
char buffer[1024], filename[200], mode[20], *bufindex, opcode;
struct sockaddr_in serverAddr, client;
struct sockaddr_storage serverStorage;
socklen_t addr_size;
udpSocket = socket(AF_INET, SOCK_DGRAM, 0);
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(69);
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
bind(udpSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr));
while(1)
{
memset(buffer, 0, 1024);
nBytes = recvfrom(udpSocket,buffer,1024,0,(struct sockaddr *)&client, &addr_size);
printf("%s",buffer);
bufindex = buffer;
bufindex++;
// Extracting the opcode from the packet...
opcode = *bufindex++;
// Extracting the filename from the packet...
strncpy(filename, bufindex, sizeof(filename)-1);
bufindex += strlen(filename) + 1;
// Extracting the mode from the packet...
strncpy(mode, bufindex, sizeof(mode)-1);
// If we received an RRQ...
if (opcode == 1)
{
puts("Received RRQ Request");
struct timeval tv;
tv.tv_sec = 5;
char path[70] = "tmp/";
char filebuf [1024];
int count = 0, i; // Number of data portions sent
unsigned char packetbuf[1024];
char recvbuf[1024];
socklen_t recv_size;
socklen_t optionslength = sizeof(tv);
setsockopt(udpSocket, SOL_SOCKET, SO_RCVTIMEO, &tv, optionslength);
FILE *fp;
char fullpath[200];
strcpy(fullpath, path);
strncat(fullpath, filename, sizeof(fullpath) -1);
fp = fopen(fullpath, "r");
if (fp == NULL)
perror("");
memset(filebuf, 0, sizeof(filebuf));
while (1)
{
int acked = 0;
int ssize = fread(filebuf, 1 , 512, fp);
count++;
sprintf((char *) packetbuf, "%c%c%c%c", 0x00, 0x03, 0x00, 0x00);
memcpy((char *) packetbuf + 4, filebuf, ssize);
packetbuf[2] = (count & 0xFF00) >> 8;
packetbuf[3] = (count & 0x00FF);
int len = 4 + ssize;
memset(recvbuf, 0, 1024);
printf("\nSending Packet #%i", count);
sendto(udpSocket, packetbuf, len, 0, (struct sockaddr *) &client, sizeof(client));
for (i=0; i<RETRIES; i++)
{
int result = recvfrom(udpSocket, recvbuf, 1024, 0, (struct sockaddr *) &client, &recv_size);
if ((result == -1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
{
sendto(udpSocket, packetbuf, len, 0, (struct sockaddr *) &client, sizeof(client));
printf("\nRetransmitting Packet #%i", count);
}
else if (result == -1)
{
// Handle Error
}
else
{
acked++;
printf("\nReceived ACK For Data Packet #%i", count);
break;
}
}
if (acked!=1)
{
puts("\nGave Up Transmission After 3 Retries");
break;
}
if (ssize != 512)
break;
}
}
}
return 0;
}
Thanks in advance :)
You loop listening on port 69 but the actual data transfer will be carried out from a different randomly selected port (please read RFC 1350).
Then your main loop must create a new thread for every new transfer, this new thread should receive a structure containing the path of the file to serve, the destination IP/port, the randomly selected local port, etc.
Something you must consider when passing a structure pointer to a thread is the memory supporting the structure.
In your case
struct clientThread clientT;
is dinamicaly created in the stack and of-course the structure is "discarded" when the block of code goes out of scope (in your case on every loop) that means you are passing a pointer to "soon to be garbage" to the just created thread.
I recommend using malloc/free when passing structures to just created threads.
Finally your main thread (dispatcher) should maintain a structure taking into account all the created threads and their status. This is necessary to detect dead threads or when needing to close the main program when there are transfers in progress.
As you can see implementing a server even for a simple protocol like TFTP is not really easy.
Your connection handler is wrong here because there is no locking whatsoever on the socket that you pass to each thread.
Most servers that are udp based are in fact not forking multiple threads. TCP servers can do it , because with each accept you get a new socket that can be delegated to a new thread that won't be used by any other thread.
But for udp, you are basically using the same socket for all your threads and this is not ok. If you were to provide protection on the socket you can make it work, but you will lose the benefits that you are trying to obtain by making it multithreaded.

read() from UDP socket drops data and blocks unexpectedly in C

I'm trying to read data from a UDP socket, but after reading the first 255 bytes, read() seems to drop the rest of the data on the socket and block until another data-gram comes in.
Here's the network code I'm using:
int sock;
struct sockaddr_in remote_addr, self_addr;
uint8_t network_init(uint16_t port)
{
memset((char *) &remote_addr, 0, sizeof(remote_addr));
remote_addr.sin_family = AF_INET;
remote_addr.sin_addr.s_addr = inet_addr("192.168.1.22");
remote_addr.sin_port = htons(3001);
memset((char *) &self_addr, 0, sizeof(self_addr));
self_addr.sin_family = AF_INET;
self_addr.sin_addr.s_addr = INADDR_ANY;
self_addr.sin_port = htons(3001);
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
fprintf(stderr, "Could not create socket.");
return 1;
}
else if (bind(sock, (struct sockaddr *) &self_addr, sizeof(self_addr)) != 0)
{
fprintf(stderr, "Could not bind to socket.");
return 1;
}
return 0;
}
void network_send(uint8_t *data, uint8_t len)
{
sendto(sock, data, len, 0, (struct sockaddr *) &remote_addr, sizeof(remote_addr));
}
void read_data()
{
int len = 0;
ioctl(sock, FIONREAD, &len);
// We have data
if (len > 0)
{
char *buffer = (char *) malloc(256);
uint8_t buflen;
printf("==== %d | Data:\n", len);
while (len > 0)
{
buflen = min(255, len);
len = len - buflen;
buffer[buflen] = '\0';
printf("len: %d, buflen: %d,\n",len, buflen);
read(sock, buffer, buflen);
printf("%s\n", buffer);
}
printf("\n");
}
}
Here's the command I'm using to send data:
echo -n '12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567' | nc -u localhost 3001
And here's the output:
==== 257 | Data:
len: 2, buflen: 255,
123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345
len: 0, buflen: 2,
^C
Also, after performing this read, ioctl(sock, FIONREAD, &len); produces a length result of 0. My suspicion is that for some reason, read() is clearing out the rest of the data before it has a chance to be read, but I can't seem to find any reference to this behaviour in any documentation.
I'm developing on an Ubuntu linux machine (x86_64).
With UDP sockets, each call to read() reads a whole datagram out of the kernel. If the read buffer isn't big enough for the entire datagram, the rest of it will be discarded. It's not like a stream socket, where you can keep calling until you get everything.
Since FIONREAD tells you the number of bytes in the message, you should use that as the size to malloc() rather than using 256:
if (len > 0) {
char *buffer = malloc(len);
...
P.S. Do I cast the result of malloc?

Using 'abstract sockets' with AF_UNIX SOCK_DGRAM

I am trying to modify the original Michael Kerrisk's AF_UNIX SOCK_DGRAM sample client/server program. Please click on the following two links (client, server) for more info. The example code was originally published in his book The Linux Programming Interface, chapter 57. My goal is to replace the 'file socket' definition with 'abstract socket' definition, based on Kerrisk's code example.
Unfortunately, I am not able to establish communication between my version of the client and server. Of course, Kerrisk's version works with a flying colors.
It is obvious to me, that I am doing something fundamentally wrong... but... I could not figured out what it is.
=================== SERVER ===============================
Here is my version of the Kerrisk's code for 'server':
int main(int argc, char *argv[])
{
struct sockaddr_un svaddr, claddr;
int sfd, j;
ssize_t numBytes;
socklen_t len;
char buf[BUF_SIZE];
char *abstract_server;
sfd = socket(AF_UNIX, SOCK_DGRAM, 0); /* Create server socket */
if (sfd == -1)
errExit("socket");
abstract_server = "viper_server";
/* Construct well-known address and bind server socket to it */
if (remove(abstract_server) == -1 && errno != ENOENT)
errExit("remove-%s", abstract_server);
memset(&svaddr, 0, sizeof(struct sockaddr_un));
svaddr.sun_family = AF_UNIX;
strncpy(&svaddr.sun_path[1], abstract_server, strlen(abstract_server));
if (bind(sfd, (struct sockaddr *) &svaddr,
sizeof(sa_family_t) + strlen(abstract_server) + 1) == -1)
errExit("bind");
/* Receive messages, convert to uppercase, and return to client */
for (;;) {
len = sizeof(struct sockaddr_un);
numBytes = recvfrom(sfd, buf, BUF_SIZE, 0,
(struct sockaddr *) &claddr, &len);
if (numBytes == -1)
errExit("recvfrom");
printf("Server received %ld bytes from %s\n", (long) numBytes,
claddr.sun_path);
for (j = 0; j < numBytes; j++)
buf[j] = toupper((unsigned char) buf[j]);
if (sendto(sfd, buf, numBytes, 0, (struct sockaddr *) &claddr, len) != numBytes)
fatal("sendto");
}
}
========================= CLIENT ============================
This is my version of the Kerrisk's code for the 'client':
int main(int argc, char *argv[])
{
struct sockaddr_un svaddr, claddr;
int sfd, j;
size_t msgLen;
ssize_t numBytes;
char resp[BUF_SIZE];
char *abstract_client;
char *abstract_server;
if (argc < 2 || strcmp(argv[1], "--help") == 0)
usageErr("%s msg...\n", argv[0]);
/* Create client socket; bind to unique pathname (based on PID) */
sfd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (sfd == -1)
errExit("socket");
abstract_client = "viper_client";
abstract_server = "viper_server";
memset(&claddr, 0, sizeof(struct sockaddr_un));
claddr.sun_family = AF_UNIX;
strncpy(&claddr.sun_path[1], abstract_client, strlen(abstract_client));
if (bind(sfd, (struct sockaddr *) &claddr,
sizeof(sa_family_t) + strlen(abstract_client) + 1) == -1)
errExit("bind");
/* Construct address of server */
memset(&svaddr, 0, sizeof(struct sockaddr_un));
svaddr.sun_family = AF_UNIX;
strncpy(&svaddr.sun_path[1], abstract_server, strlen(abstract_server));
/* Send messages to server; echo responses on stdout */
for (j = 1; j < argc; j++) {
msgLen = strlen(argv[j]); /* May be longer than BUF_SIZE */
/* code FIX */
if (sendto(sfd, argv[j], msgLen, 0, (struct sockaddr *) &svaddr,
(sizeof(sa_family_t) + strlen(abstract_server) + 1) ) != msgLen)
fatal("sendto");
/* original - non working code - replaced with the code FIX above
if (sendto(sfd, argv[j], msgLen, 0, (struct sockaddr *) &svaddr,
sizeof(struct sockaddr_un)) != msgLen)
{
fatal("sendto");
} */
numBytes = recvfrom(sfd, resp, BUF_SIZE, 0, NULL, NULL);
/* Or equivalently: numBytes = recv(sfd, resp, BUF_SIZE, 0);
or: numBytes = read(sfd, resp, BUF_SIZE); */
if (numBytes == -1)
errExit("recvfrom");
printf("Response %d: %.*s\n", j, (int) numBytes, resp);
}
remove(claddr.sun_path); /* Remove client socket pathname */
exit(EXIT_SUCCESS);
}
How I am launching the test:
> ./server &
> ./client aa bb cc
> result: ERROR: sendto
Any help | suggestion | solution | RTFM is very welcome
Igor
P.S. Since my reputation is less than 10, I can post ONLY 2 links (see Kerrisk's client URL, Kerrrisk's server URL at the top of this post). So, I did a "cut&paste" the Kerrisk's C-code snippet for "How to use abstract sockets". It was published in his book on page 1176, Listing 57-8.
int main(int argc, char *argv[])
{
int sockfd;
struct sockaddr_un addr;
char *str;
memset(&addr, 0, sizeof(struct sockaddr_un)); /* Clear address structure */
addr.sun_family = AF_UNIX; /* UNIX domain address */
/* addr.sun_path[0] has already been set to 0 by memset() */
str = "xyz"; /* Abstract name is "\0abc" */
strncpy(&addr.sun_path[1], str, strlen(str));
// In early printings of the book, the above two lines were instead:
//
// strncpy(&addr.sun_path[1], "xyz", sizeof(addr.sun_path) - 2);
// /* Abstract name is "xyz" followed by null bytes */
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfd == -1)
errExit("socket");
if (bind(sockfd, (struct sockaddr *) &addr,
sizeof(sa_family_t) + strlen(str) + 1) == -1)
errExit("bind");
// In early printings of the book, the final part of the bind() call
// above was instead:
// sizeof(struct sockaddr_un)) == -1)
sleep(60);
exit(EXIT_SUCCESS);
}
if (sendto(sfd, argv[j], msgLen, 0, (struct sockaddr *) &svaddr,
sizeof(struct sockaddr_un)) != msgLen)
The last arg is invalid, the sockaddr_un address length should be
sizeof(sa_family_t) + strlen(abstract_client) + 1;
BTW, you should print out the "errno" value to precisely locate what happened when errorly returned from the glibc API. In the above case, the "errno" value is "111", indicating the server address cannot be reached.
OK, After having read your post once more, I think I got what you mean.
When you use the no abstract unix sockets(sun_path[0] != 0), the server name len is calculated by using strlen(sun_path) in the kernel. So the last arg is not really used.
net/unix/af_unix.c:unix_mkname
if (sunaddr->sun_path[0]) {
/* ... */
((char *)sunaddr)[len] = 0;
len = strlen(sunaddr->sun_path)+1+sizeof(short);
return len;
}
But when you use the abstract unix sockets(sun_path[0] == 0), the server name len is the last arg that your "bind" or "sendto".
net/unix/af_unix.c:unix_mkname:
*hashp = unix_hash_fold(csum_partial(sunaddr, len, 0));
So when you bind the socket to the address with length,
if (bind(sfd, (struct sockaddr *) &svaddr,
sizeof(sa_family_t) + strlen(abstract_server) + 1) == -1)
Kernel think the server name is an array with that length.
When you try to send to an address with
if (sendto(sfd, argv[j], msgLen, 0, (struct sockaddr *) &svaddr,
sizeof((struct sockaddr)) != msgLen)
Kernel think the server name is an array with that length of the last arg.
Because,
sizeof((struct sockaddr)) != sizeof(sa_family_t) + strlen(abstract_server) + 1
Kernel will not think the address is the same, so sendto returns with errno 111.
Your server binds to a different address than the client uses in sendto(). This is because you calculate the length of the svaddr differently in the client and server.
server:
sizeof(sa_family_t) + strlen(abstract_server) + 1)
client:
sizeof(struct sockaddr_un)
The unix socket address is the whole given length of the path described in struct sockaddr_un.sun_path. After changing the size calculations to match the client and server work.
EDIT s/abstract_client/abstract_server/ Seems I had the same copy&paste error as the other answer.

Resources