What to do after shutdown(sock, SD_SEND) - sockets

I want to send several files from Server to the Client but I'm having a problem.
Server sendfile code:
while ((len = fread(Buffer,1,sizeof(Buffer), fs)) > 0)
{
if((resultEnviar = send(ClientSocket,Buffer,len,0)) < 0){
printf("ERROR: Failed to send file %s.\n", nombreArchivoADescargar.c_str());
break;
}
sumEnviada+=resultEnviar;
}
fclose(fs);
Client receiveFile code:
//shutdown(sock, SD_SEND); ???????
do{
recvVal = recv(sock, Buffer2, sizeof(Buffer2), 0);
if (recvVal <= 0){
printf("Can't read from socket");
recvVal =0;
fclose(fp);
continue;
}else{
int off =0;
do{
int write_sz = fwrite(Buffer2, 1, recvVal, fp);
if (write_sz < 0){
printf("Can't write to file");
fclose(fp);
break;};
if (write_sz == 0) {cout<<endl<<"Nada que copiar"<<endl; break;}
off += write_sz;
}while(off<recvVal);
bzero(Buffer2, 1024);
contador+=off;
}
}while (contador<LongitudArchivo);
cout<<endl<<"Numero de bytes recibidos: "<<contador<<endl<<endl;
printf("Ok received from client!\n");
fclose(fp);
If I don't use the SHUTDOWN(sock, SD_SEND) I don't receive all the expected bytes but if I use it I don't know how to send more files (how to wake up the send part of the socket).
Thanks!

I don't see what shutdown() has to do with it. You should receive all the bytes either way. If you want to send multiple files, you will have to send the length ahead of each one and read exactly that many following bytes from the socket into each target file.
NB If recv() returns zero you should close the socket and break. If it returns -1 you should log the errno, e.g. via perror(), close the socket, and break.

Related

socket connection lost using select function

