tesseract
3.03
|
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 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), "%d", 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 #ifdef _WIN32 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 -cp %s/ScrollView.jar;" 00300 "%s/piccolo2d-core-3.0.jar:%s/piccolo2d-extras-3.0.jar" 00301 " com.google.scrollview.ScrollView"; 00302 #else 00303 const char* cmd_template = "-c \"trap 'kill %%1' 0 1 2 ; java " 00304 "-Xms1024m -Xmx2048m -Djava.library.path=%s -cp %s/ScrollView.jar:" 00305 "%s/piccolo2d-core-3.0.jar:%s/piccolo2d-extras-3.0.jar" 00306 " com.google.scrollview.ScrollView" 00307 " & wait\""; 00308 #endif 00309 int cmdlen = strlen(cmd_template) + 4*strlen(scrollview_path.c_str()) + 1; 00310 char* cmd = new char[cmdlen]; 00311 const char* sv_path = scrollview_path.c_str(); 00312 snprintf(cmd, cmdlen, cmd_template, sv_path, sv_path, sv_path, sv_path); 00313 std::string command(cmd); 00314 delete [] cmd; 00315 return command; 00316 } 00317 00318 00319 // Platform-independent freeaddrinfo() 00320 static void FreeAddrInfo(struct addrinfo* addr_info) { 00321 #if defined(__linux__) 00322 freeaddrinfo(addr_info); 00323 #else 00324 delete addr_info->ai_addr; 00325 delete addr_info; 00326 #endif 00327 } 00328 00329 00330 // Non-linux version of getaddrinfo() 00331 #if !defined(__linux__) 00332 static int GetAddrInfoNonLinux(const char* hostname, int port, 00333 struct addrinfo** addr_info) { 00334 // Get the host data depending on the OS. 00335 struct sockaddr_in* address; 00336 *addr_info = new struct addrinfo; 00337 memset(*addr_info, 0, sizeof(struct addrinfo)); 00338 address = new struct sockaddr_in; 00339 memset(address, 0, sizeof(struct sockaddr_in)); 00340 00341 (*addr_info)->ai_addr = (struct sockaddr*) address; 00342 (*addr_info)->ai_addrlen = sizeof(struct sockaddr); 00343 (*addr_info)->ai_family = AF_INET; 00344 (*addr_info)->ai_socktype = SOCK_STREAM; 00345 00346 struct hostent *name; 00347 #ifdef _WIN32 00348 WSADATA wsaData; 00349 WSAStartup(MAKEWORD(1, 1), &wsaData); 00350 name = gethostbyname(hostname); 00351 #else 00352 name = gethostbyname(hostname); 00353 #endif 00354 00355 if (name == NULL) { 00356 FreeAddrInfo(*addr_info); 00357 *addr_info = NULL; 00358 return -1; 00359 } 00360 00361 // Fill in the appropriate variables to be able to connect to the server. 00362 address->sin_family = name->h_addrtype; 00363 memcpy((char *) &address->sin_addr.s_addr, 00364 name->h_addr_list[0], name->h_length); 00365 address->sin_port = htons(port); 00366 return 0; 00367 } 00368 #endif 00369 00370 00371 // Platform independent version of getaddrinfo() 00372 // Given a hostname:port, produce an addrinfo struct 00373 static int GetAddrInfo(const char* hostname, int port, 00374 struct addrinfo** address) { 00375 #if defined(__linux__) 00376 char port_str[40]; 00377 snprintf(port_str, 40, "%d", port); 00378 return getaddrinfo(hostname, port_str, NULL, address); 00379 #else 00380 return GetAddrInfoNonLinux(hostname, port, address); 00381 #endif 00382 } 00383 00384 00385 // Set up a connection to a ScrollView on hostname:port. 00386 SVNetwork::SVNetwork(const char* hostname, int port) { 00387 mutex_send_ = new SVMutex(); 00388 msg_buffer_in_ = new char[kMaxMsgSize + 1]; 00389 msg_buffer_in_[0] = '\0'; 00390 00391 has_content = false; 00392 buffer_ptr_ = NULL; 00393 00394 struct addrinfo *addr_info = NULL; 00395 00396 if (GetAddrInfo(hostname, port, &addr_info) != 0) { 00397 std::cerr << "Error resolving name for ScrollView host " 00398 << std::string(hostname) << ":" << port << std::endl; 00399 } 00400 00401 stream_ = socket(addr_info->ai_family, addr_info->ai_socktype, 00402 addr_info->ai_protocol); 00403 00404 // If server is not there, we will start a new server as local child process. 00405 if (connect(stream_, addr_info->ai_addr, addr_info->ai_addrlen) < 0) { 00406 const char* scrollview_path = getenv("SCROLLVIEW_PATH"); 00407 if (scrollview_path == NULL) { 00408 #ifdef SCROLLVIEW_PATH 00409 #define _STR(a) #a 00410 #define _XSTR(a) _STR(a) 00411 scrollview_path = _XSTR(SCROLLVIEW_PATH); 00412 #undef _XSTR 00413 #undef _STR 00414 #else 00415 scrollview_path = "."; 00416 #endif 00417 } 00418 const char *prog = ScrollViewProg(); 00419 std::string command = ScrollViewCommand(scrollview_path); 00420 SVSync::StartProcess(prog, command.c_str()); 00421 00422 // Wait for server to show up. 00423 // Note: There is no exception handling in case the server never turns up. 00424 00425 stream_ = socket(addr_info->ai_family, addr_info->ai_socktype, 00426 addr_info->ai_protocol); 00427 00428 while (connect(stream_, addr_info->ai_addr, 00429 addr_info->ai_addrlen) < 0) { 00430 std::cout << "ScrollView: Waiting for server...\n"; 00431 #ifdef _WIN32 00432 Sleep(1000); 00433 #else 00434 sleep(1); 00435 #endif 00436 00437 stream_ = socket(addr_info->ai_family, addr_info->ai_socktype, 00438 addr_info->ai_protocol); 00439 } 00440 } 00441 FreeAddrInfo(addr_info); 00442 } 00443 00444 SVNetwork::~SVNetwork() { 00445 delete[] msg_buffer_in_; 00446 delete mutex_send_; 00447 } 00448 00449 #endif // GRAPHICS_DISABLED