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.
Related
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.
there are two simple program to demo the unix domain DGRAM socket.
/* server */
int main(int ac, char *av[])
{
char buf[10];
int mpLogFD, len;
struct sockaddr_un serverAddress;
if((mpLogFD = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0)
mpExit("sock");
unlink(MPLOGD_SOCK);
memset(&serverAddress, 0, sizeof(serverAddress));
serverAddress.sun_family = AF_LOCAL;
strcpy(serverAddress.sun_path, "/var/run/lsvr.sock");
if(bind(mpLogFD, (struct sockaddr *)&serverAddress, sizeof(serverAddress)) < 0)
mpExit("bind");
perror("svr");
for(;;){
if(recvfrom(mpLogFD, buf, sizeof(buf), 0, (struct sockaddr *)&serverAddress, &len) < 0)
mpExit("recv");
printf("%s\n", buf);
}
}
/* client */
int main(int ac, char *av[])
{
int CliFD, len;
char buf[10];
struct sockaddr_un cliaddr;
if((CliFD = socket(AF_LOCAL, SOCK_DGRAM, 0)) == -1)
mpExit("cli sock");
memset(&cliaddr, 0, sizeof(cliaddr));
cliaddr.sun_family = AF_LOCAL;
strcpy(cliaddr.sun_path, "/var/run/lcli.sock");
if(bind(CliFD, (struct sockaddr *)&cliaddr, sizeof(cliaddr)))
mpExit("cli bind");
len = sizeof(cliaddr);
sprintf(buf, "12345678\n");
if(sendto(CliFD, buf, sizeof(buf), 0, (struct sockaddr *)&cliaddr, len) < 0)
mpExit("cli send");
perror("cli");
}
and the following is the result:
[root#jyl opt]# ./logsvr &
2033
svr: Success
[root#jyl opt]# ./logcli
cli: Success
[root#jyl opt]#
it seems like nothing wrong here. but, I get nothing from the server.
I don't know why it can't run as I expect.
You should be sending to /var/run/lsvr.sock not to /var/run/lcli.sock.
Also you don't have to bind in client so comment it out from client:
/* if(bind(CliFD, (struct sockaddr *)&cliaddr, sizeof(cliaddr)))
mpExit("cli bind");*/
I'm writing a server-client application using UDP protocol. When I run the recvfrom I get the following error and I really can't understand why:
recvfrom: Invalid argument
Here's what I assumed is the code relative to this error:
#define CLIE_PORT 5499
#define MAXMSGSIZE (1024 * 1024) // Max message size is 1MB
#define CLIE_PORT 5499
#define PACKETSZ 7
I'm running rcv_string in this way:
char *result = malloc(MAXMSGSIZE);
struct sockaddr_in sndaddr;
rcv_string((uint16_t) CLIE_PORT, &result, &sndaddr);
Here's the implementation of rcv_string (inside there's the call to recvfrom).
int rcv_string(uint16_t port, char **return_string, struct sockaddr_in *sndaddr) {
// [...]
memset((char *) sndaddr, 0, sizeof(*sndaddr));
(*sndaddr).sin_family = AF_INET;
(*sndaddr).sin_port = htons(port);
int reuse = 1;
if (setsockopt(sockfd_in, SOL_SOCKET, SO_REUSEADDR, (const char *) &reuse, sizeof(reuse)) < 0) {
perror("setsockopt");
return -1;
}
if (bind(sockfd_in, (struct sockaddr *) sndaddr, sizeof(*sndaddr)) < 0) {
perror("bind");
return -1;
}
socklen_t len;
if ((recvfrom(sockfd_in, buff, PACKETSZ + 1, 0, (struct sockaddr *) sndaddr, &len)) < 0) {
perror("recvfrom");
return -1;
}
// [...]
}
What could be the problem? (If you think I should upload more code, tell me!)
I think it should be socklen_t len=sizeof(*sndaddr);.
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.
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?