24 # include "config_auto.h"
38 #pragma comment(lib, "Ws2_32.lib")
39 # include <winsock2.h>
40 # include <ws2tcpip.h>
42 #include <arpa/inet.h>
44 #include <netinet/in.h>
46 #include <semaphore.h>
48 #include <sys/select.h>
49 #include <sys/socket.h>
51 #include <sys/prctl.h>
58 mutex_ = CreateMutex(0,
FALSE, 0);
60 pthread_mutex_init(&mutex_,
nullptr);
66 WaitForSingleObject(mutex_, INFINITE);
68 pthread_mutex_lock(&mutex_);
76 pthread_mutex_unlock(&mutex_);
83 LPTHREAD_START_ROUTINE f = (LPTHREAD_START_ROUTINE)func;
94 pthread_attr_init(&attr);
95 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
96 pthread_create(&helper, &attr, func, arg);
100 #ifndef GRAPHICS_DISABLED
109 pthread_exit(
nullptr);
116 proc.append(executable);
119 std::cout <<
"Starting " << proc << std::endl;
121 STARTUPINFO start_info;
122 PROCESS_INFORMATION proc_info;
123 GetStartupInfo(&start_info);
124 if (!CreateProcess(
nullptr,
const_cast<char*
>(proc.c_str()),
nullptr,
nullptr,
FALSE,
125 CREATE_NO_WINDOW | DETACHED_PROCESS,
nullptr,
nullptr,
126 &start_info, &proc_info))
135 prctl(PR_SET_PDEATHSIG, 2, 0, 0, 0);
137 char* mutable_args = strdup(args);
139 for (
int i = 0; mutable_args[i]; ++i) {
140 if (mutable_args[i] ==
' ') {
144 std::unique_ptr<char*[]> argv(
new char*[argc + 2]);
145 argv[0] = strdup(executable);
146 argv[1] = mutable_args;
148 bool inquote =
false;
149 for (
int i = 0; mutable_args[i]; ++i) {
150 if (!inquote && mutable_args[i] ==
' ') {
151 mutable_args[i] =
'\0';
152 argv[argc++] = mutable_args + i + 1;
153 }
else if (mutable_args[i] ==
'"') {
155 mutable_args[i] =
' ';
158 argv[argc] =
nullptr;
159 execvp(executable, argv.get());
168 semaphore_ = CreateSemaphore(0, 0, 10, 0);
169 #elif defined(__APPLE__)
171 snprintf(name,
sizeof(name),
"%ld", random());
173 semaphore_ = sem_open(name, O_CREAT , S_IWUSR, 0);
174 if (semaphore_ == SEM_FAILED) {
178 sem_init(&semaphore_, 0, 0);
184 ReleaseSemaphore(semaphore_, 1,
nullptr);
185 #elif defined(__APPLE__)
186 sem_post(semaphore_);
188 sem_post(&semaphore_);
194 WaitForSingleObject(semaphore_, INFINITE);
195 #elif defined(__APPLE__)
196 sem_wait(semaphore_);
198 sem_wait(&semaphore_);
205 msg_buffer_out_.append(msg);
212 while (!msg_buffer_out_.empty()) {
213 int i = send(stream_, msg_buffer_out_.c_str(), msg_buffer_out_.length(), 0);
214 msg_buffer_out_.erase(0, i);
222 char* result =
nullptr;
223 #if defined(_WIN32) || defined(__CYGWIN__)
224 if (has_content) { result = strtok (
nullptr,
"\n"); }
226 if (buffer_ptr_ !=
nullptr) { result = strtok_r(
nullptr,
"\n", &buffer_ptr_); }
230 if (result !=
nullptr) {
return result;
233 buffer_ptr_ =
nullptr;
245 FD_SET(stream_, &readfds);
247 int i = select(stream_+1, &readfds,
nullptr,
nullptr, &tv);
250 if (i == 0) {
return nullptr; }
256 if (i <= 0) {
return nullptr; }
257 msg_buffer_in_[i] =
'\0';
260 return strtok(msg_buffer_in_,
"\n");
263 return strtok_r(msg_buffer_in_,
"\n", &buffer_ptr_);
271 closesocket(stream_);
281 static const char* ScrollViewProg() {
283 const char* prog =
"java -Xms512m -Xmx1024m";
285 const char* prog =
"sh";
292 static std::string ScrollViewCommand(std::string scrollview_path) {
299 const char cmd_template[] =
"-Djava.library.path=%s -jar %s/ScrollView.jar";
302 const char cmd_template[] =
303 "-c \"trap 'kill %%1' 0 1 2 ; java "
304 "-Xms1024m -Xmx2048m -jar %s/ScrollView.jar"
307 size_t cmdlen =
sizeof(cmd_template) + 2 * scrollview_path.size() + 1;
308 std::vector<char> cmd(cmdlen);
309 const char* sv_path = scrollview_path.c_str();
311 snprintf(&cmd[0], cmdlen, cmd_template, sv_path, sv_path);
313 snprintf(&cmd[0], cmdlen, cmd_template, sv_path);
315 std::string command(&cmd[0]);
322 msg_buffer_in_[0] =
'\0';
325 buffer_ptr_ =
nullptr;
327 struct addrinfo *addr_info =
nullptr;
329 snprintf(port_str, 40,
"%d", port);
333 int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
335 std::cerr <<
"WSAStartup failed: " << iResult << std::endl;
339 if (getaddrinfo(hostname, port_str,
nullptr, &addr_info) != 0) {
340 std::cerr <<
"Error resolving name for ScrollView host "
341 << std::string(hostname) <<
":" << port << std::endl;
347 stream_ = socket(addr_info->ai_family, addr_info->ai_socktype,
348 addr_info->ai_protocol);
351 std::cerr <<
"Failed to open socket" << std::endl;
352 }
else if (connect(stream_, addr_info->ai_addr, addr_info->ai_addrlen) < 0) {
354 const char* scrollview_path = getenv(
"SCROLLVIEW_PATH");
355 if (scrollview_path ==
nullptr) {
356 #ifdef SCROLLVIEW_PATH
358 #define _XSTR(a) _STR(a)
359 scrollview_path = _XSTR(SCROLLVIEW_PATH);
363 scrollview_path =
".";
366 const char *prog = ScrollViewProg();
367 std::string command = ScrollViewCommand(scrollview_path);
375 stream_ = socket(addr_info->ai_family, addr_info->ai_socktype,
376 addr_info->ai_protocol);
378 if (connect(stream_, addr_info->ai_addr, addr_info->ai_addrlen) == 0) {
384 std::cout <<
"ScrollView: Waiting for server...\n";
385 std::this_thread::sleep_for(std::chrono::seconds(1));
392 freeaddrinfo(addr_info);
397 delete[] msg_buffer_in_;
static void StartThread(void *(*func)(void *), void *arg)
Create new thread.
static void ExitThread()
Signals a thread to exit.
static void StartProcess(const char *executable, const char *args)
Starts a new process.
SVSemaphore()
Sets up a semaphore.
void Wait()
Wait on a semaphore.
void Signal()
Signal a semaphore.
SVMutex()
Sets up a new mutex.
void Unlock()
Unlocks on a mutex.
void Lock()
Locks on a mutex.
void Send(const char *msg)
Put a message in the messagebuffer to the server and try to send it.
SVNetwork(const char *hostname, int port)
Set up a connection to hostname on port.
void Close()
Close the connection to the server.
void Flush()
Flush the buffer.