What is wrong with my handle_clients function - c

Fairly new to socket programming, so here goes my question. What is wrong? What my function does, is take input from the telnet session and then when you press 'enter' it should go break the while loop. But it doesn't for some reason. I can't figure out why either, I've tried various ways but, nothing I've tried thus far worked yet.
void handle_clients(socket,address)
int *socket;
const char *address;
{
char msg[256];
char cmd[128];
int bytes;
memset(msg,0,sizeof(msg));
memset(cmd,0,sizeof(cmd));
while(1) {
send(*socket,"CMD >> ",7,0);
bytes = 0;
while((bytes = recv(*socket,cmd,sizeof(cmd),0)) > 0) {
if(bytes < 0) {
sprintf(msg,"Error: receiving from %s.\r\n",
address);
send(*socket,msg,strlen(msg),0);
break;
}
if(cmd[bytes] == 10 || cmd[bytes] == 13) {
break;
}
}
if(strcmp(cmd,"exit") == 0) {
break;
} else if(strcmp(cmd,"help") == 0) {
sprintf(msg,"Commands: [exit,cmd,help]\r\n");
send(*socket,msg,strlen(msg),0);
} else if(strcmp(cmd,"cmd") == 0) {
memset(cmd,0,sizeof(cmd));
send(*socket,"Enter command: ",15,0);
bytes = 0;
while((bytes = recv(*socket,cmd,sizeof(cmd),0)) > 0) {
if(bytes < 0) {
sprintf(msg,"Error: receiving from %s.\r\n",
address);
send(*socket,msg,strlen(msg),0);
break;
}
if(cmd[bytes] == 10 || cmd[bytes] == 13) {
break;
}
}
system(cmd);
} else {
sprintf(msg,"Unknown command.\r\n");
send(*socket,msg,strlen(msg),0);
}
memset(msg,0,sizeof(msg));
memset(cmd,0,sizeof(cmd));
}
}

it should go break the while loop. But it doesn't for some reason.
In addition to the issues pointed out by my peers, I think the answer to your specific inquiry lies in the nested while loops and the missing \r\n chars from the strcmp.
Since the while loops are nested, than break might break the nested loop while the container loop remains - so you're back in the next nested loop in your next iteration.
For example:
while(1) {
send(*socket,"CMD >> ",7,0);
bytes = 0;
while((bytes = recv(*socket,cmd,sizeof(cmd),0))) {
if(bytes < 0) {
sprintf(msg,"Error: receiving from %s.\r\n",
address);
send(*socket,msg,strlen(msg),0);
break; /* <= WHICH LOOP ARE WE BREAKING? */
}
if(cmd[bytes] == 10 || cmd[bytes] == 13) {
break; /* <= WHICH LOOP ARE WE BREAKING? */
}
}
// ...
}
This is one of those cases where goto might be your friend...
...although I do think there are better and more elegant solutions and changes that might be required to your code before you go there.
Also, What's the point of re-reading the data, if you're overwriting the existing buffer?
I find it almost (in this case) more convenient and likely to ignore the possible case of incomplete TCP/IP packets/commands.
In this specific case, it seems okay to assume that if the command doesn't end with a new line, something is wrong and we can disconnect. Such short commands should pass in a single TCP/IP packet. i.e.:
while(1) {
send(*socket,"CMD >> ",7,0);
bytes = 0;
bytes = recv(*socket,cmd,sizeof(cmd),0);
if(!bytes) { // closed by peer
close(*socket);
return;
}
if(bytes < 0 || cmd[bytes-1] == 10 || cmd[bytes-1] == 13) {
if(errno == EINTR)
continue;
sprintf(msg,"Error: receiving from %s.\r\n",
address);
close(*socket);
return;
}
if(strcmp(cmd,"exit\r\n") == 0) {
break;
} else if(strcmp(cmd,"help\r\n") == 0) {}
// ...
}
This code obviously ignores the possibility of multiple commands being read in a single recv (i.e., the buffer being "help\r\ncmd\r\nX\r\nexit\r\n")... but you'll solve that at some point.

