/[svn]/linuxsampler/trunk/src/shell/LSCPClient.cpp
ViewVC logotype

Annotation of /linuxsampler/trunk/src/shell/LSCPClient.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2515 - (hide annotations) (download)
Wed Feb 5 20:45:18 2014 UTC (10 years, 3 months ago) by schoenebeck
File size: 4837 byte(s)
* WIP: Introducing the LSCP shell: for now, providing color
  highlighting while typing (indicating correct part bold white,
  incorrect part red, and turning green when the command is
  complete. The shell application is implemented as thin client,
  that is the parser work is performed on sampler side and the
  shell application is just providing output formatting.
* Bumped version (1.0.0.svn28).

1 schoenebeck 2515 /*
2     * LSCP Shell
3     *
4     * Copyright (c) 2014 Christian Schoenebeck
5     *
6     * This program is part of LinuxSampler and released under the same terms.
7     */
8    
9     #include "LSCPClient.h"
10    
11     #include <strings.h>
12    
13     LSCPClient::LSCPClient() :
14     Thread(false, false, 1, -1),
15     hSocket(-1), m_callback(NULL),
16     m_multiLineExpected(false), m_multiLineComplete(false)
17     {
18     }
19    
20     LSCPClient::~LSCPClient() {
21     disconnect();
22     }
23    
24     bool LSCPClient::connect(String host, int port) {
25     m_lineBuffer.clear();
26     m_lines.clear();
27     // resolve given host name
28     hostent* server = ::gethostbyname(host.c_str());
29     if (!server) {
30     std::cerr << "Error: Could not resolve host \"" << host << "\".\n";
31     return false;
32     }
33     // create local TCP socket
34     hSocket = ::socket(AF_INET, SOCK_STREAM, 0);
35     if (hSocket < 0) {
36     std::cerr << "Error: Could not create local socket.\n";
37     return false;
38     }
39     // TCP connect to server
40     sockaddr_in addr;
41     bzero((char*)&addr, sizeof(addr));
42     addr.sin_family = AF_INET;
43     bcopy((char*)server->h_addr, (char*)&addr.sin_addr.s_addr, server->h_length);
44     addr.sin_port = htons(port);
45     if (::connect(hSocket, (sockaddr*)&addr, sizeof(addr)) < 0) {
46     std::cerr << "Error: Could not connect to host \"" << host << "\".\n";
47     disconnect();
48     return false;
49     }
50     StartThread();
51     return true; // success
52     }
53    
54     void LSCPClient::disconnect() {
55     if (hSocket >= 0) {
56     StopThread();
57     ::close(hSocket);
58     hSocket = -1;
59     }
60     }
61    
62     bool LSCPClient::isConnected() const {
63     return hSocket >= 0;
64     }
65    
66     bool LSCPClient::send(char c) {
67     String s;
68     s += c;
69     return send(s);
70     }
71    
72     bool LSCPClient::send(String s) {
73     if (!isConnected()) return false;
74     int n = ::write(hSocket, &s[0], s.size());
75     return n == s.size();
76     }
77    
78     String LSCPClient::sendCommandSync(String s) {
79     m_linesMutex.Lock();
80     m_lines.clear();
81     m_linesMutex.Unlock();
82    
83     m_sync.Set(true);
84     if (!send(s + "\n")) return "";
85     m_sync.WaitIf(true);
86    
87     m_linesMutex.Lock();
88     String sResponse = m_lines.back();
89     m_lines.clear();
90     m_linesMutex.Unlock();
91    
92     return sResponse;
93     }
94    
95     optional<String> LSCPClient::popLine() {
96     String s;
97     LockGuard guard(m_linesMutex);
98     if (m_lines.empty()) return optional<String>::nothing;
99     s = m_lines.front();
100     m_lines.pop_front();
101     //FIXME: this is incorrect when having multiple complete messages in the queue
102     if (m_multiLineExpected && s.substr(0, 1) == ".")
103     m_multiLineExpected = m_multiLineComplete = false;
104     return s;
105     }
106    
107     optional<String> LSCPClient::lookAheadLine(int index) {
108     LockGuard guard(m_linesMutex);
109     if (index < 0 || index >= m_lines.size())
110     return optional<String>::nothing;
111     std::list<String>::iterator it = m_lines.begin();
112     for (int i = 0; i < index; ++i) ++it;
113     String s = *it;
114     return s;
115     }
116    
117     bool LSCPClient::messageComplete() {
118     if (!lineAvailable()) return false;
119     LockGuard guard(m_linesMutex);
120     if (!m_multiLineExpected) return true;
121     return m_multiLineComplete;
122     }
123    
124     bool LSCPClient::multiLine() {
125     //FIXME: returns falsely "true" in case the first message is single-line response but there is already a multi-line response in the FIFO
126     return m_multiLineExpected;
127     }
128    
129     bool LSCPClient::lineAvailable() const {
130     return !m_lines.empty(); // is thread safe
131     }
132    
133     void LSCPClient::setCallback(Callback_t fn) {
134     m_callback = fn;
135     }
136    
137     optional<String> LSCPClient::receiveLine() {
138     if (!isConnected()) return optional<String>::nothing;
139     for (char c; true; ) {
140     int n = ::read(hSocket, &c, 1);
141     if (n < 1) return optional<String>::nothing;
142     if (c == '\r') continue;
143     if (c == '\n') {
144     String s = m_lineBuffer;
145     m_lineBuffer.clear();
146     return s;
147     }
148     //printf("->%c\n", c);
149     m_lineBuffer += c;
150     }
151     return optional<String>::nothing;
152     }
153    
154     int LSCPClient::Main() {
155     static const String multiLineKey = LSCP_SHK_EXPECT_MULTI_LINE;
156     while (true) {
157     optional<String> pLine = receiveLine();
158     if (pLine) {
159     String s = *pLine;
160     //printf("->line '%s'\n", s.c_str());
161     m_linesMutex.Lock();
162     if (s.substr(0, multiLineKey.length()) == multiLineKey) {
163     m_multiLineExpected = true;
164     m_multiLineComplete = false;
165     } else {
166     if (m_multiLineExpected && s.substr(0, 1) == ".") {
167     m_multiLineComplete = true;
168     }
169     m_lines.push_back(s);
170     }
171     m_linesMutex.Unlock();
172    
173     if (m_sync.GetUnsafe()) m_sync.Set(false);
174     else if (m_callback) (*m_callback)(this);
175     }
176     TestCancel();
177     }
178     return 0; // just to avoid a warning with some old compilers
179     }

  ViewVC Help
Powered by ViewVC