I'm newbee in socket program.
I made my server program with good sample program using select function.
It works well about 20,000 connections over.
But, in some case, connection accept twice consequence without
receive data from first socket.
Only data received from second socket connection.
After that, first socket resource cannot release.
FD_SET and FD_ISSET are not working with first socket in case of consequence accept I think.
Working clients are 6.
Before this situation,
accept, receive data, and close socket, accept, rcv
data, close, ...
In case, accept,
accept, receive data from second socket, and close second socket.
Lost first socket connection.
After that, accept function assign second socket descriptor.
What is problem?
How can release fisrt socket?
BR
Paul
My code is as follow:
while(1)
{
//clear the socket set
FD_ZERO (&readfds);
//add master socket to set
FD_SET (sever_socket, &readfds);
max_sd = sever_socket;
//add child sockets to set
for ( i = 0 ; i < MAX_CLIENT ; i ++)
{
//socket descriptor
sd = client_socket [i];
//if valid socket descriptor then add to read list
if (sd > 0)
{
FD_SET( sd , &readfds);
}
//highest file descriptor number, need it for the select function
if(sd > max_sd)
{
max_sd = sd;
}
}
//wait for an activity on one of the sockets , timeout is NULL , so wait indefinitely
activity = select ( max_sd + 1 , &readfds , NULL , NULL , NULL);
if ((activity < 0) && (errno!=EINTR))
{
LOG_F (WARNING, "select error");
}
//If something happened on the master socket, then its an incoming connection
if (FD_ISSET(sever_socket, &readfds))
{
if ((new_socket = accept (sever_socket, (struct sockaddr *) &address, (socklen_t*) &addrlen)) < 0)
{
perror("accept");
exit(EXIT_FAILURE);
}
//inform user of socket number - used in send and receive commands
LOG_F (INFO, "New connection, socket fd is %d, ip is : %s, port : %d",
new_socket, inet_ntoa(address.sin_addr), ntohs(address.sin_port));
//add new socket to array of sockets
for (i = 0; i < MAX_CLIENT; i++)
{
//if position is empty
if( client_socket[i] == 0 )
{
client_socket[i] = new_socket;
LOG_F (INFO, "Adding to list of sockets as %d" , i);
break;
}
}
}
for (i = 0; i < MAX_CLIENT; i++)
{
sd = client_socket[i];
if (FD_ISSET (sd , &readfds))
{
memset (&rcvBuf, 0x00, sizeof(rcvBuf));
if ((fp = fdopen (sd, "r")) == NULL)
{
LOG_F (WARNING, "TCP_SOCKET FD_OPEN Error");
close (sd);
client_socket[i] = 0;
}
else
{
ret = ioctl (sd, FIONREAD, &nread);
if (nread == 0)
{
fclose (fp);
close (sd);
client_socket[i] = 0;
LOG_F (WARNING, "Client disconnected(as %d, fd %d)", i, sd);
}
else
{
len = recv (sd, rcvBuf, nread, 0);
if (len > 0)
{
LOG_F (INFO, "RECV size %d" , len);
...
do_msg_handler ()
}
}
...

Linux TCP socket timestamping option

Quoting form this online kernel doc
SO_TIMESTAMPING
Generates timestamps on reception, transmission or both. Supports
multiple timestamp sources, including hardware. Supports generating
timestamps for stream sockets.
Linux supports TCP timestamping, and I tried to write some demo code to get any timestamp for TCP packet.
The server code as below:
//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
perror("bind failed. Error");
return 1;
}
puts("bind done");
//Listen
listen(socket_desc , 3);
//Accept and incoming connection
puts("Waiting for incoming connections...");
int c = sizeof(struct sockaddr_in);
client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c);
if (client_sock < 0)
{
perror("accept failed");
return 1;
}
// Note: I am trying to get software timestamp only here..
int oval = SOF_TIMESTAMPING_RX_SOFTWARE | SOF_TIMESTAMPING_SOFTWARE;
int olen = sizeof( oval );
if ( setsockopt( client_sock, SOL_SOCKET, SO_TIMESTAMPING, &oval, olen ) < 0 )
{ perror( "setsockopt TIMESTAMP"); exit(1); }
puts("Connection accepted");
char buf[] = "----------------------------------------";
int len = strlen( buf );
struct iovec myiov[1] = { {buf, len } };
unsigned char cbuf[ 40 ] = { 0 };
int clen = sizeof( cbuf );
struct msghdr mymsghdr = { 0 };
mymsghdr.msg_name = NULL;
mymsghdr.msg_namelen = 0;
mymsghdr.msg_iov = myiov;
mymsghdr.msg_iovlen = 1;
mymsghdr.msg_control = cbuf;
mymsghdr.msg_controllen = clen;
mymsghdr.msg_flags = 0;
int read_size = recvmsg( client_sock, &mymsghdr, 0);
if(read_size == 0)
{
puts("Client disconnected");
fflush(stdout);
}
else if(read_size == -1)
{
perror("recv failed");
}
else
{
struct msghdr *msgp = &mymsghdr;
printf("msg received: %s \n",(char*)msgp->msg_iov[0].iov_base);// This line is successfully hit.
// Additional info: print msgp->msg_controllen inside gdb is 0.
struct cmsghdr *cmsg;
for ( cmsg = CMSG_FIRSTHDR( msgp );
cmsg != NULL;
cmsg = CMSG_NXTHDR( msgp, cmsg ) )
{
printf("Time GOT!\n"); // <-- This line is not hit.
if (( cmsg->cmsg_level == SOL_SOCKET )
&&( cmsg->cmsg_type == SO_TIMESTAMPING ))
printf("TIME GOT2\n");// <-- of course , this line is not hit
}
}
Any ideas why no timestamping is available here ? Thanks
Solution
I am able to get the software timestamp along with hardware timestamp using onload with solarflare NIC.
Still no idea how to get software timestamp alone.
The link you gave, in the comments at the end, says:
I've discovered why it doesn't work. SIOCGSTAMP only works for UDP
packets or RAW sockets, but does not work for TCP. – Gio Mar 17 '16 at 9:331
it doesn't make sense to ask for timestamps for TCP, because there's
no direct correlation between arriving packets and data becoming
available. If you really want timestamps for TCP you'll have to use
RAW sockets and implement your own TCP stack (or use a userspace TCP
library). – ecatmur Jul 4 '16 at 10:39

modbus_read_register - Error connection timed out

We are using libmodbus library to read register values from energy meter EM6400 which supports Modbus over RTU. We are facing the following two issues.
1) We are facing an issue with modbus_read_registers API, this API returns -1 and the error message is:
ERROR Connection timed out: select.
After debugging the library, we found this issue is due to the echo of request bytes in the response message.
read() API call in _modbus_rtu_recv returns request bytes first followed by response bytes. As a result, length_to_read is calculated in compute_data_length_after_meta() based on the request bytes instead of response bytes (which contains the number of bytes read) and connection timed out issue occurs.
We tried to use both 3.0.6 and 3.1.2 libmodbus versions but same issue occurs in both the versions.
2) modbus_rtu_set_serial_mode (ctx, MODBUS_RTU_RS485) returns "BAD file descriptor".
Please confirm if there is any API call missing or any parameter is not set correctly.
Our sample code to read register value is as follows.
int main()
{
modbus_t *ctx;
uint16_t tab_reg[2] = {0,0};
float avgVLL = -1;;
int res = 0;
int rc;
int i;
struct timeval response_timeout;
uint32_t tv_sec = 0;
uint32_t tv_usec = 0;
response_timeout.tv_sec = 5;
response_timeout.tv_usec = 0;
ctx = modbus_new_rtu("/dev/ttyUSB0", 19200, 'E', 8, 1);
if (NULL == ctx)
{
printf("Unable to create libmodbus context\n");
res = 1;
}
else
{
printf("created libmodbus context\n");
modbus_set_debug(ctx, TRUE);
//modbus_set_error_recovery(ctx, MODBUS_ERROR_RECOVERY_LINK |MODBUS_ERROR_RECOVERY_PROTOCOL);
rc = modbus_set_slave(ctx, 1);
printf("modbus_set_slave return: %d\n",rc);
if (rc != 0)
{
printf("modbus_set_slave: %s \n",modbus_strerror(errno));
}
/* Commented - Giving 'Bad File Descriptor' issue
rc = modbus_rtu_set_serial_mode(ctx, MODBUS_RTU_RS485);
printf("modbus_rtu_set_serial_mode: %d \n",rc);
if (rc != 0)
{
printf("modbus_rtu_set_serial_mode: %s \n",modbus_strerror(errno));
}
*/
// This code is for version 3.0.6
modbus_get_response_timeout(ctx, &response_timeout);
printf("Default response timeout:%ld sec %ld usec \n", response_timeout.tv_sec, response_timeout.tv_usec );
response_timeout.tv_sec = 60;
response_timeout.tv_usec = 0;
modbus_set_response_timeout(ctx, &response_timeout);
modbus_get_response_timeout(ctx, &response_timeout);
printf("Set response timeout:%ld sec %ld usec \n", response_timeout.tv_sec, response_timeout.tv_usec );
/* This code is for version 3.1.2
modbus_get_response_timeout(ctx, &tv_sec, &tv_usec);
printf("Default response timeout:%d sec %d usec \n",tv_sec,tv_usec );
tv_sec = 60;
tv_usec = 0;
modbus_set_response_timeout(ctx, tv_sec,tv_usec);
modbus_get_response_timeout(ctx, &tv_sec, &tv_usec);
printf("Set response timeout:%d sec %d usec \n",tv_sec,tv_usec );
*/
rc = modbus_connect(ctx);
printf("modbus_connect: %d \n",rc);
if (rc == -1) {
printf("Connection failed: %s\n", modbus_strerror(errno));
res = 1;
}
rc = modbus_read_registers(ctx, 3908, 2, tab_reg);
printf("modbus_read_registers: %d \n",rc);
if (rc == -1) {
printf("Read registers failed: %s\n", modbus_strerror(errno));
res = 1;
}
for (i=0; i < 2; i++) {
printf("reg[%d]=%d (0x%X)\n", i, tab_reg[i], tab_reg[i]);
}
avgVLL = modbus_get_float(tab_reg);
printf("Average Line to Line Voltage = %f\n", avgVLL);
modbus_close(ctx);
modbus_free(ctx);
}
}
Output of this sample is as follows:
created libmodbus context
modbus_set_slave return: 0
modbus_rtu_set_serial_mode: -1
modbus_rtu_set_serial_mode: Bad file descriptor
Default response timeout:0 sec 500000 usec
Set response timeout:60 sec 0 usec
Opening /dev/ttyUSB0 at 19200 bauds (E, 8, 1)
modbus_connect: 0
[01][03][0F][44][00][02][87][0A]
Waiting for a confirmation...
ERROR Connection timed out: select
<01><03><0F><44><00><02><87><0A><01><03><04><C4><5F><43><D4><C6><7E>modbus_read_registers: -1
Read registers failed: Connection timed out
reg[0]=0 (0x0)
reg[1]=0 (0x0)
Average Line to Line Voltage = 0.000000
Issue 1) is probably a hardware issue, with "local echo" enabled in your RS-485 adapter. Local echo is sometimes used to confirm sending of data bytes on the bus. You need to disable it, or find another RS-485 adapter.
I have written about this in the documentation of my MinimalModbus Python library: Local Echo
It lists a few common ways to disable local echo in RS-485 adapters.