This has a logic problem:
while((bytes = recv(*socket,cmd,sizeof(cmd),0)) > 0) {
if(bytes < 0) {
}
}
bytes will be always greater than zero so the if(bytes<0){} block will never
execute.
You may want to change it to
while((bytes = recv(*socket,cmd,sizeof(cmd),0))) {
if(bytes < 0) {
}
}
If bytes equals to zero, it will not enter while loop.

Related

C HTTP Client Strip Headers from Response

So, I'm writing this simple HTTP client in C and I seem to be stuck on this problem - how do I strip the HTTP headers from the response? After all, if I get a binary file I can't just write the headers out to my output file. I can't seem to go in once the data is already written to a file because linux screams when you try to even view the first few lines of a binary file, even if you know they're just text HTTP headers.
Now, here's the rub (well, I suppose the whole thing is a rub). Sometimes the whole header doesn't even in come in on the first response packet, so I can't even guarantee that we'll have the whole header in our first iteration (that is, iteration of receiving an HTTP response. We're using recv(), here), which means I need to somehow... well, I don't even know. I can't seem to mess with the data once it's already written to disk, so I need to deal with it as it's coming in, but we can't be sure how it's going to come in, and even if we were sure, strtok() is a nightmare to use.
I guess I'm just hoping someone out there has a better idea. Here's the relevant code. This is really stripped down, I'm going for MCVE, of course. Also, you can just assume that socket_file_descriptor is already instantiated and get_request contains the text of our GET request. Here is it:
FILE* fp = fopen("output", "wb"); // Open the file for writing
char buf[MAXDATASIZE]; // The buffer
size_t numbytes; // For the size of the response
/*
* Do all the socket programming stuff to get the socket file descriptor that we need
* ...
* ...
*/
send(socket_file_descriptor, get_request, strlen(get_request), 0); // Send the HTTP GET request
while ((numbytes = recv(socket_file_descriptor, buf, MAXDATASIZE - 1, 0)) > 0) {
/* I either need to do something here, to deal with getting rid of the headers before writing to file */
fwrite(buf, 1, numbytes, fp); // Write to file
memset(buf, 0, MAXDATASIZE); // This just resets the buffer to make room for the next packet
}
close(s);
fclose(fp);
/* Or I need to do something here, to strip the file of its headers after it's been written to disk */
So, I thought about doing something like this. The only thing we know for sure is that the header is going to end in \r\n\r\n (two carriage returns). So we can use that. This doesn't really work, but hopefully you can figure out where I'm trying to go with it (comments from above removed):
FILE* fp = fopen("output", "wb");
char buf[MAXDATASIZE];
size_t numbytes;
int header_found = 0; // Add a flag, here
/* ...
* ...
*/
send(socket_file_descriptor, get_request, strlen(get_request), 0);
while ((numbytes = recv(socket_file_descriptor, buf, MAXDATASIZE - 1, 0)) > 0) {
if (header_found == 1) { // So this won't happen our first pass through
fwrite(buf, 1, numbytes, fp);
memset(buf, 0, MAXDATASIZE);
}
else { // This will happen our first pass through, maybe our second or third, the header doesn't always come in in full on the first packet
/* And this is where I'm stuck.
* I'm thinking about using strtok() to parse through the lines, but....
* well I just can't figure it out. I'm hoping someone can at least point
* me in the right direction.
*
* The point here would be to somehow determine when we've seen two carriage returns
* in a row and then mark header_found as 1. But even if we DID manage to find the
* two carriage returns, we still need to write the remaining data from this packet to
* the file before moving on to the next iteration, but WITHOUT including the
* header information.
*/
}
}
close(s);
fclose(fp);
I've been staring at this code for three days straight and am slowly losing my mind, so I really appreciate any insight anyone is able to provide. To generalize the problem, I guess this really comes down to me just not understanding how to do text parsing in C.
The second self-answer is better than the first one, but it still could be made much simpler:
const char* pattern = "\r\n\r\n";
const char* patp = pattern;
while ((numbytes = recv(socket_file_descriptor, buf, MAXDATASIZE - 1, 0)) > 0) {
for (int i = 0; i < numbytes; i++) {
if (*patp == 0) {
fwrite(buf + i, 1, numbytes - i, fp);
break;
}
else if (buf[i] == *patp) ++patp;
else patp = pattern;
}
/* This memset isn't really necessary */
memset(buf, 0, MAXDATASIZE);
}
That looks like a general solution, but it's not really: there are values for pattern for which it might fail to see a terminator under particular circumstances. But this particular pattern is not problematic. You might want to think about what sort of pattern would cause a problem before taking a look at the more general solution.
So, I know this is not the most elegant way to go about this, but... I did get it. For anyone who finds this question and is curious about at least an answer, here it is:
int count = 0;
int firstr_found = 0;
int firstn_found = 0;
int secondr_found = 0;
int secondn_found = 0;
FILE* fp = fopen("output", "wb");
char buf[MAXDATASIZE];
size_t numbytes;
int header_found = 0;
/* ...
* ...
*/
send(socket_file_descriptor, get_request, strlen(get_request), 0);
while ((numbytes = recv(socket_file_descriptor, buf, MAXDATASIZE - 1, 0)) > 0) {
if (header_found == 1) {
fwrite(buf, 1, numbytes, fp);
}
else {
// These buf[i]'s are going to return as integers (ASCII)
// \r is 13 and \n is 10, so we're looking for 13 10 13 10
// This also needs to be agnostic of which packet # we're on; sometimes the header is split up.
for (int i = 0; i < numbytes; i++) {
if (firstr_found == 1 && firstn_found == 1 && secondr_found == 1 && secondn_found == 1) { // WE FOUND IT!
header_found = 1;
// We want to skip the parts of the buffer we've already looked at, that's header, and our numbytes will be decreased by that many
fwrite(buf + i, 1, numbytes - i, fp);
break;
}
if (buf[i] == 13 && firstr_found == 0) { // We found our first \r, mark it and move on to next iteration
firstr_found = 1;
continue;
}
if (buf[i] == 10 && firstr_found == 1 && firstn_found == 0) { // We found our first \n, mark it and move on
firstn_found = 1;
continue;
}
else if (buf[i] != 13 && buf[i] != 10) { // Think about the second r, it'll ignore the first if, but fail on the second if, but we don't want to jump into this else block
firstr_found = 0;
firstn_found = 0;
continue;
}
if (buf[i] == 13 && firstr_found == 1 && firstn_found == 1 && secondr_found == 0) {
secondr_found = 1;
continue;
}
else if (buf[i] != 10) {
firstr_found = 0;
firstn_found = 0;
secondr_found = 0;
continue;
}
if(buf[i] == 10 && firstr_found == 1 && firstn_found == 1 && secondr_found == 1 && secondn_found == 0) {
secondn_found = 1;
continue;
}
}
}
memset(buf, 0, MAXDATASIZE);
count++;
}
close(s);
fclose(fp);
Adding another answer because, well I suppose I think I'm clever. Thanks to #tadman for the idea of a counter. Look here (I'm going to shave off a lot of the bloat and just do the while loop, if you've looked at my other code blocks you should be able to see what I mean here) ...
/* ...
* ...
*/
int consec_success = 0;
while ((numbytes = recv(socket_file_descriptor, buf, MAXDATASIZE - 1, 0)) > 0) {
if (header_found == 1) {
fwrite(buf, 1, numbytes, fp);
}
else {
for (int i = 0; i < numbytes; i++) {
if (consec_success == 4) {
header_found = 1;
fwrite(buf + i, 1, numbytes - i, fp);
break;
}
if (buf[i] == 13 && consec_success % 2 == 0) {
consec_success++;
}
else if (buf[i] == 10 && consec_success % 2 == 1) {
consec_success++;
}
else {
consec_success = 0;
}
}
}
memset(buf, 0, MAXDATASIZE);
}
/* ...
* ...
*/

NCurses chat misbehaving, blocking in select

I wrote a C application for a socialization network and also a simple room-based chat. I used ncurses, sockets and basic networking stuff.
The problem is that my function uses select() to read from server socket AND stdin so when I start to write a message, the output window freezes and only shows messages from other clients after I hit enter.
I tried everything possible .. Is there a way to fix this ?
I also tried to force nocbreak().It works okay but if I do that, when I write the message, the echoing is disabled and nothing shows up in the input window as I type, even though the message is there but like "invisible".
Here is the code :
ssize_t safePrefRead(int sock, void *buffer)
{
size_t length = strlen(buffer);
ssize_t nbytesR = read(sock, &length, sizeof(size_t));
if (nbytesR == -1)
{
perror("read() error for length ! Exiting !\n");
exit(EXIT_FAILURE);
}
nbytesR = read(sock, buffer, length);
if (nbytesR == -1)
{
perror("read() error for data ! Exiting !\n");
exit(EXIT_FAILURE);
}
return nbytesR;
}
ssize_t safePrefWrite(int sock, const void *buffer)
{
size_t length = strlen(buffer);
ssize_t nbytesW = write(sock, &length, sizeof(size_t));
if (nbytesW == -1)
{
perror("write() error for length ! Exiting !\n");
exit(EXIT_FAILURE);
}
nbytesW = write(sock, buffer, length);
if (nbytesW == -1)
{
perror("write() error for data ! Exiting !\n");
exit(EXIT_FAILURE);
}
return nbytesW;
}
void activeChat(int sC, const char *currentUser, const char *room)
{
char inMesg[513], outMesg[513];
char user[33];
int winrows, wincols;
WINDOW *winput, *woutput;
initscr();
nocbreak();
getmaxyx(stdscr, winrows, wincols);
winput = newwin(1, wincols, winrows - 1, 0);
woutput = newwin(winrows - 1, wincols, 0, 0);
keypad(winput, true);
scrollok(woutput, true);
wrefresh(woutput);
wrefresh(winput);
fd_set all;
fd_set read_fds;
FD_ZERO(&all);
FD_ZERO(&read_fds);
FD_SET(0, &all);
FD_SET(sC, &all);
wprintw(woutput, "Welcome to room '%s' \n Use /quitChat to exit !\n!", room);
wrefresh(woutput);
while (true)
{
memcpy( &read_fds, &all, sizeof read_fds );
if (select(sC + 1, &read_fds, NULL, NULL, NULL) == -1)
{
perror("select() error or forced exit !\n");
break;
}
if (FD_ISSET(sC, &read_fds))
{
memset(inMesg, 0, 513);
safePrefRead(sC, user);
safePrefRead(sC, inMesg);
wprintw(woutput, "%s : %s\n", user, inMesg);
wrefresh(woutput);
wrefresh(winput);
}
if (FD_ISSET(0, &read_fds))
{
//wgetnstr(winput, "%s", outMesg);
int a, i = 0;
while ( i < MAX_BUF_LEN && (a = wgetch(winput)) != '\n')
{
outMesg[i] = (char)a;
i++;
}
outMesg[i] = 0;
if (outMesg[0] == 0)
continue;
if (strcmp(outMesg, "/quitChat") == 0)
{
safePrefWrite(sC, outMesg);
break;
}
safePrefWrite(sC, outMesg);
delwin(winput);
winput = newwin(1, wincols, winrows - 1, 0);
keypad(winput, true);
wrefresh(winput);
}
}
delwin(winput);
delwin(woutput);
endwin();
}
-safePrefWrite and safePrefRead are wrappers for prexied read / write and error treating
-sC is the server socket.
LE: I tried using fork and threads. Using fork was behaving the same and threads were a disaster, the terminal was messed up.
Thank you.
modify the while(true) loop to only handle one char at a time for the stdin.
Which mostly means for stdin, read a single char:
if char is '\n' then handle as currently,
otherwise, just append char to the buffer to write.
Always, before appending a char to buffer to write, check that buffer is not full.
add code to handle the case where the buffer to write is full
end the function with this sequence:
delwin(winput);
delwin(woutput);
endwin();
endwin();
to end both windows.
Do not call endwin() during processing of the socket input.
Do not call endwin() when select() returns an error condition
the fd_set is not an intrinsic size in C, so use memcpy() to set
read_fds from all. suggest:
memcpy( &read_fds, &all, sizeof read_fds );
the parameter: currentUser is not used, suggest inserting the line:
(void)currentUser;
to eliminate a compiler warning message.
for readability, and ease of understandability, suggest #define the magic numbers 513 and 33 with meaningful names, then use those meaningful names throughout the code.
#define MAX_BUF_LEN (513)
#define MAX_USER_LEN (33)
this line: outMesg[i] = a; raises a compiler warning, suggest:
outMesg[i] = (char)a;
This line: while ( (a = wgetch(winput)) != '\n') can allow the buffer outMesg[] to be overrun, resulting in undefined behaviour and can lead to a seg fault event. suggest:
while ( i < MAX_BUF_LEN && (a = wgetch(winput)) != '\n')
Suggest posting the prototypes for the safePrefWrite() and safePrefRead() functions, similar to:
void safePrefRead( int, char * );
void safePrefWrite( int, char * );
As noted by #user3629249, there are several criticisms which can be applied to the sample code. However, OP's question is not addressed by those improvements.
OP seems to have overlooked these functions:
cbreak or raw, to make wgetch read unbuffered data, i.e., not waiting for '\n'.
nodelay or timeout, to control the amount of time wgetch spends waiting for input.
By the way, making select work with a curses program will make assumptions about the curses library internal behavior: getting that to work reliably can be troublesome.
Fixed it finally by using only the big loop.
Here is the code if anyone has the same problem in the future :
if (FD_ISSET(0, &read_fds))
{
inChar = wgetch(winput);
if (inChar == 27)
{
safePrefWrite(sC, "/quit");
break;
}
if (inChar == KEY_UP || inChar == KEY_DOWN || inChar == KEY_LEFT || inChar == KEY_RIGHT)
continue;
if (inChar == KEY_BACKSPACE || inChar == KEY_DC || inChar == 127)
{
wdelch(winput);
wrefresh(winput);
if (i != 0)
{
outMesg[i - 1] = 0;
i--;
}
}
else
{
outMesg[i] = (char)inChar;
i++;
}
if (outMesg[i - 1] == '\n')
{
outMesg[i - 1] = 0;
i = 0;
if (outMesg[0] == 0)
continue;
if (strcmp(outMesg, "/quit") == 0)
{
safePrefWrite(sC, outMesg);
break;
}
safePrefWrite(sC, outMesg);
delwin(winput);
winput = newwin(1, wincols, winrows - 1, 0);
keypad(winput, true);
wrefresh(winput);
memset(outMesg, 0, 513);
}
}
I also use raw() to disable signals and to treat the codes how I want.
Anything else above and below this "if" is just like in the 1st post.

client messages don't arrive to server in tcp winsock

I have server client application.
When I'm sending messages in a row(without scanf in the code below), it's seems the server doesn't get them(doesn't print).
if I wait a little bit(with the scanf in the code below) and then send the next message the server works fine and prints all messages.
what's the problem?
how can I fix it, cause I want to do more with the message(not just to print it) that arrived to the server.
in my client code(where server prints nothing)
char message[(100)] = {0};
int x = rand();
while(i < 3)
{
printf(" I send %d\n", x);fflush(NULL);
sprintf(message, "%d",x);
if( send(mainSockfd, message,strlen(message),0) == -1)
{
printf("ERRRRRORRRR\n");fflush(NULL);
}
i++;
x = rand() % 100;
}
in my client code(when server prints the messages)
char message[(100)] = {0};
int x = rand();
while(i < 3)
{
printf(" I send %d\n", x);fflush(NULL);
sprintf(message, "%d",x);
if( send(mainSockfd, message,strlen(message),0) == -1)
{
printf("ERRRRRORRRR\n");fflush(NULL);
}
i++;
x = rand() % 100;
scanf("%d",&x); // this is the only change
}
in my server code
char command[(100+1)] = {0};
while(1)
{
readLength = recv(sockfd, command, 100+1,0);
if(readLength > 0)
{
printf("arrived = %s,\n",command);fflush(NULL);
ZeroMemory(command, sizeof(command));
}
else if( readLength == 0)
{
break;
}
else if ( readLength < 0 ){
if(GetLastError() == 10035)
{
continue;
}
if(GetLastError() == 10057 || GetLastError() == 10054)
{
break;
}
continue;
}
}
As you seem to be transferring 0-terminated "strings" without the 0 termination, you should read one char less then the read buffer provides to always have the read buffer being 0-terminated, as if you try to printf a non 0-terminated "string" you provoke undefined behaviour.
So change this
readLength = recv(sockfd, command, 100+1,0);
to become this
readLength = recv(sockfd, command, 100,0);

