tesseract 3.04.01

viewer/svutil.cpp

Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines