181 lines
3.4 KiB
C++
181 lines
3.4 KiB
C++
// $Id$
|
|
// g++ -O2 -g -pedantic -Wall fgfsclient.cxx -o fgfsclient -lstdc++
|
|
|
|
#include <errno.h>
|
|
#include <iostream>
|
|
#include <netdb.h>
|
|
#include <netinet/in.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
|
|
const int maxlen = 256;
|
|
|
|
|
|
class FGFSSocket {
|
|
int sock;
|
|
bool connected;
|
|
unsigned timeout;
|
|
public:
|
|
FGFSSocket(const char *name, const unsigned port);
|
|
~FGFSSocket() { close(); };
|
|
|
|
int write(const char *msg, ...);
|
|
const char *read(void);
|
|
inline void flush(void);
|
|
void settimeout(unsigned t) { timeout = t; };
|
|
private:
|
|
int close(void);
|
|
};
|
|
|
|
|
|
FGFSSocket::FGFSSocket(const char *hostname = "localhost", const unsigned port = 5501)
|
|
:
|
|
sock(-1),
|
|
connected(false),
|
|
timeout(1)
|
|
{
|
|
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
if (sock < 0)
|
|
throw("FGFSSocket/socket");
|
|
|
|
struct hostent *hostinfo;
|
|
hostinfo = gethostbyname(hostname);
|
|
if (!hostinfo) {
|
|
close();
|
|
throw("FGFSSocket/gethostbyname: unknown host");
|
|
}
|
|
|
|
struct sockaddr_in serv_addr;
|
|
serv_addr.sin_family = AF_INET;
|
|
serv_addr.sin_port = htons(port);
|
|
serv_addr.sin_addr = *(struct in_addr *)hostinfo->h_addr;
|
|
|
|
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
|
|
close();
|
|
throw("FGFSSocket/connect");
|
|
}
|
|
connected = true;
|
|
try {
|
|
write("data");
|
|
} catch (...) {
|
|
close();
|
|
throw;
|
|
}
|
|
}
|
|
|
|
|
|
int FGFSSocket::close(void)
|
|
{
|
|
if (connected)
|
|
write("quit");
|
|
if (sock < 0)
|
|
return 0;
|
|
int ret = ::close(sock);
|
|
sock = -1;
|
|
return ret;
|
|
}
|
|
|
|
|
|
int FGFSSocket::write(const char *msg, ...)
|
|
{
|
|
va_list va;
|
|
ssize_t len;
|
|
char buf[maxlen];
|
|
fd_set fd;
|
|
struct timeval tv;
|
|
|
|
FD_ZERO(&fd);
|
|
FD_SET(sock, &fd);
|
|
tv.tv_sec = timeout;
|
|
tv.tv_usec = 0;
|
|
if (!select(FD_SETSIZE, 0, &fd, 0, &tv))
|
|
throw("FGFSSocket::write/select: timeout exceeded");
|
|
|
|
va_start(va, msg);
|
|
vsprintf(buf, msg, va);
|
|
va_end(va);
|
|
std::cout << "SEND: " << buf << std::endl;
|
|
strcat(buf, "\015\012");
|
|
|
|
len = ::write(sock, buf, strlen(buf));
|
|
if (len < 0)
|
|
throw("FGFSSocket::write");
|
|
return len;
|
|
}
|
|
|
|
|
|
const char *FGFSSocket::read(void)
|
|
{
|
|
static char buf[maxlen];
|
|
char *p;
|
|
fd_set fd;
|
|
struct timeval tv;
|
|
ssize_t len;
|
|
|
|
FD_ZERO(&fd);
|
|
FD_SET(sock, &fd);
|
|
tv.tv_sec = timeout;
|
|
tv.tv_usec = 0;
|
|
if (!select(FD_SETSIZE, &fd, 0, 0, &tv)) {
|
|
if (timeout == 0)
|
|
return 0;
|
|
else
|
|
throw("FGFSSocket::read/select: timeout exceeded");
|
|
}
|
|
|
|
len = ::read(sock, buf, maxlen - 1);
|
|
if (len < 0)
|
|
throw("FGFSSocket::read/read");
|
|
if (len == 0)
|
|
return 0;
|
|
|
|
for (p = &buf[len - 1]; p >= buf; p--)
|
|
if (*p != '\015' && *p != '\012')
|
|
break;
|
|
*++p = '\0';
|
|
return strlen(buf) ? buf : 0;
|
|
}
|
|
|
|
|
|
inline void FGFSSocket::flush(void)
|
|
{
|
|
int i = timeout;
|
|
timeout = 0;
|
|
while (read())
|
|
;
|
|
timeout = i;
|
|
}
|
|
|
|
|
|
int main(const int argc, const char *argv[])
|
|
try {
|
|
const char *hostname = argc > 1 ? argv[1] : "localhost";
|
|
int port = argc > 2 ? atoi(argv[2]) : 5501;
|
|
|
|
FGFSSocket f(hostname, port);
|
|
f.flush();
|
|
f.write("set /controls/engines/engine[%d]/throttle %lg", 0, 1.0);
|
|
f.write("set /controls/engines/engine[%d]/throttle %lg", 1, 1.0);
|
|
f.write("get /sim/aircraft");
|
|
const char *p = f.read();
|
|
if (p)
|
|
std::cout << "RECV: " << p << std::endl;
|
|
return 0;
|
|
|
|
} catch (const char s[]) {
|
|
std::cerr << "Error: " << s << ": " << strerror(errno) << std::endl;
|
|
return -1;
|
|
|
|
} catch (...) {
|
|
std::cerr << "Error: unknown exception" << std::endl;
|
|
return -1;
|
|
}
|
|
|
|
|
|
// vim:cindent
|