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