tesseract 4.1.1
Loading...
Searching...
No Matches
svutil.cpp
Go to the documentation of this file.
1
2// File: svutil.cpp
3// Description: ScrollView Utilities
4// Author: Joern Wanke
5//
6// (C) Copyright 2007, Google Inc.
7// Licensed under the Apache License, Version 2.0 (the "License");
8// you may not use this file except in compliance with the License.
9// You may obtain a copy of the License at
10// http://www.apache.org/licenses/LICENSE-2.0
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16//
18//
19// SVUtil contains the SVSync and SVNetwork classes, which are used for
20// thread/process creation & synchronization and network connection.
21
22// Include automatically generated configuration file if running autoconf.
23#ifdef HAVE_CONFIG_H
24# include "config_auto.h"
25#endif
26
27#include "svutil.h"
28#include <cstdio>
29#include <cstdlib>
30#include <cstring>
31#include <iostream>
32#include <memory>
33#include <string>
34#include <thread> // for std::this_thread
35#include <vector>
36
37#ifdef _WIN32
38#pragma comment(lib, "Ws2_32.lib")
39# include <winsock2.h> // for fd_set, send, ..
40# include <ws2tcpip.h> // for addrinfo
41#else
42#include <arpa/inet.h>
43#include <netdb.h>
44#include <netinet/in.h>
45#include <pthread.h>
46#include <semaphore.h>
47#include <csignal>
48#include <sys/select.h>
49#include <sys/socket.h>
50#ifdef __linux__
51#include <sys/prctl.h>
52#endif
53#include <unistd.h>
54#endif
55
57#ifdef _WIN32
58 mutex_ = CreateMutex(0, FALSE, 0);
59#else
60 pthread_mutex_init(&mutex_, nullptr);
61#endif
62}
63
65#ifdef _WIN32
66 WaitForSingleObject(mutex_, INFINITE);
67#else
68 pthread_mutex_lock(&mutex_);
69#endif
70}
71
73#ifdef _WIN32
74 ReleaseMutex(mutex_);
75#else
76 pthread_mutex_unlock(&mutex_);
77#endif
78}
79
80// Create new thread.
81void SVSync::StartThread(void* (*func)(void*), void* arg) {
82#ifdef _WIN32
83 LPTHREAD_START_ROUTINE f = (LPTHREAD_START_ROUTINE)func;
84 DWORD threadid;
85 CreateThread(nullptr, // default security attributes
86 0, // use default stack size
87 f, // thread function
88 arg, // argument to thread function
89 0, // use default creation flags
90 &threadid); // returns the thread identifier
91#else
92 pthread_t helper;
93 pthread_attr_t attr;
94 pthread_attr_init(&attr);
95 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
96 pthread_create(&helper, &attr, func, arg);
97#endif
98}
99
100#ifndef GRAPHICS_DISABLED
101
102const int kMaxMsgSize = 4096;
103
104// Signals a thread to exit.
106#ifdef _WIN32
107 // ExitThread(0);
108#else
109 pthread_exit(nullptr);
110#endif
111}
112
113// Starts a new process.
114void SVSync::StartProcess(const char* executable, const char* args) {
115 std::string proc;
116 proc.append(executable);
117 proc.append(" ");
118 proc.append(args);
119 std::cout << "Starting " << proc << std::endl;
120#ifdef _WIN32
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))
127 return;
128#else
129 int pid = fork();
130 if (pid != 0) { // The father process returns
131 } else {
132#ifdef __linux__
133 // Make sure the java process terminates on exit, since its
134 // broken socket detection seems to be useless.
135 prctl(PR_SET_PDEATHSIG, 2, 0, 0, 0);
136#endif
137 char* mutable_args = strdup(args);
138 int argc = 1;
139 for (int i = 0; mutable_args[i]; ++i) {
140 if (mutable_args[i] == ' ') {
141 ++argc;
142 }
143 }
144 std::unique_ptr<char*[]> argv(new char*[argc + 2]);
145 argv[0] = strdup(executable);
146 argv[1] = mutable_args;
147 argc = 2;
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] == '"') {
154 inquote = !inquote;
155 mutable_args[i] = ' ';
156 }
157 }
158 argv[argc] = nullptr;
159 execvp(executable, argv.get());
160 free(argv[0]);
161 free(argv[1]);
162 }
163#endif
164}
165
167#ifdef _WIN32
168 semaphore_ = CreateSemaphore(0, 0, 10, 0);
169#elif defined(__APPLE__)
170 char name[50];
171 snprintf(name, sizeof(name), "%ld", random());
172 sem_unlink(name);
173 semaphore_ = sem_open(name, O_CREAT , S_IWUSR, 0);
174 if (semaphore_ == SEM_FAILED) {
175 perror("sem_open");
176 }
177#else
178 sem_init(&semaphore_, 0, 0);
179#endif
180}
181
183#ifdef _WIN32
184 ReleaseSemaphore(semaphore_, 1, nullptr);
185#elif defined(__APPLE__)
186 sem_post(semaphore_);
187#else
188 sem_post(&semaphore_);
189#endif
190}
191
193#ifdef _WIN32
194 WaitForSingleObject(semaphore_, INFINITE);
195#elif defined(__APPLE__)
196 sem_wait(semaphore_);
197#else
198 sem_wait(&semaphore_);
199#endif
200}
201
202// Place a message in the message buffer (and flush it).
203void SVNetwork::Send(const char* msg) {
204 mutex_send_.Lock();
205 msg_buffer_out_.append(msg);
206 mutex_send_.Unlock();
207}
208
209// Send the whole buffer.
211 mutex_send_.Lock();
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);
215 }
216 mutex_send_.Unlock();
217}
218
219// Receive a message from the server.
220// This will always return one line of char* (denoted by \n).
222 char* result = nullptr;
223#if defined(_WIN32) || defined(__CYGWIN__)
224 if (has_content) { result = strtok (nullptr, "\n"); }
225#else
226 if (buffer_ptr_ != nullptr) { result = strtok_r(nullptr, "\n", &buffer_ptr_); }
227#endif
228
229 // This means there is something left in the buffer and we return it.
230 if (result != nullptr) { return result;
231 // Otherwise, we read from the stream_.
232 } else {
233 buffer_ptr_ = nullptr;
234 has_content = false;
235
236 // The timeout length is not really important since we are looping anyway
237 // until a new message is delivered.
238 struct timeval tv;
239 tv.tv_sec = 10;
240 tv.tv_usec = 0;
241
242 // Set the flags to return when the stream_ is ready to be read.
243 fd_set readfds;
244 FD_ZERO(&readfds);
245 FD_SET(stream_, &readfds);
246
247 int i = select(stream_+1, &readfds, nullptr, nullptr, &tv);
248
249 // The stream_ died.
250 if (i == 0) { return nullptr; }
251
252 // Read the message buffer.
253 i = recv(stream_, msg_buffer_in_, kMaxMsgSize, 0);
254
255 // Server quit (0) or error (-1).
256 if (i <= 0) { return nullptr; }
257 msg_buffer_in_[i] = '\0';
258 has_content = true;
259#ifdef _WIN32
260 return strtok(msg_buffer_in_, "\n");
261#else
262 // Setup a new string tokenizer.
263 return strtok_r(msg_buffer_in_, "\n", &buffer_ptr_);
264#endif
265 }
266}
267
268// Close the connection to the server.
270#ifdef _WIN32
271 closesocket(stream_);
272#else
273 close(stream_);
274#endif
275 // Mark stream_ as invalid.
276 stream_ = -1;
277}
278
279
280// The program to invoke to start ScrollView
281static const char* ScrollViewProg() {
282#ifdef _WIN32
283 const char* prog = "java -Xms512m -Xmx1024m";
284#else
285 const char* prog = "sh";
286#endif
287 return prog;
288}
289
290
291// The arguments to the program to invoke to start ScrollView
292static std::string ScrollViewCommand(std::string scrollview_path) {
293 // The following ugly ifdef is to enable the output of the java runtime
294 // to be sent down a black hole on non-windows to ignore all the
295 // exceptions in piccolo. Ideally piccolo would be debugged to make
296 // this unnecessary.
297 // Also the path has to be separated by ; on windows and : otherwise.
298#ifdef _WIN32
299 const char cmd_template[] = "-Djava.library.path=%s -jar %s/ScrollView.jar";
300
301#else
302 const char cmd_template[] =
303 "-c \"trap 'kill %%1' 0 1 2 ; java "
304 "-Xms1024m -Xmx2048m -jar %s/ScrollView.jar"
305 " & wait\"";
306#endif
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();
310#ifdef _WIN32
311 snprintf(&cmd[0], cmdlen, cmd_template, sv_path, sv_path);
312#else
313 snprintf(&cmd[0], cmdlen, cmd_template, sv_path);
314#endif
315 std::string command(&cmd[0]);
316 return command;
317}
318
319// Set up a connection to a ScrollView on hostname:port.
320SVNetwork::SVNetwork(const char* hostname, int port) {
321 msg_buffer_in_ = new char[kMaxMsgSize + 1];
322 msg_buffer_in_[0] = '\0';
323
324 has_content = false;
325 buffer_ptr_ = nullptr;
326
327 struct addrinfo *addr_info = nullptr;
328 char port_str[40];
329 snprintf(port_str, 40, "%d", port);
330#ifdef _WIN32
331 // Initialize Winsock
332 WSADATA wsaData;
333 int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
334 if (iResult != 0) {
335 std::cerr << "WSAStartup failed: " << iResult << std::endl;
336 }
337#endif // _WIN32
338
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;
342#ifdef _WIN32
343 WSACleanup();
344#endif // _WIN32
345 }
346
347 stream_ = socket(addr_info->ai_family, addr_info->ai_socktype,
348 addr_info->ai_protocol);
349
350 if (stream_ < 0) {
351 std::cerr << "Failed to open socket" << std::endl;
352 } else if (connect(stream_, addr_info->ai_addr, addr_info->ai_addrlen) < 0) {
353 // If server is not there, we will start a new server as local child process.
354 const char* scrollview_path = getenv("SCROLLVIEW_PATH");
355 if (scrollview_path == nullptr) {
356#ifdef SCROLLVIEW_PATH
357#define _STR(a) #a
358#define _XSTR(a) _STR(a)
359 scrollview_path = _XSTR(SCROLLVIEW_PATH);
360#undef _XSTR
361#undef _STR
362#else
363 scrollview_path = ".";
364#endif
365 }
366 const char *prog = ScrollViewProg();
367 std::string command = ScrollViewCommand(scrollview_path);
368 SVSync::StartProcess(prog, command.c_str());
369
370 // Wait for server to show up.
371 // Note: There is no exception handling in case the server never turns up.
372
373 Close();
374 for (;;) {
375 stream_ = socket(addr_info->ai_family, addr_info->ai_socktype,
376 addr_info->ai_protocol);
377 if (stream_ >= 0) {
378 if (connect(stream_, addr_info->ai_addr, addr_info->ai_addrlen) == 0) {
379 break;
380 }
381
382 Close();
383
384 std::cout << "ScrollView: Waiting for server...\n";
385 std::this_thread::sleep_for(std::chrono::seconds(1));
386 }
387 }
388 }
389#ifdef _WIN32
390 // WSACleanup(); // This cause ScrollView windows is not displayed
391#endif // _WIN32
392 freeaddrinfo(addr_info);
393}
394
396 Close();
397 delete[] msg_buffer_in_;
398}
399
400#endif // GRAPHICS_DISABLED
#define FALSE
Definition: capi.h:52
const int kMaxMsgSize
Definition: scrollview.cpp:38
const int kMaxMsgSize
Definition: svutil.cpp:102
static void StartThread(void *(*func)(void *), void *arg)
Create new thread.
Definition: svutil.cpp:81
static void ExitThread()
Signals a thread to exit.
Definition: svutil.cpp:105
static void StartProcess(const char *executable, const char *args)
Starts a new process.
Definition: svutil.cpp:114
SVSemaphore()
Sets up a semaphore.
Definition: svutil.cpp:166
void Wait()
Wait on a semaphore.
Definition: svutil.cpp:192
void Signal()
Signal a semaphore.
Definition: svutil.cpp:182
SVMutex()
Sets up a new mutex.
Definition: svutil.cpp:56
void Unlock()
Unlocks on a mutex.
Definition: svutil.cpp:72
void Lock()
Locks on a mutex.
Definition: svutil.cpp:64
void Send(const char *msg)
Put a message in the messagebuffer to the server and try to send it.
Definition: svutil.cpp:203
char * Receive()
Definition: svutil.cpp:221
SVNetwork(const char *hostname, int port)
Set up a connection to hostname on port.
Definition: svutil.cpp:320
~SVNetwork()
Destructor.
Definition: svutil.cpp:395
void Close()
Close the connection to the server.
Definition: svutil.cpp:269
void Flush()
Flush the buffer.
Definition: svutil.cpp:210