/[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 2517 - (hide 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 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 schoenebeck 2517 std::cerr << "Is linuxsampler running and listening on port " << port << " ?\n";
48 schoenebeck 2515 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