24# include "config_auto.h"
39# pragma comment(lib, "Ws2_32.lib")
43# include <arpa/inet.h>
45# include <netinet/in.h>
46# include <semaphore.h>
47# include <sys/select.h>
48# include <sys/socket.h>
51# include <sys/prctl.h>
56#if defined(_WIN32) && !defined(__GNUC__)
57# define strtok_r(str, delim, saveptr) strtok_s(str, delim, saveptr)
60#ifndef GRAPHICS_DISABLED
69 proc.append(executable);
72 std::cout <<
"Starting " << proc << std::endl;
74 STARTUPINFO start_info;
75 PROCESS_INFORMATION proc_info;
76 GetStartupInfo(&start_info);
77 if (!CreateProcess(
nullptr,
const_cast<char *
>(proc.c_str()),
nullptr,
78 nullptr,
FALSE, CREATE_NO_WINDOW | DETACHED_PROCESS,
79 nullptr,
nullptr, &start_info, &proc_info))
88 prctl(PR_SET_PDEATHSIG, 2, 0, 0, 0);
90 std::string mutable_args(args);
92 for (
auto ch : mutable_args) {
97 std::unique_ptr<char *[]> argv(
new char *[argc + 2]);
98 std::string argv0(executable);
100 argv[1] = &mutable_args[0];
102 bool inquote =
false;
103 for (
int i = 0; mutable_args[
i]; ++
i) {
104 if (!inquote && mutable_args[
i] ==
' ') {
105 mutable_args[
i] =
'\0';
106 argv[argc++] = &mutable_args[
i + 1];
107 }
else if (mutable_args[
i] ==
'"') {
109 mutable_args[
i] =
' ';
112 argv[argc] =
nullptr;
113 execvp(executable, argv.get());
120 semaphore_ = CreateSemaphore(0, 0, 10, 0);
121# elif defined(__APPLE__)
122 auto name = std::to_string(random());
123 sem_unlink(name.c_str());
124 semaphore_ = sem_open(name.c_str(), O_CREAT, S_IWUSR, 0);
125 if (semaphore_ == SEM_FAILED) {
129 sem_init(&semaphore_, 0, 0);
135 CloseHandle(semaphore_);
136# elif defined(__APPLE__)
137 sem_close(semaphore_);
139 sem_close(&semaphore_);
145 ReleaseSemaphore(semaphore_, 1,
nullptr);
146# elif defined(__APPLE__)
147 sem_post(semaphore_);
149 sem_post(&semaphore_);
155 WaitForSingleObject(semaphore_, INFINITE);
156# elif defined(__APPLE__)
157 sem_wait(semaphore_);
159 sem_wait(&semaphore_);
165 std::lock_guard<std::mutex> guard(mutex_send_);
166 msg_buffer_out_.append(msg);
171 std::lock_guard<std::mutex> guard(mutex_send_);
172 while (!msg_buffer_out_.empty()) {
173 int i = send(stream_, msg_buffer_out_.c_str(), msg_buffer_out_.length(), 0);
174 msg_buffer_out_.erase(0,
i);
181 char *result =
nullptr;
182 if (buffer_ptr_ !=
nullptr) {
183 result = strtok_r(
nullptr,
"\n", &buffer_ptr_);
187 if (result !=
nullptr) {
191 buffer_ptr_ =
nullptr;
202 FD_SET(stream_, &readfds);
204 int i = select(stream_ + 1, &readfds,
nullptr,
nullptr, &tv);
218 msg_buffer_in_[
i] =
'\0';
220 return strtok_r(msg_buffer_in_,
"\n", &buffer_ptr_);
227 closesocket(stream_);
236static const char *ScrollViewProg() {
238 const char *prog =
"java -Xms512m -Xmx1024m";
240 const char *prog =
"sh";
246static std::string ScrollViewCommand(
const std::string &scrollview_path) {
253 const char cmd_template[] =
254 "-Djava.library.path=\"%s\" -jar \"%s/ScrollView.jar\"";
257 const char cmd_template[] =
258 "-c \"trap 'kill %%1' 0 1 2 ; java "
259 "-Xms1024m -Xmx2048m -jar %s/ScrollView.jar"
262 size_t cmdlen =
sizeof(cmd_template) + 2 * scrollview_path.size() + 1;
263 std::vector<char> cmd(cmdlen);
264 const char *sv_path = scrollview_path.c_str();
266 snprintf(&cmd[0], cmdlen, cmd_template, sv_path, sv_path);
268 snprintf(&cmd[0], cmdlen, cmd_template, sv_path);
270 std::string command(&cmd[0]);
277 msg_buffer_in_[0] =
'\0';
279 buffer_ptr_ =
nullptr;
281 struct addrinfo *addr_info =
nullptr;
282 auto port_string = std::to_string(port);
286 int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
288 std::cerr <<
"WSAStartup failed: " << iResult << std::endl;
292 if (getaddrinfo(hostname, port_string.c_str(),
nullptr, &addr_info) != 0) {
293 std::cerr <<
"Error resolving name for ScrollView host "
294 << std::string(hostname) <<
":" << port << std::endl;
300 if (addr_info ==
nullptr) {
304 stream_ = socket(addr_info->ai_family, addr_info->ai_socktype,
305 addr_info->ai_protocol);
309 std::cerr <<
"Failed to open socket" << std::endl;
310 }
else if (connect(stream_, addr_info->ai_addr, addr_info->ai_addrlen) < 0) {
313 const char *scrollview_path = getenv(
"SCROLLVIEW_PATH");
314 if (scrollview_path ==
nullptr) {
315# ifdef SCROLLVIEW_PATH
317# define _XSTR(a) _STR(a)
318 scrollview_path = _XSTR(SCROLLVIEW_PATH);
322 scrollview_path =
".";
325 const char *prog = ScrollViewProg();
326 std::string command = ScrollViewCommand(scrollview_path);
334 stream_ = socket(addr_info->ai_family, addr_info->ai_socktype,
335 addr_info->ai_protocol);
337 if (connect(stream_, addr_info->ai_addr, addr_info->ai_addrlen) == 0) {
343 std::cout <<
"ScrollView: Waiting for server...\n";
344 std::this_thread::sleep_for(std::chrono::seconds(1));
351 freeaddrinfo(addr_info);
356 delete[] msg_buffer_in_;
static void StartProcess(const char *executable, const char *args)
Starts a new process.
void Signal()
Signal a semaphore.
~SVSemaphore()
Cleans up the mutex.
SVSemaphore()
Sets up a semaphore.
void Wait()
Wait on a semaphore.
void Flush()
Flush the buffer.
SVNetwork(const char *hostname, int port)
Set up a connection to hostname on port.
void Send(const char *msg)
Put a message in the messagebuffer to the server and try to send it.
void Close()
Close the connection to the server.