Socket error 10053 is seen when fast (within 100 ms)recv and send is being done

Client is sending 1 byte of data after every 4 seconds of interval. once its receives the byte it acknowledge with 1 byte.
Some times on send error 10053 is seen.
iResult = recv(sSocket, (char*)recvbuf, 1, 0);
if(iResult > 0)
{
setsockopt(sSocket, SOL_SOCKET, SO_SNDTIMEO, (const char*)&dwTime, 1);
iResult = send(sSocket,(char*)&recvbuf,1,0);
if(iResult <= 0)
{
// WSAgetLasterrror() == 10053
}
}
Let me know if you need more details

WSAECONNABORTED (10053) error received while calling send command after fixed iterations

I'm also facing some issue where a server sends data to client and client sends back the acknowledgement. But after certain iterations the socket is aborted and I'm getting WSAECONNABORTED (10053) while sending the acknowledgement back to server.
I'm on win7 64-bit machine.
Server code(this is perl code):
sub Send_Msg_to_SourceSelector
{
(my $msg)=#_;
my $msg_len = length("$msg")+1;
print "the message length is: $msg_len\n\n";
PrintLogFile(1, ">> $CurrentTime >> The message length is : $msg_len <<<<\n\n");
print "the SOCK1 is: SOCK\n\n";
PrintLogFile(1, ">> $CurrentTime >> The sent message is : $msg <<<<\n\n");
send $SOCK,$msg,$msg_len;
print "the SOCK2 is: $SOCK\n\n";
recv $SOCK,my $awk,3,0;
PrintLogFile(1, ">> $CurrentTime >> The acknowledgement received is : $awk <<<<\n\n");
print "the SOCK3 is: $SOCK\n\n";
}
Client code (this is in C...executable generated in visual studio 2013):
void RecvDataFromSequencer(SOCKET sock, FILE *Log)
{
char n,buffer[2000];
while(!FlagTestExecutionCompleted)
{
memset (buffer , 0 , 2000);
printf("The address of buffer before is: %d\n", buffer);
n = recv(sock,buffer,2000,0); //blocking call
printf("The address of buffer after is: %d\n", buffer);
printf("in recv func: %x\n", Log);
//printlogfile(Log, buffer);
fprintf(Log,"%s%s",buffer,"\n");
fprintf(Log,"%d%s",n,"\n");
fprintf(Log,"%s%d%s","FlagTestExecutionCompleted is ==> ",FlagTestExecutionCompleted,"\n");
fflush(Log);
if (n == -1)
{
printf("recv failed: %d\n", WSAGetLastError());
fprintf(Log,"%s%s",WSAGetLastError(),"\n");
error("ERROR reading from STATS");
fprintf(Log,"%s%s","ERROR reading from STATS","\n");
fflush(Log);
}
else
{
printf("\nMessage from STATS: %s\n",buffer);
strcpy(line_tcfile,buffer);
if(strstr(line_tcfile,"SessionCompleted"))
{
printf("\n End of Test Session");
FlagTestExecutionCompleted=1;
}
FlagNewTestCaseRecieved = 1;
}
//Send acknowledgement
Sleep(1000);
**n = send(sock,"ACK",3,0);
if (n == -1)
{
fprintf(Log,"%s%d%s","in send command FlagTestExecutionCompleted is ==> ",FlagTestExecutionCompleted,"\n");
printf("send failed: %d\n", WSAGetLastError());
fprintf(Log,"%s%s",WSAGetLastError(),"\n");**
fprintf(Log,"%s%s","ERROR writing to STATS","\n");
fprintf(Log,"%d%s",n,"\n");
fflush(Log);
error("ERROR writing to STATS");
}
In this the following is happening:
1. server reads a line and sends to client
2. client reads the line and sends back the acknowledgement back to server
3. this process happens successfully to some tests
4. after some time the while sending back acknowledgement to server through send command, it returns WSAECONNABORTED (10053)
I don't know what is the reason.
Please help
Thanks,
Pankaj