|
tesseract 3.04.01
|
00001 00002 // File: svutil.cpp 00003 // Description: ScrollView Utilities 00004 // Author: Joern Wanke 00005 // Created: Thu Nov 29 2007 00006 // 00007 // (C) Copyright 2007, Google Inc. 00008 // Licensed under the Apache License, Version 2.0 (the "License"); 00009 // you may not use this file except in compliance with the License. 00010 // You may obtain a copy of the License at 00011 // http://www.apache.org/licenses/LICENSE-2.0 00012 // Unless required by applicable law or agreed to in writing, software 00013 // distributed under the License is distributed on an "AS IS" BASIS, 00014 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00015 // See the License for the specific language governing permissions and 00016 // limitations under the License. 00017 // 00019 // 00020 // SVUtil contains the SVSync and SVNetwork classes, which are used for 00021 // thread/process creation & synchronization and network connection. 00022 00023 #include <stdio.h> 00024 #ifdef _WIN32 00025 struct addrinfo { 00026 struct sockaddr* ai_addr; 00027 int ai_addrlen; 00028 int ai_family; 00029 int ai_socktype; 00030 int ai_protocol; 00031 }; 00032 #else 00033 #include <arpa/inet.h> 00034 #include <netinet/in.h> 00035 #include <pthread.h> 00036 #include <semaphore.h> 00037 #include <signal.h> 00038 #include <stdlib.h> 00039 #include <string.h> 00040 #include <netdb.h> 00041 #include <sys/select.h> 00042 #include <sys/socket.h> 00043 #ifdef __linux__ 00044 #include <sys/prctl.h> 00045 #endif 00046 #include <unistd.h> 00047 #endif 00048 00049 #include <cstdlib> 00050 #include <cstring> 00051 #include <iostream> 00052 #include <string> 00053 00054 // Include automatically generated configuration file if running autoconf. 00055 #ifdef HAVE_CONFIG_H 00056 #include "config_auto.h" 00057 #endif 00058 00059 #ifndef GRAPHICS_DISABLED 00060 00061 #include "svutil.h" 00062 00063 const int kMaxMsgSize = 4096; 00064 00065 // Signals a thread to exit. 00066 void SVSync::ExitThread() { 00067 #ifdef _WIN32 00068 // ExitThread(0); 00069 #else 00070 pthread_exit(0); 00071 #endif 00072 } 00073 00074 // Starts a new process. 00075 void SVSync::StartProcess(const char* executable, const char* args) { 00076 std::string proc; 00077 proc.append(executable); 00078 proc.append(" "); 00079 proc.append(args); 00080 std::cout << "Starting " << proc << std::endl; 00081 #ifdef _WIN32 00082 STARTUPINFO start_info; 00083 PROCESS_INFORMATION proc_info; 00084 GetStartupInfo(&start_info); 00085 if (!CreateProcess(NULL, const_cast<char*>(proc.c_str()), NULL, NULL, FALSE, 00086 CREATE_NO_WINDOW | DETACHED_PROCESS, NULL, NULL, 00087 &start_info, &proc_info)) 00088 return; 00089 #else 00090 int pid = fork(); 00091 if (pid != 0) { // The father process returns 00092 } else { 00093 #ifdef __linux__ 00094 // Make sure the java process terminates on exit, since its 00095 // broken socket detection seems to be useless. 00096 prctl(PR_SET_PDEATHSIG, 2, 0, 0, 0); 00097 #endif 00098 char* mutable_args = strdup(args); 00099 int argc = 1; 00100 for (int i = 0; mutable_args[i]; ++i) { 00101 if (mutable_args[i] == ' ') { 00102 ++argc; 00103 } 00104 } 00105 char** argv = new char*[argc + 2]; 00106 argv[0] = strdup(executable); 00107 argv[1] = mutable_args; 00108 argc = 2; 00109 bool inquote = false; 00110 for (int i = 0; mutable_args[i]; ++i) { 00111 if (!inquote && mutable_args[i] == ' ') { 00112 mutable_args[i] = '\0'; 00113 argv[argc++] = mutable_args + i + 1; 00114 } else if (mutable_args[i] == '"') { 00115 inquote = !inquote; 00116 mutable_args[i] = ' '; 00117 } 00118 } 00119 argv[argc] = NULL; 00120 execvp(executable, argv); 00121 } 00122 #endif 00123 } 00124 00125 SVSemaphore::SVSemaphore() { 00126 #ifdef _WIN32 00127 semaphore_ = CreateSemaphore(0, 0, 10, 0); 00128 #elif defined(__APPLE__) 00129 char name[50]; 00130 snprintf(name, sizeof(name), "%ld", random()); 00131 sem_unlink(name); 00132 semaphore_ = sem_open(name, O_CREAT , S_IWUSR, 0); 00133 if (semaphore_ == SEM_FAILED) { 00134 perror("sem_open"); 00135 } 00136 #else 00137 sem_init(&semaphore_, 0, 0); 00138 #endif 00139 } 00140 00141 void SVSemaphore::Signal() { 00142 #ifdef _WIN32 00143 ReleaseSemaphore(semaphore_, 1, NULL); 00144 #elif defined(__APPLE__) 00145 sem_post(semaphore_); 00146 #else 00147 sem_post(&semaphore_); 00148 #endif 00149 } 00150 00151 void SVSemaphore::Wait() { 00152 #ifdef _WIN32 00153 WaitForSingleObject(semaphore_, INFINITE); 00154 #elif defined(__APPLE__) 00155 sem_wait(semaphore_); 00156 #else 00157 sem_wait(&semaphore_); 00158 #endif 00159 } 00160 00161 SVMutex::SVMutex() { 00162 #ifdef _WIN32 00163 mutex_ = CreateMutex(0, FALSE, 0); 00164 #else 00165 pthread_mutex_init(&mutex_, NULL); 00166 #endif 00167 } 00168 00169 void SVMutex::Lock() { 00170 #ifdef _WIN32 00171 WaitForSingleObject(mutex_, INFINITE); 00172 #else 00173 pthread_mutex_lock(&mutex_); 00174 #endif 00175 } 00176 00177 void SVMutex::Unlock() { 00178 #ifdef _WIN32 00179 ReleaseMutex(mutex_); 00180 #else 00181 pthread_mutex_unlock(&mutex_); 00182 #endif 00183 } 00184 00185 // Create new thread. 00186 00187 void SVSync::StartThread(void *(*func)(void*), void* arg) { 00188 #ifdef _WIN32 00189 LPTHREAD_START_ROUTINE f = (LPTHREAD_START_ROUTINE) func; 00190 DWORD threadid; 00191 HANDLE newthread = CreateThread( 00192 NULL, // default security attributes 00193 0, // use default stack size 00194 f, // thread function 00195 arg, // argument to thread function 00196 0, // use default creation flags 00197 &threadid); // returns the thread identifier 00198 #else 00199 pthread_t helper; 00200 pthread_create(&helper, NULL, func, arg); 00201 #endif 00202 } 00203 00204 // Place a message in the message buffer (and flush it). 00205 void SVNetwork::Send(const char* msg) { 00206 mutex_send_->Lock(); 00207 msg_buffer_out_.append(msg); 00208 mutex_send_->Unlock(); 00209 } 00210 00211 // Send the whole buffer. 00212 void SVNetwork::Flush() { 00213 mutex_send_->Lock(); 00214 while (msg_buffer_out_.size() > 0) { 00215 int i = send(stream_, msg_buffer_out_.c_str(), msg_buffer_out_.length(), 0); 00216 msg_buffer_out_.erase(0, i); 00217 } 00218 mutex_send_->Unlock(); 00219 } 00220 00221 // Receive a message from the server. 00222 // This will always return one line of char* (denoted by \n). 00223 char* SVNetwork::Receive() { 00224 char* result = NULL; 00225 #if defined(_WIN32) || defined(__CYGWIN__) 00226 if (has_content) { result = strtok (NULL, "\n"); } 00227 #else 00228 if (buffer_ptr_ != NULL) { result = strtok_r(NULL, "\n", &buffer_ptr_); } 00229 #endif 00230 00231 // This means there is something left in the buffer and we return it. 00232 if (result != NULL) { return result; 00233 // Otherwise, we read from the stream_. 00234 } else { 00235 buffer_ptr_ = NULL; 00236 has_content = false; 00237 00238 // The timeout length is not really important since we are looping anyway 00239 // until a new message is delivered. 00240 struct timeval tv; 00241 tv.tv_sec = 10; 00242 tv.tv_usec = 0; 00243 00244 // Set the flags to return when the stream_ is ready to be read. 00245 fd_set readfds; 00246 FD_ZERO(&readfds); 00247 FD_SET(stream_, &readfds); 00248 00249 int i = select(stream_+1, &readfds, NULL, NULL, &tv); 00250 00251 // The stream_ died. 00252 if (i == 0) { return NULL; } 00253 00254 // Read the message buffer. 00255 i = recv(stream_, msg_buffer_in_, kMaxMsgSize, 0); 00256 00257 // Server quit (0) or error (-1). 00258 if (i <= 0) { return NULL; } 00259 msg_buffer_in_[i] = '\0'; 00260 has_content = true; 00261 #ifdef _WIN32 00262 return strtok(msg_buffer_in_, "\n"); 00263 #else 00264 // Setup a new string tokenizer. 00265 return strtok_r(msg_buffer_in_, "\n", &buffer_ptr_); 00266 #endif 00267 } 00268 } 00269 00270 // Close the connection to the server. 00271 void SVNetwork::Close() { 00272 #ifdef _WIN32 00273 closesocket(stream_); 00274 #else 00275 close(stream_); 00276 #endif 00277 } 00278 00279 00280 // The program to invoke to start ScrollView 00281 static const char* ScrollViewProg() { 00282 #ifdef _WIN32 00283 const char* prog = "java -Xms512m -Xmx1024m"; 00284 #else 00285 const char* prog = "sh"; 00286 #endif 00287 return prog; 00288 } 00289 00290 00291 // The arguments to the program to invoke to start ScrollView 00292 static std::string ScrollViewCommand(std::string scrollview_path) { 00293 // The following ugly ifdef is to enable the output of the java runtime 00294 // to be sent down a black hole on non-windows to ignore all the 00295 // exceptions in piccolo. Ideally piccolo would be debugged to make 00296 // this unnecessary. 00297 // Also the path has to be separated by ; on windows and : otherwise. 00298 #ifdef _WIN32 00299 const char* cmd_template = "-Djava.library.path=%s -jar %s/ScrollView.jar"; 00300 00301 #else 00302 const char* cmd_template = "-c \"trap 'kill %%1' 0 1 2 ; java " 00303 "-Xms1024m -Xmx2048m -jar %s/ScrollView.jar" 00304 " & wait\""; 00305 #endif 00306 int cmdlen = strlen(cmd_template) + 4*strlen(scrollview_path.c_str()) + 1; 00307 char* cmd = new char[cmdlen]; 00308 const char* sv_path = scrollview_path.c_str(); 00309 snprintf(cmd, cmdlen, cmd_template, sv_path, sv_path, sv_path, sv_path); 00310 std::string command(cmd); 00311 delete [] cmd; 00312 return command; 00313 } 00314 00315 00316 // Platform-independent freeaddrinfo() 00317 static void FreeAddrInfo(struct addrinfo* addr_info) { 00318 #if defined(__linux__) 00319 freeaddrinfo(addr_info); 00320 #else 00321 delete addr_info->ai_addr; 00322 delete addr_info; 00323 #endif 00324 } 00325 00326 00327 // Non-linux version of getaddrinfo() 00328 #if !defined(__linux__) 00329 static int GetAddrInfoNonLinux(const char* hostname, int port, 00330 struct addrinfo** addr_info) { 00331 // Get the host data depending on the OS. 00332 struct sockaddr_in* address; 00333 *addr_info = new struct addrinfo; 00334 memset(*addr_info, 0, sizeof(struct addrinfo)); 00335 address = new struct sockaddr_in; 00336 memset(address, 0, sizeof(struct sockaddr_in)); 00337 00338 (*addr_info)->ai_addr = (struct sockaddr*) address; 00339 (*addr_info)->ai_addrlen = sizeof(struct sockaddr); 00340 (*addr_info)->ai_family = AF_INET; 00341 (*addr_info)->ai_socktype = SOCK_STREAM; 00342 00343 struct hostent *name; 00344 #ifdef _WIN32 00345 WSADATA wsaData; 00346 WSAStartup(MAKEWORD(1, 1), &wsaData); 00347 name = gethostbyname(hostname); 00348 #else 00349 name = gethostbyname(hostname); 00350 #endif 00351 00352 if (name == NULL) { 00353 FreeAddrInfo(*addr_info); 00354 *addr_info = NULL; 00355 return -1; 00356 } 00357 00358 // Fill in the appropriate variables to be able to connect to the server. 00359 address->sin_family = name->h_addrtype; 00360 memcpy((char *) &address->sin_addr.s_addr, 00361 name->h_addr_list[0], name->h_length); 00362 address->sin_port = htons(port); 00363 return 0; 00364 } 00365 #endif 00366 00367 00368 // Platform independent version of getaddrinfo() 00369 // Given a hostname:port, produce an addrinfo struct 00370 static int GetAddrInfo(const char* hostname, int port, 00371 struct addrinfo** address) { 00372 #if defined(__linux__) 00373 char port_str[40]; 00374 snprintf(port_str, 40, "%d", port); 00375 return getaddrinfo(hostname, port_str, NULL, address); 00376 #else 00377 return GetAddrInfoNonLinux(hostname, port, address); 00378 #endif 00379 } 00380 00381 00382 // Set up a connection to a ScrollView on hostname:port. 00383 SVNetwork::SVNetwork(const char* hostname, int port) { 00384 mutex_send_ = new SVMutex(); 00385 msg_buffer_in_ = new char[kMaxMsgSize + 1]; 00386 msg_buffer_in_[0] = '\0'; 00387 00388 has_content = false; 00389 buffer_ptr_ = NULL; 00390 00391 struct addrinfo *addr_info = NULL; 00392 00393 if (GetAddrInfo(hostname, port, &addr_info) != 0) { 00394 std::cerr << "Error resolving name for ScrollView host " 00395 << std::string(hostname) << ":" << port << std::endl; 00396 } 00397 00398 stream_ = socket(addr_info->ai_family, addr_info->ai_socktype, 00399 addr_info->ai_protocol); 00400 00401 // If server is not there, we will start a new server as local child process. 00402 if (connect(stream_, addr_info->ai_addr, addr_info->ai_addrlen) < 0) { 00403 const char* scrollview_path = getenv("SCROLLVIEW_PATH"); 00404 if (scrollview_path == NULL) { 00405 #ifdef SCROLLVIEW_PATH 00406 #define _STR(a) #a 00407 #define _XSTR(a) _STR(a) 00408 scrollview_path = _XSTR(SCROLLVIEW_PATH); 00409 #undef _XSTR 00410 #undef _STR 00411 #else 00412 scrollview_path = "."; 00413 #endif 00414 } 00415 const char *prog = ScrollViewProg(); 00416 std::string command = ScrollViewCommand(scrollview_path); 00417 SVSync::StartProcess(prog, command.c_str()); 00418 00419 // Wait for server to show up. 00420 // Note: There is no exception handling in case the server never turns up. 00421 00422 stream_ = socket(addr_info->ai_family, addr_info->ai_socktype, 00423 addr_info->ai_protocol); 00424 00425 while (connect(stream_, addr_info->ai_addr, 00426 addr_info->ai_addrlen) < 0) { 00427 std::cout << "ScrollView: Waiting for server...\n"; 00428 #ifdef _WIN32 00429 Sleep(1000); 00430 #else 00431 sleep(1); 00432 #endif 00433 00434 stream_ = socket(addr_info->ai_family, addr_info->ai_socktype, 00435 addr_info->ai_protocol); 00436 } 00437 } 00438 FreeAddrInfo(addr_info); 00439 } 00440 00441 SVNetwork::~SVNetwork() { 00442 delete[] msg_buffer_in_; 00443 delete mutex_send_; 00444 } 00445 00446 #endif // GRAPHICS_DISABLED