tesseract  3.05.02
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 <stdio.h>
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 <signal.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <sys/select.h>
43 #include <sys/socket.h>
44 #ifdef __linux__
45 #include <sys/prctl.h>
46 #endif
47 #include <unistd.h>
48 #endif
49 
50 #include <cstdlib>
51 #include <cstring>
52 #include <iostream>
53 #include <string>
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_, NULL);
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 #ifndef GRAPHICS_DISABLED
87 
88 const int kMaxMsgSize = 4096;
89 
90 // Signals a thread to exit.
92 #ifdef _WIN32
93  // ExitThread(0);
94 #else
95  pthread_exit(0);
96 #endif
97 }
98 
99 // Starts a new process.
100 void SVSync::StartProcess(const char* executable, const char* args) {
101  std::string proc;
102  proc.append(executable);
103  proc.append(" ");
104  proc.append(args);
105  std::cout << "Starting " << proc << std::endl;
106 #ifdef _WIN32
107  STARTUPINFO start_info;
108  PROCESS_INFORMATION proc_info;
109  GetStartupInfo(&start_info);
110  if (!CreateProcess(NULL, const_cast<char*>(proc.c_str()), NULL, NULL, FALSE,
111  CREATE_NO_WINDOW | DETACHED_PROCESS, NULL, NULL,
112  &start_info, &proc_info))
113  return;
114 #else
115  int pid = fork();
116  if (pid != 0) { // The father process returns
117  } else {
118 #ifdef __linux__
119  // Make sure the java process terminates on exit, since its
120  // broken socket detection seems to be useless.
121  prctl(PR_SET_PDEATHSIG, 2, 0, 0, 0);
122 #endif
123  char* mutable_args = strdup(args);
124  int argc = 1;
125  for (int i = 0; mutable_args[i]; ++i) {
126  if (mutable_args[i] == ' ') {
127  ++argc;
128  }
129  }
130  char** argv = new char*[argc + 2];
131  argv[0] = strdup(executable);
132  argv[1] = mutable_args;
133  argc = 2;
134  bool inquote = false;
135  for (int i = 0; mutable_args[i]; ++i) {
136  if (!inquote && mutable_args[i] == ' ') {
137  mutable_args[i] = '\0';
138  argv[argc++] = mutable_args + i + 1;
139  } else if (mutable_args[i] == '"') {
140  inquote = !inquote;
141  mutable_args[i] = ' ';
142  }
143  }
144  argv[argc] = NULL;
145  execvp(executable, argv);
146  free(argv[0]);
147  free(argv[1]);
148  delete[] argv;
149  }
150 #endif
151 }
152 
154 #ifdef _WIN32
155  semaphore_ = CreateSemaphore(0, 0, 10, 0);
156 #elif defined(__APPLE__)
157  char name[50];
158  snprintf(name, sizeof(name), "%ld", random());
159  sem_unlink(name);
160  semaphore_ = sem_open(name, O_CREAT , S_IWUSR, 0);
161  if (semaphore_ == SEM_FAILED) {
162  perror("sem_open");
163  }
164 #else
165  sem_init(&semaphore_, 0, 0);
166 #endif
167 }
168 
170 #ifdef _WIN32
171  ReleaseSemaphore(semaphore_, 1, NULL);
172 #elif defined(__APPLE__)
173  sem_post(semaphore_);
174 #else
175  sem_post(&semaphore_);
176 #endif
177 }
178 
180 #ifdef _WIN32
181  WaitForSingleObject(semaphore_, INFINITE);
182 #elif defined(__APPLE__)
183  sem_wait(semaphore_);
184 #else
185  sem_wait(&semaphore_);
186 #endif
187 }
188 
189 
190 // Create new thread.
191 
192 void SVSync::StartThread(void *(*func)(void*), void* arg) {
193 #ifdef _WIN32
194  LPTHREAD_START_ROUTINE f = (LPTHREAD_START_ROUTINE) func;
195  DWORD threadid;
196  HANDLE newthread = CreateThread(
197  NULL, // default security attributes
198  0, // use default stack size
199  f, // thread function
200  arg, // argument to thread function
201  0, // use default creation flags
202  &threadid); // returns the thread identifier
203 #else
204  pthread_t helper;
205  pthread_attr_t attr;
206  pthread_attr_init(&attr);
207  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
208  pthread_create(&helper, &attr, func, arg);
209 #endif
210 }
211 
212 // Place a message in the message buffer (and flush it).
213 void SVNetwork::Send(const char* msg) {
214  mutex_send_->Lock();
215  msg_buffer_out_.append(msg);
216  mutex_send_->Unlock();
217 }
218 
219 // Send the whole buffer.
221  mutex_send_->Lock();
222  while (!msg_buffer_out_.empty()) {
223  int i = send(stream_, msg_buffer_out_.c_str(), msg_buffer_out_.length(), 0);
224  msg_buffer_out_.erase(0, i);
225  }
226  mutex_send_->Unlock();
227 }
228 
229 // Receive a message from the server.
230 // This will always return one line of char* (denoted by \n).
232  char* result = NULL;
233 #if defined(_WIN32) || defined(__CYGWIN__)
234  if (has_content) { result = strtok (NULL, "\n"); }
235 #else
236  if (buffer_ptr_ != NULL) { result = strtok_r(NULL, "\n", &buffer_ptr_); }
237 #endif
238 
239  // This means there is something left in the buffer and we return it.
240  if (result != NULL) { return result;
241  // Otherwise, we read from the stream_.
242  } else {
243  buffer_ptr_ = NULL;
244  has_content = false;
245 
246  // The timeout length is not really important since we are looping anyway
247  // until a new message is delivered.
248  struct timeval tv;
249  tv.tv_sec = 10;
250  tv.tv_usec = 0;
251 
252  // Set the flags to return when the stream_ is ready to be read.
253  fd_set readfds;
254  FD_ZERO(&readfds);
255  FD_SET(stream_, &readfds);
256 
257  int i = select(stream_+1, &readfds, NULL, NULL, &tv);
258 
259  // The stream_ died.
260  if (i == 0) { return NULL; }
261 
262  // Read the message buffer.
263  i = recv(stream_, msg_buffer_in_, kMaxMsgSize, 0);
264 
265  // Server quit (0) or error (-1).
266  if (i <= 0) { return NULL; }
267  msg_buffer_in_[i] = '\0';
268  has_content = true;
269 #ifdef _WIN32
270  return strtok(msg_buffer_in_, "\n");
271 #else
272  // Setup a new string tokenizer.
273  return strtok_r(msg_buffer_in_, "\n", &buffer_ptr_);
274 #endif
275  }
276 }
277 
278 // Close the connection to the server.
280 #ifdef _WIN32
281  closesocket(stream_);
282 #else
283  close(stream_);
284 #endif
285 }
286 
287 
288 // The program to invoke to start ScrollView
289 static const char* ScrollViewProg() {
290 #ifdef _WIN32
291  const char* prog = "java -Xms512m -Xmx1024m";
292 #else
293  const char* prog = "sh";
294 #endif
295  return prog;
296 }
297 
298 
299 // The arguments to the program to invoke to start ScrollView
300 static std::string ScrollViewCommand(std::string scrollview_path) {
301  // The following ugly ifdef is to enable the output of the java runtime
302  // to be sent down a black hole on non-windows to ignore all the
303  // exceptions in piccolo. Ideally piccolo would be debugged to make
304  // this unnecessary.
305  // Also the path has to be separated by ; on windows and : otherwise.
306 #ifdef _WIN32
307  const char* cmd_template = "-Djava.library.path=%s -jar %s/ScrollView.jar";
308 
309 #else
310  const char* cmd_template =
311  "-c \"trap 'kill %%1' 0 1 2 ; java "
312  "-Xms1024m -Xmx2048m -jar %s/ScrollView.jar"
313  " & wait\"";
314 #endif
315  int cmdlen = strlen(cmd_template) + 4*strlen(scrollview_path.c_str()) + 1;
316  char* cmd = new char[cmdlen];
317  const char* sv_path = scrollview_path.c_str();
318  snprintf(cmd, cmdlen, cmd_template, sv_path, sv_path, sv_path, sv_path);
319  std::string command(cmd);
320  delete [] cmd;
321  return command;
322 }
323 
324 
325 // Platform-independent freeaddrinfo()
326 static void FreeAddrInfo(struct addrinfo* addr_info) {
327  #if defined(__linux__)
328  freeaddrinfo(addr_info);
329  #else
330  delete addr_info->ai_addr;
331  delete addr_info;
332  #endif
333 }
334 
335 
336 // Non-linux version of getaddrinfo()
337 #if !defined(__linux__)
338 static int GetAddrInfoNonLinux(const char* hostname, int port,
339  struct addrinfo** addr_info) {
340 // Get the host data depending on the OS.
341  struct sockaddr_in* address;
342  *addr_info = new struct addrinfo;
343  memset(*addr_info, 0, sizeof(struct addrinfo));
344  address = new struct sockaddr_in;
345  memset(address, 0, sizeof(struct sockaddr_in));
346 
347  (*addr_info)->ai_addr = (struct sockaddr*) address;
348  (*addr_info)->ai_addrlen = sizeof(struct sockaddr);
349  (*addr_info)->ai_family = AF_INET;
350  (*addr_info)->ai_socktype = SOCK_STREAM;
351 
352  struct hostent *name;
353 #ifdef _WIN32
354  WSADATA wsaData;
355  WSAStartup(MAKEWORD(1, 1), &wsaData);
356  name = gethostbyname(hostname);
357 #else
358  name = gethostbyname(hostname);
359 #endif
360 
361  if (name == NULL) {
362  FreeAddrInfo(*addr_info);
363  *addr_info = NULL;
364  return -1;
365  }
366 
367  // Fill in the appropriate variables to be able to connect to the server.
368  address->sin_family = name->h_addrtype;
369  memcpy((char *) &address->sin_addr.s_addr,
370  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, NULL, 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  mutex_send_ = new SVMutex();
394  msg_buffer_in_ = new char[kMaxMsgSize + 1];
395  msg_buffer_in_[0] = '\0';
396 
397  has_content = false;
398  buffer_ptr_ = NULL;
399 
400  struct addrinfo *addr_info = NULL;
401 
402  if (GetAddrInfo(hostname, port, &addr_info) != 0) {
403  std::cerr << "Error resolving name for ScrollView host "
404  << std::string(hostname) << ":" << port << std::endl;
405  }
406 
407  stream_ = socket(addr_info->ai_family, addr_info->ai_socktype,
408  addr_info->ai_protocol);
409 
410  // If server is not there, we will start a new server as local child process.
411  if (connect(stream_, addr_info->ai_addr, addr_info->ai_addrlen) < 0) {
412  const char* scrollview_path = getenv("SCROLLVIEW_PATH");
413  if (scrollview_path == NULL) {
414 #ifdef SCROLLVIEW_PATH
415 #define _STR(a) #a
416 #define _XSTR(a) _STR(a)
417  scrollview_path = _XSTR(SCROLLVIEW_PATH);
418 #undef _XSTR
419 #undef _STR
420 #else
421  scrollview_path = ".";
422 #endif
423  }
424  const char *prog = ScrollViewProg();
425  std::string command = ScrollViewCommand(scrollview_path);
426  SVSync::StartProcess(prog, command.c_str());
427 
428  // Wait for server to show up.
429  // Note: There is no exception handling in case the server never turns up.
430 
431  Close();
432  stream_ = socket(addr_info->ai_family, addr_info->ai_socktype,
433  addr_info->ai_protocol);
434 
435  while (connect(stream_, addr_info->ai_addr,
436  addr_info->ai_addrlen) < 0) {
437  std::cout << "ScrollView: Waiting for server...\n";
438 #ifdef _WIN32
439  Sleep(1000);
440 #else
441  sleep(1);
442 #endif
443 
444  Close();
445  stream_ = socket(addr_info->ai_family, addr_info->ai_socktype,
446  addr_info->ai_protocol);
447  }
448  }
449  FreeAddrInfo(addr_info);
450 }
451 
453  delete[] msg_buffer_in_;
454  delete mutex_send_;
455 }
456 
457 #endif // GRAPHICS_DISABLED
const int kMaxMsgSize
Definition: svutil.cpp:88
SVSemaphore()
Sets up a semaphore.
Definition: svutil.cpp:153
static void ExitThread()
Signals a thread to exit.
Definition: svutil.cpp:91
~SVNetwork()
Destructor.
Definition: svutil.cpp:452
SVMutex()
Sets up a new mutex.
Definition: svutil.cpp:62
void Wait()
Wait on a semaphore.
Definition: svutil.cpp:179
static void StartProcess(const char *executable, const char *args)
Starts a new process.
Definition: svutil.cpp:100
char * Receive()
Definition: svutil.cpp:231
void Send(const char *msg)
Put a message in the messagebuffer to the server and try to send it.
Definition: svutil.cpp:213
#define FALSE
Definition: capi.h:46
void Lock()
Locks on a mutex.
Definition: svutil.cpp:70
SVNetwork(const char *hostname, int port)
Set up a connection to hostname on port.
Definition: svutil.cpp:392
void Flush()
Flush the buffer.
Definition: svutil.cpp:220
Definition: svutil.h:90
void Unlock()
Unlocks on a mutex.
Definition: svutil.cpp:78
void Close()
Close the connection to the server.
Definition: svutil.cpp:279
void Signal()
Signal a semaphore.
Definition: svutil.cpp:169
static void StartThread(void *(*func)(void *), void *arg)
Create new thread.
Definition: svutil.cpp:192