// $Id$ // g++ -O2 -g -pedantic -Wall fgfsclient.cxx -o fgfsclient -lstdc++ // Public Domain #include #include #include #include #include #include #include #include #include #include #include #include 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