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