Select Git revision
-
Raphael GIRARDOT authoredRaphael GIRARDOT authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
LinuxSocketLecroy.cpp 10.94 KiB
//*******************************************************************************
//* Copyright (c) 2008-2014 Synchrotron SOLEIL
//* All rights reserved. This program and the accompanying materials
//* are made available under the terms of the GNU Lesser Public License v3
//* which accompanies this distribution, and is available at
//* http://www.gnu.org/licenses/lgpl.html
//******************************************************************************
//******************************************************************************************
//
//
// september 13, 2004 : Source file for the communication in socket mode
//
// with a Lecroy scope (avaiable for all models)
//
// author : X.Elattaoui
//
// SocketLecroy.cpp: implementation of the SocketLecroy class.
//
//******************************************************************************************
//- INCLUDE
#include <iostream>
#include "SocketLecroy.h"
#include <sys/time.h>
#include <time.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <sys/select.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <cstdio>
static int hSocket;
static int sTimeout = 1; //- second(s)
static char sCurrentAddress[256];
static int sConnectedFlag = false;
const int CMD_BUF_LEN = 8192;
static char sCommandBuffer[CMD_BUF_LEN];
//- init of the static instance
SocketLecroy* SocketLecroy::SL_instance = 0; //- ptr on the SocketLecroy instance
SocketLecroy* SocketLecroy::get_instance()
{
if( !SL_instance )
SL_instance = new SocketLecroy();
return SL_instance;
}
void SocketLecroy::delete_instance(SocketLecroy* SL_instance)
{
if(SL_instance)
{
delete SL_instance ;
SL_instance = 0;
}
}
//- CTOR
SocketLecroy::SocketLecroy()
{
sConnectedFlag=false;
}
//- DTOR
SocketLecroy::~SocketLecroy()
{
TCP_Disconnect();
}
//- Build the connection
void SocketLecroy::TCP_Connect(char *ip_address) throw (lecroy::SocketException)
{
struct sockaddr_in serverAddr;
int result;
const int resp = 1;
fd_set wr_set;
FD_ZERO(&wr_set);
struct timeval tval;
unsigned long argp;
char tmpStr[256];
//- connection test
if (sConnectedFlag)
return;
strcpy(sCurrentAddress, ip_address);
tval.tv_sec = sTimeout;
tval.tv_usec = 0;
//- build server socket address
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(SERVER_PORT);
if ((serverAddr.sin_addr.s_addr = inet_addr(ip_address)) == -1)
{
throw lecroy::SocketException("COMMUNICATION_BROKEN ",
"Bad server address.",
"SocketLecroy::TCP_Connect( ).");
}
//- create client's socket
if ((hSocket = socket(AF_INET, SOCK_STREAM, 0)) == -1) //INVALID_SOCKET)
{
throw lecroy::SocketException("COMMUNICATION_BROKEN ",
"Unable to create client's socket.",
"SocketLecroy::TCP_Connect( ).");
}
if (setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (char*)&resp, sizeof(resp)) != 0)
{
throw lecroy::SocketException("COMMUNICATION_BROKEN ",
"Unable to set socket option to TCP_NODELAY.",
"SocketLecroy::TCP_Connect( ).");
}
FD_SET(hSocket, &wr_set);
argp = 1;//-non blocking mode
ioctl(hSocket, FIONBIO, &argp);
int opts;
opts = fcntl (hSocket, F_GETFL);
if (opts >= 0)
opts = (opts | O_NONBLOCK);
fcntl (hSocket, F_SETFL, opts);
//connect(hSocket, (SOCKADDR FAR *) &serverAddr, sockAddrSize);
int status = ::connect(hSocket, ( sockaddr *)&serverAddr, sizeof(serverAddr));
if(status < 0) // We are not connected : so retry
{
if(errno == EINPROGRESS) // But the connection is in progress
{
int nb = 0;
struct timespec time_to_sleep, time_remaining;
while(nb++ < 5) // We will attempt to connect every 100 ms for 5 times max.
{
status = ::connect (hSocket, ( sockaddr *)&serverAddr, sizeof(serverAddr));
if(status != 0) // Still not connected
{
if(errno == EALREADY) // This is the right error !
{
time_to_sleep.tv_sec = 0;
time_to_sleep.tv_nsec = 15000000L;
nanosleep(&time_to_sleep, &time_remaining); // Sleep for 150 ms
}
}// Connection is OK.
else
break;
}//TODO : throw ; // Too much attempts, so failure !
}// TODO : throw ; // Not the right error, so failure !
}// Connected at first attempt !
result = select(hSocket, NULL, &wr_set, NULL, &tval);
argp = 0;//-blocking mode
ioctl(hSocket, FIONBIO, &argp);
//- connect to server (scope)
if (result < 0)
{
sprintf(tmpStr, "Unable to make connection to IP:%s", ip_address);
throw lecroy::SocketException("COMMUNICATION_BROKEN ",
tmpStr,
"SocketLecroy::TCP_Connect( ).");
}
sConnectedFlag = true;
}
//- DisconnectFromScope: disconnect from a network device
void SocketLecroy::TCP_Disconnect(void) throw (lecroy::SocketException)
{
if (sConnectedFlag)
{
close(hSocket);
sConnectedFlag = false;
}
}
//- Clear a connection
void SocketLecroy::TCP_ClearDevice(void) throw (lecroy::SocketException)
{
if ( !sConnectedFlag )
throw lecroy::SocketException("COMMUNICATION_BROKEN",
"Disconnection already done.",
"SocketLecroy::TCP_ClearDevice( ).");
TCP_Disconnect();
TCP_Connect(sCurrentAddress);
}
//- Send commands to the remote device
void SocketLecroy::TCP_WriteDevice(char *buf, int len, bool eoi_flag) throw (lecroy::SocketException)
{
TCP_HEADER header;
int result, bytes_more, bytes_xferd;
char *idxPtr;
//- test connection
if ( !sConnectedFlag )
throw lecroy::SocketException("COMMUNICATION_BROKEN ",
"Device not connected.",
"SocketLecroy::TCP_WriteDevice( ).");
if (len < CMD_BUF_LEN)
strcpy(sCommandBuffer, buf);
//- set the header info
header.bEOI_Flag = DATA_FLAG;
header.bEOI_Flag |= (eoi_flag)? EOI_FLAG:0;
header.reserved[0] = 1;
header.reserved[1] = 0;
header.reserved[2] = 0;
header.iLength = htonl(len);
//- write the header first
if (send(hSocket, (char *) &header, sizeof(TCP_HEADER), 0) != sizeof(TCP_HEADER))
{
throw lecroy::SocketException("COMMUNICATION_BROKEN ",
"Unable to send header info to the server.",
"SocketLecroy::TCP_WriteDevice( ).");
}
bytes_more = len;
idxPtr = buf;
bytes_xferd = 0;
while (1)
{
//- then write the rest of the block
idxPtr = buf + bytes_xferd;
if ((result = send(hSocket, (char *) idxPtr, bytes_more, 0)) < 0)
{
throw lecroy::SocketException("COMMUNICATION_BROKEN ",
"Unable to send data to the server.",
"SocketLecroy::TCP_WriteDevice( ).");
}
bytes_xferd += result;
bytes_more -= result;
if (bytes_more <= 0)
break;
}
}
//- Read the device answer
void SocketLecroy::TCP_ReadDevice(char *buf, int len, int *recv_count) throw (lecroy::SocketException)
{
TCP_HEADER header;
int result;
unsigned int accum, space_left, bytes_more, buf_count;
char tmpStr[256];
char *idxPtr;
fd_set rd_set;
FD_ZERO(&rd_set);
struct timeval tval;
//- test connection
if ( !sConnectedFlag )
throw lecroy::SocketException("COMMUNICATION_BROKEN ",
"Device not connected.",
"SocketLecroy::TCP_ReadDevice( ).");
*recv_count = 0;
if (!buf)
throw lecroy::SocketException("COMMUNICATION_BROKEN ",
"Buffer memory not allocated.",
"SocketLecroy::TCP_ReadDevice( ).");
FD_SET(hSocket, &rd_set);
tval.tv_sec = sTimeout;
tval.tv_usec = 0;
memset(buf, 0, len);
buf_count = 0;
space_left = len;
while (1)
{
result = select(hSocket, &rd_set, NULL, NULL, &tval);
if (result < 0)
{
TCP_ClearDevice();
throw lecroy::SocketException("COMMUNICATION_BROKEN ",
"Read Timeout.",
"SocketLecroy::TCP_ReadDevice( ).");
}
//- get the header info first
accum = 0;
while (1)
{
memset(&header, 0, sizeof(TCP_HEADER));
if ((result = recv(hSocket, (char *) &header + accum, sizeof(header) - accum, 0)) < 0)
{
TCP_ClearDevice();
throw lecroy::SocketException("COMMUNICATION_BROKEN ",
"Unable to receive header info from the server.",
"SocketLecroy::TCP_ReadDevice( ).");
}
accum += result;
if (accum>=sizeof(header))
break;
}
header.iLength = ntohl(header.iLength);
//- only read to len amount
if (header.iLength > space_left)
{
header.iLength = space_left;
throw lecroy::SocketException("COMMUNICATION_BROKEN ",
"Read buffer size is too small.",
"SocketLecroy::TCP_ReadDevice( ).");
}
//- read the rest of the block
accum = 0;
while (1)
{
idxPtr = buf + (buf_count + accum);
bytes_more = header.iLength - accum;
if ((space_left-accum) < TCP_MINIMUM_PACKET_SIZE)
{
TCP_ClearDevice();
sprintf(tmpStr, "Read buffer needs to be adjusted, must be minimum of %d bytes", TCP_MINIMUM_PACKET_SIZE);
throw lecroy::SocketException("COMMUNICATION_BROKEN ",
tmpStr,
"SocketLecroy::TCP_ReadDevice( ).");
}
if ((result = recv(hSocket, (char *) idxPtr, (bytes_more>2048)?2048:bytes_more, 0)) < 0)
{
TCP_ClearDevice();
//-MessageBox(0, "Unable to receive data from the server.", "ERROR", MB_OK);
throw lecroy::SocketException("COMMUNICATION_BROKEN ",
"Unable to receive data from the server",
"SocketLecroy::TCP_ReadDevice( ).");
}
accum += result;
if (accum >= header.iLength)
break;
if ((accum + buf_count) >= len)
break;
}
buf_count += accum;
space_left -= accum;
if (header.bEOI_Flag & EOI_FLAG)
break;
if (space_left <= 0)
break;
}
*recv_count = buf_count;
}