most files - check if this is all we need
This commit is contained in:
601
sicsconn.cpp
Normal file
601
sicsconn.cpp
Normal file
@ -0,0 +1,601 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/select.h>
|
||||
#include <string.h>
|
||||
#include "sicsconn.h"
|
||||
#include "instr_hosts.h"
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
|
||||
|
||||
int printit(void);
|
||||
|
||||
int uselect(int nfds,
|
||||
fd_set * readfds, fd_set * writefds, fd_set * exceptfds,
|
||||
struct timeval *timeout)
|
||||
{
|
||||
|
||||
sigset_t sigmask;
|
||||
struct timespec tmo, *tmoPtr;
|
||||
int result;
|
||||
|
||||
sigfillset(&sigmask);
|
||||
if (timeout) {
|
||||
tmo.tv_sec = timeout->tv_sec;
|
||||
tmo.tv_nsec = timeout->tv_usec * 1000;
|
||||
tmoPtr = &tmo;
|
||||
} else {
|
||||
tmoPtr = NULL;
|
||||
}
|
||||
result = pselect(nfds, readfds, writefds, exceptfds, tmoPtr, &sigmask);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int sigpipe_ignored = 0;
|
||||
|
||||
int SicsSockAdr(struct sockaddr_in *sockaddr, const char *hostport,
|
||||
int defaultPort, const char *server) {
|
||||
// create sockadr from hostport (hostname and port number separated with colon)
|
||||
// hostport may also be an instrument name, in this case server has to be defined
|
||||
|
||||
struct hostent *hostent; /* Host database entry */
|
||||
struct in_addr addr; /* For 64/32 bit madness */
|
||||
char *p;
|
||||
char host[128], instr[32];
|
||||
int port;
|
||||
int l;
|
||||
|
||||
(void) memset((char *) sockaddr, '\0', sizeof(struct sockaddr_in));
|
||||
if (hostport == NULL) hostport="";
|
||||
p = strchr((char *)hostport, ':');
|
||||
if (p != NULL) {
|
||||
l = p - hostport;
|
||||
port = atoi(p+1);
|
||||
} else {
|
||||
InstrHost((char *)server, (char *)hostport, instr, sizeof instr,
|
||||
host, sizeof host, &port);
|
||||
if (port == 0) {
|
||||
port = atoi(hostport);
|
||||
if (port != 0) {
|
||||
l = 0;
|
||||
} else {
|
||||
l = strlen(hostport);
|
||||
}
|
||||
} else {
|
||||
l = -1;
|
||||
}
|
||||
}
|
||||
if (l>= 0) {
|
||||
if (l >= (int)sizeof host) return -1;
|
||||
strncpy(host, hostport, l);
|
||||
host[l]='\0';
|
||||
}
|
||||
if (port == 0) port = defaultPort;
|
||||
if (port == 0) return -1;
|
||||
|
||||
sockaddr->sin_family = AF_INET;
|
||||
sockaddr->sin_port = htons((unsigned short) (port & 0xFFFF));
|
||||
|
||||
if (host[0]=='\0') {
|
||||
addr.s_addr = INADDR_ANY;
|
||||
} else {
|
||||
hostent = gethostbyname(host);
|
||||
if (hostent != NULL) {
|
||||
memcpy((char *) &addr,
|
||||
(char *) hostent->h_addr_list[0], (size_t) hostent->h_length);
|
||||
} else {
|
||||
addr.s_addr = inet_addr(host);
|
||||
if (addr.s_addr == (unsigned long)-1) {
|
||||
return -1; /* error */
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* There is a rumor that this assignment may require care on
|
||||
* some 64 bit machines.
|
||||
*/
|
||||
sockaddr->sin_addr.s_addr = addr.s_addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SicsConnect(const char *hostport, const char *server, bool async) {
|
||||
struct sockaddr_in sadr;
|
||||
int iret, fd;
|
||||
int oldopts;
|
||||
|
||||
iret = SicsSockAdr(&sadr, hostport, 8641, server);
|
||||
if (iret < 0) return -1;
|
||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (fd < 0) return -1;
|
||||
if (async) {
|
||||
oldopts = fcntl(fd, F_GETFL, 0);
|
||||
fcntl(fd, F_SETFL, oldopts | O_NONBLOCK);
|
||||
}
|
||||
iret = connect(fd, (struct sockaddr *)&sadr, sizeof(sadr));
|
||||
if (iret < 0) {
|
||||
switch (errno) {
|
||||
case EINPROGRESS:
|
||||
case EALREADY:
|
||||
case EISCONN:
|
||||
return fd;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int SicsConnectSuccess(int fd)
|
||||
{
|
||||
// returns 1 on success, 0 when pending, -1 on error
|
||||
fd_set wmask, rmask;
|
||||
struct timeval tmo = { 0, 0 };
|
||||
int oldopts;
|
||||
int ret;
|
||||
|
||||
oldopts = fcntl(fd, F_GETFL, 0);
|
||||
assert(oldopts | O_NONBLOCK); /* fd must be in non-blocking mode */
|
||||
|
||||
FD_ZERO(&wmask);
|
||||
FD_ZERO(&rmask);
|
||||
FD_SET(fd, &wmask);
|
||||
FD_SET(fd, &rmask);
|
||||
ret = uselect(fd + 1, &rmask, &wmask, NULL, &tmo);
|
||||
if (ret > 0) {
|
||||
if (FD_ISSET(fd, &rmask)) { /* there may already be data for read */
|
||||
if (recv(fd, NULL, 0, 0) < 0) { /* zero length, check only return value */
|
||||
ret = -1; /* first recv failed */
|
||||
}
|
||||
} else {
|
||||
if (FD_ISSET(fd,&wmask)) {
|
||||
if (send(fd, NULL, 0, 0) < 0) { /* zero length, check only return value */
|
||||
ret = -2; /* first send failed */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fcntl(fd, F_SETFL, oldopts & ~O_NONBLOCK); /* reset to blocking mode */
|
||||
return ret;
|
||||
}
|
||||
|
||||
SicsConnection::SicsConnection(QObject *parent) : QObject(parent) {
|
||||
hostport = NULL;
|
||||
userpass = NULL;
|
||||
server = NULL;
|
||||
state = disconnected;
|
||||
bufline = "";
|
||||
bufstate = buf_got_line;
|
||||
connect_state = connect_start;
|
||||
command2send = "";
|
||||
tmo = 0;
|
||||
if (!sigpipe_ignored) {
|
||||
signal (SIGPIPE, SIG_IGN);
|
||||
sigpipe_ignored = 1;
|
||||
}
|
||||
rdbuffer = "";
|
||||
progressPos = 0;
|
||||
rdpos = 0;
|
||||
debug = 0;
|
||||
}
|
||||
|
||||
//SicsConnection::SicsConnection(SicsConnection *copy) {
|
||||
// hostport = strdup(copy->hostport);
|
||||
// userpass = NULL;
|
||||
// state = disconnected;
|
||||
//}
|
||||
|
||||
SicsConnection::~SicsConnection() {
|
||||
if (state != disconnected) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
if (hostport) free(hostport);
|
||||
if (userpass) free(userpass);
|
||||
if (server) free(server);
|
||||
}
|
||||
|
||||
void SicsConnection::setHost(const char *hostport, const char *server) {
|
||||
if (this->hostport != NULL) free(this->hostport);
|
||||
if (hostport != NULL) {
|
||||
this->hostport = strdup(hostport);
|
||||
} else {
|
||||
this->hostport = NULL;
|
||||
}
|
||||
if (this->server != NULL) free(this->server);
|
||||
this->server = strdup(server);
|
||||
}
|
||||
|
||||
void SicsConnection::setUser(const char *userpass) {
|
||||
if (this->userpass != NULL) free(this->userpass);
|
||||
if (userpass != NULL) {
|
||||
this->userpass = strdup(userpass);
|
||||
} else {
|
||||
this->userpass = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int SicsConnection::handleBuffer(void) {
|
||||
return handleBuffer(0);
|
||||
}
|
||||
|
||||
int SicsConnection::handleBuffer(int tmo) {
|
||||
fd_set mask;
|
||||
struct timeval tmov;
|
||||
int iret = 1;
|
||||
int pos;
|
||||
char ch;
|
||||
char line[128];
|
||||
|
||||
switch (connect_state) {
|
||||
case connect_start:
|
||||
fd = SicsConnect(hostport, server, true);
|
||||
if (fd < 0) {
|
||||
connect_state = connect_error; // what else?
|
||||
return -1;
|
||||
}
|
||||
connect_state = connect_wait;
|
||||
return 0;
|
||||
case connect_wait:
|
||||
iret = SicsConnectSuccess(fd);
|
||||
if (iret <= 0) {
|
||||
if (startServer) {
|
||||
iret = system(startServer);
|
||||
if (iret) {
|
||||
printf("can not connect to sea and failed to start the sea server\n");
|
||||
printf("\n");
|
||||
pos = strcspn(hostport, ":");
|
||||
printf("please execute 'sea start' from the instrument account of %.*s\n", pos, hostport);
|
||||
printf("\n");
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
iret = 1;
|
||||
}
|
||||
startServer = NULL;
|
||||
return iret;
|
||||
}
|
||||
connect_state = connect_login;
|
||||
return 0;
|
||||
case connect_login:
|
||||
if (userpass == NULL) {
|
||||
snprintf(line, sizeof line, "Spy 007\n");
|
||||
} else {
|
||||
snprintf(line, sizeof line, "%s", userpass);
|
||||
}
|
||||
bufstate = buf_sent_line;
|
||||
send(fd, line, strlen(line), 0);
|
||||
connect_state = connect_waitlogin;
|
||||
// if (strcmp(server, "sea") == 0 && userpass != NULL) {
|
||||
// printf("*** send login (%s %s)\n", server, line);
|
||||
// }
|
||||
return 0;
|
||||
case connect_error:
|
||||
return -2;
|
||||
default: break;
|
||||
}
|
||||
|
||||
FD_ZERO(&mask);
|
||||
while (bufstate > buf_got_finished) {
|
||||
do {
|
||||
FD_SET(fd, &mask);
|
||||
tmov.tv_sec = tmo;
|
||||
tmov.tv_usec = 0;
|
||||
iret = select(fd+1, &mask, NULL, NULL, &tmov);
|
||||
if (iret < 0) {
|
||||
perror("select");
|
||||
close(fd);
|
||||
fd = -1;
|
||||
connect_state = connect_error;
|
||||
state = disconnected;
|
||||
return -2;
|
||||
} else if (iret == 0) {
|
||||
return -1; /* no more data */
|
||||
}
|
||||
iret = recv(fd, &ch, 1, 0);
|
||||
if (iret <= 0) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
connect_state = connect_error;
|
||||
state = disconnected;
|
||||
if (printit()) printf("zero on receive -> disconnected\n");
|
||||
// printf("*** disconnected (zero on receive)\n");
|
||||
return -2;
|
||||
}
|
||||
bufline.append(ch);
|
||||
} while (ch != '\n');
|
||||
iret = 0;
|
||||
rdbuffer += bufline;
|
||||
if (debug) {
|
||||
// printf("%s bufline{%s}\n", debug, bufline.latin1());
|
||||
}
|
||||
if ((int)rdbuffer.length() >= progressPos + 1000) {
|
||||
progress(rdbuffer.length() - progressPos);
|
||||
progressPos = rdbuffer.length();
|
||||
}
|
||||
// if (strcmp(server, "sea") == 0 && userpass != NULL) {
|
||||
// printf("*** bufline %s", bufline.latin1());
|
||||
// }
|
||||
if (bufstate == buf_got_start && bufline.startsWith("TRANSACTIONFINISHED")) {
|
||||
bufstate = buf_got_finished;
|
||||
iret = 1;
|
||||
}
|
||||
if (bufstate == buf_sent_transact && bufline.startsWith("TRANSACTIONSTART")) {
|
||||
bufstate = buf_got_start;
|
||||
}
|
||||
if (bufstate == buf_sent_line) {
|
||||
bufstate = buf_got_line;
|
||||
if (connect_state == connect_waitlogin) {
|
||||
if (debug) {
|
||||
printf("connectlogin %s\n", bufline.latin1());
|
||||
}
|
||||
if (bufline.startsWith("Login OK\n")) {
|
||||
connect_state = connect_done;
|
||||
state = connected;
|
||||
if (command2send != "") {
|
||||
sendThis(command2send.latin1());
|
||||
command2send = "";
|
||||
if (state == disconnected) {
|
||||
return -1;
|
||||
}
|
||||
bufstate = buf_sent_transact;
|
||||
}
|
||||
} else {
|
||||
bufstate = buf_sent_line;
|
||||
}
|
||||
} else {
|
||||
iret = 1;
|
||||
}
|
||||
}
|
||||
bufline = "";
|
||||
}
|
||||
|
||||
return iret;
|
||||
}
|
||||
|
||||
int SicsConnection::getLine(QString &line) {
|
||||
QString qline;
|
||||
int pos, len;
|
||||
|
||||
if (state == disconnected) {
|
||||
return -1;
|
||||
}
|
||||
handleBuffer(0);
|
||||
if (rdpos >= (int)rdbuffer.length() && tmo > 0) {
|
||||
if (handleBuffer(tmo) < 0) {
|
||||
printf("timeout %d\n", tmo);
|
||||
}
|
||||
}
|
||||
if (rdpos < (long)rdbuffer.length()) {
|
||||
pos = rdbuffer.find('\n', rdpos);
|
||||
if (pos < rdpos) { // lf not found, return up to end of buffer (is this correct?)
|
||||
return 0; /***/
|
||||
len = rdbuffer.length() - rdpos;
|
||||
line = rdbuffer.mid(rdpos);
|
||||
progressPos -= rdbuffer.length();
|
||||
rdbuffer="";
|
||||
rdpos = 0;
|
||||
} else {
|
||||
len = pos - rdpos;
|
||||
line = rdbuffer.mid(rdpos,len);
|
||||
rdpos = pos + 1;
|
||||
//rdbuffer.remove(0, pos + 1);
|
||||
}
|
||||
if (debug) {
|
||||
//printf("%s getLine{%s}{%s}\n", debug, line.latin1(), rdbuffer.mid(rdpos,9).latin1());
|
||||
printf("%s getLine{%s}\n", debug, line.latin1());
|
||||
}
|
||||
if (line.startsWith("TRANSACTIONFINISHED")) {
|
||||
if (state == replying) {
|
||||
state = connected;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
} else {
|
||||
if (debug) {
|
||||
// printf("%s error\n", debug);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SicsConnection::swallow() {
|
||||
QString line;
|
||||
bool done;
|
||||
|
||||
if (debug) {
|
||||
printf("%s swallow start\n", debug);
|
||||
}
|
||||
while (state == replying) {
|
||||
if (getLine(line) > 0) {
|
||||
done = false;
|
||||
handle(line, &done);
|
||||
if (!done) {
|
||||
//printf("*** swallow {%s}\n", line);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (debug) {
|
||||
printf("%s swallow end\n", debug);
|
||||
}
|
||||
}
|
||||
|
||||
int SicsConnection::sendThis(const char *str) {
|
||||
int l, iret;
|
||||
if (state != disconnected) {
|
||||
l = strlen(str);
|
||||
// if (strcmp(server, "sea") == 0 && userpass != NULL) {
|
||||
// printf("*** send {%s}\n", str);
|
||||
// }
|
||||
iret = send(fd, str, l, 0);
|
||||
if (iret != l) {
|
||||
printf("sent %d of %d, disconnect\n", iret, l);
|
||||
close(fd);
|
||||
fd = -1;
|
||||
state = disconnected;
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void SicsConnection::reconnect(void) {
|
||||
if (state != disconnected) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
state = disconnected;
|
||||
}
|
||||
connect_state = connect_start;
|
||||
command2send.sprintf("fulltransact config listen 1\n");
|
||||
}
|
||||
|
||||
void SicsConnection::disconnect(void) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
state = disconnected;
|
||||
}
|
||||
|
||||
int SicsConnection::sendCommand(const char *cmd) {
|
||||
char *nl;
|
||||
|
||||
if (debug) {
|
||||
printf("%s swallow before %s\n", debug, cmd);
|
||||
}
|
||||
swallow();
|
||||
if (debug) {
|
||||
printf("%s sendCommand %s\n", debug, cmd);
|
||||
}
|
||||
nl = strrchr((char *)cmd, '\n'); /* check if we have to add a final line break */
|
||||
if (nl == NULL || nl[1] != '\0') {
|
||||
command2send.sprintf("fulltransact %s\n", cmd);
|
||||
} else {
|
||||
command2send.sprintf("fulltransact %s", cmd);
|
||||
}
|
||||
|
||||
if (state == disconnected) {
|
||||
// printf("*** reconnect!\n");
|
||||
connect_state = connect_start;
|
||||
} else {
|
||||
sendThis(command2send.latin1());
|
||||
bufstate = buf_sent_transact;
|
||||
command2send = "";
|
||||
if (state == disconnected) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SicsConnection::getResponse() { // get BEGINNING of response
|
||||
int iret;
|
||||
QString line;
|
||||
|
||||
state = connected;
|
||||
tmo = 10;
|
||||
while (1) {
|
||||
iret = getLine(line);
|
||||
if (iret <= 0) {
|
||||
if (iret == -2) {
|
||||
if (printit()) printf("timeout on sea command\n");
|
||||
}
|
||||
//printf("error in getLine %d\n", iret);
|
||||
if (debug) {
|
||||
printf("%s error in getResponse {%s}\n", debug, rdbuffer.latin1() + rdpos);
|
||||
}
|
||||
return iret;
|
||||
}
|
||||
if (line.startsWith("TRANSACTIONSTART")) break;
|
||||
if (debug) {
|
||||
printf("%s getResponse handle %s\n", debug, line.latin1());
|
||||
}
|
||||
handle(line.latin1());
|
||||
};
|
||||
state = replying;
|
||||
if (debug) {
|
||||
printf("%s gotResponse\n", debug);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SicsConnection::command(const char *cmd) {
|
||||
int iret;
|
||||
int cnt, tries;
|
||||
|
||||
tries = 3;
|
||||
do {
|
||||
cnt = 5;
|
||||
while (cnt > 0 && (connect_state != connect_done || bufstate > buf_got_finished)) {
|
||||
handleBuffer(1);
|
||||
cnt--;
|
||||
}
|
||||
iret = sendCommand(cmd);
|
||||
handleBuffer(5);
|
||||
iret = getResponse();
|
||||
tries--;
|
||||
} while (iret < 0 && tries > 0);
|
||||
return iret;
|
||||
}
|
||||
|
||||
int SicsConnection::handleMessages(int tmoArg) {
|
||||
int iret;
|
||||
QString line;
|
||||
bool bs=false;
|
||||
|
||||
tmo = tmoArg;
|
||||
if (bufstate <= buf_got_finished) {
|
||||
bufstate = buf_sent_line;
|
||||
bs = true;
|
||||
}
|
||||
iret = getLine(line);
|
||||
tmo = 0;
|
||||
while (iret >= 0) {
|
||||
if (iret > 0) {
|
||||
handle(line.latin1());
|
||||
}
|
||||
iret = getLine(line);
|
||||
}
|
||||
if (bs && bufstate == buf_sent_line) {
|
||||
bufstate = buf_got_line;
|
||||
}
|
||||
return iret;
|
||||
}
|
||||
|
||||
#ifdef TESTSC
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void) {
|
||||
SicsConnection *sc;
|
||||
char line[256];
|
||||
char *lin;
|
||||
int iret;
|
||||
|
||||
sc = SicsNewConnection("lnsl15", 13006);
|
||||
if (sc == NULL) return -1;
|
||||
while (1) {
|
||||
printf("> ");
|
||||
lin = fgets(line, sizeof line, stdin);
|
||||
if (lin == NULL) return 1;
|
||||
iret = SicsCommand(sc, line);
|
||||
if (iret < 0) return 2;
|
||||
while (1) {
|
||||
iret = getLine(line);
|
||||
if (iret == 0) break;
|
||||
if (iret < 0) return 3;
|
||||
if (iret > 0) {
|
||||
printf("(%s)\n", line.latin1());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user