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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2517 - (show annotations) (download)
Fri Feb 7 19:53:09 2014 UTC (10 years, 2 months ago) by schoenebeck
File size: 4926 byte(s)
* LSCP shell (WIP): show a prompt & welcome message
* LSCP shell (WIP): fixed startup crash that happened
  on some systems
* Bumped version (1.0.0.svn30).

1 /*
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 std::cerr << "Is linuxsampler running and listening on port " << port << " ?\n";
48 disconnect();
49 return false;
50 }
51 StartThread();
52 return true; // success
53 }
54
55 void LSCPClient::disconnect() {
56 if (hSocket >= 0) {
57 StopThread();
58 ::close(hSocket);
59 hSocket = -1;
60 }
61 }
62
63 bool LSCPClient::isConnected() const {
64 return hSocket >= 0;
65 }
66
67 bool LSCPClient::send(char c) {
68 String s;
69 s += c;
70 return send(s);
71 }
72
73 bool LSCPClient::send(String s) {
74 if (!isConnected()) return false;
75 int n = ::write(hSocket, &s[0], s.size());
76 return n == s.size();
77 }
78
79 String LSCPClient::sendCommandSync(String s) {
80 m_linesMutex.Lock();
81 m_lines.clear();
82 m_linesMutex.Unlock();
83
84 m_sync.Set(true);
85 if (!send(s + "\n")) return "";
86 m_sync.WaitIf(true);
87
88 m_linesMutex.Lock();
89 String sResponse = m_lines.back();
90 m_lines.clear();
91 m_linesMutex.Unlock();
92
93 return sResponse;
94 }
95
96 optional<String> LSCPClient::popLine() {
97 String s;
98 LockGuard guard(m_linesMutex);
99 if (m_lines.empty()) return optional<String>::nothing;
100 s = m_lines.front();
101 m_lines.pop_front();
102 //FIXME: this is incorrect when having multiple complete messages in the queue
103 if (m_multiLineExpected && s.substr(0, 1) == ".")
104 m_multiLineExpected = m_multiLineComplete = false;
105 return s;
106 }
107
108 optional<String> LSCPClient::lookAheadLine(int index) {
109 LockGuard guard(m_linesMutex);
110 if (index < 0 || index >= m_lines.size())
111 return optional<String>::nothing;
112 std::list<String>::iterator it = m_lines.begin();
113 for (int i = 0; i < index; ++i) ++it;
114 String s = *it;
115 return s;
116 }
117
118 bool LSCPClient::messageComplete() {
119 if (!lineAvailable()) return false;
120 LockGuard guard(m_linesMutex);
121 if (!m_multiLineExpected) return true;
122 return m_multiLineComplete;
123 }
124
125 bool LSCPClient::multiLine() {
126 //FIXME: returns falsely "true" in case the first message is single-line response but there is already a multi-line response in the FIFO
127 return m_multiLineExpected;
128 }
129
130 bool LSCPClient::lineAvailable() const {
131 return !m_lines.empty(); // is thread safe
132 }
133
134 void LSCPClient::setCallback(Callback_t fn) {
135 m_callback = fn;
136 }
137
138 optional<String> LSCPClient::receiveLine() {
139 if (!isConnected()) return optional<String>::nothing;
140 for (char c; true; ) {
141 int n = ::read(hSocket, &c, 1);
142 if (n < 1) return optional<String>::nothing;
143 if (c == '\r') continue;
144 if (c == '\n') {
145 String s = m_lineBuffer;
146 m_lineBuffer.clear();
147 return s;
148 }
149 //printf("->%c\n", c);
150 m_lineBuffer += c;
151 }
152 return optional<String>::nothing;
153 }
154
155 int LSCPClient::Main() {
156 static const String multiLineKey = LSCP_SHK_EXPECT_MULTI_LINE;
157 while (true) {
158 optional<String> pLine = receiveLine();
159 if (pLine) {
160 String s = *pLine;
161 //printf("->line '%s'\n", s.c_str());
162 m_linesMutex.Lock();
163 if (s.substr(0, multiLineKey.length()) == multiLineKey) {
164 m_multiLineExpected = true;
165 m_multiLineComplete = false;
166 } else {
167 if (m_multiLineExpected && s.substr(0, 1) == ".") {
168 m_multiLineComplete = true;
169 }
170 m_lines.push_back(s);
171 }
172 m_linesMutex.Unlock();
173
174 if (m_sync.GetUnsafe()) m_sync.Set(false);
175 else if (m_callback) (*m_callback)(this);
176 }
177 TestCancel();
178 }
179 return 0; // just to avoid a warning with some old compilers
180 }

  ViewVC Help
Powered by ViewVC