C pointer segmentation fault - c

I have this C code:
#include <errno.h>
#include <sys/errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include<fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
char *buf;
int c,s; int port=45678;
int recv_m(int c,char *buf);
void get(){
char fileNameBuf[20];
int i=0;
char *s = buf;
if (*s=='/') {
s++;
while (*s!=' ') {
fileNameBuf[i]=*s;
*s++;
i++;
}
fileNameBuf[i]='\0';
}
}
int main(){
//server connected
while ((c = accept(s, (struct sockaddr *) &client, (socklen_t *) &clientlen)) > 0){
// Do whatever a web server does.
char recv_buf[50];
char *r=recv_buf;
while(recv(c, r , 1, 0)!=0){
//stores the received message in recv_buf
}
recv_buf[i]='\0';
if (strncmp(recv_buf, "GET ", 4)==0){
buf=recv_buf+4;
get();
}
}
return (0);
}
*buf points to string /index.html HTTP/1.0. At the end of the function, fileNameBuf should store the string index.html.
The number of times in the while loop should be 10. When I run this code, i = 381 and I get a segmentation fault (core dump).
What am I doing wrong?
Here is the whole code, so *buf is the problem?

Either your assumptions about what is in buf must be faulty — or we're faulty in our interpretation of what you mean when you say:
*buf points to string "/index.html HTTP/1.1".
If you declared char **buf; and set:
char *str = "/index.html HTTP/1.1";
char **buf = str;
Then *buf points to the start of the string. This is why creating an SSCCE (Short, Self-Contained, Correct Example) is important; it removes the ambiguities.
An SSCCE
This code:
#include <stdio.h>
const char *buf = "/index.html HTTP/1.1";
static
void get(void)
{
char fileNameBuf[10];
int i=0;
if (*buf=='/')
{
buf++;
while (*buf!=' ')
{
fileNameBuf[i]=*buf;
buf++;
i++;
printf("%d\n", i);
}
}
printf("%.*s\n", (int)sizeof(fileNameBuf), fileNameBuf);
}
int main(void)
{
get();
return 0;
}
produces this output:
1
2
3
4
5
6
7
8
9
10
index.html
Granted, I had to take care not to print beyond the end of the array. Your array is minimally sized; it cannot hold a string containing the file name (no space for the null terminator). But it should not crash — if char *buf = "/index.html HTTP/1.1";!
Completed code — stage 1
This is closely based on what was submitted as the program. It compiles cleanly — I've not tried running it.
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/socket.h>
char *buf;
int c, s; int port = 45678;
struct sockaddr_in server, client;
char *ipaddress = "127.0.0.1";
int clientlen = sizeof(client);
int portset = 0;
int recv_m(int c, char *buf);
static
void get(void)
{
printf("in get method\n");
char fileNameBuf[20];
int i = 0;
printf("%s\n", buf);
char *s = buf;
if (*s == '/')
{
printf("buf==/\n");
s++;
while (*s != ' ')
{
// printf("%c\n",*buf);
// printf("in while\n");
fileNameBuf[i] = *s;
s++;
i++;
printf("%d\n", i);
}
fileNameBuf[i]='\0';
printf("<<%s>>\n", fileNameBuf);
}
else
{
printf("!= '/'\n");
}
}
int main(void)
{
bzero(&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(port);
// if (!inet_aton(ipaddress, &server.sin_addr))
// fprintf (stderr, "inet_addr() conversion error\n");
s = socket(AF_INET, SOCK_STREAM, 0); // Create socket
if (!s) {
perror("socket");
exit(0);
}
if (bind(s, (struct sockaddr *) &server, sizeof(server)) < 0) {
perror("bind");
exit(0);
}
printf("binded\n");
if (listen(s, SOMAXCONN) < 0) {
perror("listen");
exit(0);
}
printf("Waiting for connection\n");
while ((c = accept(s, (struct sockaddr *) &client, (socklen_t *) &clientlen)) > 0)
{
// Do whatever a web server does.
printf("got connected\n");
char recv_buf[50];
char el[4] = "\r\n\r\n";
int h = 0; int i = 0;
char *r = recv_buf;
while (recv(c, r, 1, 0) != 0)
{
if (h == 4) break;
if (*r == el[h]) {
h++;
}
r++;
i++;
if (h == 4) break;
}
recv_buf[i] = '\0';
printf("%s\n", recv_buf);
if ( strncmp(recv_buf, "GET ", 4) == 0) {
printf("check get\n");
buf = recv_buf+4;
printf("%s\n", buf);
get();
}
}
return(0);
}
This is not an SSCCE. All the code related to setting up the socket and reading from the socket should be tangential to the problem at hand.
Reduced Code — Stage 2
The reduction process involves eliminating the inessential.
#include <stdio.h>
#include <string.h>
char *buf;
static void get(void)
{
printf("in get method\n");
char fileNameBuf[20];
int i = 0;
printf("%s\n", buf);
char *s = buf;
if (*s == '/')
{
printf("buf==/\n");
s++;
while (*s != ' ')
{
fileNameBuf[i] = *s;
s++;
i++;
printf("%d\n", i);
}
fileNameBuf[i]='\0';
printf("<<%s>>\n", fileNameBuf);
}
else
{
printf("!= '/'\n");
}
}
int main(void)
{
char recv_buf[50];
strcpy(recv_buf, "GET /index.html HTTP/1.1\r\n\r\n");
printf("<<%s>>\n", recv_buf);
if (strncmp(recv_buf, "GET ", 4) == 0)
{
printf("check get\n");
buf = recv_buf+4;
printf("%s\n", buf);
get();
}
return(0);
}
This too compiles cleanly; unfortunately, it also runs successfully for me (GCC 4.8.1, Mac OS X 10.8.4):
<<GET /index.html HTTP/1.1
>>
check get
/index.html HTTP/1.1
in get method
/index.html HTTP/1.1
buf==/
1
2
3
4
5
6
7
8
9
10
<<index.html>>
This happens sometimes; you are too ruthless in your clean-up. So, you have to go back to the previous code and remove things more slowly.
Retrenching — Stage 3
Let's take the full code from Stage 1 and run it locally. The browser can connect to localhost:45678/index.html and the output is:
binded
Waiting for connection
got connected
GET /index.html HTTP/1.1
Host: localhost:45678
check get
/index.html HTTP/1.1
Host: localhost:45678
in get method
/index.html HTTP/1.1
Host: localhost:45678
buf==/
1
2
3
4
5
6
7
8
9
10
<<index.html>>
There is nothing sent back to the waiting browser (it's still waiting, but will time out shortly). The code loops back to the next accept; it isn't clear that it shuts up shop properly, but it didn't crash on the first cycle.
So, this has been a somewhat fruitless exercise...your code seems to work OK. It should still be improved — starting off by making every one of those global variables into a local in main(), and then passing buf to a modified get() with the signature void get(char *buf).
Does the code you showed really crash for you? If so, what does the debugger say about why it crashes?
Bullet-proofing — Stage 4
After establishing that the string pointed to by buf was actually "/index.html\r\n\r\n" and not"/index.html HTTP/1.1\r\n\r\n"`, it is clear that I was remiss in not ensuring that the code would not read past the end of null terminated strings nor write past the ends of buffers. However, this is precisely why an SSCCE is so important, and why diagnostic printing is so important. If the question had included the actual string that was being scanned, it would have been a lot simpler to spot the issue.
This code is more nearly bullet-proof. Amongst other major changes, it attempts to read the request in a single recv() operation, rather than reading the request byte by byte. This puts the onus on avoiding an overflow on recv(). All the global variables are gone; buf is passed to get() as an argument. get() has been written to detect EOS and overlong names, as well as handling names up to the first space. It still has the debug code for each character in the file name. The code in main() has been dolled up to send back a response that is valid HTTP — or valid enough HTTP — with a bit of HTML that changes each time it is handled. It's interesting seeing the requests the browser makes. There's also an error reporting function that writes to standard error, takes a format string and arguments as with printf() et al, and also adds the correct error number and message for the system error, and then exits with a failure status. This makes error reporting less painful; a one-line call suffices for each error, instead of 3 or 4 lines (depending on your choice of formatting). The errors can be more expressive than perror() too.
#include <ctype.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/socket.h>
#include <unistd.h>
static void err_exit(const char *fmt, ...);
static
void get(char *buf)
{
printf("in get method\n");
char fileNameBuf[256];
size_t i = 0;
printf("%s\n", buf);
char *s = buf;
if (*s == '/')
{
printf("buf==/\n");
s++;
while (*s != '\0' && *s != ' ' && i < sizeof(fileNameBuf))
{
printf("i = %3d: c = %3d = 0x%.2X = '%c'\n",
(int)i, *s, *s & 0xFF, isprint(*s) ? *s : '.');
fileNameBuf[i++] = *s++;
}
fileNameBuf[i]='\0';
printf("<<%s>>\n", fileNameBuf);
}
else
{
printf("!= '/'\n");
}
}
int main(void)
{
char *buf;
int fd;
int s;
int port = 45678;
struct sockaddr_in server, client;
int clientlen = sizeof(client);
int msgnum = 314159;
bzero(&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(port);
s = socket(AF_INET, SOCK_STREAM, 0);
if (!s)
err_exit("socket()\n");
if (bind(s, (struct sockaddr *) &server, sizeof(server)) < 0)
err_exit("bind()\n");
printf("bound to address\n");
if (listen(s, SOMAXCONN) < 0)
err_exit("listen()\n");
printf("Waiting for connection\n");
while ((fd = accept(s, (struct sockaddr *) &client, (socklen_t *) &clientlen)) > 0)
{
printf("got connection\n");
char recv_buf[4096];
char el[5] = "\r\n\r\n";
ssize_t length;
/* Read message in one go; leave space for a null at the end */
if ((length = recv(fd, recv_buf, sizeof(recv_buf)-1, 0)) > 0)
{
recv_buf[length] = '\0';
if (strstr(recv_buf, el) == 0)
err_exit("Incomplete message (%d bytes and no CRLF, CRLF pair)\n", length);
printf("%d: <<%s>>\n", (int)length, recv_buf);
if (strncmp(recv_buf, "GET ", 4) == 0)
{
printf("check get\n");
buf = recv_buf + 4;
printf("<<%s>>\n", buf);
get(buf);
char message[256];
char format1[] =
"<html><head><title>Hello World!</title></head>"
"<body><h1>This is no fun at all (%d).</h1></body></html>\r\n\r\n";
int msg_len = snprintf(message, sizeof(message), format1, msgnum++);
char format2[] =
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Content-Length: %d\r\n"
"Content-Encoding: UTF-8\r\n\r\n%s";
char response[1024];
size_t nbytes = snprintf(response, sizeof(response), format2,
msg_len, message);
write(fd, response, nbytes);
}
}
close(fd);
}
return(0);
}
static void err_exit(const char *fmt, ...)
{
int errnum = errno;
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
fprintf(stderr, "%d: %s\n", errnum, strerror(errnum));
exit(1);
}

It appears that buf is a char array. If so, you should access the buf using a char pointer. Try this:
int main () {
char buf[] = "/index.html HTTP/1.0";
char fileNameBuf[10];
int i=0;
char *s = buf;
if (*s=='/') {
s++;
while (*s!=' ') {
fileNameBuf[i]=*s;
*s++;
i++;
printf("%d\n",i);
}
}
}
If buf is an array of char and even though arrays and pointers have several things in common, doing buf++ is not legal by C.Here is a text from Kernighan/Ritchie C book. You have probably buf declared as an array as well.
There is one difference between an array name and a pointer that must be kept in mind. A pointer is a variable, so pa=a and pa++ are legal. But an array name is not a variable; constructions like a=pa and a++ are illegal.
Due to this reason, doing "arr++" would be an error in the following code.
int main() {
int arr[10];
int *ptr = arr;
arr++; // Would be illegal.
ptr++; // This is okay.
}

Related

Problems in client server application when using malloc to allocate buffer

I am working on a project including server-client communication.
Our code doesn't work all the time, sometimes it works perfectly. But sometimes we either get a timeout or our buffer doesn't work properly. Thats why we want to implement malloc(). Do you think this could help?
our code before malloc():
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#define BUFFERSIZE 1024
#define VERSION "VERSION 3.4\n"
#include "functions.h"
char buffer[BUFFERSIZE];
void resetBuffer(char *buffer) {
memset((buffer), '\0', strlen(buffer));
}
void receiveAnswer(int sock) {
resetBuffer(buffer);
size_t length;
bool x = true;
while (x) {
recv(sock, buffer, sizeof(buffer), 0);
length = strlen(buffer);
if (buffer[length-1] == '\n') {
x = false;
}
}
if (buffer[0] == '-') {
printf("Error: %s", buffer);
} else {
printf("%s\n ", buffer);
}
}
void sendResponse(int sock, char *message) {
resetBuffer(buffer);
strcpy(buffer, message);
bool x = true;
size_t length;
while(x) {
send(sock, buffer, strlen(buffer), 0);
length = strlen(buffer);
if (buffer[length - 1] == '\n') {
x = false;
}
}
printf("Client: %s\n", buffer);
}
int performConnection(int sock, char *gameID) {
receiveAnswer(sock);
sleep(1);
receiveAnswer(sock);
sleep(1);
sendResponse(sock, VERSION);
sleep(1);
receiveAnswer(sock);
sleep(1);
sendResponse(sock, gameID);
sleep(1);
receiveAnswer(sock);
sleep(1);
sendResponse(sock, "PLAYER \n");
sleep(1);
receiveAnswer(sock);
resetBuffer(buffer);
return 0;
}
Our code with malloc() doesn't work at all anymore:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#define BUFFERSIZE 1024
#define VERSION "VERSION 3.4\n"
#include "functions.h"
char *buffer;
void resetBuffer(char *buffer) {
memset((buffer), '\0', strlen(buffer));
}
void receiveAnswer(int sock) {
resetBuffer(buffer);
size_t length;
bool x = true;
while (x) {
recv(sock, buffer, sizeof(buffer), 0);
length = strlen(buffer);
if (buffer[length-1] == '\n') {
x = false;
}
}
if (buffer[0] == '-') {
printf("Error: %s", buffer);
} else {
printf("%s\n ", buffer);
}
}
void sendResponse(int sock, char *message) {
resetBuffer(buffer);
strcpy(buffer, message);
bool x = true;
size_t length;
while (x) {
send(sock, buffer, strlen(buffer), 0);
length = strlen(buffer);
if (buffer[length - 1] == '\n') {
x = false;
}
}
printf("Client: %s\n", buffer);
}
int performConnection(int sock, char *gameID) {
buffer = (char *)malloc(sizeof(char) * BUFFERSIZE);
receiveAnswer(sock);
sleep(1);
receiveAnswer(sock);
sleep(1);
sendResponse(sock, VERSION);
sleep(1);
receiveAnswer(sock);
sleep(1);
sendResponse(sock, gameID);
sleep(1);
receiveAnswer(sock);
sleep(1);
sendResponse(sock, "PLAYER \n");
sleep(1);
receiveAnswer(sock);
resetBuffer(buffer);
free(buffer);
return 0;
}
Any help is appreciated!
Best Enno
resetBuffer(buffer); fails as it attempts strlen(buffer) on uninitialized data. This invokes undefined behavior (UB) as strlen() expects a pointer to a string.
Instead:
// resetBuffer(buffer);
memset(buffer, 0, sizeof(char)* BUFFERSIZE);
// or simply
memset(buffer, 0, BUFFERSIZE);
this
void resetBuffer(char* buffer){
memset((buffer), '\0', strlen(buffer));
}
is undefined behavior. It depends of the previous contents of buffer (strlen looks for 0 terminator)
you need to pass in a length (not got from strlen)
Why are you bothering with the function reset_buffer() at all?
Each invocation appears immediately ahead of, for instance, strcpy(). The latter doesn't care if the buffer has be "reset". (Hopefully the buffer is large enough to hold what is being put into it.)
The last invocation appears immediately ahead of free(). Again, the content of the buffer is irrelevant.
More of a worry is that buffer[] has become *buffer... The sizeof(buffer) in the receive function is now telling recv there are 8 bytes available (the size of a pointer on your machine) to be filled, not the 1024 bytes of the "pre-malloc" version.
Change:
void receiveAnswer (int sock){
// ...
recv(sock, buffer, sizeof(buffer), 0);
to
recv(sock, buffer, BUFFERSIZE, 0);
This is not a MRE, so this "fix", while correct, may not be the entire solution.
buffer does not necessarily contain a proper C string, hence using strlen to compute the number of bytes received is incorrect: use the return value of recv instead. Similarly, the buffer clearing function should either get the length as an argument or use BUFFER_SIZE.
Whether buffer is defined as a global array of bytes or allocated from the heap before use does not matter, and your code has nothing to do with implementing the malloc function.

linux TCP multiclient echo server in c

I am currently studying TCP multiclient echo server and client using fork, thread, multiplexing IO and so on.
Below are the simple server and client using fork().
server_fork.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <arpa/inet.h>
static const int BUFSIZE = 1024;
int readn(int fd, char *buf, short n);
int main(void)
{
int cnt = 0;
int listenFD, connectFD;
struct sockaddr_in listenSocket, connectSocket;
char buffer [BUFSIZE];
if ((listenFD = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket() error\n");
exit(0);
}
if (setsockopt(listenFD, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int)) < 0) {
perror("sockopt error\n");
exit(0);
}
memset(&listenSocket, 0, sizeof(listenSocket));
listenSocket.sin_family = AF_INET;
listenSocket.sin_addr.s_addr = inet_addr("0.0.0.0");
listenSocket.sin_port = htons(7777);
if (bind(listenFD, (struct sockaddr *)&listenSocket, sizeof(listenSocket)) < 0) {
perror("bind() error\n");
exit(0);
}
if (listen(listenFD, 1) < 0) {
perror("listen() error\n");
exit(0);
}
signal(SIGCHLD, SIG_IGN);
int connectSocketLen;
short readLen;
pid_t pid;
while (1) {
connectSocketLen = sizeof(connectSocket);
if ((connectFD = accept(listenFD, (struct sockaddr *)&connectSocket,
&connectSocketLen)) < 0) {
perror("accept() error\n");
exit(0);
}
pid = fork();
cnt++;
if (pid == 0) {
close(listenFD);
while (1) {
memset(buffer, 0, BUFSIZE);
if (readn(connectFD, buffer, 2) == 0) {
break;
}
readLen = (*(short *)&buffer);
if(readLen != 12)
printf("[%d] : %d\n", cnt, readLen);
if (readn(connectFD, buffer, readLen) == 0) {
break;
}
buffer[readLen] = 0;
int n;
if ((n = write(connectFD, buffer, readLen)) <= 0) {
perror("!!");
}
sleep(0);
}
close(connectFD);
exit(0);
}
else if (pid > 0) {
close(connectFD);
}
else {
perror("fork() error\n");
exit(0);
}
}
close(listenFD);
return 0;
}
int readn(int fd, char *buf, short n)
{
short sp = 0, readed;
while (n) {
readed = read(fd, buf + sp, n);
if (readed <= 0) {
return 0;
}
n -= readed;
sp += readed;
}
return 1;
}
client.c
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
static const int bufSize = 1024;
int main(int argc,char *argv[])
{
signal(SIGCHLD, SIG_IGN);
fork();
fork();
fork();
fork();
fork();
fork();
fork();
fork();
//fork();
//fork();
char length[2], recvBuf[bufSize];
char buf[]="hello, world\0";
short len = strlen(buf);
sprintf(length,"%c",len);
int client_sockfd, size, i, n, state;
uint64_t delta_us = 0;
struct sockaddr_in server_addr;
struct timespec start, end;
client_sockfd = socket(PF_INET, SOCK_STREAM, 0);
memset(&server_addr, 0, sizeof server_addr);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(7777);
inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr.s_addr);
state = connect(client_sockfd, (struct sockaddr *)&server_addr,
sizeof server_addr);
if (state < 0) {
perror("connect err");
exit(1);
}
for (i=0;i<10;i++) {
clock_gettime(CLOCK_MONOTONIC_RAW, &start);
n = write(client_sockfd, length, sizeof length);
if (n<=0) {
perror("write err");
exit(1);
}
n = write(client_sockfd, buf, *((short *)&length));
if (n<=0) {
perror("write err");
exit(1);
}
n = read(client_sockfd, recvBuf, *((short *)&length));
if (n<=0) {
perror("read err");
exit(1);
}
clock_gettime(CLOCK_MONOTONIC_RAW, &end);
delta_us += (end.tv_sec - start.tv_sec) * 1000000 +
(end.tv_nsec - start.tv_nsec)/1000;
printf("%lu\n", delta_us);
sleep(1);
}
return 0;
}
The client first transmits the length of the message represented by 2 bytes.
Then client sends a "hello, world" message to the server in buf.
The server first reads 2 bytes through readn () and reads the message as much.
But in all cases (fork, thread, multiplexing IO... whatever), I have a common difficulty.
The problem is that : In the above source code, the length of the message("hello, world" is 12. so it is expected to read 12 in the first readn () of the server.
In fact, when the number of clients is small (the number of forks on the client is 7 or less), it works fine.
However, if the number of clients increases, the value of readLen will be 25960 on some connections. 25960 is the value that represents "he" in hex.
Why is this problem happening when there are many clients?
I wonder if it is the same as sending a TCP packet at one time and dividing it two times.
Below is a tcpdump capture of the above problem situation.
I'm sorry that I could not upload the image right away.
tcpdump
On the client side, you have multiple problems surrounding how you send the message length. Starting here:
char length[2], recvBuf[bufSize];
char buf[]="hello, world\0";
short len = strlen(buf);
sprintf(length,"%c",len);
Your sprintf format promises that the third argument will be of type char (promoted to int), and instructs it to output the corresponding character into the string. In fact, the argument is a short (promoted to int), and this mismatch produces undefined behavior.
In practice, the overall sprintf call is probably equivalent to this:
length[0] = (char)(int)len;
length[1] = '\0';
That has implementation-defined characteristics if char is a signed type, but in any event, it cannot capture a length greater than the maximum value that can be represented by an unsigned char.
The client goes on to do this:
n = write(client_sockfd, length, sizeof length);
That's not inherently wrong, but it does fail to accommodate the possibility of a short write. Moreover, the server does not interpret this part of the message in a manner consistent with the way it was prepared:
if (readn(connectFD, buffer, 2) == 0) {
break;
}
readLen = (*(short *)&buffer);
As it turns out, that combination might happen to work if the server uses a 16-bit, little-endian representation for type short (subject to the restriction I already described on representable message length) and an execution character set compatible with the client's, but those are not safe assumptions for network software in general.
In part, you seem to be missing an important point about read() and write() and char pointers: a char * can be used to read the representation of an object of any type, so you do not need to move your data into a char array in order to send or receive it.
Overall, this would be a more appropriate approach:
// Client:
uint16_t len = strlen(buf); // risk: buf may be too long
uint16_t len_n = htons(len);
int n = writen(client_sockfd, &len_n, 2); // a write() analog of readn()
// ... handle possible error ...
// Sever:
uint16_t len_n;
int n = readn(connectFD, &len_n, 2);
// ... possible handle error ...
uint16_t readLen = ntohs(len_n);
Note that there is no need to copy the length into a separate char array to send it, nor to receive it into a char array. On the other hand, note also the use of a specified-size data type (uint16_t) on both sides, and the use of htons() and ntohs() to ensure that the client and server interpret the bytes of the data the same way. Furthermore, note the use of a write analog of readn() to send the data, which otherwise could be sent incompletely.
By the same token the client and server should both use the (hypothetical) writen() function to send the text of the message, and just like the server, the client should use readn() to read it. Failing to account for the possibility of short reads and writes is a significant flaw, especially in a protocol such as yours whose message boundaries are not easily distinguishable from data. An unnoticed short read or write will cause your client and server to fall out of sync, with no easy way to recover.
Apart from the problems already noticed by #JohnBollinger, you only use a listen window of 1 in server.c when all your forked client processes try to connect at the same time. It caused plenty of connect : conn reset by peer errors in my tests. I had to use a window greater than 64 on my FreeBSD (no errors at 256) to get rid of them :
if (listen(listenFD, 256) < 0) {
perror("listen() error\n");
exit(0);
}

UDP server not responding to client

Working on a program that is meant to emulate data layers in networking. I've got messages coming through to the server correctly, however, the client is not receiving the ACK frame from the server. This is causing my program to wait endlessly. Any help in fixing the matter is appreciated.
Sender
#include <stdio.h>
#include <unistd.h>
#define MAXFRAME 97
main(int argc, char* argv[]){
char *frame;
int len = 0;
int c;
dlinits("spirit.cba.csuohio.edu", 43525);
frame = malloc(MAXFRAME);
FILE *file = fopen(argv[1], "r");
if (file == NULL)
return NULL;
while ((c = fgetc(file)) != EOF)
{
if(len == (MAXFRAME-1)){
dlsend(frame, len, 0);
len = 0;
memset(frame,0,strlen(frame));
}
frame[len++] = (char) c;
}
dlsend(frame, len, 1);
}
Receiver
#include <string.h>
#include <unistd.h>
char* dlrecv();
main(){
char* test[100];
dlinitr(43525);
while(1){
strcpy(test,dlrecv());
printf("%s\n", test);
}
}
Data Layer
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define BUFMAX 100
static int sk;
static struct sockaddr_in remote;
static struct sockaddr_in local;
static int fnum = 0;
static expFra = 0x00;
dlinits(char* host, int port){//initialize sender
struct hostent *hp;
sk = socket(AF_INET, SOCK_DGRAM, 0);
remote.sin_family = AF_INET;
hp = gethostbyname(host);
if (hp == NULL){
printf("Can't find host name\n");
exit(1);
}
bcopy(hp->h_addr,&remote.sin_addr.s_addr,hp->h_length);
remote.sin_port = ntohs(port);
}
dlinitr(int port){//initialize receiver
int rlen = sizeof(remote);
int len = sizeof(local);
char buf[BUFMAX];
sk = socket(AF_INET,SOCK_DGRAM,0);
local.sin_family = AF_INET;
local.sin_addr.s_addr = INADDR_ANY;
local.sin_port = htons(port);
bind (sk, &local,sizeof(local));
getsockname(sk,&local,&len);
}
dlsend(char* msg, int len, int end){//send data
int header = 0x00;
int result;
char *ackframe = malloc(3);
unsigned char *nmsg;
nmsg = malloc(100);
if ((fnum%2) == 1){
header = header|0x02;
}
if (end == 1){
header = header|0x40;
}
header = header^0xff;
printf("%x\n %x\n", header, 0);
nmsg[0] = (char)header;
len++;
printf("%s\n", nmsg);
memcpy(nmsg + 1, msg, strlen(msg));
result = crc(nmsg, len);
nmsg[len++] = ((result >> 8) & 0xff);
nmsg[len++] = (result & 0xff);
printf("%s\n", nmsg);
sendto(sk,nmsg,len,0,&remote,sizeof(remote));
read(sk,ackframe,3);
printf("Ack Received: %s\n", ackframe);
fnum++;
}
char* dlrecv(){//receive data
int result;
int header;
int ACK = 1;
char alen = 1;
char *ackframe = malloc(3);
unsigned char* msg = malloc(100);
while (ACK){
recvfrom(sk,msg,BUFMAX,0,&remote,sizeof(remote));
int len = strlen(msg);
result = crc(msg, len);
if (result == 0){
msg[--len] = 0;
msg[--len] = 0;
header = msg[0];
printf("Header %x expFra %x\n", header, expFra);
header = header^0xff;
printf("Header %x expFra %x\n", header, expFra);
if ((header<<4) == (expFra<<4)){
expFra = expFra^0x02;
ackframe[0] = (0x10|header);
result = crc(ackframe, alen);
ackframe[alen++] = ((result >> 8) & 0xff);
ackframe[alen++] = (result & 0xff);
sendto(sk,ackframe,strlen(ackframe),0,&remote,sizeof(remote));
printf("Ack Sent: %s\n", ackframe);
ACK = 0;
}
}
}
printf("%s\n", msg);
return ++msg;
}
EDIT for the moment these are working on the same machine.
EDIT I ran a check using errno, which returned error 22 for the sendto inside of dlrecv.
My experience with UDP has been that read() (which you're using at the end of your dlsend()) is very hit-or-miss, especially when paired with sendto(). Unless there's a good reason not to do it, changing read() to recvfrom() should fix the problem.
Your code also throws a lot of warnings for mismatched types. They're kinda-sorta harmless, but make tracking anything else down more complicated.
After that, the final acknowledgment-sendto() is using bad socket data. Poking around, the reason is that you're passing an integer in (sizeof(remote)) as a pointer to the address's size in the previous recvfrom() call. If the initial size given is too small, recvfrom() produces unreliable results. If it needs less space than that, it'll change that value to tell you what it used.
So, you need to declare a integer initialized to the size of a sockaddr_in structure, and pass a pointer to it as that last parameter. With those changes, assuming the server arrives at the sendto() function (your sample only has it under a single conditional branch), you'll get the right values for the address and will be able to send the acknowledgment.
The big lessons learned should be (a) make sure all the types are correct and review every warning and (b) check the return value of every socket call and print the error if you get a -1 back.

Why am i getting "direct://" as output for my program?

I am in the early stages of writing a proxy server in c for class and while debugging, my program gives me a weird output simpley with two lines of
direct://
direct://
what does this mean? I've never had this happen before. The program even outputs this when i dont provide 3 arguments which i required for this program to execute.
#include <pthread.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <time.h>
#include <string.h>
int main (int argc, char *argv[]){
if(argc!=3){
printf("Usage: proxy <IP address> <port no.>");
exit(1);
}
int csock, ssock, clen, slen;
int csocka, ssocka;
int rc, fd, ttl;
char method[40];
char uri[80];
char prot[40];
char cbuf[100];
time_t logtime;
char * pch;
struct sockaddr_in caddr;
struct sockaddr_in caddr2;
struct sockaddr_in saddr;
struct sockaddr_in saddr2;
csock = socket(AF_INET, SOCK_STREAM, 0);
caddr.sin_family = AF_INET;
caddr.sin_addr.s_addr = inet_addr(argv[1]);
caddr.sin_port = htons(atoi(argv[2]));
clen = sizeof(caddr);
rc = bind(csock, (struct sockaddr *) &caddr, clen);
if(rc < 0){
printf("bind failed");
exit(1);
}
rc = listen(csock, 5);
if(rc < 0){
printf("listen failed");
exit(1);
}
printf("hey");
csocka = accept(csock, (struct sockaddr *) &caddr2, &clen);
if(csocka < 0){
printf("accept failed");
exit(1);
}
while(1){
read(csocka,&cbuf,sizeof(cbuf));
time(&logtime); //time of req.
if(cbuf==NULL){
cerror("400 Bad Request: empty request");
write(csocka, &errbuf, sizeof(errbuf));
continue;
}
ttl = strlen(cbuf);
while(cbuf[ttl-1] == '\n' || cbuf[ttl-1] == '\r'){
cbuf[ttl--] = '\0';
}
if(sscanf(cbuf,"%[^ ] %[^ ] %[^ ]", method, uri, prot) != 3){
cerror("400 Bad Request: Unexpected number of arguments");
write(csocka, &errbuf, sizeof(errbuf));
continue;
}
if(method!="GET" || method !="HEAD"){
cerror("405 Method Not Allowed: GET/HEAD only");
write(csocka, &errbuf, sizeof(errbuf));
continue;
}
if(uri == (char*) 0){
cerror("400 Bad Request: empty url");
write(csocka, &errbuf, sizeof(errbuf));
continue;
}
printf("%s \n", cbuf);
}
close(csocka);
}
The most probable reason is that you aren't running your program, but some system program.
If you are on a Linux machine, type:
which <program name>
to find out which executable you are actually running.
type:
./<program name>
to run your program instead (provided that you are in the same directory as your executable).
Why are you ignoring the return value of read? What makes you think read is null-terminating cbuf for you? If read isn't null terminating cbuf, then what makes you think it's safe to pass buf to strlen? You're invoking undefined behaviour by passing something that isn't a string to strlen... The behaviour that follows may seem strange or inconsistent, but that's the nature of undefined behaviour.
int len = read(csocka,&cbuf,sizeof(cbuf));
if (len <= 0) {
/* something went wrong in read().
* report an error and stop here... */
break;
}
/* Once error checking is performed, len is the number of bytes recieved by read. */
Consider the code above. Do you need the line ttl=strlen(cbuf);, if you correctly check for errors?
printf("%s \n", cbuf); is wrong, because cbuf isn't a string. Consider fwrite(cbuf, len, stdout); putchar('\n'); or printf("%.*s\n", len, stdout);.
write(csocka, &errbuf, sizeof(errbuf)); also looks wrong, but I'll leave that in your hands. If you need us to fix these kinds of errors for you, then your method of learning isn't working very well. Which book are you reading?

Transmission of audio file using c sockets

I am trying to send audio file from one computer to other using socket programming in c. When I send simple string without any framing information such as header or tailer it gets sent perfectly. But when I try to send the same information with some header information like size of the socket_data or packet_no. it doesn't get sent properly. Even the terminal output is SAME on both the machines but the file which gets created is totally different and unplayable. I have used serializing concept to send packet. Am attaching codes. Please comment whats going wrong.
Server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
void set_socket(struct sockaddr_in *socket, int type, int host_short, int addr_type)
{
socket -> sin_family = type;
socket -> sin_port = htons(host_short);
socket -> sin_addr.s_addr = htonl(addr_type);
}
void serialize(char *buffer, int count, char *data)
{
int i=0, j=0;
char temp1[20];
sprintf(temp1, "%d", count);
while(temp1[i] != '\0')
{
buffer[j++] = temp1[i++];
}
buffer[j++]=' ';
for(i=0; data[i] != '\0'; i++)
{
buffer[j++] = data[i];
}
buffer[j] = '\0';
printf("BUFFER =%ld\n", sizeof(buffer));
}
int main()
{
int sid = 0, bid = 0, fp;
char *send_data = (char *)malloc(1024*sizeof(char));
char temp[1024];
char *receive_data = (char *)malloc(1024*sizeof(char));
int fd, count, cnt=0;
struct sockaddr_in server_socket, client_socket;
int size = sizeof(client_socket);
if((sid = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
{
printf("Connection error..\n");
exit(1);
}
set_socket(&server_socket, AF_INET, 6000, INADDR_ANY);
if((bid = bind(sid, (struct sockaddr *)&server_socket, sizeof(struct sockaddr))) == -1)
{
printf("Binding error..\n");
exit(1);
}
printf("I am waiting for client..\n");
recvfrom(sid, receive_data, 1024, 0,(struct sockaddr *)&client_socket, &size);
printf("received data is : %s\n", receive_data);
fd = open(receive_data, O_RDONLY);
printf("size = %ld\n", sizeof(send_data));
while((count=read(fd, temp, 500)) != 0)
{
printf("I am inside the loop : %d\n", cnt++);
serialize(send_data, count, temp);
printf("Serialized : %s\n", send_data);
sendto(sid, send_data, 1024, 0, (struct sockaddr *)&client_socket, size);
}
printf("I am outside the loop : %d\n", count);
strcpy(temp, "ENDOFFILE");
serialize(send_data, sizeof(temp), temp);
sendto(sid, send_data, 1024, 0, (struct sockaddr *)&client_socket, size);
fcloseall();
close(sid);
close(fd);
return 0;
}
Client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
void set_socket(struct sockaddr_in *socket, int type, int host_short)
{
socket -> sin_family = type;
socket -> sin_port = htons(host_short);
}
void deserialize(char *buffer, int *size, char *data)
{
int i=0, j=0;
char temp1[20];
while(buffer[i] != ' ')
{
temp1[j++] = buffer[i++];
}
temp1[j] = '\0';
printf("\nINT : %s\n", temp1);
*size = atoi(temp1);
i++;
j=0;
while(buffer[i] != '\0')
{
data[j++] = buffer[i++];
}
data[j++] = '\0';
}
int main()
{
int sid = 0, bid = 0, con = 0;
char *send_data = (char *)malloc(1024*sizeof(char));
char *receive_data = (char *)malloc(1024*sizeof(char));
char *temp = (char *)malloc(1024*sizeof(char));
struct hostent *host;
struct sockaddr_in server_socket;
int size = sizeof(server_socket);
if((sid = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
{
printf("Connection error at client side..\n");
exit(1);
}
set_socket(&server_socket, AF_INET, 6000);
if (inet_aton("127.0.0.1", &server_socket.sin_addr)==0)
{
fprintf(stderr, "inet_aton() failed\n");
exit(1);
}
printf("Enter the name of the file you want to see : ");
scanf("%s", send_data);
int fd = open("sanket.mp3", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IXUSR);
sendto(sid, send_data, 1024, 0, (struct sockaddr *)&server_socket, size);
printf("================= Contents of the File =====================\n");
while(1)
{
int size;
recvfrom(sid, temp, 1024, 0, (struct sockaddr *)&server_socket, &size);
printf("Deserialize it : %s\n",temp);
deserialize(temp, &size, receive_data);
if(!strcmp(receive_data, "ENDOFFILE"))
{
printf("============================================================\n");
break;
}
else
write(fd, receive_data, size);
}
fcloseall();
close(sid);
return 0;
}
When I checked the size of the sent and received file, sizes are same but the contents are different, thus I am unable to play received audio file.
You seem to be reading from a binary data-file, yet inside your serialize function you are treating the data as-if it were null-terminated string data. For instance, this loop inside serialize:
for(i=0; data[i] != '\0'; i++)
{
buffer[j++] = data[i];
}
will terminate on the first zero-value it encounters. If this is true binary data from your audio file though, then I'm sure you'll get 0 values that are actual audio data rather than indicating the end of the buffer. Instead of terminating on a NULL-value, you should be terminating on the size of the buffer that you're passing to serialize that was read in your call to read in the while-loop. That way you can be sure you are getting all the data that was read from your read call packed into your send-buffer.
Secondly, printing sizeof(buffer), when buffer is a pointer, will only print the size of a pointer-type, not the size of the actual buffer the pointer is pointing to. Again, you're going to have to explicitly pass that value to your serialize function.
Third, you're terminating the buffer with a null-value ... again, that's not going to be a good idea based on the first point about this being raw binary data and not null-terminated strings. You should either come up with some type of string to indicate the end-of-transmission in the buffer that would be a set of values that would be impossible to be part of the data, or you should explicitly read the number of bytes that are in the "count" that you've embedded in the packet data.
Finally, you're not really serializing your data ... the concept of serializing typically means to transfer the data in a platform-independent way. You're simply packing up the bytes read and sending them across the network, assuming that the receiving side has the same endianness, etc. A fairly simple serialization approach would do something like creating ASCII strings from all the data-values, with the downside that this will create quite a bit of data-bloat. There are other cross-platform standards for serialized data such as JSON, SOAP, etc.

Resources