00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00031
00032 #ifdef HAVE_CONFIG_H
00033 #include "autoconfig.h"
00034 #endif
00035
00036 #ifdef EXTERNAL_TRANSCODING
00037
00038 #include <sys/types.h>
00039 #include <sys/stat.h>
00040 #include <fcntl.h>
00041 #include <signal.h>
00042 #include <unistd.h>
00043 #include "common.h"
00044 #include "process_io_handler.h"
00045 #include "process.h"
00046 #include "content_manager.h"
00047
00048
00049
00050
00051
00052 #define MAX_TIMEOUTS 2 // maximum allowe consecutive timeouts
00053
00054 using namespace zmm;
00055
00056 ProcListItem::ProcListItem(Ref<Executor> exec, bool abortOnDeath)
00057 {
00058 executor = exec;
00059 abort = abortOnDeath;
00060 }
00061
00062 Ref<Executor> ProcListItem::getExecutor()
00063 {
00064 return executor;
00065 }
00066
00067 bool ProcListItem::abortOnDeath()
00068 {
00069 return abort;
00070 }
00071
00072 bool ProcessIOHandler::abort()
00073 {
00074 bool abort = false;
00075
00076 if (proclist == nil)
00077 return abort;
00078
00079 for (int i = 0; i < proclist->size(); i++)
00080 {
00081 Ref<Executor> exec = proclist->get(i)->getExecutor();
00082 if ((exec != nil) && (!exec->isAlive()))
00083 {
00084 if (proclist->get(i)->abortOnDeath())
00085 abort = true;
00086 break;
00087 }
00088 }
00089
00090 return abort;
00091 }
00092
00093 void ProcessIOHandler::killall()
00094 {
00095 if (proclist == nil)
00096 return;
00097
00098 for (int i = 0; i < proclist->size(); i++)
00099 {
00100 Ref<Executor> exec = proclist->get(i)->getExecutor();
00101 if (exec != nil)
00102 exec->kill();
00103 }
00104 }
00105
00106 void ProcessIOHandler::registerAll()
00107 {
00108 if (main_proc != nil)
00109 ContentManager::getInstance()->registerExecutor(main_proc);
00110
00111 if (proclist == nil)
00112 return;
00113
00114 for (int i = 0; i < proclist->size(); i++)
00115 {
00116 Ref<Executor> exec = proclist->get(i)->getExecutor();
00117 if (exec != nil)
00118 ContentManager::getInstance()->registerExecutor(exec);
00119 }
00120 }
00121
00122 void ProcessIOHandler::unregisterAll()
00123 {
00124 if (main_proc != nil)
00125 ContentManager::getInstance()->unregisterExecutor(main_proc);
00126
00127 if (proclist == nil)
00128 return;
00129
00130 for (int i = 0; i < proclist->size(); i++)
00131 {
00132 Ref<Executor> exec = proclist->get(i)->getExecutor();
00133 if (exec != nil)
00134 ContentManager::getInstance()->unregisterExecutor(exec);
00135 }
00136 }
00137
00138 ProcessIOHandler::ProcessIOHandler(String filename,
00139 zmm::Ref<Executor> main_proc,
00140 zmm::Ref<zmm::Array<ProcListItem> > proclist,
00141 bool ignoreSeek) : IOHandler()
00142 {
00143 this->filename = filename;
00144 this->proclist = proclist;
00145 this->main_proc = main_proc;
00146 this->ignore_seek = ignoreSeek;
00147
00148 if ((main_proc != nil) && ((!main_proc->isAlive() || abort())))
00149 {
00150 killall();
00151 throw _Exception(_("process terminated early"));
00152 }
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164 registerAll();
00165 }
00166
00167 void ProcessIOHandler::open(IN enum UpnpOpenFileMode mode)
00168 {
00169 if ((main_proc != nil) && ((!main_proc->isAlive() || abort())))
00170 {
00171 killall();
00172 throw _Exception(_("process terminated early"));
00173 }
00174
00175 if (mode == UPNP_READ)
00176 fd = ::open(filename.c_str(), O_RDONLY | O_NONBLOCK);
00177 else if (mode == UPNP_WRITE)
00178 fd = ::open(filename.c_str(), O_WRONLY | O_NONBLOCK);
00179 else
00180 fd = -1;
00181
00182 if (fd == -1)
00183 {
00184 if (errno == ENXIO)
00185 {
00186 throw _TryAgainException(_("open failed: ") + strerror(errno));
00187 }
00188
00189 killall();
00190 if (main_proc != nil)
00191 main_proc->kill();
00192 unlink(filename.c_str());
00193 throw _Exception(_("open: failed to open: ") + filename.c_str());
00194 }
00195 }
00196
00197 int ProcessIOHandler::read(OUT char *buf, IN size_t length)
00198 {
00199 fd_set readSet;
00200 struct timeval timeout;
00201 ssize_t bytes_read = 0;
00202 int num_bytes = 0;
00203 char* p_buffer = buf;
00204 int exit_status = EXIT_SUCCESS;
00205 int ret = 0;
00206 int timeout_count = 0;
00207
00208 while (true)
00209 {
00210 FD_ZERO(&readSet);
00211 FD_SET(fd, &readSet);
00212
00213 timeout.tv_sec = FIFO_READ_TIMEOUT;
00214 timeout.tv_usec = 0;
00215
00216 ret = select(fd + 1, &readSet, NULL, NULL, &timeout);
00217 if (ret == -1)
00218 {
00219 if (errno == EINTR)
00220 continue;
00221 }
00222
00223
00224 if (ret == 0)
00225 {
00226 if (main_proc != nil)
00227 {
00228 bool main_ok = main_proc->isAlive();
00229 if (!main_ok || abort())
00230 {
00231 if (!main_ok)
00232 {
00233 exit_status = main_proc->getStatus();
00234 log_debug("process exited with status %d\n", exit_status);
00235 killall();
00236 if (exit_status == EXIT_SUCCESS)
00237 return 0;
00238 else
00239 return -1;
00240 }
00241 else
00242 {
00243 main_proc->kill();
00244 killall();
00245 return -1;
00246 }
00247 }
00248 }
00249 else
00250 {
00251 killall();
00252 return 0;
00253 }
00254
00255 timeout_count++;
00256 if (timeout_count > MAX_TIMEOUTS)
00257 {
00258 log_debug("max timeouts, checking socket!\n");
00259 return CHECK_SOCKET;
00260 }
00261 }
00262
00263 if (FD_ISSET(fd, &readSet))
00264 {
00265 timeout_count = 0;
00266 bytes_read = ::read(fd, p_buffer, length);
00267 if (bytes_read == 0)
00268 break;
00269
00270 if (bytes_read < 0)
00271 {
00272 log_debug("aborting read!!!\n");
00273 return -1;
00274 }
00275
00276 num_bytes = num_bytes + bytes_read;
00277 length = length - bytes_read;
00278
00279 if (length <= 0)
00280 break;
00281
00282 p_buffer = buf + num_bytes;
00283 }
00284 }
00285
00286 if (num_bytes < 0)
00287 {
00288
00289
00290 ret = -1;
00291
00292 if (main_proc != nil)
00293 {
00294 if (!main_proc->isAlive())
00295 {
00296 if (main_proc->getStatus() == EXIT_SUCCESS)
00297 ret = 0;
00298
00299 }
00300 else
00301 {
00302 main_proc->kill();
00303 }
00304 }
00305 else
00306 ret = 0;
00307
00308 killall();
00309 return ret;
00310 }
00311
00312 return num_bytes;
00313 }
00314
00315 int ProcessIOHandler::write(IN char *buf, IN size_t length)
00316 {
00317 fd_set writeSet;
00318 struct timeval timeout;
00319 ssize_t bytes_written = 0;
00320 int num_bytes = 0;
00321 char* p_buffer = buf;
00322 int exit_status = EXIT_SUCCESS;
00323 int ret = 0;
00324
00325 while (true)
00326 {
00327 FD_ZERO(&writeSet);
00328 FD_SET(fd, &writeSet);
00329
00330 timeout.tv_sec = FIFO_WRITE_TIMEOUT;
00331 timeout.tv_usec = 0;
00332
00333 ret = select(fd + 1, NULL, &writeSet, NULL, &timeout);
00334 if (ret == -1)
00335 {
00336 if (errno == EINTR)
00337 {
00338 continue;
00339 }
00340 }
00341
00342
00343 if (ret == 0)
00344 {
00345 if (main_proc != nil)
00346 {
00347 bool main_ok = main_proc->isAlive();
00348 if (!main_ok || abort())
00349 {
00350 if (!main_ok)
00351 {
00352 exit_status = main_proc->getStatus();
00353 log_debug("process exited with status %d\n", exit_status);
00354 killall();
00355 if (exit_status == EXIT_SUCCESS)
00356 return 0;
00357 else
00358 return -1;
00359 }
00360 else
00361 {
00362 main_proc->kill();
00363 killall();
00364 return -1;
00365 }
00366 }
00367 }
00368 else
00369 {
00370 killall();
00371 return 0;
00372 }
00373 }
00374
00375 if (FD_ISSET(fd, &writeSet))
00376 {
00377 bytes_written= ::write(fd, p_buffer, length);
00378 if (bytes_written == 0)
00379 break;
00380
00381 if (bytes_written < 0)
00382 {
00383 log_debug("aborting write!!!\n");
00384 return -1;
00385 }
00386
00387 num_bytes = num_bytes + bytes_written;
00388 length = length - bytes_written;
00389 if (length <= 0)
00390 break;
00391
00392 p_buffer = buf + num_bytes;
00393 }
00394 }
00395
00396 if (num_bytes < 0)
00397 {
00398
00399
00400 ret = -1;
00401
00402 if (main_proc != nil)
00403 {
00404 if (!main_proc->isAlive())
00405 {
00406 if (main_proc->getStatus() == EXIT_SUCCESS)
00407 ret = 0;
00408
00409 }
00410 else
00411 {
00412 main_proc->kill();
00413 }
00414 }
00415 else
00416 ret = 0;
00417
00418 killall();
00419 return ret;
00420 }
00421
00422 return num_bytes;
00423 }
00424
00425
00426 void ProcessIOHandler::seek(IN off_t offset, IN int whence)
00427 {
00428
00429 if (!ignore_seek)
00430 throw _Exception(_("fseek failed"));
00431 }
00432
00433 void ProcessIOHandler::close()
00434 {
00435 bool ret;
00436
00437
00438 log_debug("terminating process, closing %s\n", this->filename.c_str());
00439 unregisterAll();
00440
00441 if (main_proc != nil)
00442 {
00443 ret = main_proc->kill();
00444 }
00445 else
00446 ret = true;
00447
00448 killall();
00449
00450 ::close(fd);
00451
00452 unlink(filename.c_str());
00453
00454 if (!ret)
00455 throw _Exception(_("failed to kill process!"));
00456 }
00457
00458 ProcessIOHandler::~ProcessIOHandler()
00459 {
00460 try
00461 {
00462 close();
00463 }
00464 catch (Exception ex) {}
00465 }
00466
00467 #endif // EXTERNAL_TRANSCODING