C (Linux) Checking socket - c

I'm writting a client-server C project where the server processes messages from the client, and replicates them to a backup server. It works well, but one of the points of the project (its a university project) is to be prepared for errors, in this case - the backup server dying.
I have this on my replication function:
int table_skel_replicate(struct message_t *msg, int sockSecundario){
char *msg_buf;
int buf_size_net = 0;
int buf_size=0;
int okk;
struct sockaddr_in server;
msg->opcode--;
buf_size = message_to_buffer ( msg, &msg_buf );
buf_size_net = htonl(buf_size);
okk = write( sockSecundario, &buf_size_net, sizeof(int) );
if(okk == -1 || okk == 0) {
msg->opcode++;
return okk;
}
okk = write_all ( sockSecundario, msg_buf, buf_size );
if(okk == -1) {
msg->opcode++;
return okk;
}
okk = read ( sockSecundario, &buf_size_net, sizeof(int) );
if(okk == -1 || okk == 0) {
msg->opcode++;
return okk;
}
buf_size = ntohl(buf_size_net);
msg_buf = malloc ( buf_size );
okk = read_all( sockSecundario, msg_buf, buf_size );
msg->opcode++;
return okk;
}
it was supposed to fail the first write() as soon as the backup server died. but it doesnt.
Instead, it proceds to the write_all() function (which is basicly a write() inside a while for long transfers) and dies on the first write() there. i tried using the checksockopt() function but it return the status as ok...
The main application simply closes. Any help appreciated...

Your checks of the write() calls presumably are not effective because the program terminates due to SIGPIPE. man 2 write:
fd is connected to a pipe or socket whose reading end is
closed. When this happens the writing process will also receive a
SIGPIPE signal. (Thus, the write return value is seen only if
the program catches, blocks or ignores this signal.)
To easily avoid this, replace every
write( sockSecundario, …, … )
by
send(sockSecundario, …, …, MSG_NOSIGNAL)

Related

Implementing threads with sockets in C

so i'm trying to implement a basic client-server calculator with threads. I was able to implement the communication between cliente-server with sockets but i'm at a loss when i try to add threads to the code.
This is my first time using this forum so please sorry if i'm making a dumb question but i already searched for some answers and i can't find anything that helps :(
I can upload my whole code bit for now i think this will suffice:
Creating a thread in main:
while(cliente_socket_fd = accept(socket_fd,(struct sockaddr*)&name_cliente,(socklen_t*)&cliente_name_len))
{
pthread_t thread;
new_sock = malloc(1);
*new_sock = cliente_socket_fd;
if(i <= nThreads) // nThreads is the maximum of threads permitted
{
if(pthread_create(&thread, NULL, connectionSocket, (void*)new_sock) < 0)
{
perror("Error");
return 1;
}
i++;
}
}
Function that recives information from create thread:
void *connectionSocket(void *sockR)
{
int sock = *(int*)sockR;
int x;
char buffer[1024];
do{
x = strlen(buffer) + 1;
read(sock,buffer, x);
readSocket(sock, buffer);
}while(1 || strcmp(buffer,"end") != 0);
close(sock);
return 0;
}
Server read socket function:
int readSocket(int sock, const char* buffer)
{
//char buffer[1024];
//char message[1024] ;
int ssize;
ssize = strlen(buffer);
if(ssize == 0)
return 0;
char* message = (char*) malloc(ssize);
//memset(buffer, 0, sizeof buffer);
memset(message, 0, sizeof message);
strcat(message, buffer);
...
writeSocket(sock, message);
...
Function that writes in the socket:
void writeSocket(int sock, const char* mensagem)
{
int ssize = strlen(message) + 1;
write(sock, &ssize, sizeof(ssize));
write(sock, message, ssize);
}
Again sorry if i'm being a noob or asking too much but any help is greatly appreciated. Thanks.
in function: connectionSocket()
this line
x = strlen(buffer) + 1;
is garbage because strlen() stops when it finds a NUL byte.
However, the buffer has not been set to a known condition so there may or may not be a NUL byte in the buffer. I.E. undefined behavior.
the accept() function returns -1 when an error occurs, However the posted code will blindly continue into the body of the loop
Suggest writing that line similar to:
while( 1 )
{
cliente_socket_fd = accept(socket_fd,(struct sockaddr*)&name_cliente, (socklen_t*)&cliente_name_len) );
if( -1 == cliente_socket_fd )
{
perror( "accept failed" );
break; // exit loop
}
// implied else, accept successful
then, to be able to access those threads, later, this line:
if(pthread_create(&thread, NULL, connectionSocket, (void*)new_sock) < 0)
should be setting a 'unique' 'thread' rather than the only 'thread' Suggest:
pthread_t thread[ nThreads ] = {0};
if(pthread_create(&thread[i], NULL, connectionSocket, (void*)new_sock) < 0)
then, a socket is (effectively) an integer, which, depending on the underlying hardware architecture is 4 or 8 bytes So this line:
new_sock = malloc(1);
does not allocate enough bytes, it should be:
new_sock = malloc( sizeof( int ) );
if( !new_sock )
{ // then, malloc failed
perror( "malloc failed" );
break; // exit loop
}
// implied else, malloc successful
*new_sock = cliente_socket_fd;
this line:
}while(1 || strcmp(buffer,"end") != 0);
will never exit the loop. Suggest:
}while( strcmp(buffer,"end") != 0 );
this line:
read(sock,buffer, x);
will try to read some random number of bytes because the value in 'x' is not valid. Suggest;
read(sock,buffer, sizeof( buffer ));
the above are the most obvious problems in the posted code. If you had posted a cleanly compiles, short, example that can be run and still shows the problems, I could have helped you more.

