Tesseract 3.02

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

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