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