recv stalls or does not return all data (C code)

I have a web service written in .net on a remote computer with IIS, I am trying to connect to it with a C program using socker to do a SOAP request.
My problem is that I have some probem receiving the data:
The receiving data loop does not work in a way or in another.
If I write:
nByte = 1;
while(nByte!=512)
{
nByte = recv(sockfd,buffer,512, 0);
if( nByte < 0 )
{
// check the error
}
if( nByte > 0)
{
// append buffer to received data
}
}
sometime does not return all data, if it run without debugger and breackpoints.
If I try: while(nByte!=0) at the end of data it stalls and go in error.
How is it supposed to be done?
Thanks,
Antonino
** EDIT **
I resolved my situation in another way, I check the returned value for soap xml end:
nByte = 1;
while(nByte!=0)
{
nByte = recv(sockfd,buffer,512, 0);
if( nByte < 0 )
{
// check the error
}
if( nByte > 0)
{
// append nByte buffer to received data
if( strstr("</soap:Envelope>", buffer) != NULL)
break;
}
}
It is very sad...
#define BUFFERSIZE 512
byte buffer[BUFFERSIZE];
int nByte = BUFFERSIZE;
int rByte;
while(nByte!=0)
{
rByte = recv(sockfd, &buffer[BUFFERSIZE-nByte], nByte, 0);
if( rByte < 0 )
{
// socket error
break;
}
if( rByte == 0)
{
// connection closed by remote side or network breakdown, buffer is incomplete
break;
}
if(rByte>nByte)
{
// impossible but you must check it: memory crash, system error
break;
}
nByte -= rByte; // rByte>0 all is ok
// if nByte==0 automatically end of loop, you read all
// if nByte >0 goto next recv, you need read more bytes, recv is prtialy in this case
}
//**EDIT**
if(nByte!=0) return false;
// TO DO - buffer complete
Where does it say it fills the buffer? Read the man image. It blocks until at least one byte of data can be transferred, then transfers whatever data has arrived.

write() is blocked forever after writing big data