Correct way to write/read data over a fifo

I've created, as an homework, a big project which simulate a mailbox server (only through process on the same computer, so through fifo, it's a homework)
I can't post the project because is big (there are a lot of files), but I can say that sometimes I lost some data or it doesn't preserve it's integrity.
I use these code snippet to transmit data, is it somewhat wrong?Network_IO is the function I'm talking about:
#include "Network.h"
int Network_Open(const char* path,int oflag)
{
return open(path,oflag);
}
ssize_t Network_IO(int fifo,NetworkOpCodes opcode,void* data,size_t dataSize)
{
ssize_t retsize = 0;
ssize_t tmpDataSize = (ssize_t)dataSize;
errno = 0;
if (tmpDataSize == 0) return 0;
while ((retsize = (opcode == NetworkOpCode_Write? write(fifo,data,tmpDataSize) : read(fifo,data,tmpDataSize))) != tmpDataSize)
{
if (errno != EINTR) break;
}
return retsize;
}
Boolean Network_Send(int fifo,const void* data,size_t dataSize)
{
return ((ssize_t)dataSize) == Network_IO(fifo,NetworkOpCode_Write,(void*)data,dataSize);
}
Boolean Network_Receive(int fifo,void* data,size_t dataSize)
{
return ((ssize_t)dataSize) == Network_IO(fifo,NetworkOpCode_Read,data,dataSize);
}
Boolean Network_Close(int fifo)
{
if (fifo >= 0)
return close(fifo) == 0;
}
Edit 1: Code snippet which I'm using to test actually
Boolean Network_IO(int fifo,NetworkOpCodes opcode,void* data,size_t dataSize)
{
ssize_t retsize = 0;
ssize_t tmpDataSize = (ssize_t)dataSize;
ssize_t sentDataSize = 0;
errno = 0;
if (tmpDataSize == 0) return True;
while (sentDataSize < tmpDataSize)
{
switch(opcode)
{
case NetworkOpCode_Write:
retsize = write(fifo,data + sentDataSize,tmpDataSize - sentDataSize);
break;
case NetworkOpCode_Read:
retsize = read(fifo,data + sentDataSize,tmpDataSize - sentDataSize);
break;
}
if (retsize < 0)
{
if (errno != EINTR) return False;
else
{
errno = 0;
continue;
}
}
sentDataSize += retsize;
}
if (errno != 0)
return False;
return sentDataSize == tmpDataSize;
}
Boolean Network_Send(int fifo,const void* data,size_t dataSize)
{
return Network_IO(fifo,NetworkOpCode_Write,(void*)data,dataSize);
}
Boolean Network_Receive(int fifo,void* data,size_t dataSize)
{
return Network_IO(fifo,NetworkOpCode_Read,data,dataSize);
}
IMHO the Network_IO() function serves no purpose. It's only purpose is to 'demultiplex' the opcodes for read/write calls, that were given to it by the Network_Send() and Network_Receive() functions. Better would be to call read() and write directly in the Network_Send() and Network_Receive() functions. Your choice of return type (Boolean) is also strange.
The error conditions on read() and write() could be different, in the future maybe more than just EINTR needs to be handled in one of them. Also: your functions block, that means: they don't return until the desired amount has actually been sent or received. Also note that for pipes and fifos, the amount of bufferspace supplied by the kernel is very limited, typically 1 memory page. This increases the chance of the reader or writer blocking in reads or writes, and results in (at least) two context switches per block of data transferred.
The "loop until done" method; as supplied by Mat is about the standard way of doing things. Also be be prepared for read/write returning zero.
EDIT: what Mat meant is that you need to handle partial reads/writes: you need to start over where you left off, sending/receiving the remaining part of the buffer. Here is a start:
int mywrite(int fd, char *buff, size_t size)
{
int rc;
size_t done, todo;
for (done=0; done < size; ) {
todo = size - done;
rc = write (fd, buff+done, todo);
switch (rc) {
case -1: /* some read error: check it */
switch(errno) {
case EINTR: continue;
/* ... maybe some other cases you need to handle */
default: return -1;
}
break;
case 0: /* (in some cases) the other side closed the connection */
/* handle it here; possibly return error */
break;
default: /* the normal case */
done += rc;
break;
}
}
return done;
}
For the write case, your code boils down to
while ((retsize = write(fifo,data,tmpDataSize)) != tmpDataSize) { ... }
Imagine that on the first write, only one byte gets written. If that happens, you need the next write to attempt to push tmpDataSize-1 bytes, starting at data+1. But what you do now will resend everything, including that first byte.
In pseudo-code, the logic should be something like:
while (bytesLeftToSend > 0) {
sent = write(fifo, data, bytesLeftToSend);
if (sent == -1) {
// report error and bail out
}
bytesLeftToSend -= sent;
data += sent;
}
Same thing for the read case.
BTW, that while with an assignment and a ?: construct is really hard to read.

