//******************************************************************************* //* 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. // //****************************************************************************************** static int hSocket; static int sTimeout = 15; static char sCurrentAddress[256]; static int sConnectedFlag = false; const int CMD_BUF_LEN = 8192; static char sCommandBuffer[CMD_BUF_LEN]; //- INCLUDE #include "SocketLecroy.h" //- 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) { SOCKADDR_IN serverAddr; int sockAddrSize = sizeof (SOCKADDR), result; const int resp = 1; fd_set wr_set = {1, {0}}; 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)) == 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( )."); } wr_set.fd_array[0] = hSocket; argp = 1;//-non blocking mode ioctlsocket(hSocket, FIONBIO, &argp); int status = connect(hSocket, (SOCKADDR FAR *) &serverAddr, sockAddrSize); int error_code = WSAGetLastError(); //- already connected ! if ( status && error_code == WSAEISCONN ) return; if( status != 0 ) // We are not connected : so retry { if ( error_code == WSAEINPROGRESS || error_code == WSAEWOULDBLOCK ) // But the connection is in progress { int nb = 0; while ( nb++ < 5 ) // We will attempt to connect every 150 ms for 5 times max. { status = ::connect(hSocket, ( sockaddr *)&serverAddr, sizeof(serverAddr)); error_code = WSAGetLastError(); if ( status != 0 ) // Still not connected { if ( errno == WSAEISCONN ) // This is the right error ! { Sleep(150); // Sleep for 150 ms } }// Connection is OK. else break; } //- end while // Too much attempts, so failure ! if ( nb >= 5 ) { throw lecroy::SocketException("COMMUNICATION_BROKEN ", "Too much attempt to (re)build socket connection.", "SocketLecroy::TCP_Connect( )."); } }// TODO : throw ; // Not the right error, so failure ! }// Connected at first attempt ! result = select(hSocket, NULL, &wr_set, NULL, &tval); argp = 0;//-blocking mode ioctlsocket(hSocket, FIONBIO, &argp); //- connect to server (scope) if (result == SOCKET_ERROR) { 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) { if (sConnectedFlag) { closesocket(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, accum, space_left, bytes_more, buf_count; char tmpStr[256]; char *idxPtr; fd_set rd_set = {1, {0}}; 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( )."); rd_set.fd_array[0] = hSocket; 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 || result == SOCKET_ERROR) { 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; }