write() doesn't get response after writing big data. Are there any limit for writing over one socket? Or is it limited by OS?(I ran this on ubuntu)
My own code works for small file lower than 1kb with (5 byte per write, little write number) or (1Mb per write, 1 write ) attempt. But the code doesn't work for big file about 3Mb with (5 byte per write, a lot of write) or (1Mb per write, 3 write) attempt.
For example, 3M file with 1Mb per write case, third write is blocked forever and can't get return value.
below is actual my own code. input from stdin and write it to server. lprintf,l2printf are just 'log printf'.
int BSIZE = 1024;
//int BSIZE = 5;
char buffer[BSIZE];
int n = 0;
//phase 2-1 write
//read from outter
int bi =0;
int c;
int temp= 0;
int t2 =0;
while (EOF!=(c = fgetc(stdin))) {
if(temp++%(1024*1024) == 0){
l2printf("over 1m\n");
t2++;
if (t2 == 2){
//loglevel=1;
}
}
/*
if(temp++ > 3500){
printf("\ntemp 3500\n")
break;
}
*/
lprintf("|");
lprintf("%x",c & 0xff);
if(c =='\\'){
char input[2] = "\\\\";
lprintf("%x",input[0] & 0xff);
buffer[bi++] = '\\';
if(bi == sizeof(buffer)){
lprintf("\n");
l2printf ("\nB/1:%x\n", buffer[1]);
n = write(sockfd,buffer,sizeof(buffer));
bi = 0;
}
buffer[bi++] = '\\';
if(bi == sizeof(buffer)){
lprintf("\n");
l2printf ("\nB/2:%x\n", buffer[1]);
n = write(sockfd,buffer,sizeof(buffer));
bi = 0;
}
//n = write(sockfd,input,sizeof(char)*2);
}
else{
buffer[bi++] = c;
if(bi == sizeof(buffer)){
lprintf("\n");
l2printf ("\nBc:%x\n", buffer);
n = write(sockfd,buffer,sizeof(buffer));
l2printf("n = %d \n", n);
bi = 0;
}
//n = write(sockfd,&c,sizeof(char));
//lprintf("%c",c);
}
if( n <0 ){
error("ERROR writing to socket 2-1");
}
}
//adding EOF
//clear buffer
lprintf("\n");
l2printf ("\nEB:%x\n", buffer);
n = write(sockfd,buffer,sizeof(char)*bi);
char input[2] = "\\0";
n = write(sockfd,input,sizeof(char)*2);
lprintf("*\\0*");
if( n <0 ){
error("ERROR writing to socket 2-1 EOF");
}
The receiving peer is not reading the data, so the sender blocks.
there are a number of 'oops' in the posted code.
here is an example, without the logging, etc
but with proper error checking
however, the send() will still hang if the receiver
is not reading the data
// without all the logging, special case for \\, etc
// note: write() is for open files, using a file descriptor
// so using send() for TCP communication over a socket
#define BSIZE (1024)
char buffer[BSIZE] = {'\0'};
int n = 0;
while( fgets( buffer, BSIZE, stdin );
{
if( 0 > (n = send(sockfd,buffer,strlen(buffer), 0 ) ) )
{ // then, send failed
perror( "send for buffer through socket failed" );
// handle error
}
} // end while
//adding EOF
// note this is not really EOF, it is a string terminator
// EOF is supplied automatically when the file is closed
// by the receiver
char input[2] = {'\0'};
if( 0 > (n = send(sockfd,input,1, 0) ) )
{ // then send failed
perror( "send for file terminator failed" );
// handle error
}
This is the case that you have consumed the whole send buffer of the socket, and the receiver has not yet called recv() at its end. When the receiver will call recv(), the underlying kernel implementation will remove the received bytes from the send buffer at sender side. This will create more space and the remaining bytes in your write() call will be written to send buffer. When all the bytes are written, write() will return.
In your case you are saying that write is blocked. So to avoid this you can do two things
Use non-blocking write by making use of ioctl() function. A good start point will be http://www.kegel.com/dkftpbench/nonblocking.html
You can increase the send buffer in case of TCP. For this purpose setsockopt() is your friend. The option will be SO_SNDBUF. Set the value of send buffer large enough that at lease 2 or 3 writes are successfull, even if the receiver does not call receive for some time. Example can be found here Understanding set/getsockopt SO_SNDBUF
Hope this will solve your problem

fgets() blocking when buffer too large

I'm currently using select() to tell if there is data to be read in a file descriptor because I don't want fgets to block. This works 99% of the time, however, if select() detects data in fp, but the data doesn't have a newline and the data is smaller than my buffer, it will block. Is there any way to tell how many bytes are ready to be read?
//See if there is data in fp, waiting up to 5 seconds
select_rv = checkForData(fp, 5);
//If there is data in fp...
if (select_rv > 0)
{
//Blocks if data doesn't have a newline and the data in fp is smaller than the size of command_out!!
if (fgets(command_out, sizeof(command_out)-1, fp) != NULL)
{
printf("WGET: %s", command_out);
}
}
else if (select_rv == 0)
{
printf("select() timed out... No output from command process!\n");
}
I guess what I really want is a way to know if a full line is ready to be read before calling fgets.
As MBlanc mentions, implementing your own buffering using read() is the way to go here.
Here's a program that demonstrates the general method. I don't recommend doing exactly this, since:
The function presented here uses static variables, and will only work for one single file, and will be unusable once that's over. In reality, you'd want to set up a separate struct for each file and store the state for each file in there, passing it into your function each time.
This maintains the buffer by simply memmove()ing the remaining data after some is removed from the buffer. In reality, implementing a circular queue would probably be a better approach, although the basic usage will be the same.
If the output buffer here is larger than the internal buffer, it'll never use that extra space. In reality, if you get into this situation, you'd either resize the internal buffer, or copy the internal buffer into the output string, and go back and try for a second read() call before returning.
but implementing all this would add too much complexity to an example program, and the general approach here will show how to accomplish the task.
To simulate delays in receiving input, the main program will pipe the output from the following program, which just outputs a few times, sometimes with newlines, sometimes without, and sleep()s in between outputs:
delayed_output.c:
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <unistd.h>
int main(void)
{
printf("Here is some input...");
fflush(stdout);
sleep(3);
printf("and here is some more.\n");
printf("Yet more output is here...");
fflush(stdout);
sleep(3);
printf("and here's the end of it.\n");
printf("Here's some more, not ending with a newline. ");
printf("There are some more words here, to exceed our buffer.");
fflush(stdout);
return 0;
}
The main program:
buffer.c:
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stdarg.h>
#include <unistd.h>
#include <sys/select.h>
#define INTBUFFERSIZE 1024
#define BUFFERSIZE 60
#define GET_LINE_DEBUG true
/* Prints a debug message if debugging is on */
void get_line_debug_msg(const char * msg, ...)
{
va_list ap;
va_start(ap, msg);
if ( GET_LINE_DEBUG ) {
vfprintf(stderr, msg, ap);
}
va_end(ap);
}
/*
* Gets a line from a file if one is available.
*
* Returns:
* 1 if a line was successfully gotten
* 0 if a line is not yet available
* -1 on end-of-file (no more input available)
*
* NOTE: This function can be used only with one file, and will
* be unusable once that file has reached the end.
*/
int get_line_if_ready(int fd, char * out_buffer, const size_t size)
{
static char int_buffer[INTBUFFERSIZE + 1] = {0}; /* Internal buffer */
static char * back = int_buffer; /* Next available space in buffer */
static bool end_of_file = false;
if ( !end_of_file ) {
/* Check if input is available */
fd_set fds;
FD_ZERO(&fds);
FD_SET(fd, &fds);
struct timeval tv = {0, 0};
int status;
if ( (status = select(fd + 1, &fds, NULL, NULL, &tv)) == -1 ) {
perror("error calling select()");
exit(EXIT_FAILURE);
}
else if ( status == 0 ) {
/* Return zero if no input available */
return 0;
}
/* Get as much available input as will fit in buffer */
const size_t bufferspace = INTBUFFERSIZE - (back - int_buffer) - 1;
const ssize_t numread = read(fd, back, bufferspace);
if ( numread == -1 ) {
perror("error calling read()");
exit(EXIT_FAILURE);
}
else if ( numread == 0 ) {
end_of_file = true;
}
else {
const char * oldback = back;
back += numread;
*back = 0;
get_line_debug_msg("(In function, just read [%s])\n"
"(Internal buffer is [%s])\n",
oldback, int_buffer);
}
}
/* Write line to output buffer if a full line is available,
* or if we have reached the end of the file. */
char * endptr;
const size_t bufferspace = INTBUFFERSIZE - (back - int_buffer) - 1;
if ( (endptr = strchr(int_buffer, '\n')) ||
bufferspace == 0 ||
end_of_file ) {
const size_t buf_len = back - int_buffer;
if ( end_of_file && buf_len == 0 ) {
/* Buffer empty, we're done */
return -1;
}
endptr = (end_of_file || bufferspace == 0) ? back : endptr + 1;
const size_t line_len = endptr - int_buffer;
const size_t numcopy = line_len > (size - 1) ? (size - 1) : line_len;
strncpy(out_buffer, int_buffer, numcopy);
out_buffer[numcopy] = 0;
memmove(int_buffer, int_buffer + numcopy, INTBUFFERSIZE - numcopy);
back -= numcopy;
return 1;
}
/* No full line available, and
* at end of file, so return 0. */
return 0;
}
int main(void)
{
char buffer[BUFFERSIZE];
FILE * fp = popen("./delayed_output", "r");
if ( !fp ) {
perror("error calling popen()");
return EXIT_FAILURE;
}
sleep(1); /* Give child process some time to write output */
int n = 0;
while ( n != -1 ) {
/* Loop until we get a line */
while ( !(n = get_line_if_ready(fileno(fp), buffer, BUFFERSIZE)) ) {
/* Here's where you could do other stuff if no line
* is available. Here, we'll just sleep for a while. */
printf("Line is not ready. Sleeping for five seconds.\n");
sleep(5);
}
/* Output it if we're not at end of file */
if ( n != -1 ) {
const size_t len = strlen(buffer);
if ( buffer[len - 1] == '\n' ) {
buffer[len - 1] = 0;
}
printf("Got line: %s\n", buffer);
}
}
if ( pclose(fp) == -1 ) {
perror("error calling pclose()");
return EXIT_FAILURE;
}
return 0;
}
and the output:
paul#thoth:~/src/sandbox/buffer$ ./buffer
(In function, just read [Here is some input...])
(Internal buffer is [Here is some input...])
Line is not ready. Sleeping for five seconds.
(In function, just read [and here is some more.
Yet more output is here...])
(Internal buffer is [Here is some input...and here is some more.
Yet more output is here...])
Got line: Here is some input...and here is some more.
Line is not ready. Sleeping for five seconds.
(In function, just read [and here's the end of it.
Here's some more, not ending with a newline. There are some more words here, to exceed our buffer.])
(Internal buffer is [Yet more output is here...and here's the end of it.
Here's some more, not ending with a newline. There are some more words here, to exceed our buffer.])
Got line: Yet more output is here...and here's the end of it.
Got line: Here's some more, not ending with a newline. There are some
Got line: more words here, to exceed our buffer.
paul#thoth:~/src/sandbox/buffer$
Is there any way to tell how many bytes are ready to be read?
Not that I'm aware of in C99/POSIX. I'm guessing this functionality wasn't deemed useful since files have a fixed size (most of the time, anyways). Unfortunately select() is very rudimentary as you have already seen.
I guess what I really want is a way to know if a full line is ready to be read before calling fgets.
fgets() buffers in a loop until a '\n' is reached. This action consumes the input from the underlying file descriptor, so you'll need to implement a non-blocking version yourself.

Bad File Descriptor on a serial port

I'm implementing a simple protocol to do file transfer between 2 PC's over serial port and I'm getting a weird error.
On the main I call a function "llopen":
int
llopen(int port, int type) {
int fd = 0;
char* PORT;
PORT = malloc( sizeof(char) * (strlen(COM) + 1) );
sprintf(PORT,"%s%d",COM,port);
fd = initialization(PORT); // Open(...): returns a file descriptor!
switch(type) {
case SENDER:
return connectSender(fd);
break;
case RECEIVER:
return connectReceiver(fd);
break;
}
return fd; // The fd value here is 5
}
After that, I call a function llwrite(int fd, ...) to write a string to the file descriptor, but I'm getting an error: "Bad file descriptor" on llwrite(int fd, ...). If I call again the initialization(port) function, before that, it works and it writes the N bytes on the file descriptor, but if I don't it gives to me the "Bad file descriptor" error again.
Here it is the llwrite(int fd, ...) function:
int
llwrite(int fileDescriptor, unsigned char* buffer, unsigned int length) {
// The fd value here is 5
return writeBuffer(fileDescriptor,buffer,length);
}
Even before the return statement if I call, for instance, the tcflush(...) function I'm getting the "Bad file descriptor" error.
Any clue? Thanks in advance!
EDIT:
The problem is solved.
llopen(...) was wrong. I was returning the number of bytes wrote on the ConnectReceiver(...) / ConnectSender(...) and not the file descriptor
Now it's right:
int
llopen(int port, int type) {
int fd = 0;
char* PORT;
PORT = malloc( sizeof(char) * (strlen(COM) + 1) );
sprintf(PORT,"%s%d",COM,port);
fd = initialization(PORT); // Open(...): returns a file descriptor!
switch(type) {
case SENDER:
if( connectSender(fd) > 0 ) return fd;
case RECEIVER:
if( connectReceiver(fd) > 0 ) return fd;
}
return -1;
}
There's not really enough information here, but it's worth a shot noting that you do
return connectSender(fd);
break;
The break there is dead code, since the return stops execution of the function. Perhaps you didn't mean to return?
If that's not the case try using strace to get more details about what's going on. If you're not on linux other OSes should have similar tools, such as dtruss or ktrace.

Resources