Socket programming problem in C

From the below piece of code, why I am getting Reading Socket for response
int Read(int sock, char *p, int size)
{
int remain, read=0;
remain = size;
while (remain > 0 ) {
if ((read = recv(sock, p, remain, 0)) < 0) {
/* Error */
return(read);
} else if (read == 0 || *p == 0x0a) {
/* EOF */
break;
}
remain -= read;
p += read;
}
return(size - remain);
}
while (!done)
{
printf("***Reading Socket for response***");
rsplen= Read(myVsHandle.sock,(char *)encXMLResponse,MAX_RSP_LEN);
if (rsplen < 0 )
{
printf("Internal Communication Error");
return -1;
}
else if (rsplen >0)
printf("Revieved response");
done++;
return 0;
else if (rsplen == 0)
{
printf("Reading socket");
}
You are waiting for MAX_RSP_LEN bytes to be read - is there that many bytes to be read? Maybe your process is stuck in a blocking read().
Also depending on the sort of socket you are recv()ing from, there is no guarantee on the amount of data you will read, so specifically looking for a value 0x0a may not work.
Your problem could be that you are not ending your output with a newline. Try ending your outputs with a newline (\n). stdout is line buffered, so you may not see anything for a long time if you don't output a newline.
Another possibility is that you don't return from Read() unless you read the specified number of bytes. Depending upon the value of MAX_RSP_LEN, and the amount of data available, Read() may wait forever.
Also, your test: *p == 0x0a looks suspicious. What are you testing here?
Edit: There is another "bug":
else if (rsplen >0)
printf("Revieved response");
done++;
return 0;
else...
You are missing curly braces. In the current form, the code shouldn't compile. Please post actual code.
This:
if ((read = recv(sock, p, remain, 0)) < 0) {
Should be
if ((read = recv(sock, p, remain, 0)) > 0) { // Greater then 0, because recv returns the number of bytes received if successful, if it fails -1.
You're missing curly braces around the:
else if(rsplen > 0)
... statements
It should be:
...
}else if (rsplen >0){
printf("Revieved response");
done++;
return 0;
} ...

Resources