Tesseract
3.02
|
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/socket.h> 00042 #ifdef __linux__ 00043 #include <sys/prctl.h> 00044 #endif 00045 #include <unistd.h> 00046 #endif 00047 00048 #include <cstdlib> 00049 #include <cstring> 00050 #include <iostream> 00051 #include <string> 00052 00053 // Include automatically generated configuration file if running autoconf. 00054 #ifdef HAVE_CONFIG_H 00055 #include "config_auto.h" 00056 #endif 00057 00058 #ifndef GRAPHICS_DISABLED 00059 00060 #include "svutil.h" 00061 00062 const int kBufferSize = 65536; 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 #ifdef _WIN32 00077 std::string proc; 00078 proc.append(executable); 00079 proc.append(" "); 00080 proc.append(args); 00081 std::cout << "Starting " << proc << std::endl; 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 #else 00129 sem_init(&semaphore_, 0, 0); 00130 #endif 00131 } 00132 00133 void SVSemaphore::Signal() { 00134 #ifdef _WIN32 00135 ReleaseSemaphore(semaphore_, 1, NULL); 00136 #else 00137 sem_post(&semaphore_); 00138 #endif 00139 } 00140 00141 void SVSemaphore::Wait() { 00142 #ifdef _WIN32 00143 WaitForSingleObject(semaphore_, INFINITE); 00144 #else 00145 sem_wait(&semaphore_); 00146 #endif 00147 } 00148 00149 SVMutex::SVMutex() { 00150 #ifdef _WIN32 00151 mutex_ = CreateMutex(0, FALSE, 0); 00152 #else 00153 pthread_mutex_init(&mutex_, NULL); 00154 #endif 00155 } 00156 00157 void SVMutex::Lock() { 00158 #ifdef _WIN32 00159 WaitForSingleObject(mutex_, INFINITE); 00160 #else 00161 pthread_mutex_lock(&mutex_); 00162 #endif 00163 } 00164 00165 void SVMutex::Unlock() { 00166 #ifdef _WIN32 00167 ReleaseMutex(mutex_); 00168 #else 00169 pthread_mutex_unlock(&mutex_); 00170 #endif 00171 } 00172 00173 // Create new thread. 00174 00175 void SVSync::StartThread(void *(*func)(void*), void* arg) { 00176 #ifdef _WIN32 00177 LPTHREAD_START_ROUTINE f = (LPTHREAD_START_ROUTINE) func; 00178 DWORD threadid; 00179 HANDLE newthread = CreateThread( 00180 NULL, // default security attributes 00181 0, // use default stack size 00182 f, // thread function 00183 arg, // argument to thread function 00184 0, // use default creation flags 00185 &threadid); // returns the thread identifier 00186 #else 00187 pthread_t helper; 00188 pthread_create(&helper, NULL, func, arg); 00189 #endif 00190 } 00191 00192 // Place a message in the message buffer (and flush it). 00193 void SVNetwork::Send(const char* msg) { 00194 mutex_send_->Lock(); 00195 msg_buffer_out_.append(msg); 00196 mutex_send_->Unlock(); 00197 } 00198 00199 // Send the whole buffer. 00200 void SVNetwork::Flush() { 00201 mutex_send_->Lock(); 00202 while (msg_buffer_out_.size() > 0) { 00203 int i = send(stream_, msg_buffer_out_.c_str(), msg_buffer_out_.length(), 0); 00204 msg_buffer_out_.erase(0, i); 00205 } 00206 mutex_send_->Unlock(); 00207 } 00208 00209 // Receive a message from the server. 00210 // This will always return one line of char* (denoted by \n). 00211 char* SVNetwork::Receive() { 00212 char* result = NULL; 00213 #ifdef _WIN32 00214 if (has_content) { result = strtok (NULL, "\n"); } 00215 #else 00216 if (buffer_ptr_ != NULL) { result = strtok_r(NULL, "\n", &buffer_ptr_); } 00217 #endif 00218 00219 // This means there is something left in the buffer and we return it. 00220 if (result != NULL) { return result; 00221 // Otherwise, we read from the stream_. 00222 } else { 00223 buffer_ptr_ = NULL; 00224 has_content = false; 00225 00226 // The timeout length is not really important since we are looping anyway 00227 // until a new message is delivered. 00228 struct timeval tv; 00229 tv.tv_sec = 10; 00230 tv.tv_usec = 0; 00231 00232 // Set the flags to return when the stream_ is ready to be read. 00233 fd_set readfds; 00234 FD_ZERO(&readfds); 00235 FD_SET(stream_, &readfds); 00236 00237 int i = select(stream_+1, &readfds, NULL, NULL, &tv); 00238 00239 // The stream_ died. 00240 if (i == 0) { return NULL; } 00241 00242 // Read the message buffer. 00243 i = recv(stream_, msg_buffer_in_, kMaxMsgSize, 0); 00244 00245 // Server quit (0) or error (-1). 00246 if (i <= 0) { return NULL; } 00247 msg_buffer_in_[i] = '\0'; 00248 has_content = true; 00249 #ifdef _WIN32 00250 return strtok(msg_buffer_in_, "\n"); 00251 #else 00252 // Setup a new string tokenizer. 00253 return strtok_r(msg_buffer_in_, "\n", &buffer_ptr_); 00254 #endif 00255 } 00256 } 00257 00258 // Close the connection to the server. 00259 void SVNetwork::Close() { 00260 #ifdef _WIN32 00261 closesocket(stream_); 00262 #else 00263 close(stream_); 00264 #endif 00265 } 00266 00267 00268 // The program to invoke to start ScrollView 00269 static const char* ScrollViewProg() { 00270 #ifdef _WIN32 00271 const char* prog = "java -Xms512m -Xmx1024m"; 00272 #else 00273 const char* prog = "sh"; 00274 #endif 00275 return prog; 00276 } 00277 00278 00279 // The arguments to the program to invoke to start ScrollView 00280 static std::string ScrollViewCommand(std::string scrollview_path) { 00281 // The following ugly ifdef is to enable the output of the java runtime 00282 // to be sent down a black hole on non-windows to ignore all the 00283 // exceptions in piccolo. Ideally piccolo would be debugged to make 00284 // this unnecessary. 00285 // Also the path has to be separated by ; on windows and : otherwise. 00286 #ifdef _WIN32 00287 const char* cmd_template = "-Djava.library.path=%s -cp %s/ScrollView.jar;" 00288 "%s/piccolo-1.2.jar;%s/piccolox-1.2.jar" 00289 " com.google.scrollview.ScrollView"; 00290 #else 00291 const char* cmd_template = "-c \"trap 'kill %1' 0 1 2 ; java " 00292 "-Xms1024m -Xmx2048m -Djava.library.path=%s -cp %s/ScrollView.jar:" 00293 "%s/piccolo-1.2.jar:%s/piccolox-1.2.jar" 00294 " com.google.scrollview.ScrollView" 00295 " >/dev/null 2>&1 & wait\""; 00296 #endif 00297 int cmdlen = strlen(cmd_template) + 4*strlen(scrollview_path.c_str()) + 1; 00298 char* cmd = new char[cmdlen]; 00299 const char* sv_path = scrollview_path.c_str(); 00300 snprintf(cmd, cmdlen, cmd_template, sv_path, sv_path, sv_path, sv_path); 00301 std::string command(cmd); 00302 delete [] cmd; 00303 return command; 00304 } 00305 00306 00307 // Platform-independent freeaddrinfo() 00308 static void FreeAddrInfo(struct addrinfo* addr_info) { 00309 #if defined(__linux__) 00310 freeaddrinfo(addr_info); 00311 #else 00312 delete addr_info->ai_addr; 00313 delete addr_info; 00314 #endif 00315 } 00316 00317 00318 // Non-linux version of getaddrinfo() 00319 #if !defined(__linux__) 00320 static int GetAddrInfoNonLinux(const char* hostname, int port, 00321 struct addrinfo** addr_info) { 00322 // Get the host data depending on the OS. 00323 struct sockaddr_in* address; 00324 *addr_info = new struct addrinfo; 00325 memset(*addr_info, 0, sizeof(struct addrinfo)); 00326 address = new struct sockaddr_in; 00327 memset(address, 0, sizeof(struct sockaddr_in)); 00328 00329 (*addr_info)->ai_addr = (struct sockaddr*) address; 00330 (*addr_info)->ai_addrlen = sizeof(struct sockaddr); 00331 (*addr_info)->ai_family = AF_INET; 00332 (*addr_info)->ai_socktype = SOCK_STREAM; 00333 00334 struct hostent *name; 00335 #ifdef _WIN32 00336 WSADATA wsaData; 00337 WSAStartup(MAKEWORD(1, 1), &wsaData); 00338 name = gethostbyname(hostname); 00339 #else 00340 name = gethostbyname(hostname); 00341 #endif 00342 00343 if (name == NULL) { 00344 FreeAddrInfo(*addr_info); 00345 *addr_info = NULL; 00346 return -1; 00347 } 00348 00349 // Fill in the appropriate variables to be able to connect to the server. 00350 address->sin_family = name->h_addrtype; 00351 memcpy((char *) &address->sin_addr.s_addr, 00352 name->h_addr_list[0], name->h_length); 00353 address->sin_port = htons(port); 00354 return 0; 00355 } 00356 #endif 00357 00358 00359 // Platform independent version of getaddrinfo() 00360 // Given a hostname:port, produce an addrinfo struct 00361 static int GetAddrInfo(const char* hostname, int port, 00362 struct addrinfo** address) { 00363 #if defined(__linux__) 00364 char port_str[40]; 00365 snprintf(port_str, 40, "%d", port); 00366 return getaddrinfo(hostname, port_str, NULL, address); 00367 #else 00368 return GetAddrInfoNonLinux(hostname, port, address); 00369 #endif 00370 } 00371 00372 00373 // Set up a connection to a ScrollView on hostname:port. 00374 SVNetwork::SVNetwork(const char* hostname, int port) { 00375 mutex_send_ = new SVMutex(); 00376 msg_buffer_in_ = new char[kMaxMsgSize + 1]; 00377 msg_buffer_in_[0] = '\0'; 00378 00379 has_content = false; 00380 buffer_ptr_ = NULL; 00381 00382 struct addrinfo *addr_info = NULL; 00383 00384 if (GetAddrInfo(hostname, port, &addr_info) != 0) { 00385 std::cerr << "Error resolving name for ScrollView host " 00386 << std::string(hostname) << ":" << port << std::endl; 00387 } 00388 00389 stream_ = socket(addr_info->ai_family, addr_info->ai_socktype, 00390 addr_info->ai_protocol); 00391 00392 // If server is not there, we will start a new server as local child process. 00393 if (connect(stream_, addr_info->ai_addr, addr_info->ai_addrlen) < 0) { 00394 const char* scrollview_path = getenv("SCROLLVIEW_PATH"); 00395 if (scrollview_path == NULL) { 00396 #ifdef SCROLLVIEW_PATH 00397 #define _STR(a) #a 00398 #define _XSTR(a) _STR(a) 00399 scrollview_path = _XSTR(SCROLLVIEW_PATH); 00400 #undef _XSTR 00401 #undef _STR 00402 #else 00403 scrollview_path = "."; 00404 #endif 00405 } 00406 const char *prog = ScrollViewProg(); 00407 std::string command = ScrollViewCommand(scrollview_path); 00408 SVSync::StartProcess(prog, command.c_str()); 00409 00410 // Wait for server to show up. 00411 // Note: There is no exception handling in case the server never turns up. 00412 while (connect(stream_, (struct sockaddr *) addr_info->ai_addr, 00413 addr_info->ai_addrlen) < 0) { 00414 std::cout << "ScrollView: Waiting for server...\n"; 00415 #ifdef _WIN32 00416 Sleep(1000); 00417 #else 00418 sleep(1); 00419 #endif 00420 } 00421 } 00422 FreeAddrInfo(addr_info); 00423 } 00424 00425 SVNetwork::~SVNetwork() { 00426 delete[] msg_buffer_in_; 00427 delete mutex_send_; 00428 } 00429 00430 #endif // GRAPHICS_DISABLED